From 32ab4dcac723e189ce8a1be796f0539975a48eae Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 15:52:30 -0400 Subject: Implement rate utils --- packages/order-utils/src/index.ts | 1 + packages/order-utils/src/rate_utils.ts | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 packages/order-utils/src/rate_utils.ts (limited to 'packages') diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts index 858f500c6..a52f936b6 100644 --- a/packages/order-utils/src/index.ts +++ b/packages/order-utils/src/index.ts @@ -33,3 +33,4 @@ export { EIP712Utils } from './eip712_utils'; export { OrderValidationUtils } from './order_validation_utils'; export { ExchangeTransferSimulator } from './exchange_transfer_simulator'; export { marketUtils } from './market_utils'; +export { rateUtils } from './rate_utils'; diff --git a/packages/order-utils/src/rate_utils.ts b/packages/order-utils/src/rate_utils.ts new file mode 100644 index 000000000..212431e0c --- /dev/null +++ b/packages/order-utils/src/rate_utils.ts @@ -0,0 +1,44 @@ +import { schemas } from '@0xproject/json-schemas'; +import { SignedOrder } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; + +import { assert } from './assert'; +import { constants } from './constants'; + +export const rateUtils = { + /** + * Takes a signed order and calculates the fee adjusted rate (takerAsset/makerAsset) by calculating how much takerAsset + * is required to cover the fees (feeRate * takerFee), adding the takerAssetAmount and dividing by makerAssetAmount + * @param signedOrder An object that conforms to the signedOrder interface + * @param feeRate The market rate of ZRX denominated in takerAssetAmount + * (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) + * @return The rate (takerAsset/makerAsset) of the order adjusted for fees + */ + getFeeAdjustedRateOfOrder(signedOrder: SignedOrder, feeRate: BigNumber): BigNumber { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + assert.isBigNumber('feeRate', feeRate); + assert.assert(feeRate.greaterThan(constants.ZERO_AMOUNT), `Expected feeRate: ${feeRate} to be greater than 0`); + const takerAssetAmountNeededToPayForFees = signedOrder.takerFee.mul(feeRate); + const totalTakerAssetAmount = takerAssetAmountNeededToPayForFees.plus(signedOrder.takerAssetAmount); + const rate = totalTakerAssetAmount.div(signedOrder.makerAssetAmount); + return rate; + }, + /** + * Takes a signed fee order (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) and calculates + * the fee adjusted rate (WETH/ZRX) by dividing the takerAssetAmount by the makerAmount minus the takerFee + * @param signedFeeOrder An object that conforms to the signedOrder interface + * @return The rate (WETH/ZRX) of the fee order adjusted for fees + */ + getFeeAdjustedRateOfFeeOrder(signedFeeOrder: SignedOrder): BigNumber { + assert.doesConformToSchema('signedFeeOrder', signedFeeOrder, schemas.signedOrderSchema); + const zrxAmountAfterFees = signedFeeOrder.makerAssetAmount.sub(signedFeeOrder.takerFee); + assert.assert( + zrxAmountAfterFees.greaterThan(constants.ZERO_AMOUNT), + `Expected takerFee: ${JSON.stringify( + signedFeeOrder.takerFee, + )} to be less than makerAssetAmount: ${JSON.stringify(signedFeeOrder.makerAssetAmount)}`, + ); + const rate = signedFeeOrder.takerAssetAmount.div(zrxAmountAfterFees); + return rate; + }, +}; -- cgit v1.2.3 From a1860b076d9d3408e64d8ff5e6bc0657e9ff7e7b Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 17:24:08 -0400 Subject: Add tests for rateUtils --- packages/order-utils/test/rate_utils_test.ts | 55 ++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 packages/order-utils/test/rate_utils_test.ts (limited to 'packages') diff --git a/packages/order-utils/test/rate_utils_test.ts b/packages/order-utils/test/rate_utils_test.ts new file mode 100644 index 000000000..2f321a7db --- /dev/null +++ b/packages/order-utils/test/rate_utils_test.ts @@ -0,0 +1,55 @@ +import { BigNumber } from '@0xproject/utils'; +import * as chai from 'chai'; +import 'mocha'; + +import { constants, rateUtils } from '../src'; + +import { chaiSetup } from './utils/chai_setup'; +import { testOrderFactory } from './utils/test_order_factory'; + +chaiSetup.configure(); +const expect = chai.expect; + +describe('rateUtils', () => { + const testOrder = testOrderFactory.generateTestSignedOrder({ + makerAssetAmount: new BigNumber(100), + takerAssetAmount: new BigNumber(100), + takerFee: new BigNumber(20), + }); + describe('#getFeeAdjustedRateOfOrder', () => { + it('throws when feeRate is zero', async () => { + const feeRate = constants.ZERO_AMOUNT; + expect(() => rateUtils.getFeeAdjustedRateOfOrder(testOrder, feeRate)).to.throw( + 'Expected feeRate: 0 to be greater than 0', + ); + }); + it('throws when feeRate is less than zero', async () => { + const feeRate = new BigNumber(-1); + expect(() => rateUtils.getFeeAdjustedRateOfOrder(testOrder, feeRate)).to.throw( + 'Expected feeRate: -1 to be greater than 0', + ); + }); + it('correctly calculates fee adjusted rate', async () => { + const feeRate = new BigNumber(2); // ZRX costs 2 units of takerAsset per 1 unit of ZRX + const feeAdjustedRate = rateUtils.getFeeAdjustedRateOfOrder(testOrder, feeRate); + // the order actually takes 100 + (2 * 20) takerAsset units to fill 100 units of makerAsset + expect(feeAdjustedRate).to.bignumber.equal(new BigNumber(1.4)); + }); + }); + describe('#getFeeAdjustedRateOfFeeOrder', () => { + it('throws when takerFee exceeds makerAssetAmount', async () => { + const badOrder = testOrderFactory.generateTestSignedOrder({ + makerAssetAmount: new BigNumber(100), + takerFee: new BigNumber(101), + }); + expect(() => rateUtils.getFeeAdjustedRateOfFeeOrder(badOrder)).to.throw( + 'Expected takerFee: "101" to be less than makerAssetAmount: "100"', + ); + }); + it('correctly calculates fee adjusted rate', async () => { + const feeAdjustedRate = rateUtils.getFeeAdjustedRateOfFeeOrder(testOrder); + // the order actually takes 100 takerAsset units to fill (100 - 20) units of makerAsset + expect(feeAdjustedRate).to.bignumber.equal(new BigNumber(1.25)); + }); + }); +}); -- cgit v1.2.3 From c0924d8067079f246c5cad32f7acb3d1f6cfd9b9 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 17:49:22 -0400 Subject: Implement sorting utils --- packages/order-utils/src/index.ts | 1 + packages/order-utils/src/sorting_utils.ts | 69 +++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 packages/order-utils/src/sorting_utils.ts (limited to 'packages') diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts index a52f936b6..359954641 100644 --- a/packages/order-utils/src/index.ts +++ b/packages/order-utils/src/index.ts @@ -34,3 +34,4 @@ export { OrderValidationUtils } from './order_validation_utils'; export { ExchangeTransferSimulator } from './exchange_transfer_simulator'; export { marketUtils } from './market_utils'; export { rateUtils } from './rate_utils'; +export { sortingUtils } from './sorting_utils'; diff --git a/packages/order-utils/src/sorting_utils.ts b/packages/order-utils/src/sorting_utils.ts new file mode 100644 index 000000000..7474a302f --- /dev/null +++ b/packages/order-utils/src/sorting_utils.ts @@ -0,0 +1,69 @@ +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'; +import { rateUtils } from './rate_utils'; + +export const sortingUtils = { + /** + * Takes an array of signed orders and sorts them by takerAsset/makerAsset rate in ascending order (best rate first). + * Adjusts the rate of each order according to the feeRate and takerFee for that order. + * @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 feeRate The market rate of ZRX denominated in takerAssetAmount + * (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) + * @return The input orders sorted by rate in ascending order + */ + sortOrdersByFeeAdjustedRate(signedOrders: SignedOrder[], feeRate: BigNumber): SignedOrder[] { + assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + assert.isBigNumber('feeRate', feeRate); + assert.assert(feeRate.greaterThan(constants.ZERO_AMOUNT), `Expected feeRate: ${feeRate} to be greater than 0`); + const rateCalculator = (signedOrder: SignedOrder) => rateUtils.getFeeAdjustedRateOfOrder(signedOrder, feeRate); + const sortedOrders = sortOrders(signedOrders, rateCalculator); + return sortedOrders; + }, + /** + * Takes an array of signed fee orders (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) + * and sorts them by rate in ascending order (best rate first). Adjusts the rate according to the takerFee. + * @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. + * @return The input orders sorted by rate in ascending order + */ + sortFeeOrdersByFeeAdjustedRate(signedFeeOrders: SignedOrder[]): SignedOrder[] { + assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema); + const rateCalculator = rateUtils.getFeeAdjustedRateOfFeeOrder; + const sortedOrders = sortOrders(signedFeeOrders, rateCalculator); + return sortedOrders; + }, +}; + +type RateCalculator = (signedOrder: SignedOrder) => BigNumber; + +// takes an array of orders, copies them, and sorts the copy based on the rate definition provided by rateCalculator +const sortOrders = (signedOrders: SignedOrder[], rateCalculator: RateCalculator): SignedOrder[] => { + const copiedOrders = _.cloneDeep(signedOrders); + const feeOrderComparator = getOrderComparator(rateCalculator); + copiedOrders.sort(feeOrderComparator); + return copiedOrders; +}; + +type Comparator = (first: T, second: T) => number; + +// takes a function that calculates rate for a signed order and returns a comparator that sorts based on rate +const getOrderComparator = (rateCalculator: RateCalculator): Comparator => ( + firstSignedOrder, + secondSignedOrder, +) => { + const firstOrderRate = rateCalculator(firstSignedOrder); + const secondOrderRate = rateCalculator(secondSignedOrder); + if (firstOrderRate.lt(secondOrderRate)) { + return -1; + } else if (firstOrderRate.gt(secondOrderRate)) { + return 1; + } else { + return 0; + } +}; -- cgit v1.2.3 From fcd57d2743e4b6a1363b8071696147a91d2afb00 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 18:43:31 -0400 Subject: Add tests for sortingUtils --- packages/order-utils/src/sorting_utils.ts | 1 - packages/order-utils/test/sorting_utils_test.ts | 66 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 packages/order-utils/test/sorting_utils_test.ts (limited to 'packages') diff --git a/packages/order-utils/src/sorting_utils.ts b/packages/order-utils/src/sorting_utils.ts index 7474a302f..2acd8180f 100644 --- a/packages/order-utils/src/sorting_utils.ts +++ b/packages/order-utils/src/sorting_utils.ts @@ -20,7 +20,6 @@ export const sortingUtils = { sortOrdersByFeeAdjustedRate(signedOrders: SignedOrder[], feeRate: BigNumber): SignedOrder[] { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); assert.isBigNumber('feeRate', feeRate); - assert.assert(feeRate.greaterThan(constants.ZERO_AMOUNT), `Expected feeRate: ${feeRate} to be greater than 0`); const rateCalculator = (signedOrder: SignedOrder) => rateUtils.getFeeAdjustedRateOfOrder(signedOrder, feeRate); const sortedOrders = sortOrders(signedOrders, rateCalculator); return sortedOrders; diff --git a/packages/order-utils/test/sorting_utils_test.ts b/packages/order-utils/test/sorting_utils_test.ts new file mode 100644 index 000000000..efce13d3f --- /dev/null +++ b/packages/order-utils/test/sorting_utils_test.ts @@ -0,0 +1,66 @@ +import { BigNumber } from '@0xproject/utils'; +import * as chai from 'chai'; +import * as _ from 'lodash'; +import 'mocha'; + +import { constants, rateUtils, sortingUtils } from '../src'; + +import { chaiSetup } from './utils/chai_setup'; +import { testOrderFactory } from './utils/test_order_factory'; + +chaiSetup.configure(); +const expect = chai.expect; + +describe('sortingUtils', () => { + describe('#sortOrdersByFeeAdjustedRate', () => { + // rate: 2 takerAsset / makerAsset + const testOrder1 = testOrderFactory.generateTestSignedOrder({ + makerAssetAmount: new BigNumber(100), + takerAssetAmount: new BigNumber(200), + }); + // rate: 1 takerAsset / makerAsset + const testOrder2 = testOrderFactory.generateTestSignedOrder({ + makerAssetAmount: new BigNumber(100), + takerAssetAmount: new BigNumber(100), + }); + // rate: 2.5 takerAsset / makerAsset + const testOrder3 = testOrderFactory.generateTestSignedOrder({ + makerAssetAmount: new BigNumber(100), + takerAssetAmount: new BigNumber(200), + takerFee: new BigNumber(50), + }); + it('correctly sorts by fee adjusted rate', async () => { + const feeRate = new BigNumber(1); // ZRX costs 1 unit of takerAsset per 1 unit of ZRX + const orders = [testOrder1, testOrder2, testOrder3]; + const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate( + [testOrder1, testOrder2, testOrder3], + feeRate, + ); + expect(sortedOrders).to.deep.equal([testOrder2, testOrder1, testOrder3]); + }); + }); + describe('#sortFeeOrdersByFeeAdjustedRate', () => { + // rate: 200 takerAsset / makerAsset + const testOrder1 = testOrderFactory.generateTestSignedOrder({ + makerAssetAmount: new BigNumber(100), + takerAssetAmount: new BigNumber(200), + takerFee: new BigNumber(99), + }); + // rate: 1 takerAsset / makerAsset + const testOrder2 = testOrderFactory.generateTestSignedOrder({ + makerAssetAmount: new BigNumber(100), + takerAssetAmount: new BigNumber(100), + }); + // rate: 4 takerAsset / makerAsset + const testOrder3 = testOrderFactory.generateTestSignedOrder({ + makerAssetAmount: new BigNumber(100), + takerAssetAmount: new BigNumber(200), + takerFee: new BigNumber(50), + }); + it('correctly sorts by fee adjusted rate', async () => { + const orders = [testOrder1, testOrder2, testOrder3]; + const sortedOrders = sortingUtils.sortFeeOrdersByFeeAdjustedRate([testOrder1, testOrder2, testOrder3]); + expect(sortedOrders).to.deep.equal([testOrder2, testOrder3, testOrder1]); + }); + }); +}); -- cgit v1.2.3 From cbe639866ec9d6088cc7aa133033d2735524c5a0 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 18:54:17 -0400 Subject: Make feeRate optional with a default of 0 --- packages/order-utils/src/rate_utils.ts | 9 +++++++-- packages/order-utils/src/sorting_utils.ts | 6 +++++- packages/order-utils/test/rate_utils_test.ts | 8 +------- 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'packages') diff --git a/packages/order-utils/src/rate_utils.ts b/packages/order-utils/src/rate_utils.ts index 212431e0c..72d11584a 100644 --- a/packages/order-utils/src/rate_utils.ts +++ b/packages/order-utils/src/rate_utils.ts @@ -1,6 +1,7 @@ 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'; @@ -12,12 +13,16 @@ export const rateUtils = { * @param signedOrder An object that conforms to the signedOrder interface * @param feeRate The market rate of ZRX denominated in takerAssetAmount * (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) + * Defaults to 0 * @return The rate (takerAsset/makerAsset) of the order adjusted for fees */ - getFeeAdjustedRateOfOrder(signedOrder: SignedOrder, feeRate: BigNumber): BigNumber { + getFeeAdjustedRateOfOrder(signedOrder: SignedOrder, feeRate: BigNumber = constants.ZERO_AMOUNT): BigNumber { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isBigNumber('feeRate', feeRate); - assert.assert(feeRate.greaterThan(constants.ZERO_AMOUNT), `Expected feeRate: ${feeRate} to be greater than 0`); + assert.assert( + feeRate.gte(constants.ZERO_AMOUNT), + `Expected feeRate: ${feeRate} to be greater than or equal to 0`, + ); const takerAssetAmountNeededToPayForFees = signedOrder.takerFee.mul(feeRate); const totalTakerAssetAmount = takerAssetAmountNeededToPayForFees.plus(signedOrder.takerAssetAmount); const rate = totalTakerAssetAmount.div(signedOrder.makerAssetAmount); diff --git a/packages/order-utils/src/sorting_utils.ts b/packages/order-utils/src/sorting_utils.ts index 2acd8180f..8424060fc 100644 --- a/packages/order-utils/src/sorting_utils.ts +++ b/packages/order-utils/src/sorting_utils.ts @@ -15,9 +15,13 @@ export const sortingUtils = { * the makerAsset and WETH as the takerAsset. * @param feeRate The market rate of ZRX denominated in takerAssetAmount * (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) + * Defaults to 0 * @return The input orders sorted by rate in ascending order */ - sortOrdersByFeeAdjustedRate(signedOrders: SignedOrder[], feeRate: BigNumber): SignedOrder[] { + sortOrdersByFeeAdjustedRate( + signedOrders: SignedOrder[], + feeRate: BigNumber = constants.ZERO_AMOUNT, + ): SignedOrder[] { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); assert.isBigNumber('feeRate', feeRate); const rateCalculator = (signedOrder: SignedOrder) => rateUtils.getFeeAdjustedRateOfOrder(signedOrder, feeRate); diff --git a/packages/order-utils/test/rate_utils_test.ts b/packages/order-utils/test/rate_utils_test.ts index 2f321a7db..167a40465 100644 --- a/packages/order-utils/test/rate_utils_test.ts +++ b/packages/order-utils/test/rate_utils_test.ts @@ -17,16 +17,10 @@ describe('rateUtils', () => { takerFee: new BigNumber(20), }); describe('#getFeeAdjustedRateOfOrder', () => { - it('throws when feeRate is zero', async () => { - const feeRate = constants.ZERO_AMOUNT; - expect(() => rateUtils.getFeeAdjustedRateOfOrder(testOrder, feeRate)).to.throw( - 'Expected feeRate: 0 to be greater than 0', - ); - }); it('throws when feeRate is less than zero', async () => { const feeRate = new BigNumber(-1); expect(() => rateUtils.getFeeAdjustedRateOfOrder(testOrder, feeRate)).to.throw( - 'Expected feeRate: -1 to be greater than 0', + 'Expected feeRate: -1 to be greater than or equal to 0', ); }); it('correctly calculates fee adjusted rate', async () => { -- cgit v1.2.3 From af52598d320462357d3ce40d37cf7de9a4f054ee Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 18:59:29 -0400 Subject: Update tests for optional feeRate --- packages/order-utils/test/rate_utils_test.ts | 8 +++++++- packages/order-utils/test/sorting_utils_test.ts | 9 +++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/order-utils/test/rate_utils_test.ts b/packages/order-utils/test/rate_utils_test.ts index 167a40465..b23a6467a 100644 --- a/packages/order-utils/test/rate_utils_test.ts +++ b/packages/order-utils/test/rate_utils_test.ts @@ -23,12 +23,18 @@ describe('rateUtils', () => { 'Expected feeRate: -1 to be greater than or equal to 0', ); }); - it('correctly calculates fee adjusted rate', async () => { + it('correctly calculates fee adjusted rate when feeRate is provided', async () => { const feeRate = new BigNumber(2); // ZRX costs 2 units of takerAsset per 1 unit of ZRX const feeAdjustedRate = rateUtils.getFeeAdjustedRateOfOrder(testOrder, feeRate); // the order actually takes 100 + (2 * 20) takerAsset units to fill 100 units of makerAsset expect(feeAdjustedRate).to.bignumber.equal(new BigNumber(1.4)); }); + it('correctly calculates fee adjusted rate when no feeRate is provided', async () => { + const feeAdjustedRate = rateUtils.getFeeAdjustedRateOfOrder(testOrder); + // because no feeRate was provided we just assume 0 fees + // the order actually takes 100 takerAsset units to fill 100 units of makerAsset + expect(feeAdjustedRate).to.bignumber.equal(new BigNumber(1)); + }); }); describe('#getFeeAdjustedRateOfFeeOrder', () => { it('throws when takerFee exceeds makerAssetAmount', async () => { diff --git a/packages/order-utils/test/sorting_utils_test.ts b/packages/order-utils/test/sorting_utils_test.ts index efce13d3f..5a33cb2ca 100644 --- a/packages/order-utils/test/sorting_utils_test.ts +++ b/packages/order-utils/test/sorting_utils_test.ts @@ -13,6 +13,7 @@ const expect = chai.expect; describe('sortingUtils', () => { describe('#sortOrdersByFeeAdjustedRate', () => { + const feeRate = new BigNumber(1); // ZRX costs 1 unit of takerAsset per 1 unit of ZRX // rate: 2 takerAsset / makerAsset const testOrder1 = testOrderFactory.generateTestSignedOrder({ makerAssetAmount: new BigNumber(100), @@ -29,8 +30,7 @@ describe('sortingUtils', () => { takerAssetAmount: new BigNumber(200), takerFee: new BigNumber(50), }); - it('correctly sorts by fee adjusted rate', async () => { - const feeRate = new BigNumber(1); // ZRX costs 1 unit of takerAsset per 1 unit of ZRX + it('correctly sorts by fee adjusted rate when feeRate is Provided', async () => { const orders = [testOrder1, testOrder2, testOrder3]; const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate( [testOrder1, testOrder2, testOrder3], @@ -38,6 +38,11 @@ describe('sortingUtils', () => { ); expect(sortedOrders).to.deep.equal([testOrder2, testOrder1, testOrder3]); }); + it('correctly sorts by fee adjusted rate when no feeRate is Provided', async () => { + const orders = [testOrder1, testOrder2, testOrder3]; + const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate([testOrder1, testOrder2, testOrder3]); + expect(sortedOrders).to.deep.equal([testOrder2, testOrder1, testOrder3]); + }); }); describe('#sortFeeOrdersByFeeAdjustedRate', () => { // rate: 200 takerAsset / makerAsset -- cgit v1.2.3 From b86210332f94ad90cdabcf2083ae4a99075daf33 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 19:10:57 -0400 Subject: Fix lint errors --- packages/order-utils/src/rate_utils.ts | 1 - packages/order-utils/src/sorting_utils.ts | 2 +- packages/order-utils/test/rate_utils_test.ts | 2 +- packages/order-utils/test/sorting_utils_test.ts | 12 ++++-------- 4 files changed, 6 insertions(+), 11 deletions(-) (limited to 'packages') diff --git a/packages/order-utils/src/rate_utils.ts b/packages/order-utils/src/rate_utils.ts index 72d11584a..e82c03873 100644 --- a/packages/order-utils/src/rate_utils.ts +++ b/packages/order-utils/src/rate_utils.ts @@ -1,7 +1,6 @@ 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'; diff --git a/packages/order-utils/src/sorting_utils.ts b/packages/order-utils/src/sorting_utils.ts index 8424060fc..f019aa4a8 100644 --- a/packages/order-utils/src/sorting_utils.ts +++ b/packages/order-utils/src/sorting_utils.ts @@ -37,7 +37,7 @@ export const sortingUtils = { */ sortFeeOrdersByFeeAdjustedRate(signedFeeOrders: SignedOrder[]): SignedOrder[] { assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema); - const rateCalculator = rateUtils.getFeeAdjustedRateOfFeeOrder; + const rateCalculator = rateUtils.getFeeAdjustedRateOfFeeOrder.bind(rateUtils); const sortedOrders = sortOrders(signedFeeOrders, rateCalculator); return sortedOrders; }, diff --git a/packages/order-utils/test/rate_utils_test.ts b/packages/order-utils/test/rate_utils_test.ts index b23a6467a..2e299c209 100644 --- a/packages/order-utils/test/rate_utils_test.ts +++ b/packages/order-utils/test/rate_utils_test.ts @@ -2,7 +2,7 @@ import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import 'mocha'; -import { constants, rateUtils } from '../src'; +import { rateUtils } from '../src'; import { chaiSetup } from './utils/chai_setup'; import { testOrderFactory } from './utils/test_order_factory'; diff --git a/packages/order-utils/test/sorting_utils_test.ts b/packages/order-utils/test/sorting_utils_test.ts index 5a33cb2ca..016432505 100644 --- a/packages/order-utils/test/sorting_utils_test.ts +++ b/packages/order-utils/test/sorting_utils_test.ts @@ -1,9 +1,8 @@ import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; -import * as _ from 'lodash'; import 'mocha'; -import { constants, rateUtils, sortingUtils } from '../src'; +import { sortingUtils } from '../src'; import { chaiSetup } from './utils/chai_setup'; import { testOrderFactory } from './utils/test_order_factory'; @@ -32,15 +31,12 @@ describe('sortingUtils', () => { }); it('correctly sorts by fee adjusted rate when feeRate is Provided', async () => { const orders = [testOrder1, testOrder2, testOrder3]; - const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate( - [testOrder1, testOrder2, testOrder3], - feeRate, - ); + const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate(orders, feeRate); expect(sortedOrders).to.deep.equal([testOrder2, testOrder1, testOrder3]); }); it('correctly sorts by fee adjusted rate when no feeRate is Provided', async () => { const orders = [testOrder1, testOrder2, testOrder3]; - const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate([testOrder1, testOrder2, testOrder3]); + const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate(orders); expect(sortedOrders).to.deep.equal([testOrder2, testOrder1, testOrder3]); }); }); @@ -64,7 +60,7 @@ describe('sortingUtils', () => { }); it('correctly sorts by fee adjusted rate', async () => { const orders = [testOrder1, testOrder2, testOrder3]; - const sortedOrders = sortingUtils.sortFeeOrdersByFeeAdjustedRate([testOrder1, testOrder2, testOrder3]); + const sortedOrders = sortingUtils.sortFeeOrdersByFeeAdjustedRate(orders); expect(sortedOrders).to.deep.equal([testOrder2, testOrder3, testOrder1]); }); }); -- cgit v1.2.3 From ab64ea7377b4cd0a0a7e3ec219f958037c5fabbe Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 19:20:07 -0400 Subject: Updated CHANGELOG --- packages/order-utils/CHANGELOG.json | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'packages') diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index fa82976ad..ee0030b6b 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -13,6 +13,10 @@ }, { "note": "Dependencies updated" + }, + { + "note": "Added rateUtils and sortingUtils", + "pr": 953 } ] }, -- cgit v1.2.3 From d8593998414aa3234533b8fa868b05495ac54457 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 13 Aug 2018 17:45:50 -0700 Subject: Change rateUtils to use Order --- packages/order-utils/src/rate_utils.ts | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'packages') diff --git a/packages/order-utils/src/rate_utils.ts b/packages/order-utils/src/rate_utils.ts index e82c03873..c9ca72c59 100644 --- a/packages/order-utils/src/rate_utils.ts +++ b/packages/order-utils/src/rate_utils.ts @@ -1,5 +1,5 @@ import { schemas } from '@0xproject/json-schemas'; -import { SignedOrder } from '@0xproject/types'; +import { Order } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import { assert } from './assert'; @@ -7,42 +7,42 @@ import { constants } from './constants'; export const rateUtils = { /** - * Takes a signed order and calculates the fee adjusted rate (takerAsset/makerAsset) by calculating how much takerAsset + * Takes an order and calculates the fee adjusted rate (takerAsset/makerAsset) by calculating how much takerAsset * is required to cover the fees (feeRate * takerFee), adding the takerAssetAmount and dividing by makerAssetAmount - * @param signedOrder An object that conforms to the signedOrder interface - * @param feeRate The market rate of ZRX denominated in takerAssetAmount - * (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) - * Defaults to 0 + * @param order An object that conforms to the order interface + * @param feeRate The market rate of ZRX denominated in takerAssetAmount + * (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) + * Defaults to 0 * @return The rate (takerAsset/makerAsset) of the order adjusted for fees */ - getFeeAdjustedRateOfOrder(signedOrder: SignedOrder, feeRate: BigNumber = constants.ZERO_AMOUNT): BigNumber { - assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + getFeeAdjustedRateOfOrder(order: Order, feeRate: BigNumber = constants.ZERO_AMOUNT): BigNumber { + assert.doesConformToSchema('order', order, schemas.orderSchema); assert.isBigNumber('feeRate', feeRate); assert.assert( feeRate.gte(constants.ZERO_AMOUNT), `Expected feeRate: ${feeRate} to be greater than or equal to 0`, ); - const takerAssetAmountNeededToPayForFees = signedOrder.takerFee.mul(feeRate); - const totalTakerAssetAmount = takerAssetAmountNeededToPayForFees.plus(signedOrder.takerAssetAmount); - const rate = totalTakerAssetAmount.div(signedOrder.makerAssetAmount); + const takerAssetAmountNeededToPayForFees = order.takerFee.mul(feeRate); + const totalTakerAssetAmount = takerAssetAmountNeededToPayForFees.plus(order.takerAssetAmount); + const rate = totalTakerAssetAmount.div(order.makerAssetAmount); return rate; }, /** - * Takes a signed fee order (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) and calculates + * Takes a fee order (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) and calculates * the fee adjusted rate (WETH/ZRX) by dividing the takerAssetAmount by the makerAmount minus the takerFee - * @param signedFeeOrder An object that conforms to the signedOrder interface + * @param feeOrder An object that conforms to the order interface * @return The rate (WETH/ZRX) of the fee order adjusted for fees */ - getFeeAdjustedRateOfFeeOrder(signedFeeOrder: SignedOrder): BigNumber { - assert.doesConformToSchema('signedFeeOrder', signedFeeOrder, schemas.signedOrderSchema); - const zrxAmountAfterFees = signedFeeOrder.makerAssetAmount.sub(signedFeeOrder.takerFee); + getFeeAdjustedRateOfFeeOrder(feeOrder: Order): BigNumber { + assert.doesConformToSchema('feeOrder', feeOrder, schemas.orderSchema); + const zrxAmountAfterFees = feeOrder.makerAssetAmount.sub(feeOrder.takerFee); assert.assert( zrxAmountAfterFees.greaterThan(constants.ZERO_AMOUNT), - `Expected takerFee: ${JSON.stringify( - signedFeeOrder.takerFee, - )} to be less than makerAssetAmount: ${JSON.stringify(signedFeeOrder.makerAssetAmount)}`, + `Expected takerFee: ${JSON.stringify(feeOrder.takerFee)} to be less than makerAssetAmount: ${JSON.stringify( + feeOrder.makerAssetAmount, + )}`, ); - const rate = signedFeeOrder.takerAssetAmount.div(zrxAmountAfterFees); + const rate = feeOrder.takerAssetAmount.div(zrxAmountAfterFees); return rate; }, }; -- cgit v1.2.3 From 99b744ba52f538752bb0966e6d8b50d9f5a2f032 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 13 Aug 2018 18:31:41 -0700 Subject: Update sortingUtils to support Order and SignedOrder --- packages/order-utils/src/sorting_utils.ts | 70 ++++++++++++------------------- 1 file changed, 26 insertions(+), 44 deletions(-) (limited to 'packages') diff --git a/packages/order-utils/src/sorting_utils.ts b/packages/order-utils/src/sorting_utils.ts index f019aa4a8..8811bcaf8 100644 --- a/packages/order-utils/src/sorting_utils.ts +++ b/packages/order-utils/src/sorting_utils.ts @@ -1,5 +1,5 @@ import { schemas } from '@0xproject/json-schemas'; -import { SignedOrder } from '@0xproject/types'; +import { Order } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; @@ -9,64 +9,46 @@ import { rateUtils } from './rate_utils'; export const sortingUtils = { /** - * Takes an array of signed orders and sorts them by takerAsset/makerAsset rate in ascending order (best rate first). + * Takes an array of orders and sorts them by takerAsset/makerAsset rate in ascending order (best rate first). * Adjusts the rate of each order according to the feeRate and takerFee for that order. - * @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 feeRate The market rate of ZRX denominated in takerAssetAmount - * (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) - * Defaults to 0 + * @param orders An array of objects that extend the Order interface. All orders should specify ZRX as + * the makerAsset and WETH as the takerAsset. + * @param feeRate The market rate of ZRX denominated in takerAssetAmount + * (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX) + * Defaults to 0 * @return The input orders sorted by rate in ascending order */ - sortOrdersByFeeAdjustedRate( - signedOrders: SignedOrder[], - feeRate: BigNumber = constants.ZERO_AMOUNT, - ): SignedOrder[] { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + sortOrdersByFeeAdjustedRate(orders: T[], feeRate: BigNumber = constants.ZERO_AMOUNT): T[] { + assert.doesConformToSchema('orders', orders, schemas.ordersSchema); assert.isBigNumber('feeRate', feeRate); - const rateCalculator = (signedOrder: SignedOrder) => rateUtils.getFeeAdjustedRateOfOrder(signedOrder, feeRate); - const sortedOrders = sortOrders(signedOrders, rateCalculator); + const rateCalculator = (order: Order) => rateUtils.getFeeAdjustedRateOfOrder(order, feeRate); + const sortedOrders = sortOrders(orders, rateCalculator); return sortedOrders; }, /** - * Takes an array of signed fee orders (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) + * Takes an array of fee orders (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) * and sorts them by rate in ascending order (best rate first). Adjusts the rate according to the takerFee. - * @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 feeOrders An array of objects that extend the Order interface. All orders should specify ZRX as + * the makerAsset and WETH as the takerAsset. * @return The input orders sorted by rate in ascending order */ - sortFeeOrdersByFeeAdjustedRate(signedFeeOrders: SignedOrder[]): SignedOrder[] { - assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema); + sortFeeOrdersByFeeAdjustedRate(feeOrders: Order[]): Order[] { + assert.doesConformToSchema('feeOrders', feeOrders, schemas.ordersSchema); const rateCalculator = rateUtils.getFeeAdjustedRateOfFeeOrder.bind(rateUtils); - const sortedOrders = sortOrders(signedFeeOrders, rateCalculator); + const sortedOrders = sortOrders(feeOrders, rateCalculator); return sortedOrders; }, }; -type RateCalculator = (signedOrder: SignedOrder) => BigNumber; +type RateCalculator = (order: Order) => BigNumber; // takes an array of orders, copies them, and sorts the copy based on the rate definition provided by rateCalculator -const sortOrders = (signedOrders: SignedOrder[], rateCalculator: RateCalculator): SignedOrder[] => { - const copiedOrders = _.cloneDeep(signedOrders); - const feeOrderComparator = getOrderComparator(rateCalculator); - copiedOrders.sort(feeOrderComparator); +function sortOrders(orders: T[], rateCalculator: RateCalculator): T[] { + const copiedOrders = _.cloneDeep(orders); + copiedOrders.sort((firstOrder, secondOrder) => { + const firstOrderRate = rateCalculator(firstOrder); + const secondOrderRate = rateCalculator(secondOrder); + return firstOrderRate.comparedTo(secondOrderRate); + }); return copiedOrders; -}; - -type Comparator = (first: T, second: T) => number; - -// takes a function that calculates rate for a signed order and returns a comparator that sorts based on rate -const getOrderComparator = (rateCalculator: RateCalculator): Comparator => ( - firstSignedOrder, - secondSignedOrder, -) => { - const firstOrderRate = rateCalculator(firstSignedOrder); - const secondOrderRate = rateCalculator(secondSignedOrder); - if (firstOrderRate.lt(secondOrderRate)) { - return -1; - } else if (firstOrderRate.gt(secondOrderRate)) { - return 1; - } else { - return 0; - } -}; +} -- cgit v1.2.3 From dd7e03c7d7434e5fd5aa96812e773a69247b8546 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 13 Aug 2018 18:46:54 -0700 Subject: Add defaults for networkId and pagination --- packages/sra-api/package.json | 2 +- packages/sra-api/public/api.json | 2 +- packages/sra-api/src/parameters.ts | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/sra-api/package.json b/packages/sra-api/package.json index 4a8526a28..70e645c5b 100644 --- a/packages/sra-api/package.json +++ b/packages/sra-api/package.json @@ -33,7 +33,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-api/README.md", "dependencies": { - "@0xproject/json-schemas": "1.0.1-rc.3" + "@0xproject/json-schemas": "^1.0.1-rc.3" }, "devDependencies": { "@0xproject/tslint-config": "^1.0.4", diff --git a/packages/sra-api/public/api.json b/packages/sra-api/public/api.json index 36b08ad1a..9c727cfbd 100644 --- a/packages/sra-api/public/api.json +++ b/packages/sra-api/public/api.json @@ -1 +1 @@ -{"openapi":"3.0.0","info":{"version":"2.0.0","title":"Standard Relayer REST API","description":"# Testing\n\nUse the [sra-report](https://github.com/0xProject/0x-monorepo/tree/development/packages/sra-report) command line tool to test your API for SRA compliance.\n\n# Schemas\n\nThe [JSON schemas](http://json-schema.org/) for the API payloads and responses can be found in [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas). Examples of each payload and response can be found in the library's [test suite](https://github.com/0xProject/0x.js/blob/development/packages/json-schemas/test/schema_test.ts#L1).\n\n```bash\nnpm install @0xproject/json-schemas --save\n```\n\nYou can easily validate your API's payloads and responses using the [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas) package:\n\n```js\nimport {SchemaValidator, ValidatorResult, schemas} from '@0xproject/json-schemas';\n\nconst {relayerApiTokenPairsResponseSchema} = schemas;\nconst validator = new SchemaValidator();\n\nconst tokenPairsResponse = {\n ...\n};\nconst validatorResult: ValidatorResult = validator.validate(tokenPairsResponse, relayerApiTokenPairsResponseSchema);\n```\n\n# Pagination\n\nRequests that return potentially large collections should respond to the **?page** and **?perPage** parameters. For example:\n\n```bash\n$ curl https://api.example-relayer.com/v2/asset_pairs?page=3&perPage=20\n```\n\nPage numbering should be 1-indexed, not 0-indexed. If a query provides an unreasonable (ie. too high) `perPage` value, the response can return a validation error as specified in the [errors section](#section/Errors). If the query specifies a `page` that does not exist (ie. there are not enough `records`), the response should just return an empty `records` array.\n\nAll endpoints that are paginated should return a `total`, `page`, `perPage` and a `records` value in the top level of the collection. The value of `total` should be the total number of records for a given query, whereas `records` should be an array representing the response to the query for that page. `page` and `perPage`, are the same values that were specified in the request. See the note in [miscellaneous](#section/Misc.) about formatting `snake_case` vs. `lowerCamelCase`.\n\nThese requests include the [`/v2/asset_pairs`](#operation/getAssetPairs), [`/v2/orders`](#operation/getOrders), [`/v2/fee_recipients`](#operation/getFeeRecipients) and [`/v2/orderbook`](#operation/getOrderbook) endpoints.\n\n# Network Id\n\nAll requests should be able to specify a **?networkId** query param for all supported networks. For example:\n\n```bash\n$ curl https://api.example-relayer.com/v2/asset_pairs?networkId=1\n```\n\nIf the query param is not provided, it should default to **1** (mainnet).\n\nNetworks and their Ids:\n\n| Network Id | Network Name |\n| ---------- | ------------ |\n| 1 | Mainnet |\n| 42 | Kovan |\n| 3 | Ropsten |\n| 4 | Rinkeby |\n\nIf a certain network is not supported, the response should **400** as specified in the [error response](#section/Errors) section. For example:\n\n```json\n{\n \"code\": 100,\n \"reason\": \"Validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"networkId\",\n \"code\": 1006,\n \"reason\": \"Network id 42 is not supported\"\n }\n ]\n}\n```\n\n# Link Header\n\nA [Link Header](https://tools.ietf.org/html/rfc5988) can be included in a response to provide clients with more context about paging\nFor example:\n\n```bash\nLink: ; rel=\"next\",\n; rel=\"last\"\n```\n\nThis `Link` response header contains one or more Hypermedia link relations.\n\nThe possible `rel` values are:\n\n| Name | Description |\n| ----- | ------------------------------------------------------------- |\n| next | The link relation for the immediate next page of results. |\n| last | The link relation for the last page of results. |\n| first | The link relation for the first page of results. |\n| prev | The link relation for the immediate previous page of results. |\n\n# Rate Limits\n\nRate limit guidance for clients can be optionally returned in the response headers:\n\n| Header Name | Description |\n| --------------------- | ---------------------------------------------------------------------------- |\n| X-RateLimit-Limit | The maximum number of requests you're permitted to make per hour. |\n| X-RateLimit-Remaining | The number of requests remaining in the current rate limit window. |\n| X-RateLimit-Reset | The time at which the current rate limit window resets in UTC epoch seconds. |\n\nFor example:\n\n```bash\n$ curl -i https://api.example-relayer.com/v2/asset_pairs\nHTTP/1.1 200 OK\nDate: Mon, 20 Oct 2017 12:30:06 GMT\nStatus: 200 OK\nX-RateLimit-Limit: 60\nX-RateLimit-Remaining: 56\nX-RateLimit-Reset: 1372700873\n```\n\nWhen a rate limit is exceeded, a status of **429 Too Many Requests** should be returned.\n\n# Errors\n\nUnless the spec defines otherwise, errors to bad requests should respond with HTTP 4xx or status codes.\n\n## Common error codes\n\n| Code | Reason |\n| ---- | --------------------------------------- |\n| 400 | Bad Request – Invalid request format |\n| 404 | Not found |\n| 429 | Too many requests - Rate limit exceeded |\n| 500 | Internal Server Error |\n| 501 | Not Implemented |\n\n## Error reporting format\n\nFor all **400** responses, see the [error response schema](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_error_response_schema.ts#L1).\n\n```json\n{\n \"code\": 101,\n \"reason\": \"Validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"maker\",\n \"code\": 1002,\n \"reason\": \"Invalid address\"\n }\n ]\n}\n```\n\nGeneral error codes:\n\n```bash\n100 - Validation Failed\n101 - Malformed JSON\n102 - Order submission disabled\n103 - Throttled\n```\n\nValidation error codes:\n\n```bash\n1000 - Required field\n1001 - Incorrect format\n1002 - Invalid address\n1003 - Address not supported\n1004 - Value out of range\n1005 - Invalid signature or hash\n1006 - Unsupported option\n```\n\n# Asset Data Encoding\n\nAs we now support multiple [token transfer proxies](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy), the identifier of which proxy to use for the token transfer must be encoded, along with the token information. Each proxy in 0x v2 has a unique identifier. If you're using 0x.js there will be helper methods for this [encoding](https://0xproject.com/docs/0x.js#zeroEx-encodeERC20AssetData) and [decoding](https://0xproject.com/docs/0x.js#zeroEx-decodeAssetProxyId).\n\nThe identifier for the Proxy uses a similar scheme to [ABI function selectors](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#function-selector).\n\n```js\n// ERC20 Proxy ID 0xf47261b0\nbytes4(keccak256('ERC20Token(address)'));\n// ERC721 Proxy ID 0x08e937fa\nbytes4(keccak256('ERC721Token(address,uint256)'));\n```\n\nAsset data is encoded using [ABI encoding](https://solidity.readthedocs.io/en/develop/abi-spec.html).\n\nFor example, encoding the ERC20 token contract (address: 0x1dc4c1cefef38a777b15aa20260a54e584b16c48) using the ERC20 Transfer Proxy (id: 0xf47261b0) would be:\n\n```bash\n0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48\n```\n\nEncoding the ERC721 token contract (address: `0x371b13d97f4bf77d724e78c16b7dc74099f40e84`), token id (id: `99`, which hex encoded is `0x63`) and the ERC721 Transfer Proxy (id: 0x08e937fa) would be:\n\n```bash\n0x08e937fa000000000000000000000000371b13d97f4bf77d724e78c16b7dc74099f40e840000000000000000000000000000000000000000000000000000000000000063\n```\n\nFor more information see [the Asset Proxy](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#erc20proxy) section of the v2 spec and the [Ethereum ABI Spec](https://solidity.readthedocs.io/en/develop/abi-spec.html).\n\n# Meta Data in Order Responses\n\nIn v2 of the standard relayer API we added the `metaData` field. It is meant to provide a standard place for relayers to put optional, custom or non-standard fields that may of interest to the consumer of the API.\n\nA good example of such a field is `remainingTakerAssetAmount`, which is a convenience field that communicates how much of a 0x order is potentially left to be filled. Unlike the other fields in a 0x order, it is not guaranteed to be correct as it is derived from whatever mechanism the implementer (ie. the relayer) is using. While convenient for prototyping and low stakes situations, we recommend validating the value of the field by checking the state of the blockchain yourself, such as by using [Order Watcher](https://0xproject.com/wiki#0x-OrderWatcher).\n\n# Misc.\n\n* All requests and responses should be of **application/json** content type\n* All token amounts are sent in amounts of the smallest level of precision (base units). (e.g if a token has 18 decimal places, selling 1 token would show up as selling `'1000000000000000000'` units by this API).\n* All addresses are sent as lower-case (non-checksummed) Ethereum addresses with the `0x` prefix.\n* All parameters are to be written in `lowerCamelCase`.\n","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"}},"paths":{"/v2/asset_pairs":{"get":{"description":"Retrieves a list of available asset pairs and the information required to trade them (in any order). Setting only `assetDataA` or `assetDataB` returns pairs filtered by that asset only.","operationId":"getAssetPairs","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number"}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number"}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number"}},{"name":"assetDataA","in":"query","description":"The assetData value for the first asset in the pair.","example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"assetDataB","in":"query","description":"The assetData value for the second asset in the pair.","example":"0x0257179264389b814a946f3e92105513705ca6b990","schema":{"$ref":"#/components/schemas/hexSchema"}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"Returns a collection of available asset pairs with some meta info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiAssetDataPairsResponseSchema"},"example":{"total":43,"page":1,"perPage":100,"records":[{"assetDataA":{"minAmount":"0","maxAmount":"10000000000000000000","precision":5,"assetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d"},"assetDataB":{"minAmount":"0","maxAmount":"50000000000000000000","precision":5,"assetData":"0x0257179264389b814a946f3e92105513705ca6b990"}}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/orders":{"get":{"description":"Retrieves a list of orders given query parameters. This endpoint should be [paginated](#section/Pagination). For querying an entire orderbook snapshot, the [orderbook endpoint](#operation/getOrderbook) is recommended. If both makerAssetData and takerAssetData are specified, returned orders will be sorted by price determined by (takerTokenAmount/makerTokenAmount) in ascending order. By default, orders returned by this endpoint are unsorted.","operationId":"getOrders","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number"}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number"}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number"}},{"name":"makerAssetProxyId","in":"query","description":"The maker [asset proxy id](https://0xproject.com/docs/0x.js#types-AssetProxyId) (example: \"0xf47261b0\" for ERC20, \"0x02571792\" for ERC721).","example":"0xf47261b0","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"takerAssetProxyId","in":"query","description":"The taker asset [asset proxy id](https://0xproject.com/docs/0x.js#types-AssetProxyId) (example: \"0xf47261b0\" for ERC20, \"0x02571792\" for ERC721).","example":"0x02571792","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"makerAssetAddress","in":"query","description":"The contract address for the maker asset.","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"takerAssetAddress","in":"query","description":"The contract address for the taker asset.","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"exchangeAddress","in":"query","description":"Same as exchangeAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"senderAddress","in":"query","description":"Same as senderAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"makerAssetData","in":"query","description":"Same as makerAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"takerAssetData","in":"query","description":"Same as takerAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"traderAssetData","in":"query","description":"Same as traderAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"makerAddress","in":"query","description":"Same as makerAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"traderAddress","in":"query","description":"Same as traderAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"feeRecipientAddress","in":"query","description":"Same as feeRecipientAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"A collection of 0x orders with meta-data as specified by query params","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"},"example":{"total":984,"page":1,"perPage":100,"records":[{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order/{orderHash}":{"get":{"description":"Retrieves the 0x order with meta info that is associated with the hash.","operationId":"getOrder","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number"}},{"name":"orderHash","in":"path","description":"The hash of the desired 0x order.","example":"0xd4b103c42d2512eef3fee775e097f044291615d25f5d71e0ac70dbd49d223591","schema":{"$ref":"#/components/schemas/orderHashSchema"}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The order and meta info associated with the orderHash","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderSchema"},"example":{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/orderbook":{"get":{"description":"Retrieves the orderbook for a given asset pair. This endpoint should be [paginated](#section/Pagination). Bids will be sorted in descending order by price, and asks will be sorted in ascending order by price. Within the price sorted orders, the orders are further sorted by _taker fee price_ which is defined as the **takerFee** divided by **takerTokenAmount**. After _taker fee price_, orders are to be sorted by expiration in ascending order. The way pagination works for this endpoint is that the **page** and **perPage** query params apply to both `bids` and `asks` collections, and if `page` * `perPage` > `total` for a certain collection, the `records` for that collection should just be empty. ","operationId":"getOrderbook","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number"}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number"}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number"}},{"name":"baseAssetData","in":"query","description":"assetData (makerAssetData or takerAssetData) designated as the base currency in the [currency pair calculation](https://en.wikipedia.org/wiki/Currency_pair) of price.","required":true,"example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"quoteAssetData","in":"query","description":"assetData (makerAssetData or takerAssetData) designated as the quote currency in the currency pair calculation of price (required).","required":true,"example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The sorted order book for the specified asset pair.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderbookResponseSchema"},"example":{"bids":{"total":325,"page":2,"perPage":100,"records":[{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}]},"asks":{"total":500,"page":2,"perPage":100,"records":[{"order":{"makerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","takerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"20000000000000000","takerAssetAmount":"10000000000000000","makerFee":"200000000000000","takerFee":"100000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","takerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x013842a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b3518891"},"metaData":{}}]}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order_config":{"get":{"description":"Relayers have full discretion over the orders that they are willing to host on their orderbooks (e.g what fees they charge, etc...). In order for traders to discover their requirements programmatically, they can send an incomplete order to this endpoint and receive the missing fields, specifc to that order. This gives relayers a large amount of flexibility to tailor fees to unique traders, trading pairs and volume amounts. Submit a partial order and receive information required to complete the order: `senderAddress`, `feeRecipientAddress`, `makerFee`, `takerFee`. ","operationId":"getOrderConfig","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number"}}],"requestBody":{"description":"The fields of a 0x order the relayer may want to decide what configuration to send back.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderConfigPayloadSchema"},"example":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","expirationTimeSeconds":"1532560590"}}}},"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The additional fields necessary in order to submit an order to the relayer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderConfigResponseSchema"},"example":{"senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","makerFee":"100000000000000","takerFee":"200000000000000"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/fee_recipients":{"get":{"description":"Retrieves a collection of all fee recipient addresses for a relayer. This endpoint should be [paginated](#section/Pagination).","operationId":"getFeeRecipients","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number"}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number"}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number"}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"A collection of all used fee recipient addresses.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiFeeRecipientsResponseSchema"},"example":{"total":3,"page":1,"perPage":10,"records":["0x6eC92694ea172ebC430C30fa31De87620967A082","0x9e56625509c2f60af937f23b7b532600390e8c8b","0xa2b31dacf30a9c50ca473337c01d8a201ae33e32"]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order":{"post":{"description":"Submit a signed order to the relayer.","operationId":"postOrder","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number"}}],"requestBody":{"description":"A valid signed 0x order based on the schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/signedOrderSchema"},"example":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"}}}},"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"OK","content":{}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}}},"components":{"schemas":{"numberSchema":{"type":"string","pattern":"^\\d+(\\.\\d+)?$"},"addressSchema":{"type":"string","pattern":"^0x[0-9a-f]{40}$"},"hexSchema":{"type":"string","pattern":"^0x(([0-9a-f][0-9a-f])+)?$"},"orderHashSchema":{"type":"string","pattern":"^0x[0-9a-fA-F]{64}$"},"orderSchema":{"properties":{"makerAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAddress":{"$ref":"#/components/schemas/addressSchema"},"makerFee":{"$ref":"#/components/schemas/numberSchema"},"takerFee":{"$ref":"#/components/schemas/numberSchema"},"senderAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"takerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"salt":{"$ref":"#/components/schemas/numberSchema"},"exchangeAddress":{"$ref":"#/components/schemas/addressSchema"},"feeRecipientAddress":{"$ref":"#/components/schemas/addressSchema"},"expirationTimeSeconds":{"$ref":"#/components/schemas/numberSchema"}},"required":["makerAddress","takerAddress","makerFee","takerFee","senderAddress","makerAssetAmount","takerAssetAmount","makerAssetData","takerAssetData","salt","exchangeAddress","feeRecipientAddress","expirationTimeSeconds"],"type":"object"},"signedOrderSchema":{"allOf":[{"$ref":"#/components/schemas/orderSchema"},{"properties":{"signature":{"$ref":"#/components/schemas/hexSchema"}},"required":["signature"]}]},"signedOrdersSchema":{"type":"array","items":{"$ref":"#/components/schemas/signedOrderSchema"}},"ordersSchema":{"type":"array","items":{"$ref":"#/components/schemas/orderSchema"}},"paginatedCollectionSchema":{"type":"object","properties":{"total":{"type":"number"},"perPage":{"type":"number"},"page":{"type":"number"}},"required":["total","perPage","page"]},"relayerApiErrorResponseSchema":{"type":"object","properties":{"code":{"type":"integer","minimum":100,"maximum":103},"reason":{"type":"string"},"validationErrors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"code":{"type":"integer","minimum":1000,"maximum":1006},"reason":{"type":"string"}},"required":["field","code","reason"]}}},"required":["code","reason"]},"relayerApiFeeRecipientsResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/addressSchema"}},"required":["records"]}]},"relayerApiOrderSchema":{"type":"object","properties":{"order":{"$ref":"#/components/schemas/orderSchema"},"metaData":{"type":"object"}},"required":["order","metaData"]},"relayerApiOrdersSchema":{"type":"array","items":{"$ref":"#/components/schemas/relayerApiOrderSchema"}},"relayerApiOrderConfigPayloadSchema":{"type":"object","properties":{"makerAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"takerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"exchangeAddress":{"$ref":"#/components/schemas/addressSchema"},"expirationTimeSeconds":{"$ref":"#/components/schemas/numberSchema"}},"required":["makerAddress","takerAddress","makerAssetAmount","takerAssetAmount","makerAssetData","takerAssetData","exchangeAddress","expirationTimeSeconds"]},"relayerApiOrderConfigResponseSchema":{"type":"object","properties":{"makerFee":{"$ref":"#/components/schemas/numberSchema"},"takerFee":{"$ref":"#/components/schemas/numberSchema"},"feeRecipientAddress":{"$ref":"#/components/schemas/addressSchema"},"senderAddress":{"$ref":"#/components/schemas/addressSchema"}},"required":["makerFee","takerFee","feeRecipientAddress","senderAddress"]},"relayerApiOrderbookResponseSchema":{"type":"object","properties":{"bids":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"},"asks":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"}},"required":["bids","asks"]},"relayerApiAssetDataPairsResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/relayerApiAssetDataPairsSchema"}},"required":["records"]}]},"relayerApiAssetDataTradeInfoSchema":{"type":"object","properties":{"assetData":{"$ref":"#/components/schemas/hexSchema"},"minAmount":{"$ref":"#/components/schemas/numberSchema"},"maxAmount":{"$ref":"#/components/schemas/numberSchema"},"precision":{"type":"number"}},"required":["assetData"]},"relayerApiOrdersChannelSubscribeSchema":{"type":"object","properties":{"type":{"enum":["subscribe"]},"channel":{"enum":["orders"]},"requestId":{"type":"string"},"payload":{"$ref":"#/components/schemas/relayerApiOrdersChannelSubscribePayload"}},"required":["type","channel","requestId"]},"relayerApiOrdersChannelSubscribePayload":{"type":"object","properties":{"makerAssetProxyId":{"$ref":"#/components/schemas/hexSchema"},"takerAssetProxyId":{"$ref":"#/components/schemas/hexSchema"},"networkId":{"type":"number"},"makerAssetAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAssetAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"traderAssetData":{"$ref":"#/components/schemas/hexSchema"}}},"relayerApiOrdersChannelUpdateSchema":{"type":"object","properties":{"type":{"enum":["update"]},"channel":{"enum":["orders"]},"requestId":{"type":"string"},"payload":{"$ref":"#/components/schemas/relayerApiOrdersSchema"}},"required":["type","channel","requestId"]},"relayerApiOrdersResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/relayerApiOrdersSchema"}},"required":["records"]}]},"relayerApiAssetDataPairsSchema":{"type":"array","items":{"properties":{"assetDataA":{"$ref":"#/components/schemas/relayerApiAssetDataTradeInfoSchema"},"assetDataB":{"$ref":"#/components/schemas/relayerApiAssetDataTradeInfoSchema"}},"required":["assetDataA","assetDataB"],"type":"object"}}}}} \ No newline at end of file +{"openapi":"3.0.0","info":{"version":"2.0.0","title":"Standard Relayer REST API","description":"# Testing\n\nUse the [sra-report](https://github.com/0xProject/0x-monorepo/tree/development/packages/sra-report) command line tool to test your API for SRA compliance.\n\n# Schemas\n\nThe [JSON schemas](http://json-schema.org/) for the API payloads and responses can be found in [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas). Examples of each payload and response can be found in the library's [test suite](https://github.com/0xProject/0x.js/blob/development/packages/json-schemas/test/schema_test.ts#L1).\n\n```bash\nnpm install @0xproject/json-schemas --save\n```\n\nYou can easily validate your API's payloads and responses using the [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas) package:\n\n```js\nimport {SchemaValidator, ValidatorResult, schemas} from '@0xproject/json-schemas';\n\nconst {relayerApiTokenPairsResponseSchema} = schemas;\nconst validator = new SchemaValidator();\n\nconst tokenPairsResponse = {\n ...\n};\nconst validatorResult: ValidatorResult = validator.validate(tokenPairsResponse, relayerApiTokenPairsResponseSchema);\n```\n\n# Pagination\n\nRequests that return potentially large collections should respond to the **?page** and **?perPage** parameters. For example:\n\n```bash\n$ curl https://api.example-relayer.com/v2/asset_pairs?page=3&perPage=20\n```\n\nPage numbering should be 1-indexed, not 0-indexed. If a query provides an unreasonable (ie. too high) `perPage` value, the response can return a validation error as specified in the [errors section](#section/Errors). If the query specifies a `page` that does not exist (ie. there are not enough `records`), the response should just return an empty `records` array.\n\nAll endpoints that are paginated should return a `total`, `page`, `perPage` and a `records` value in the top level of the collection. The value of `total` should be the total number of records for a given query, whereas `records` should be an array representing the response to the query for that page. `page` and `perPage`, are the same values that were specified in the request. See the note in [miscellaneous](#section/Misc.) about formatting `snake_case` vs. `lowerCamelCase`.\n\nThese requests include the [`/v2/asset_pairs`](#operation/getAssetPairs), [`/v2/orders`](#operation/getOrders), [`/v2/fee_recipients`](#operation/getFeeRecipients) and [`/v2/orderbook`](#operation/getOrderbook) endpoints.\n\n# Network Id\n\nAll requests should be able to specify a **?networkId** query param for all supported networks. For example:\n\n```bash\n$ curl https://api.example-relayer.com/v2/asset_pairs?networkId=1\n```\n\nIf the query param is not provided, it should default to **1** (mainnet).\n\nNetworks and their Ids:\n\n| Network Id | Network Name |\n| ---------- | ------------ |\n| 1 | Mainnet |\n| 42 | Kovan |\n| 3 | Ropsten |\n| 4 | Rinkeby |\n\nIf a certain network is not supported, the response should **400** as specified in the [error response](#section/Errors) section. For example:\n\n```json\n{\n \"code\": 100,\n \"reason\": \"Validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"networkId\",\n \"code\": 1006,\n \"reason\": \"Network id 42 is not supported\"\n }\n ]\n}\n```\n\n# Link Header\n\nA [Link Header](https://tools.ietf.org/html/rfc5988) can be included in a response to provide clients with more context about paging\nFor example:\n\n```bash\nLink: ; rel=\"next\",\n; rel=\"last\"\n```\n\nThis `Link` response header contains one or more Hypermedia link relations.\n\nThe possible `rel` values are:\n\n| Name | Description |\n| ----- | ------------------------------------------------------------- |\n| next | The link relation for the immediate next page of results. |\n| last | The link relation for the last page of results. |\n| first | The link relation for the first page of results. |\n| prev | The link relation for the immediate previous page of results. |\n\n# Rate Limits\n\nRate limit guidance for clients can be optionally returned in the response headers:\n\n| Header Name | Description |\n| --------------------- | ---------------------------------------------------------------------------- |\n| X-RateLimit-Limit | The maximum number of requests you're permitted to make per hour. |\n| X-RateLimit-Remaining | The number of requests remaining in the current rate limit window. |\n| X-RateLimit-Reset | The time at which the current rate limit window resets in UTC epoch seconds. |\n\nFor example:\n\n```bash\n$ curl -i https://api.example-relayer.com/v2/asset_pairs\nHTTP/1.1 200 OK\nDate: Mon, 20 Oct 2017 12:30:06 GMT\nStatus: 200 OK\nX-RateLimit-Limit: 60\nX-RateLimit-Remaining: 56\nX-RateLimit-Reset: 1372700873\n```\n\nWhen a rate limit is exceeded, a status of **429 Too Many Requests** should be returned.\n\n# Errors\n\nUnless the spec defines otherwise, errors to bad requests should respond with HTTP 4xx or status codes.\n\n## Common error codes\n\n| Code | Reason |\n| ---- | --------------------------------------- |\n| 400 | Bad Request – Invalid request format |\n| 404 | Not found |\n| 429 | Too many requests - Rate limit exceeded |\n| 500 | Internal Server Error |\n| 501 | Not Implemented |\n\n## Error reporting format\n\nFor all **400** responses, see the [error response schema](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_error_response_schema.ts#L1).\n\n```json\n{\n \"code\": 101,\n \"reason\": \"Validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"maker\",\n \"code\": 1002,\n \"reason\": \"Invalid address\"\n }\n ]\n}\n```\n\nGeneral error codes:\n\n```bash\n100 - Validation Failed\n101 - Malformed JSON\n102 - Order submission disabled\n103 - Throttled\n```\n\nValidation error codes:\n\n```bash\n1000 - Required field\n1001 - Incorrect format\n1002 - Invalid address\n1003 - Address not supported\n1004 - Value out of range\n1005 - Invalid signature or hash\n1006 - Unsupported option\n```\n\n# Asset Data Encoding\n\nAs we now support multiple [token transfer proxies](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy), the identifier of which proxy to use for the token transfer must be encoded, along with the token information. Each proxy in 0x v2 has a unique identifier. If you're using 0x.js there will be helper methods for this [encoding](https://0xproject.com/docs/0x.js#zeroEx-encodeERC20AssetData) and [decoding](https://0xproject.com/docs/0x.js#zeroEx-decodeAssetProxyId).\n\nThe identifier for the Proxy uses a similar scheme to [ABI function selectors](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#function-selector).\n\n```js\n// ERC20 Proxy ID 0xf47261b0\nbytes4(keccak256('ERC20Token(address)'));\n// ERC721 Proxy ID 0x08e937fa\nbytes4(keccak256('ERC721Token(address,uint256)'));\n```\n\nAsset data is encoded using [ABI encoding](https://solidity.readthedocs.io/en/develop/abi-spec.html).\n\nFor example, encoding the ERC20 token contract (address: 0x1dc4c1cefef38a777b15aa20260a54e584b16c48) using the ERC20 Transfer Proxy (id: 0xf47261b0) would be:\n\n```bash\n0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48\n```\n\nEncoding the ERC721 token contract (address: `0x371b13d97f4bf77d724e78c16b7dc74099f40e84`), token id (id: `99`, which hex encoded is `0x63`) and the ERC721 Transfer Proxy (id: 0x08e937fa) would be:\n\n```bash\n0x08e937fa000000000000000000000000371b13d97f4bf77d724e78c16b7dc74099f40e840000000000000000000000000000000000000000000000000000000000000063\n```\n\nFor more information see [the Asset Proxy](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#erc20proxy) section of the v2 spec and the [Ethereum ABI Spec](https://solidity.readthedocs.io/en/develop/abi-spec.html).\n\n# Meta Data in Order Responses\n\nIn v2 of the standard relayer API we added the `metaData` field. It is meant to provide a standard place for relayers to put optional, custom or non-standard fields that may of interest to the consumer of the API.\n\nA good example of such a field is `remainingTakerAssetAmount`, which is a convenience field that communicates how much of a 0x order is potentially left to be filled. Unlike the other fields in a 0x order, it is not guaranteed to be correct as it is derived from whatever mechanism the implementer (ie. the relayer) is using. While convenient for prototyping and low stakes situations, we recommend validating the value of the field by checking the state of the blockchain yourself, such as by using [Order Watcher](https://0xproject.com/wiki#0x-OrderWatcher).\n\n# Misc.\n\n* All requests and responses should be of **application/json** content type\n* All token amounts are sent in amounts of the smallest level of precision (base units). (e.g if a token has 18 decimal places, selling 1 token would show up as selling `'1000000000000000000'` units by this API).\n* All addresses are sent as lower-case (non-checksummed) Ethereum addresses with the `0x` prefix.\n* All parameters are to be written in `lowerCamelCase`.\n","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"}},"paths":{"/v2/asset_pairs":{"get":{"description":"Retrieves a list of available asset pairs and the information required to trade them (in any order). Setting only `assetDataA` or `assetDataB` returns pairs filtered by that asset only.","operationId":"getAssetPairs","parameters":[{"name":"assetDataA","in":"query","description":"The assetData value for the first asset in the pair.","example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"assetDataB","in":"query","description":"The assetData value for the second asset in the pair.","example":"0x0257179264389b814a946f3e92105513705ca6b990","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"Returns a collection of available asset pairs with some meta info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiAssetDataPairsResponseSchema"},"example":{"total":43,"page":1,"perPage":100,"records":[{"assetDataA":{"minAmount":"0","maxAmount":"10000000000000000000","precision":5,"assetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d"},"assetDataB":{"minAmount":"0","maxAmount":"50000000000000000000","precision":5,"assetData":"0x0257179264389b814a946f3e92105513705ca6b990"}}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/orders":{"get":{"description":"Retrieves a list of orders given query parameters. This endpoint should be [paginated](#section/Pagination). For querying an entire orderbook snapshot, the [orderbook endpoint](#operation/getOrderbook) is recommended. If both makerAssetData and takerAssetData are specified, returned orders will be sorted by price determined by (takerTokenAmount/makerTokenAmount) in ascending order. By default, orders returned by this endpoint are unsorted.","operationId":"getOrders","parameters":[{"name":"makerAssetProxyId","in":"query","description":"The maker [asset proxy id](https://0xproject.com/docs/0x.js#types-AssetProxyId) (example: \"0xf47261b0\" for ERC20, \"0x02571792\" for ERC721).","example":"0xf47261b0","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"takerAssetProxyId","in":"query","description":"The taker asset [asset proxy id](https://0xproject.com/docs/0x.js#types-AssetProxyId) (example: \"0xf47261b0\" for ERC20, \"0x02571792\" for ERC721).","example":"0x02571792","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"makerAssetAddress","in":"query","description":"The contract address for the maker asset.","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"takerAssetAddress","in":"query","description":"The contract address for the taker asset.","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"exchangeAddress","in":"query","description":"Same as exchangeAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"senderAddress","in":"query","description":"Same as senderAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"makerAssetData","in":"query","description":"Same as makerAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"takerAssetData","in":"query","description":"Same as takerAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"traderAssetData","in":"query","description":"Same as traderAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"makerAddress","in":"query","description":"Same as makerAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"traderAddress","in":"query","description":"Same as traderAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"feeRecipientAddress","in":"query","description":"Same as feeRecipientAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"A collection of 0x orders with meta-data as specified by query params","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"},"example":{"total":984,"page":1,"perPage":100,"records":[{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order/{orderHash}":{"get":{"description":"Retrieves the 0x order with meta info that is associated with the hash.","operationId":"getOrder","parameters":[{"name":"orderHash","in":"path","description":"The hash of the desired 0x order.","example":"0xd4b103c42d2512eef3fee775e097f044291615d25f5d71e0ac70dbd49d223591","schema":{"$ref":"#/components/schemas/orderHashSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The order and meta info associated with the orderHash","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderSchema"},"example":{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/orderbook":{"get":{"description":"Retrieves the orderbook for a given asset pair. This endpoint should be [paginated](#section/Pagination). Bids will be sorted in descending order by price, and asks will be sorted in ascending order by price. Within the price sorted orders, the orders are further sorted by _taker fee price_ which is defined as the **takerFee** divided by **takerTokenAmount**. After _taker fee price_, orders are to be sorted by expiration in ascending order. The way pagination works for this endpoint is that the **page** and **perPage** query params apply to both `bids` and `asks` collections, and if `page` * `perPage` > `total` for a certain collection, the `records` for that collection should just be empty. ","operationId":"getOrderbook","parameters":[{"name":"baseAssetData","in":"query","description":"assetData (makerAssetData or takerAssetData) designated as the base currency in the [currency pair calculation](https://en.wikipedia.org/wiki/Currency_pair) of price.","required":true,"example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"quoteAssetData","in":"query","description":"assetData (makerAssetData or takerAssetData) designated as the quote currency in the currency pair calculation of price (required).","required":true,"example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The sorted order book for the specified asset pair.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderbookResponseSchema"},"example":{"bids":{"total":325,"page":2,"perPage":100,"records":[{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}]},"asks":{"total":500,"page":2,"perPage":100,"records":[{"order":{"makerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","takerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"20000000000000000","takerAssetAmount":"10000000000000000","makerFee":"200000000000000","takerFee":"100000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","takerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x013842a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b3518891"},"metaData":{}}]}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order_config":{"get":{"description":"Relayers have full discretion over the orders that they are willing to host on their orderbooks (e.g what fees they charge, etc...). In order for traders to discover their requirements programmatically, they can send an incomplete order to this endpoint and receive the missing fields, specifc to that order. This gives relayers a large amount of flexibility to tailor fees to unique traders, trading pairs and volume amounts. Submit a partial order and receive information required to complete the order: `senderAddress`, `feeRecipientAddress`, `makerFee`, `takerFee`. ","operationId":"getOrderConfig","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"requestBody":{"description":"The fields of a 0x order the relayer may want to decide what configuration to send back.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderConfigPayloadSchema"},"example":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","expirationTimeSeconds":"1532560590"}}}},"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The additional fields necessary in order to submit an order to the relayer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderConfigResponseSchema"},"example":{"senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","makerFee":"100000000000000","takerFee":"200000000000000"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/fee_recipients":{"get":{"description":"Retrieves a collection of all fee recipient addresses for a relayer. This endpoint should be [paginated](#section/Pagination).","operationId":"getFeeRecipients","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"A collection of all used fee recipient addresses.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiFeeRecipientsResponseSchema"},"example":{"total":3,"page":1,"perPage":10,"records":["0x6eC92694ea172ebC430C30fa31De87620967A082","0x9e56625509c2f60af937f23b7b532600390e8c8b","0xa2b31dacf30a9c50ca473337c01d8a201ae33e32"]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order":{"post":{"description":"Submit a signed order to the relayer.","operationId":"postOrder","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"requestBody":{"description":"A valid signed 0x order based on the schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/signedOrderSchema"},"example":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"}}}},"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"OK","content":{}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}}},"components":{"schemas":{"numberSchema":{"type":"string","pattern":"^\\d+(\\.\\d+)?$"},"addressSchema":{"type":"string","pattern":"^0x[0-9a-f]{40}$"},"hexSchema":{"type":"string","pattern":"^0x(([0-9a-f][0-9a-f])+)?$"},"orderHashSchema":{"type":"string","pattern":"^0x[0-9a-fA-F]{64}$"},"orderSchema":{"properties":{"makerAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAddress":{"$ref":"#/components/schemas/addressSchema"},"makerFee":{"$ref":"#/components/schemas/numberSchema"},"takerFee":{"$ref":"#/components/schemas/numberSchema"},"senderAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"takerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"salt":{"$ref":"#/components/schemas/numberSchema"},"exchangeAddress":{"$ref":"#/components/schemas/addressSchema"},"feeRecipientAddress":{"$ref":"#/components/schemas/addressSchema"},"expirationTimeSeconds":{"$ref":"#/components/schemas/numberSchema"}},"required":["makerAddress","takerAddress","makerFee","takerFee","senderAddress","makerAssetAmount","takerAssetAmount","makerAssetData","takerAssetData","salt","exchangeAddress","feeRecipientAddress","expirationTimeSeconds"],"type":"object"},"signedOrderSchema":{"allOf":[{"$ref":"#/components/schemas/orderSchema"},{"properties":{"signature":{"$ref":"#/components/schemas/hexSchema"}},"required":["signature"]}]},"signedOrdersSchema":{"type":"array","items":{"$ref":"#/components/schemas/signedOrderSchema"}},"ordersSchema":{"type":"array","items":{"$ref":"#/components/schemas/orderSchema"}},"paginatedCollectionSchema":{"type":"object","properties":{"total":{"type":"number"},"perPage":{"type":"number"},"page":{"type":"number"}},"required":["total","perPage","page"]},"relayerApiErrorResponseSchema":{"type":"object","properties":{"code":{"type":"integer","minimum":100,"maximum":103},"reason":{"type":"string"},"validationErrors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"code":{"type":"integer","minimum":1000,"maximum":1006},"reason":{"type":"string"}},"required":["field","code","reason"]}}},"required":["code","reason"]},"relayerApiFeeRecipientsResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/addressSchema"}},"required":["records"]}]},"relayerApiOrderSchema":{"type":"object","properties":{"order":{"$ref":"#/components/schemas/orderSchema"},"metaData":{"type":"object"}},"required":["order","metaData"]},"relayerApiOrdersSchema":{"type":"array","items":{"$ref":"#/components/schemas/relayerApiOrderSchema"}},"relayerApiOrderConfigPayloadSchema":{"type":"object","properties":{"makerAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"takerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"exchangeAddress":{"$ref":"#/components/schemas/addressSchema"},"expirationTimeSeconds":{"$ref":"#/components/schemas/numberSchema"}},"required":["makerAddress","takerAddress","makerAssetAmount","takerAssetAmount","makerAssetData","takerAssetData","exchangeAddress","expirationTimeSeconds"]},"relayerApiOrderConfigResponseSchema":{"type":"object","properties":{"makerFee":{"$ref":"#/components/schemas/numberSchema"},"takerFee":{"$ref":"#/components/schemas/numberSchema"},"feeRecipientAddress":{"$ref":"#/components/schemas/addressSchema"},"senderAddress":{"$ref":"#/components/schemas/addressSchema"}},"required":["makerFee","takerFee","feeRecipientAddress","senderAddress"]},"relayerApiOrderbookResponseSchema":{"type":"object","properties":{"bids":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"},"asks":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"}},"required":["bids","asks"]},"relayerApiAssetDataPairsResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/relayerApiAssetDataPairsSchema"}},"required":["records"]}]},"relayerApiAssetDataTradeInfoSchema":{"type":"object","properties":{"assetData":{"$ref":"#/components/schemas/hexSchema"},"minAmount":{"$ref":"#/components/schemas/numberSchema"},"maxAmount":{"$ref":"#/components/schemas/numberSchema"},"precision":{"type":"number"}},"required":["assetData"]},"relayerApiOrdersChannelSubscribeSchema":{"type":"object","properties":{"type":{"enum":["subscribe"]},"channel":{"enum":["orders"]},"requestId":{"type":"string"},"payload":{"$ref":"#/components/schemas/relayerApiOrdersChannelSubscribePayload"}},"required":["type","channel","requestId"]},"relayerApiOrdersChannelSubscribePayload":{"type":"object","properties":{"makerAssetProxyId":{"$ref":"#/components/schemas/hexSchema"},"takerAssetProxyId":{"$ref":"#/components/schemas/hexSchema"},"networkId":{"type":"number"},"makerAssetAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAssetAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"traderAssetData":{"$ref":"#/components/schemas/hexSchema"}}},"relayerApiOrdersChannelUpdateSchema":{"type":"object","properties":{"type":{"enum":["update"]},"channel":{"enum":["orders"]},"requestId":{"type":"string"},"payload":{"$ref":"#/components/schemas/relayerApiOrdersSchema"}},"required":["type","channel","requestId"]},"relayerApiOrdersResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/relayerApiOrdersSchema"}},"required":["records"]}]},"relayerApiAssetDataPairsSchema":{"type":"array","items":{"properties":{"assetDataA":{"$ref":"#/components/schemas/relayerApiAssetDataTradeInfoSchema"},"assetDataB":{"$ref":"#/components/schemas/relayerApiAssetDataTradeInfoSchema"}},"required":["assetDataA","assetDataB"],"type":"object"}}}}} \ No newline at end of file diff --git a/packages/sra-api/src/parameters.ts b/packages/sra-api/src/parameters.ts index 10382894c..48ffb036d 100644 --- a/packages/sra-api/src/parameters.ts +++ b/packages/sra-api/src/parameters.ts @@ -7,6 +7,7 @@ export const paginationParameters: ParameterObject[] = [ example: 3, schema: { type: 'number', + default: 1, }, }, { @@ -16,6 +17,7 @@ export const paginationParameters: ParameterObject[] = [ example: 10, schema: { type: 'number', + default: 100, }, }, ]; @@ -27,10 +29,11 @@ export const networkdIdParameter: ParameterObject = { example: 42, schema: { type: 'number', + default: 1, }, }; export const generateParameters = (parameters: ParameterObject[], isPaginated: boolean = false): ParameterObject[] => { const optionalParameters = isPaginated ? paginationParameters : []; - return [networkdIdParameter, ...optionalParameters, ...parameters]; + return [...parameters, networkdIdParameter, ...optionalParameters]; }; -- cgit v1.2.3 From c10c4cec1db2c5bc0b71177aea7590ee6fda8735 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 21:14:46 -0400 Subject: Update marketUtils api --- packages/order-utils/src/market_utils.ts | 93 +++++++++++++++----------- packages/order-utils/src/types.ts | 28 ++++++++ packages/order-utils/test/market_utils_test.ts | 67 ++++++++++++------- 3 files changed, 125 insertions(+), 63 deletions(-) (limited to 'packages') diff --git a/packages/order-utils/src/market_utils.ts b/packages/order-utils/src/market_utils.ts index 681059ddf..58e9ab7ba 100644 --- a/packages/order-utils/src/market_utils.ts +++ b/packages/order-utils/src/market_utils.ts @@ -5,37 +5,42 @@ import * as _ from 'lodash'; import { assert } from './assert'; import { constants } from './constants'; +import { FindFeeOrdersThatCoverFeesForTargetOrdersOpts, FindOrdersThatCoverMakerAssetFillAmountOpts } from './types'; 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. + * Takes an array of orders and returns a subset of those orders that has enough makerAssetAmount + * in order to fill the input makerAssetFillAmount plus slippageBufferAmount. Iterates from first order to last order. * 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. + * @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 makerAssetFillAmount The amount of makerAsset desired to be filled. + * @param opts Optional arguments this function accepts. * @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, + opts?: FindOrdersThatCoverMakerAssetFillAmountOpts, ): { resultOrders: SignedOrder[]; remainingFillAmount: BigNumber } { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + assert.isValidBaseUnitAmount('makerAssetFillAmount', makerAssetFillAmount); + // try to get remainingFillableMakerAssetAmounts from opts, if it's not there, use makerAssetAmount values from signedOrders + const remainingFillableMakerAssetAmounts = _.get( + opts, + 'remainingFillableMakerAssetAmounts', + _.map(signedOrders, order => order.makerAssetAmount), + ) as BigNumber[]; _.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', + 'Expected signedOrders.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 signedOrders input from left to right until we have enough makerAsset to fill totalFillAmount @@ -64,47 +69,53 @@ export const marketUtils = { 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 + * Takes an array of orders and an array of feeOrders. Returns a subset of the feeOrders that has enough ZRX + * 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. + * @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 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 opts Optional arguments this function accepts. * @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, + opts?: FindFeeOrdersThatCoverFeesForTargetOrdersOpts, ): { resultOrders: SignedOrder[]; remainingFeeAmount: BigNumber } { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema); + // try to get remainingFillableMakerAssetAmounts from opts, if it's not there, use makerAssetAmount values from signedOrders + const remainingFillableMakerAssetAmounts = _.get( + opts, + 'remainingFillableMakerAssetAmounts', + _.map(signedOrders, order => order.makerAssetAmount), + ) as BigNumber[]; _.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', + 'Expected signedOrders.length to equal opts.remainingFillableMakerAssetAmounts.length', + ); + // try to get remainingFillableFeeAmounts from opts, if it's not there, use makerAssetAmount values from signedFeeOrders + const remainingFillableFeeAmounts = _.get( + opts, + 'remainingFillableFeeAmounts', + _.map(signedFeeOrders, order => order.makerAssetAmount), + ) as BigNumber[]; + _.forEach(remainingFillableFeeAmounts, (amount, index) => + assert.isValidBaseUnitAmount(`remainingFillableFeeAmounts[${index}]`, amount), ); assert.assert( signedOrders.length === remainingFillableMakerAssetAmounts.length, - 'Expected signedFeeOrders.length to equal remainingFillableFeeAmounts.length', + 'Expected signedFeeOrders.length to equal opts.remainingFillableFeeAmounts.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 ZRX needed to fill signedOrders const totalFeeAmount = _.reduce( signedOrders, @@ -119,9 +130,11 @@ export const marketUtils = { ); const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( signedFeeOrders, - remainingFillableFeeAmounts, totalFeeAmount, - slippageBufferAmount, + { + remainingFillableMakerAssetAmounts: remainingFillableFeeAmounts, + slippageBufferAmount, + }, ); return { resultOrders, diff --git a/packages/order-utils/src/types.ts b/packages/order-utils/src/types.ts index 1fbd8cf7b..8a9a4cafe 100644 --- a/packages/order-utils/src/types.ts +++ b/packages/order-utils/src/types.ts @@ -41,3 +41,31 @@ export interface CreateOrderOpts { salt?: BigNumber; expirationTimeSeconds?: BigNumber; } + +/** + * remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `signedOrders` parameter. + * You can use `OrderStateUtils` `@0xproject/order-utils` to perform blockchain lookups for these values. + * Defaults to `makerAssetAmount` values from the signedOrders param. + * slippageBufferAmount: An additional amount of makerAsset to be covered by the result in case of trade collisions or partial fills. + * Defaults to 0 + */ +export interface FindOrdersThatCoverMakerAssetFillAmountOpts { + remainingFillableMakerAssetAmounts?: BigNumber[]; + slippageBufferAmount?: BigNumber; +} + +/** + * remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `signedOrders` parameter. + * You can use `OrderStateUtils` `@0xproject/order-utils` to perform blockchain lookups for these values. + * Defaults to `makerAssetAmount` values from the signedOrders 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. + * Defaults to `makerAssetAmount` values from the signedFeeOrders param. + * slippageBufferAmount: An additional amount of fee to be covered by the result in case of trade collisions or partial fills. + * Defaults to 0 + */ +export interface FindFeeOrdersThatCoverFeesForTargetOrdersOpts { + remainingFillableMakerAssetAmounts?: BigNumber[]; + remainingFillableFeeAmounts?: BigNumber[]; + slippageBufferAmount?: BigNumber; +} diff --git a/packages/order-utils/test/market_utils_test.ts b/packages/order-utils/test/market_utils_test.ts index 21c0a4802..2f6bb7bd1 100644 --- a/packages/order-utils/test/market_utils_test.ts +++ b/packages/order-utils/test/market_utils_test.ts @@ -11,13 +11,12 @@ chaiSetup.configure(); const expect = chai.expect; // tslint:disable: no-unused-expression -describe('marketUtils', () => { +describe.only('marketUtils', () => { describe('#findOrdersThatCoverMakerAssetFillAmount', () => { describe('no orders', () => { it('returns empty and unchanged remainingFillAmount', async () => { const fillAmount = new BigNumber(10); const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( - [], [], fillAmount, ); @@ -43,9 +42,11 @@ describe('marketUtils', () => { const slippageBufferAmount = new BigNumber(10); const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( inputOrders, - remainingFillableMakerAssetAmounts, fillAmount, - slippageBufferAmount, + { + remainingFillableMakerAssetAmounts, + slippageBufferAmount, + }, ); expect(resultOrders).to.be.deep.equal(inputOrders); expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -57,9 +58,11 @@ describe('marketUtils', () => { const slippageBufferAmount = new BigNumber(10); const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( inputOrders, - remainingFillableMakerAssetAmounts, fillAmount, - slippageBufferAmount, + { + remainingFillableMakerAssetAmounts, + slippageBufferAmount, + }, ); expect(resultOrders).to.be.deep.equal(inputOrders); expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -71,9 +74,11 @@ describe('marketUtils', () => { const slippageBufferAmount = new BigNumber(5); const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( inputOrders, - remainingFillableMakerAssetAmounts, fillAmount, - slippageBufferAmount, + { + remainingFillableMakerAssetAmounts, + slippageBufferAmount, + }, ); expect(resultOrders).to.be.deep.equal(inputOrders); expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(5)); @@ -83,8 +88,10 @@ describe('marketUtils', () => { const fillAmount = new BigNumber(10); const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( inputOrders, - remainingFillableMakerAssetAmounts, fillAmount, + { + remainingFillableMakerAssetAmounts, + }, ); expect(resultOrders).to.be.deep.equal([inputOrders[0]]); expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -94,8 +101,10 @@ describe('marketUtils', () => { const fillAmount = new BigNumber(15); const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( inputOrders, - remainingFillableMakerAssetAmounts, fillAmount, + { + remainingFillableMakerAssetAmounts, + }, ); expect(resultOrders).to.be.deep.equal([inputOrders[0], inputOrders[1]]); expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -120,8 +129,10 @@ describe('marketUtils', () => { const fillAmount = new BigNumber(30); const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( inputOrders, - remainingFillableMakerAssetAmounts, fillAmount, + { + remainingFillableMakerAssetAmounts, + }, ); expect(resultOrders).to.be.deep.equal([inputOrders[1], inputOrders[2]]); expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(15)); @@ -142,10 +153,11 @@ describe('marketUtils', () => { describe('no target orders', () => { it('returns empty and zero remainingFeeAmount', async () => { const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( - [], [], inputFeeOrders, - remainingFillableFeeAmounts, + { + remainingFillableFeeAmounts, + }, ); expect(resultOrders).to.be.empty; expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -168,9 +180,10 @@ describe('marketUtils', () => { it('returns empty and non-zero remainingFeeAmount', async () => { const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( inputOrders, - remainingFillableMakerAssetAmounts, - [], [], + { + remainingFillableMakerAssetAmounts, + }, ); expect(resultOrders).to.be.empty; expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30)); @@ -190,9 +203,11 @@ describe('marketUtils', () => { it('returns empty and zero remainingFeeAmount', async () => { const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( inputOrders, - remainingFillableMakerAssetAmounts, inputFeeOrders, - remainingFillableFeeAmounts, + { + remainingFillableMakerAssetAmounts, + remainingFillableFeeAmounts, + }, ); expect(resultOrders).to.be.empty; expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -215,9 +230,11 @@ describe('marketUtils', () => { it('returns input fee orders and zero remainingFeeAmount', async () => { const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( inputOrders, - remainingFillableMakerAssetAmounts, inputFeeOrders, - remainingFillableFeeAmounts, + { + remainingFillableMakerAssetAmounts, + remainingFillableFeeAmounts, + }, ); expect(resultOrders).to.be.deep.equal(inputFeeOrders); expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -243,9 +260,11 @@ describe('marketUtils', () => { it('returns first two input fee orders and zero remainingFeeAmount', async () => { const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( inputOrders, - remainingFillableMakerAssetAmounts, inputFeeOrders, - remainingFillableFeeAmounts, + { + remainingFillableMakerAssetAmounts, + remainingFillableFeeAmounts, + }, ); expect(resultOrders).to.be.deep.equal([inputFeeOrders[0], inputFeeOrders[1]]); expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -268,9 +287,11 @@ describe('marketUtils', () => { it('returns input fee orders and non-zero remainingFeeAmount', async () => { const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( inputOrders, - remainingFillableMakerAssetAmounts, inputFeeOrders, - remainingFillableFeeAmounts, + { + remainingFillableMakerAssetAmounts, + remainingFillableFeeAmounts, + }, ); expect(resultOrders).to.be.deep.equal(inputFeeOrders); expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30)); -- cgit v1.2.3 From 66745c5260d2e2802211697980ce91a0cf084e83 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 21:18:13 -0400 Subject: Remove remaining amounts that are now defaults in tests --- packages/order-utils/test/market_utils_test.ts | 37 +------------------------- 1 file changed, 1 insertion(+), 36 deletions(-) (limited to 'packages') diff --git a/packages/order-utils/test/market_utils_test.ts b/packages/order-utils/test/market_utils_test.ts index 2f6bb7bd1..109420a02 100644 --- a/packages/order-utils/test/market_utils_test.ts +++ b/packages/order-utils/test/market_utils_test.ts @@ -11,7 +11,7 @@ chaiSetup.configure(); const expect = chai.expect; // tslint:disable: no-unused-expression -describe.only('marketUtils', () => { +describe('marketUtils', () => { describe('#findOrdersThatCoverMakerAssetFillAmount', () => { describe('no orders', () => { it('returns empty and unchanged remainingFillAmount', async () => { @@ -33,8 +33,6 @@ describe.only('marketUtils', () => { }, 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 @@ -44,7 +42,6 @@ describe.only('marketUtils', () => { inputOrders, fillAmount, { - remainingFillableMakerAssetAmounts, slippageBufferAmount, }, ); @@ -60,7 +57,6 @@ describe.only('marketUtils', () => { inputOrders, fillAmount, { - remainingFillableMakerAssetAmounts, slippageBufferAmount, }, ); @@ -76,7 +72,6 @@ describe.only('marketUtils', () => { inputOrders, fillAmount, { - remainingFillableMakerAssetAmounts, slippageBufferAmount, }, ); @@ -89,9 +84,6 @@ describe.only('marketUtils', () => { const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( inputOrders, fillAmount, - { - remainingFillableMakerAssetAmounts, - }, ); expect(resultOrders).to.be.deep.equal([inputOrders[0]]); expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -102,9 +94,6 @@ describe.only('marketUtils', () => { const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( inputOrders, fillAmount, - { - remainingFillableMakerAssetAmounts, - }, ); expect(resultOrders).to.be.deep.equal([inputOrders[0], inputOrders[1]]); expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -148,16 +137,11 @@ describe.only('marketUtils', () => { }, 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); @@ -198,16 +182,10 @@ describe.only('marketUtils', () => { }, 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, inputFeeOrders, - { - remainingFillableMakerAssetAmounts, - remainingFillableFeeAmounts, - }, ); expect(resultOrders).to.be.empty; expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -225,16 +203,10 @@ describe.only('marketUtils', () => { }, 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, inputFeeOrders, - { - remainingFillableMakerAssetAmounts, - remainingFillableFeeAmounts, - }, ); expect(resultOrders).to.be.deep.equal(inputFeeOrders); expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT); @@ -263,7 +235,6 @@ describe.only('marketUtils', () => { inputFeeOrders, { remainingFillableMakerAssetAmounts, - remainingFillableFeeAmounts, }, ); expect(resultOrders).to.be.deep.equal([inputFeeOrders[0], inputFeeOrders[1]]); @@ -282,16 +253,10 @@ describe.only('marketUtils', () => { }, 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, inputFeeOrders, - { - remainingFillableMakerAssetAmounts, - remainingFillableFeeAmounts, - }, ); expect(resultOrders).to.be.deep.equal(inputFeeOrders); expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30)); -- cgit v1.2.3 From a2192e62df56efd95a0e3540296cd17a23cb2033 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 9 Aug 2018 21:26:45 -0400 Subject: Update CHANGELOG --- packages/order-utils/CHANGELOG.json | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'packages') diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index a81eb077d..7cefc1670 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -18,6 +18,11 @@ }, { "note": "Dependencies updated" + }, + { + "note": + "Update marketUtils api such that all optional parameters are bundled into one optional param and more defaults are provided", + "pr": 954 } ], "timestamp": 1534210131 -- cgit v1.2.3 From 6a2634d362e50e5a611f388c0785df3209cee308 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 13 Aug 2018 21:29:35 -0700 Subject: Make marketUtils interface compatible with Order and SignedOrder --- packages/order-utils/src/market_utils.ts | 72 ++++++++++++++++---------------- packages/order-utils/src/types.ts | 12 +++--- 2 files changed, 42 insertions(+), 42 deletions(-) (limited to 'packages') diff --git a/packages/order-utils/src/market_utils.ts b/packages/order-utils/src/market_utils.ts index 58e9ab7ba..a0a827546 100644 --- a/packages/order-utils/src/market_utils.ts +++ b/packages/order-utils/src/market_utils.ts @@ -1,5 +1,5 @@ import { schemas } from '@0xproject/json-schemas'; -import { SignedOrder } from '@0xproject/types'; +import { Order } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; @@ -12,40 +12,40 @@ export const marketUtils = { * Takes an array of orders and returns a subset of those orders that has enough makerAssetAmount * in order to fill the input makerAssetFillAmount plus slippageBufferAmount. Iterates from first order to last order. * 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. + * @param orders An array of objects that extend the Order interface. All orders should specify the same makerAsset. * All orders should specify WETH as the takerAsset. * @param makerAssetFillAmount The amount of makerAsset desired to be filled. * @param opts Optional arguments this function accepts. * @return Resulting orders and remaining fill amount that could not be covered by the input. */ - findOrdersThatCoverMakerAssetFillAmount( - signedOrders: SignedOrder[], + findOrdersThatCoverMakerAssetFillAmount( + orders: T[], makerAssetFillAmount: BigNumber, opts?: FindOrdersThatCoverMakerAssetFillAmountOpts, - ): { resultOrders: SignedOrder[]; remainingFillAmount: BigNumber } { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + ): { resultOrders: T[]; remainingFillAmount: BigNumber } { + 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 signedOrders + // try to get remainingFillableMakerAssetAmounts from opts, if it's not there, use makerAssetAmount values from orders const remainingFillableMakerAssetAmounts = _.get( opts, 'remainingFillableMakerAssetAmounts', - _.map(signedOrders, order => order.makerAssetAmount), + _.map(orders, order => order.makerAssetAmount), ) as BigNumber[]; _.forEach(remainingFillableMakerAssetAmounts, (amount, index) => assert.isValidBaseUnitAmount(`remainingFillableMakerAssetAmount[${index}]`, amount), ); assert.assert( - signedOrders.length === remainingFillableMakerAssetAmounts.length, - 'Expected signedOrders.length to equal opts.remainingFillableMakerAssetAmounts.length', + 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 signedOrders input from left to right until we have enough makerAsset to fill totalFillAmount + // iterate through the orders input from left to right until we have enough makerAsset to fill totalFillAmount const result = _.reduce( - signedOrders, + orders, ({ resultOrders, remainingFillAmount }, order, index) => { if (remainingFillAmount.lessThanOrEqualTo(constants.ZERO_AMOUNT)) { return { resultOrders, remainingFillAmount: constants.ZERO_AMOUNT }; @@ -64,61 +64,61 @@ export const marketUtils = { }; } }, - { resultOrders: [] as SignedOrder[], remainingFillAmount: totalFillAmount }, + { resultOrders: [] as T[], remainingFillAmount: totalFillAmount }, ); return result; }, /** * Takes an array of orders and an array of feeOrders. Returns a subset of the feeOrders that has enough ZRX - * in order to fill the takerFees required by signedOrders plus a slippageBufferAmount. + * in order to fill the takerFees required by orders 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 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 opts Optional arguments this function accepts. + * @param orders An array of objects that extend the Order interface. All orders should specify ZRX as + * the makerAsset and WETH as the takerAsset. + * @param feeOrders An array of objects that extend the Order interface. All orders should specify ZRX as + * the makerAsset and WETH as the takerAsset. + * @param opts Optional arguments this function accepts. * @return Resulting orders and remaining fee amount that could not be covered by the input. */ - findFeeOrdersThatCoverFeesForTargetOrders( - signedOrders: SignedOrder[], - signedFeeOrders: SignedOrder[], + findFeeOrdersThatCoverFeesForTargetOrders( + orders: T[], + feeOrders: T[], opts?: FindFeeOrdersThatCoverFeesForTargetOrdersOpts, - ): { resultOrders: SignedOrder[]; remainingFeeAmount: BigNumber } { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema); - // try to get remainingFillableMakerAssetAmounts from opts, if it's not there, use makerAssetAmount values from signedOrders + ): { resultOrders: T[]; remainingFeeAmount: BigNumber } { + assert.doesConformToSchema('orders', orders, schemas.ordersSchema); + assert.doesConformToSchema('feeOrders', feeOrders, schemas.ordersSchema); + // try to get remainingFillableMakerAssetAmounts from opts, if it's not there, use makerAssetAmount values from orders const remainingFillableMakerAssetAmounts = _.get( opts, 'remainingFillableMakerAssetAmounts', - _.map(signedOrders, order => order.makerAssetAmount), + _.map(orders, order => order.makerAssetAmount), ) as BigNumber[]; _.forEach(remainingFillableMakerAssetAmounts, (amount, index) => assert.isValidBaseUnitAmount(`remainingFillableMakerAssetAmount[${index}]`, amount), ); assert.assert( - signedOrders.length === remainingFillableMakerAssetAmounts.length, - 'Expected signedOrders.length to equal opts.remainingFillableMakerAssetAmounts.length', + orders.length === remainingFillableMakerAssetAmounts.length, + 'Expected orders.length to equal opts.remainingFillableMakerAssetAmounts.length', ); - // try to get remainingFillableFeeAmounts from opts, if it's not there, use makerAssetAmount values from signedFeeOrders + // try to get remainingFillableFeeAmounts from opts, if it's not there, use makerAssetAmount values from feeOrders const remainingFillableFeeAmounts = _.get( opts, 'remainingFillableFeeAmounts', - _.map(signedFeeOrders, order => order.makerAssetAmount), + _.map(feeOrders, order => order.makerAssetAmount), ) as BigNumber[]; _.forEach(remainingFillableFeeAmounts, (amount, index) => assert.isValidBaseUnitAmount(`remainingFillableFeeAmounts[${index}]`, amount), ); assert.assert( - signedOrders.length === remainingFillableMakerAssetAmounts.length, - 'Expected signedFeeOrders.length to equal opts.remainingFillableFeeAmounts.length', + feeOrders.length === remainingFillableFeeAmounts.length, + 'Expected feeOrders.length to equal opts.remainingFillableFeeAmounts.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 ZRX needed to fill signedOrders + // calculate total amount of ZRX needed to fill orders const totalFeeAmount = _.reduce( - signedOrders, + orders, (accFees, order, index) => { const makerAssetAmountAvailable = remainingFillableMakerAssetAmounts[index]; const feeToFillMakerAssetAmountAvailable = makerAssetAmountAvailable @@ -129,7 +129,7 @@ export const marketUtils = { constants.ZERO_AMOUNT, ); const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( - signedFeeOrders, + feeOrders, totalFeeAmount, { remainingFillableMakerAssetAmounts: remainingFillableFeeAmounts, diff --git a/packages/order-utils/src/types.ts b/packages/order-utils/src/types.ts index 8a9a4cafe..2e9c79d80 100644 --- a/packages/order-utils/src/types.ts +++ b/packages/order-utils/src/types.ts @@ -43,9 +43,9 @@ export interface CreateOrderOpts { } /** - * remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `signedOrders` parameter. + * remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter. * You can use `OrderStateUtils` `@0xproject/order-utils` to perform blockchain lookups for these values. - * Defaults to `makerAssetAmount` values from the signedOrders param. + * Defaults to `makerAssetAmount` values from the orders param. * slippageBufferAmount: An additional amount of makerAsset to be covered by the result in case of trade collisions or partial fills. * Defaults to 0 */ @@ -55,12 +55,12 @@ export interface FindOrdersThatCoverMakerAssetFillAmountOpts { } /** - * remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `signedOrders` parameter. + * remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter. * You can use `OrderStateUtils` `@0xproject/order-utils` to perform blockchain lookups for these values. - * Defaults to `makerAssetAmount` values from the signedOrders param. - * remainingFillableFeeAmounts: An array of BigNumbers corresponding to the signedFeeOrders parameter. + * Defaults to `makerAssetAmount` values from the orders param. + * remainingFillableFeeAmounts: An array of BigNumbers corresponding to the feeOrders parameter. * You can use OrderStateUtils @0xproject/order-utils to perform blockchain lookups for these values. - * Defaults to `makerAssetAmount` values from the signedFeeOrders param. + * Defaults to `makerAssetAmount` values from the feeOrders param. * slippageBufferAmount: An additional amount of fee to be covered by the result in case of trade collisions or partial fills. * Defaults to 0 */ -- cgit v1.2.3 From db20ad1c5db5677b7d5ad54bf76a928b5857fe8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 14 Aug 2018 06:21:07 +0000 Subject: Bump @types/fetch-mock from 5.12.2 to 6.0.3 Bumps [@types/fetch-mock](https://github.com/DefinitelyTyped/DefinitelyTyped) from 5.12.2 to 6.0.3. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits) Signed-off-by: dependabot[bot] --- packages/connect/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/connect/package.json b/packages/connect/package.json index 1cc5e1bab..0fad3e14c 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@0xproject/monorepo-scripts": "^1.0.5", "@0xproject/tslint-config": "^1.0.5", - "@types/fetch-mock": "^5.12.2", + "@types/fetch-mock": "^6.0.3", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", "@types/query-string": "^5.0.1", -- cgit v1.2.3 From 6baa5ef311112941ccaec3fb8a877dd57b63627b Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Mon, 13 Aug 2018 12:46:43 -0700 Subject: feat: Upgrade TypeScript to 3.0.1 --- packages/0x.js/package.json | 2 +- packages/abi-gen/package.json | 2 +- packages/assert/package.json | 2 +- packages/base-contract/package.json | 2 +- packages/connect/package.json | 2 +- packages/contract-wrappers/package.json | 2 +- packages/contracts/package.json | 2 +- packages/dev-utils/package.json | 2 +- packages/ethereum-types/package.json | 2 +- packages/fill-scenarios/package.json | 2 +- packages/json-schemas/package.json | 2 +- packages/metacoin/package.json | 2 +- packages/migrations/package.json | 2 +- packages/monorepo-scripts/package.json | 2 +- packages/order-utils/package.json | 2 +- packages/order-watcher/package.json | 2 +- packages/react-docs-example/package.json | 2 +- packages/react-docs/package.json | 2 +- packages/react-shared/package.json | 2 +- packages/sol-compiler/package.json | 2 +- packages/sol-cov/package.json | 2 +- packages/sol-resolver/package.json | 2 +- packages/sra-report/package.json | 2 +- packages/subproviders/package.json | 2 +- packages/testnet-faucets/package.json | 2 +- packages/tslint-config/package.json | 2 +- packages/types/package.json | 2 +- packages/utils/package.json | 2 +- packages/web3-wrapper/package.json | 2 +- packages/website/package.json | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) (limited to 'packages') diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index cf7b1962f..2daf40b54 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -94,7 +94,7 @@ "source-map-support": "^0.5.0", "tslint": "5.11.0", "typedoc": "0xProject/typedoc", - "typescript": "2.9.2", + "typescript": "3.0.1", "webpack": "^3.1.0" }, "dependencies": { diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json index 8ea055a15..565fe4058 100644 --- a/packages/abi-gen/package.json +++ b/packages/abi-gen/package.json @@ -63,7 +63,7 @@ "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "publishConfig": { "access": "public" diff --git a/packages/assert/package.json b/packages/assert/package.json index 9d2669955..d249b4cd1 100644 --- a/packages/assert/package.json +++ b/packages/assert/package.json @@ -44,7 +44,7 @@ "nyc": "^11.0.1", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@0xproject/json-schemas": "^1.0.1-rc.4", diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json index e658d9cfa..c5375ecf6 100644 --- a/packages/base-contract/package.json +++ b/packages/base-contract/package.json @@ -40,7 +40,7 @@ "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@0xproject/typescript-typings": "^1.0.4", diff --git a/packages/connect/package.json b/packages/connect/package.json index 1cc5e1bab..4ab5cec64 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -83,7 +83,7 @@ "shx": "^0.2.2", "tslint": "5.11.0", "typedoc": "~0.8.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "publishConfig": { "access": "public" diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 7667b5b7f..ae2867e6c 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -68,7 +68,7 @@ "sinon": "^4.0.0", "source-map-support": "^0.5.0", "tslint": "5.11.0", - "typescript": "2.9.2", + "typescript": "3.0.1", "web3-provider-engine": "14.0.6" }, "dependencies": { diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 799f72d9e..01858894b 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -68,7 +68,7 @@ "solc": "^0.4.24", "solhint": "^1.2.1", "tslint": "5.11.0", - "typescript": "2.9.2", + "typescript": "3.0.1", "yargs": "^10.0.3" }, "dependencies": { diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 5aa6edcd8..544ff23fa 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -42,7 +42,7 @@ "nyc": "^11.0.1", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@0xproject/subproviders": "^1.0.5", diff --git a/packages/ethereum-types/package.json b/packages/ethereum-types/package.json index 0e89a8049..c2092a1d3 100644 --- a/packages/ethereum-types/package.json +++ b/packages/ethereum-types/package.json @@ -41,7 +41,7 @@ "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@types/node": "^8.0.53", diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json index c3e8afb0e..466e96258 100644 --- a/packages/fill-scenarios/package.json +++ b/packages/fill-scenarios/package.json @@ -38,7 +38,7 @@ "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@0xproject/base-contract": "^2.0.0-rc.1", diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index 40cb71c18..a5941a971 100644 --- a/packages/json-schemas/package.json +++ b/packages/json-schemas/package.json @@ -70,7 +70,7 @@ "shx": "^0.2.2", "tslint": "5.11.0", "typedoc": "0xProject/typedoc", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "publishConfig": { "access": "public" diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json index 6900da198..322708b50 100644 --- a/packages/metacoin/package.json +++ b/packages/metacoin/package.json @@ -56,6 +56,6 @@ "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" } } diff --git a/packages/migrations/package.json b/packages/migrations/package.json index d496393f7..dc481a972 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -49,7 +49,7 @@ "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2", + "typescript": "3.0.1", "yargs": "^10.0.3" }, "dependencies": { diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index 4d92ed495..87135fd93 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -40,7 +40,7 @@ "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@lerna/batch-packages": "^3.0.0-beta.18", diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json index fa8f3563e..bedbdc6d2 100644 --- a/packages/order-utils/package.json +++ b/packages/order-utils/package.json @@ -70,7 +70,7 @@ "sinon": "^4.0.0", "tslint": "5.11.0", "typedoc": "0xProject/typedoc", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@0xproject/assert": "^1.0.5", diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json index ba4fed358..5ce1805e7 100644 --- a/packages/order-watcher/package.json +++ b/packages/order-watcher/package.json @@ -67,7 +67,7 @@ "sinon": "^4.0.0", "source-map-support": "^0.5.0", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@0xproject/assert": "^1.0.5", diff --git a/packages/react-docs-example/package.json b/packages/react-docs-example/package.json index 1701e6adb..001b354d7 100644 --- a/packages/react-docs-example/package.json +++ b/packages/react-docs-example/package.json @@ -45,7 +45,7 @@ "source-map-loader": "^0.2.3", "style-loader": "^0.20.2", "tslint": "^5.9.1", - "typescript": "2.9.2", + "typescript": "3.0.1", "webpack": "^3.11.0", "webpack-dev-server": "^2.11.1" }, diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index e24ed8e6f..a530e526d 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -33,7 +33,7 @@ "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "tslint": "^5.9.1", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@0xproject/react-shared": "^1.0.6", diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json index 9761c246e..6eaac9d07 100644 --- a/packages/react-shared/package.json +++ b/packages/react-shared/package.json @@ -32,7 +32,7 @@ "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "tslint": "^5.9.1", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@types/is-mobile": "0.3.0", diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json index 7cb07e970..29b8f9f3a 100644 --- a/packages/sol-compiler/package.json +++ b/packages/sol-compiler/package.json @@ -71,7 +71,7 @@ "tslint": "5.11.0", "typedoc": "0xProject/typedoc", "types-bn": "^0.0.1", - "typescript": "2.9.2", + "typescript": "3.0.1", "web3-typescript-typings": "^0.10.2", "zeppelin-solidity": "1.8.0" }, diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json index 4c3000360..1d98faf8b 100644 --- a/packages/sol-cov/package.json +++ b/packages/sol-cov/package.json @@ -89,7 +89,7 @@ "sinon": "^4.0.0", "tslint": "5.11.0", "typedoc": "0xProject/typedoc", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "publishConfig": { "access": "public" diff --git a/packages/sol-resolver/package.json b/packages/sol-resolver/package.json index 7a3c7509a..46ad8f784 100644 --- a/packages/sol-resolver/package.json +++ b/packages/sol-resolver/package.json @@ -30,7 +30,7 @@ "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@0xproject/types": "^1.0.1-rc.4", diff --git a/packages/sra-report/package.json b/packages/sra-report/package.json index 42321359c..175a4ca1b 100644 --- a/packages/sra-report/package.json +++ b/packages/sra-report/package.json @@ -66,7 +66,7 @@ "nyc": "^11.0.1", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "publishConfig": { "access": "public" diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index 405b89db3..ab3ae1a5a 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -84,7 +84,7 @@ "sinon": "^4.0.0", "tslint": "5.11.0", "typedoc": "0xProject/typedoc", - "typescript": "2.9.2", + "typescript": "3.0.1", "webpack": "^3.1.0" }, "optionalDependencies": { diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json index ce2a1a52d..769fdf371 100644 --- a/packages/testnet-faucets/package.json +++ b/packages/testnet-faucets/package.json @@ -43,7 +43,7 @@ "shx": "^0.2.2", "source-map-loader": "^0.1.6", "tslint": "5.11.0", - "typescript": "2.9.2", + "typescript": "3.0.1", "webpack": "^3.1.0", "webpack-node-externals": "^1.6.0" } diff --git a/packages/tslint-config/package.json b/packages/tslint-config/package.json index 1cc778caf..6956a9105 100644 --- a/packages/tslint-config/package.json +++ b/packages/tslint-config/package.json @@ -39,7 +39,7 @@ "copyfiles": "^1.2.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "lodash": "^4.17.5", diff --git a/packages/types/package.json b/packages/types/package.json index c97984e10..6a36b897b 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -30,7 +30,7 @@ "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@types/node": "^8.0.53", diff --git a/packages/utils/package.json b/packages/utils/package.json index 0fd925715..c596f0620 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -40,7 +40,7 @@ "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@0xproject/types": "^1.0.1-rc.4", diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index 3f9ee9019..437a1c6b5 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -61,7 +61,7 @@ "shx": "^0.2.2", "tslint": "5.11.0", "typedoc": "0xProject/typedoc", - "typescript": "2.9.2" + "typescript": "3.0.1" }, "dependencies": { "@0xproject/assert": "^1.0.5", diff --git a/packages/website/package.json b/packages/website/package.json index f4638229d..0fcf9c9b9 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -98,7 +98,7 @@ "style-loader": "0.13.x", "tslint": "5.11.0", "tslint-config-0xproject": "^0.0.2", - "typescript": "2.9.2", + "typescript": "3.0.1", "uglifyjs-webpack-plugin": "^1.2.5", "webpack": "^3.1.0", "webpack-dev-middleware": "^1.10.0", -- cgit v1.2.3 From b6cdc00a3145e6b13102676b2a881d0fe52b3a61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 14 Aug 2018 21:51:13 +0000 Subject: Bump copyfiles from 1.2.0 to 2.0.0 Bumps [copyfiles](https://github.com/calvinmetcalf/copyfiles) from 1.2.0 to 2.0.0. - [Release notes](https://github.com/calvinmetcalf/copyfiles/releases) - [Commits](https://github.com/calvinmetcalf/copyfiles/compare/v1.2.0...v2.0.0) Signed-off-by: dependabot[bot] --- packages/0x.js/package.json | 2 +- packages/abi-gen/package.json | 2 +- packages/assert/package.json | 2 +- packages/base-contract/package.json | 2 +- packages/connect/package.json | 2 +- packages/contract-wrappers/package.json | 2 +- packages/contracts/package.json | 2 +- packages/dev-utils/package.json | 2 +- packages/ethereum-types/package.json | 2 +- packages/fill-scenarios/package.json | 2 +- packages/json-schemas/package.json | 2 +- packages/migrations/package.json | 2 +- packages/order-utils/package.json | 2 +- packages/order-watcher/package.json | 2 +- packages/react-docs-example/package.json | 2 +- packages/react-docs/package.json | 2 +- packages/react-shared/package.json | 2 +- packages/sol-compiler/package.json | 2 +- packages/sol-cov/package.json | 2 +- packages/sol-resolver/package.json | 2 +- packages/sra-report/package.json | 2 +- packages/subproviders/package.json | 2 +- packages/tslint-config/package.json | 2 +- packages/types/package.json | 2 +- packages/typescript-typings/package.json | 2 +- packages/utils/package.json | 2 +- packages/web3-wrapper/package.json | 2 +- packages/website/package.json | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) (limited to 'packages') diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index 2daf40b54..bbb902b49 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -81,7 +81,7 @@ "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^2.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "json-loader": "^0.5.4", "make-promises-safe": "^1.1.0", diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json index 565fe4058..3e3494585 100644 --- a/packages/abi-gen/package.json +++ b/packages/abi-gen/package.json @@ -56,7 +56,7 @@ "@types/tmp": "^0.0.33", "@types/yargs": "^10.0.0", "chai": "^4.1.2", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^5.2.0", diff --git a/packages/assert/package.json b/packages/assert/package.json index d249b4cd1..64e60a1e1 100644 --- a/packages/assert/package.json +++ b/packages/assert/package.json @@ -36,7 +36,7 @@ "@types/mocha": "^2.2.42", "@types/valid-url": "^1.0.2", "chai": "^4.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json index c5375ecf6..d31a02dda 100644 --- a/packages/base-contract/package.json +++ b/packages/base-contract/package.json @@ -34,7 +34,7 @@ "@0xproject/tslint-config": "^1.0.5", "@types/lodash": "4.14.104", "chai": "^4.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", "npm-run-all": "^4.1.2", diff --git a/packages/connect/package.json b/packages/connect/package.json index 3894be6ea..8f2e423b5 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -73,7 +73,7 @@ "async-child-process": "^1.1.1", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "fetch-mock": "^5.13.1", "make-promises-safe": "^1.1.0", diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index ae2867e6c..098c95ef0 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -57,7 +57,7 @@ "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^2.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 01858894b..8bd808a27 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -59,7 +59,7 @@ "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^2.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 544ff23fa..79e75a06e 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -35,7 +35,7 @@ "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", "chai": "^4.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", "npm-run-all": "^4.1.2", diff --git a/packages/ethereum-types/package.json b/packages/ethereum-types/package.json index c2092a1d3..4fa273c6a 100644 --- a/packages/ethereum-types/package.json +++ b/packages/ethereum-types/package.json @@ -37,7 +37,7 @@ "devDependencies": { "@0xproject/monorepo-scripts": "^1.0.5", "@0xproject/tslint-config": "^1.0.5", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "tslint": "5.11.0", diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json index 466e96258..ccc04caf8 100644 --- a/packages/fill-scenarios/package.json +++ b/packages/fill-scenarios/package.json @@ -33,7 +33,7 @@ "@0xproject/sol-compiler": "^1.0.5", "@0xproject/tslint-config": "^1.0.5", "@types/lodash": "4.14.104", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index a5941a971..062304585 100644 --- a/packages/json-schemas/package.json +++ b/packages/json-schemas/package.json @@ -60,7 +60,7 @@ "@types/lodash.values": "^4.3.3", "@types/mocha": "^2.2.42", "chai": "^4.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "lodash.foreach": "^4.5.0", "make-promises-safe": "^1.1.0", diff --git a/packages/migrations/package.json b/packages/migrations/package.json index dc481a972..c1ef61257 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -44,7 +44,7 @@ "@0xproject/tslint-config": "^1.0.5", "@0xproject/types": "^1.0.1-rc.4", "@types/yargs": "^10.0.0", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json index bedbdc6d2..07d6fa1b6 100644 --- a/packages/order-utils/package.json +++ b/packages/order-utils/package.json @@ -61,7 +61,7 @@ "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^2.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json index 5ce1805e7..59d80fd08 100644 --- a/packages/order-watcher/package.json +++ b/packages/order-watcher/package.json @@ -55,7 +55,7 @@ "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^2.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "json-loader": "^0.5.4", "make-promises-safe": "^1.1.0", diff --git a/packages/react-docs-example/package.json b/packages/react-docs-example/package.json index 001b354d7..8efe35089 100644 --- a/packages/react-docs-example/package.json +++ b/packages/react-docs-example/package.json @@ -34,7 +34,7 @@ "@types/react-dom": "^16.0.3", "@types/react-tap-event-plugin": "0.0.30", "awesome-typescript-loader": "^3.1.3", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "css-loader": "^0.28.9", "json-loader": "^0.5.4", "less": "^2.7.2", diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index a530e526d..f09bb64a0 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -29,7 +29,7 @@ "@0xproject/monorepo-scripts": "^1.0.5", "@0xproject/tslint-config": "^1.0.5", "@types/compare-versions": "^3.0.0", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "tslint": "^5.9.1", diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json index 6eaac9d07..83b4cc5c9 100644 --- a/packages/react-shared/package.json +++ b/packages/react-shared/package.json @@ -28,7 +28,7 @@ "@0xproject/dev-utils": "^1.0.4", "@0xproject/monorepo-scripts": "^1.0.5", "@0xproject/tslint-config": "^1.0.5", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "tslint": "^5.9.1", diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json index 29b8f9f3a..6543b782b 100644 --- a/packages/sol-compiler/package.json +++ b/packages/sol-compiler/package.json @@ -61,7 +61,7 @@ "@types/semver": "^5.5.0", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json index 1d98faf8b..bc24fd1dc 100644 --- a/packages/sol-cov/package.json +++ b/packages/sol-cov/package.json @@ -79,7 +79,7 @@ "@types/rimraf": "^2.0.2", "@types/solidity-parser-antlr": "^0.2.1", "chai": "^4.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", diff --git a/packages/sol-resolver/package.json b/packages/sol-resolver/package.json index 46ad8f784..85d11e9e7 100644 --- a/packages/sol-resolver/package.json +++ b/packages/sol-resolver/package.json @@ -26,7 +26,7 @@ "devDependencies": { "@0xproject/monorepo-scripts": "^1.0.5", "@0xproject/tslint-config": "^1.0.5", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "tslint": "5.11.0", diff --git a/packages/sra-report/package.json b/packages/sra-report/package.json index 175a4ca1b..8c213ee26 100644 --- a/packages/sra-report/package.json +++ b/packages/sra-report/package.json @@ -57,7 +57,7 @@ "@types/yargs": "^10.0.0", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index ab3ae1a5a..57b0a13b3 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -74,7 +74,7 @@ "@types/sinon": "^2.2.2", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", diff --git a/packages/tslint-config/package.json b/packages/tslint-config/package.json index 6956a9105..c0a1977f9 100644 --- a/packages/tslint-config/package.json +++ b/packages/tslint-config/package.json @@ -36,7 +36,7 @@ "devDependencies": { "@0xproject/monorepo-scripts": "^1.0.5", "@types/lodash": "4.14.104", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "typescript": "3.0.1" diff --git a/packages/types/package.json b/packages/types/package.json index 6a36b897b..a41f78aac 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -26,7 +26,7 @@ "devDependencies": { "@0xproject/monorepo-scripts": "^1.0.5", "@0xproject/tslint-config": "^1.0.5", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", "tslint": "5.11.0", diff --git a/packages/typescript-typings/package.json b/packages/typescript-typings/package.json index 01a1d8adc..5d9768cb0 100644 --- a/packages/typescript-typings/package.json +++ b/packages/typescript-typings/package.json @@ -33,7 +33,7 @@ }, "devDependencies": { "@0xproject/monorepo-scripts": "^1.0.5", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "shx": "^0.2.2" }, "publishConfig": { diff --git a/packages/utils/package.json b/packages/utils/package.json index c596f0620..28a967a35 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -34,7 +34,7 @@ "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", "chai": "^4.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", "npm-run-all": "^4.1.2", diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index 437a1c6b5..d672db7e4 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -51,7 +51,7 @@ "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^2.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "ganache-core": "0xProject/ganache-core#monorepo-dep", "make-promises-safe": "^1.1.0", diff --git a/packages/website/package.json b/packages/website/package.json index 0fcf9c9b9..3b4055856 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -84,7 +84,7 @@ "@types/redux": "^3.6.0", "awesome-typescript-loader": "^3.1.3", "copy-webpack-plugin": "^4.0.1", - "copyfiles": "^1.2.0", + "copyfiles": "^2.0.0", "css-loader": "0.23.x", "exports-loader": "0.6.x", "imports-loader": "0.6.x", -- cgit v1.2.3 From 622509c508272790e3e69c09cf1a1f9696815147 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Mon, 13 Aug 2018 12:23:29 +1000 Subject: [Order-utils] Order is valid when maker amount is very small Previously our min fillable calculation would throw a rounding error when encountering a valid order (with a small maker amount). This was inconsistent with the on-chain logic which allowed this order to be filled. --- packages/contracts/test/exchange/fill_order.ts | 11 ++ .../test/utils/fill_order_combinatorial_utils.ts | 7 ++ .../test/utils/order_factory_from_scenario.ts | 23 ++++ packages/contracts/test/utils/types.ts | 3 +- packages/order-utils/CHANGELOG.json | 4 + packages/order-utils/src/order_state_utils.ts | 36 +++--- .../order-utils/test/order_state_utils_test.ts | 122 +++++++++++++++++++++ packages/order-watcher/test/order_watcher_test.ts | 20 ++-- 8 files changed, 195 insertions(+), 31 deletions(-) create mode 100644 packages/order-utils/test/order_state_utils_test.ts (limited to 'packages') diff --git a/packages/contracts/test/exchange/fill_order.ts b/packages/contracts/test/exchange/fill_order.ts index 1494fe093..e79e2239e 100644 --- a/packages/contracts/test/exchange/fill_order.ts +++ b/packages/contracts/test/exchange/fill_order.ts @@ -104,6 +104,17 @@ describe('FillOrder Tests', () => { }; await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); }); + it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount with zero decimals', async () => { + const fillScenario = { + ...defaultFillScenario, + orderScenario: { + ...defaultFillScenario.orderScenario, + makerAssetAmountScenario: OrderAssetAmountScenario.Small, + makerAssetDataScenario: AssetDataScenario.ERC20ZeroDecimals, + }, + }; + await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario); + }); it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => { const fillScenario = { ...defaultFillScenario, diff --git a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts index 284c4a2db..f18ad0dd3 100644 --- a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts +++ b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts @@ -81,6 +81,12 @@ export async function fillOrderCombinatorialUtilsFactoryAsync( erc20FiveDecimalTokenCount, fiveDecimals, ); + const zeroDecimals = new BigNumber(0); + const erc20ZeroDecimalTokenCount = 2; + const [erc20ZeroDecimalTokenA, erc20ZeroDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync( + erc20ZeroDecimalTokenCount, + zeroDecimals, + ); const erc20Proxy = await erc20Wrapper.deployProxyAsync(); await erc20Wrapper.setBalancesAndAllowancesAsync(); @@ -119,6 +125,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync( zrxToken.address, [erc20EighteenDecimalTokenA.address, erc20EighteenDecimalTokenB.address], [erc20FiveDecimalTokenA.address, erc20FiveDecimalTokenB.address], + [erc20ZeroDecimalTokenA.address, erc20ZeroDecimalTokenB.address], erc721Token, erc721Balances, exchangeContract.address, diff --git a/packages/contracts/test/utils/order_factory_from_scenario.ts b/packages/contracts/test/utils/order_factory_from_scenario.ts index a908140b9..8e04db588 100644 --- a/packages/contracts/test/utils/order_factory_from_scenario.ts +++ b/packages/contracts/test/utils/order_factory_from_scenario.ts @@ -21,6 +21,8 @@ const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100_000_000_000_000_000) const POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(50_000_000_000_000_000); const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1_000_000); const FIVE_UNITS_FIVE_DECIMALS = new BigNumber(500_000); +const TEN_UNITS_ZERO_DECIMALS = new BigNumber(10); +const ONE_THOUSAND_UNITS_ZERO_DECIMALS = new BigNumber(1000); const ONE_NFT_UNIT = new BigNumber(1); export class OrderFactoryFromScenario { @@ -28,6 +30,7 @@ export class OrderFactoryFromScenario { private readonly _zrxAddress: string; private readonly _nonZrxERC20EighteenDecimalTokenAddresses: string[]; private readonly _erc20FiveDecimalTokenAddresses: string[]; + private readonly _erc20ZeroDecimalTokenAddresses: string[]; private readonly _erc721Token: DummyERC721TokenContract; private readonly _erc721Balances: ERC721TokenIdsByOwner; private readonly _exchangeAddress: string; @@ -36,6 +39,7 @@ export class OrderFactoryFromScenario { zrxAddress: string, nonZrxERC20EighteenDecimalTokenAddresses: string[], erc20FiveDecimalTokenAddresses: string[], + erc20ZeroDecimalTokenAddresses: string[], erc721Token: DummyERC721TokenContract, erc721Balances: ERC721TokenIdsByOwner, exchangeAddress: string, @@ -44,6 +48,7 @@ export class OrderFactoryFromScenario { this._zrxAddress = zrxAddress; this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses; this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses; + this._erc20ZeroDecimalTokenAddresses = erc20ZeroDecimalTokenAddresses; this._erc721Token = erc721Token; this._erc721Balances = erc721Balances; this._exchangeAddress = exchangeAddress; @@ -89,6 +94,9 @@ export class OrderFactoryFromScenario { erc721MakerAssetIds[0], ); break; + case AssetDataScenario.ERC20ZeroDecimals: + makerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[0]); + break; default: throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); } @@ -109,6 +117,9 @@ export class OrderFactoryFromScenario { erc721TakerAssetIds[0], ); break; + case AssetDataScenario.ERC20ZeroDecimals: + takerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[1]); + break; default: throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); } @@ -126,6 +137,9 @@ export class OrderFactoryFromScenario { case AssetDataScenario.ERC721: makerAssetAmount = ONE_NFT_UNIT; break; + case AssetDataScenario.ERC20ZeroDecimals: + makerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS; + break; default: throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); } @@ -142,6 +156,9 @@ export class OrderFactoryFromScenario { case AssetDataScenario.ERC721: makerAssetAmount = ONE_NFT_UNIT; break; + case AssetDataScenario.ERC20ZeroDecimals: + makerAssetAmount = TEN_UNITS_ZERO_DECIMALS; + break; default: throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario); } @@ -166,6 +183,9 @@ export class OrderFactoryFromScenario { case AssetDataScenario.ERC721: takerAssetAmount = ONE_NFT_UNIT; break; + case AssetDataScenario.ERC20ZeroDecimals: + takerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS; + break; default: throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); } @@ -182,6 +202,9 @@ export class OrderFactoryFromScenario { case AssetDataScenario.ERC721: takerAssetAmount = ONE_NFT_UNIT; break; + case AssetDataScenario.ERC20ZeroDecimals: + takerAssetAmount = TEN_UNITS_ZERO_DECIMALS; + break; default: throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario); } diff --git a/packages/contracts/test/utils/types.ts b/packages/contracts/test/utils/types.ts index 67313b647..481ee87d6 100644 --- a/packages/contracts/test/utils/types.ts +++ b/packages/contracts/test/utils/types.ts @@ -177,10 +177,11 @@ export enum ExpirationTimeSecondsScenario { } export enum AssetDataScenario { - ERC721 = 'ERC721', + ERC20ZeroDecimals = 'ERC20_ZERO_DECIMALS', ZRXFeeToken = 'ZRX_FEE_TOKEN', ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS', ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS', + ERC721 = 'ERC721', } export enum TakerAssetFillAmountScenario { diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index 6b49d2ee6..86f0da65a 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -2,6 +2,10 @@ { "version": "1.0.1-rc.4", "changes": [ + { + "note": "Remove rounding error being thrown when maker amount is very small", + "pr": 959 + }, { "note": "Added rateUtils and sortingUtils", "pr": 953 diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts index 189bf4180..7974d5d0b 100644 --- a/packages/order-utils/src/order_state_utils.ts +++ b/packages/order-utils/src/order_state_utils.ts @@ -11,6 +11,7 @@ import { BigNumber } from '@0xproject/utils'; import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher'; import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher'; import { orderHashUtils } from './order_hash'; +import { OrderValidationUtils } from './order_validation_utils'; import { RemainingFillableCalculator } from './remaining_fillable_calculator'; import { utils } from './utils'; @@ -22,10 +23,9 @@ interface SidedOrderRelevantState { traderFeeProxyAllowance: BigNumber; filledTakerAssetAmount: BigNumber; remainingFillableAssetAmount: BigNumber; + isOrderCancelled: boolean; } -const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001; - export class OrderStateUtils { private readonly _balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher; private readonly _orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher; @@ -34,6 +34,9 @@ export class OrderStateUtils { sidedOrderRelevantState: SidedOrderRelevantState, ): void { const isMakerSide = sidedOrderRelevantState.isMakerSide; + if (sidedOrderRelevantState.isOrderCancelled) { + throw new Error(ExchangeContractErrs.OrderAlreadyCancelledOrFilled); + } const availableTakerAssetAmount = signedOrder.takerAssetAmount.minus( sidedOrderRelevantState.filledTakerAssetAmount, ); @@ -71,23 +74,15 @@ export class OrderStateUtils { ); } } - - let minFillableTakerAssetAmountWithinNoRoundingErrorRange; - if (isMakerSide) { - minFillableTakerAssetAmountWithinNoRoundingErrorRange = signedOrder.takerAssetAmount - .dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR) - .dividedBy(signedOrder.makerAssetAmount); - } else { - minFillableTakerAssetAmountWithinNoRoundingErrorRange = signedOrder.makerAssetAmount - .dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR) - .dividedBy(signedOrder.takerAssetAmount); - } - - if ( - sidedOrderRelevantState.remainingFillableAssetAmount.lessThan( - minFillableTakerAssetAmountWithinNoRoundingErrorRange, - ) - ) { + const remainingTakerAssetAmount = signedOrder.takerAssetAmount.minus( + sidedOrderRelevantState.filledTakerAssetAmount, + ); + const isRoundingError = OrderValidationUtils.isRoundingError( + remainingTakerAssetAmount, + signedOrder.takerAssetAmount, + signedOrder.makerAssetAmount, + ); + if (isRoundingError) { throw new Error(ExchangeContractErrs.OrderFillRoundingError); } } @@ -101,6 +96,7 @@ export class OrderStateUtils { public async getOpenOrderStateAsync(signedOrder: SignedOrder): Promise { const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); + const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(orderHash); const sidedOrderRelevantState = { isMakerSide: true, traderBalance: orderRelevantState.makerBalance, @@ -109,6 +105,7 @@ export class OrderStateUtils { traderFeeProxyAllowance: orderRelevantState.makerFeeProxyAllowance, filledTakerAssetAmount: orderRelevantState.filledTakerAssetAmount, remainingFillableAssetAmount: orderRelevantState.remainingFillableMakerAssetAmount, + isOrderCancelled, }; try { OrderStateUtils._validateIfOrderIsValid(signedOrder, sidedOrderRelevantState); @@ -278,6 +275,7 @@ export class OrderStateUtils { traderFeeProxyAllowance, filledTakerAssetAmount, remainingFillableAssetAmount, + isOrderCancelled, }; return sidedOrderRelevantState; } diff --git a/packages/order-utils/test/order_state_utils_test.ts b/packages/order-utils/test/order_state_utils_test.ts new file mode 100644 index 000000000..9292c40a4 --- /dev/null +++ b/packages/order-utils/test/order_state_utils_test.ts @@ -0,0 +1,122 @@ +import { BigNumber } from '@0xproject/utils'; +import * as chai from 'chai'; +import 'mocha'; + +import { AbstractBalanceAndProxyAllowanceFetcher, AbstractOrderFilledCancelledFetcher, OrderStateUtils } from '../src'; + +import { chaiSetup } from './utils/chai_setup'; +import { testOrderFactory } from './utils/test_order_factory'; + +chaiSetup.configure(); +const expect = chai.expect; + +describe('OrderStateUtils', () => { + describe('#getOpenOrderStateAsync', () => { + const buildMockBalanceFetcher = (takerBalance: BigNumber): AbstractBalanceAndProxyAllowanceFetcher => { + const balanceFetcher = { + async getBalanceAsync(_assetData: string, _userAddress: string): Promise { + return takerBalance; + }, + async getProxyAllowanceAsync(_assetData: string, _userAddress: string): Promise { + return takerBalance; + }, + }; + return balanceFetcher; + }; + const buildMockOrderFilledFetcher = ( + filledAmount: BigNumber = new BigNumber(0), + cancelled: boolean = false, + ): AbstractOrderFilledCancelledFetcher => { + const orderFetcher = { + async getFilledTakerAmountAsync(_orderHash: string): Promise { + return filledAmount; + }, + async isOrderCancelledAsync(_orderHash: string): Promise { + return cancelled; + }, + getZRXAssetData(): string { + return ''; + }, + }; + return orderFetcher; + }; + it('should have valid order state if order can be fully filled with small maker amount', async () => { + const makerAssetAmount = new BigNumber(10); + const takerAssetAmount = new BigNumber(10000000000000000); + const takerBalance = takerAssetAmount; + const orderFilledAmount = new BigNumber(0); + const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance); + const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount); + const [signedOrder] = testOrderFactory.generateTestSignedOrders( + { + makerAssetAmount, + takerAssetAmount, + }, + 1, + ); + + const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); + const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); + expect(orderState.isValid).to.eq(true); + }); + it('should be invalid when an order is partially filled where only a rounding error remains', async () => { + const makerAssetAmount = new BigNumber(1001); + const takerAssetAmount = new BigNumber(3); + const takerBalance = takerAssetAmount; + const orderFilledAmount = new BigNumber(2); + const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance); + const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount); + const [signedOrder] = testOrderFactory.generateTestSignedOrders( + { + makerAssetAmount, + takerAssetAmount, + }, + 1, + ); + + const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); + const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); + expect(orderState.isValid).to.eq(false); + }); + it('should be invalid when an order is cancelled', async () => { + const makerAssetAmount = new BigNumber(1000); + const takerAssetAmount = new BigNumber(2); + const takerBalance = takerAssetAmount; + const orderFilledAmount = new BigNumber(0); + const isCancelled = true; + const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance); + const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount, isCancelled); + const [signedOrder] = testOrderFactory.generateTestSignedOrders( + { + makerAssetAmount, + takerAssetAmount, + }, + 1, + ); + + const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); + const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); + expect(orderState.isValid).to.eq(false); + }); + it('should be invalid when an order is fully filled', async () => { + const makerAssetAmount = new BigNumber(1000); + const takerAssetAmount = new BigNumber(2); + const takerBalance = takerAssetAmount; + const orderFilledAmount = takerAssetAmount; + const isCancelled = false; + const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance); + const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount, isCancelled); + const [signedOrder] = testOrderFactory.generateTestSignedOrders( + { + makerAssetAmount, + takerAssetAmount, + }, + 1, + ); + + const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); + const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); + expect(orderState.isValid).to.eq(false); + }); + }); +}); diff --git a/packages/order-watcher/test/order_watcher_test.ts b/packages/order-watcher/test/order_watcher_test.ts index 00962bed0..0f4caeb63 100644 --- a/packages/order-watcher/test/order_watcher_test.ts +++ b/packages/order-watcher/test/order_watcher_test.ts @@ -501,25 +501,27 @@ describe('OrderWatcher', () => { expect(orderState.isValid).to.be.false(); const invalidOrderState = orderState as OrderStateInvalid; expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError); + expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderAlreadyCancelledOrFilled); }); orderWatcher.subscribe(callback); await contractWrappers.exchange.cancelOrderAsync(signedOrder); })().catch(done); }); - it('should emit orderStateInvalid when within rounding error range', (done: DoneCallback) => { + it('should emit orderStateInvalid when within rounding error range after a partial fill', (done: DoneCallback) => { (async () => { - const remainingFillableAmountInBaseUnits = new BigNumber(100); - signedOrder = await fillScenarios.createFillableSignedOrderAsync( + const fillAmountInBaseUnits = new BigNumber(2); + const makerAssetAmount = new BigNumber(1001); + const takerAssetAmount = new BigNumber(3); + signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( makerAssetData, takerAssetData, makerAddress, takerAddress, - fillableAmount, + makerAssetAmount, + takerAssetAmount, ); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { expect(orderState.isValid).to.be.false(); const invalidOrderState = orderState as OrderStateInvalid; @@ -527,11 +529,7 @@ describe('OrderWatcher', () => { expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError); }); orderWatcher.subscribe(callback); - await contractWrappers.exchange.fillOrderAsync( - signedOrder, - fillableAmount.minus(remainingFillableAmountInBaseUnits), - takerAddress, - ); + await contractWrappers.exchange.fillOrderAsync(signedOrder, fillAmountInBaseUnits, takerAddress); })().catch(done); }); describe('erc721', () => { -- cgit v1.2.3 From 88c99396a2d1b880bffb21ef19507d02b474ba9b Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Wed, 15 Aug 2018 13:03:31 +1000 Subject: Rename OrderAlreadyCancelledOrFilled -> OrderCancelled. Remove try catch of throwing errors in favour of returning the Errors in a OrderValidationResult --- packages/order-utils/src/order_state_utils.ts | 61 ++++++++++++---------- .../order-utils/test/order_state_utils_test.ts | 4 +- packages/order-watcher/test/order_watcher_test.ts | 2 +- packages/types/src/index.ts | 3 +- packages/website/ts/utils/utils.ts | 7 +-- 5 files changed, 40 insertions(+), 37 deletions(-) (limited to 'packages') diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts index 7974d5d0b..18fc18bf6 100644 --- a/packages/order-utils/src/order_state_utils.ts +++ b/packages/order-utils/src/order_state_utils.ts @@ -25,6 +25,14 @@ interface SidedOrderRelevantState { remainingFillableAssetAmount: BigNumber; isOrderCancelled: boolean; } +interface OrderValidResult { + isValid: true; +} +interface OrderInvalidResult { + isValid: false; + error: ExchangeContractErrs; +} +type OrderValidationResult = OrderValidResult | OrderInvalidResult; export class OrderStateUtils { private readonly _balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher; @@ -32,46 +40,42 @@ export class OrderStateUtils { private static _validateIfOrderIsValid( signedOrder: SignedOrder, sidedOrderRelevantState: SidedOrderRelevantState, - ): void { + ): OrderValidationResult { const isMakerSide = sidedOrderRelevantState.isMakerSide; if (sidedOrderRelevantState.isOrderCancelled) { - throw new Error(ExchangeContractErrs.OrderAlreadyCancelledOrFilled); + return { isValid: false, error: ExchangeContractErrs.OrderCancelled }; } const availableTakerAssetAmount = signedOrder.takerAssetAmount.minus( sidedOrderRelevantState.filledTakerAssetAmount, ); if (availableTakerAssetAmount.eq(0)) { - throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero); + return { isValid: false, error: ExchangeContractErrs.OrderRemainingFillAmountZero }; } if (sidedOrderRelevantState.traderBalance.eq(0)) { - throw new Error( - isMakerSide - ? ExchangeContractErrs.InsufficientMakerBalance - : ExchangeContractErrs.InsufficientTakerBalance, - ); + const error = isMakerSide + ? ExchangeContractErrs.InsufficientMakerBalance + : ExchangeContractErrs.InsufficientTakerBalance; + return { isValid: false, error }; } if (sidedOrderRelevantState.traderProxyAllowance.eq(0)) { - throw new Error( - isMakerSide - ? ExchangeContractErrs.InsufficientMakerAllowance - : ExchangeContractErrs.InsufficientTakerAllowance, - ); + const error = isMakerSide + ? ExchangeContractErrs.InsufficientMakerAllowance + : ExchangeContractErrs.InsufficientTakerAllowance; + return { isValid: false, error }; } if (!signedOrder.makerFee.eq(0)) { if (sidedOrderRelevantState.traderFeeBalance.eq(0)) { - throw new Error( - isMakerSide - ? ExchangeContractErrs.InsufficientMakerFeeBalance - : ExchangeContractErrs.InsufficientTakerFeeBalance, - ); + const error = isMakerSide + ? ExchangeContractErrs.InsufficientMakerFeeBalance + : ExchangeContractErrs.InsufficientTakerFeeBalance; + return { isValid: false, error }; } if (sidedOrderRelevantState.traderFeeProxyAllowance.eq(0)) { - throw new Error( - isMakerSide - ? ExchangeContractErrs.InsufficientMakerFeeAllowance - : ExchangeContractErrs.InsufficientTakerFeeAllowance, - ); + const error = isMakerSide + ? ExchangeContractErrs.InsufficientMakerFeeAllowance + : ExchangeContractErrs.InsufficientTakerFeeAllowance; + return { isValid: false, error }; } } const remainingTakerAssetAmount = signedOrder.takerAssetAmount.minus( @@ -83,8 +87,9 @@ export class OrderStateUtils { signedOrder.makerAssetAmount, ); if (isRoundingError) { - throw new Error(ExchangeContractErrs.OrderFillRoundingError); + return { isValid: false, error: ExchangeContractErrs.OrderFillRoundingError }; } + return { isValid: true }; } constructor( balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher, @@ -107,19 +112,19 @@ export class OrderStateUtils { remainingFillableAssetAmount: orderRelevantState.remainingFillableMakerAssetAmount, isOrderCancelled, }; - try { - OrderStateUtils._validateIfOrderIsValid(signedOrder, sidedOrderRelevantState); + const orderValidationResult = OrderStateUtils._validateIfOrderIsValid(signedOrder, sidedOrderRelevantState); + if (orderValidationResult.isValid) { const orderState: OrderStateValid = { isValid: true, orderHash, orderRelevantState, }; return orderState; - } catch (err) { + } else { const orderState: OrderStateInvalid = { isValid: false, orderHash, - error: err.message, + error: orderValidationResult.error, }; return orderState; } diff --git a/packages/order-utils/test/order_state_utils_test.ts b/packages/order-utils/test/order_state_utils_test.ts index 9292c40a4..91ef23b69 100644 --- a/packages/order-utils/test/order_state_utils_test.ts +++ b/packages/order-utils/test/order_state_utils_test.ts @@ -2,7 +2,9 @@ import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import 'mocha'; -import { AbstractBalanceAndProxyAllowanceFetcher, AbstractOrderFilledCancelledFetcher, OrderStateUtils } from '../src'; +import { AbstractBalanceAndProxyAllowanceFetcher } from '../src/abstract/abstract_balance_and_proxy_allowance_fetcher'; +import { AbstractOrderFilledCancelledFetcher } from '../src/abstract/abstract_order_filled_cancelled_fetcher'; +import { OrderStateUtils } from '../src/order_state_utils'; import { chaiSetup } from './utils/chai_setup'; import { testOrderFactory } from './utils/test_order_factory'; diff --git a/packages/order-watcher/test/order_watcher_test.ts b/packages/order-watcher/test/order_watcher_test.ts index 0f4caeb63..38bfde7ef 100644 --- a/packages/order-watcher/test/order_watcher_test.ts +++ b/packages/order-watcher/test/order_watcher_test.ts @@ -501,7 +501,7 @@ describe('OrderWatcher', () => { expect(orderState.isValid).to.be.false(); const invalidOrderState = orderState as OrderStateInvalid; expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderAlreadyCancelledOrFilled); + expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderCancelled); }); orderWatcher.subscribe(callback); await contractWrappers.exchange.cancelOrderAsync(signedOrder); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index fa634420d..04480d093 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -62,8 +62,7 @@ export interface ValidatorSignature { export enum ExchangeContractErrs { OrderFillExpired = 'ORDER_FILL_EXPIRED', OrderCancelExpired = 'ORDER_CANCEL_EXPIRED', - OrderCancelAmountZero = 'ORDER_CANCEL_AMOUNT_ZERO', - OrderAlreadyCancelledOrFilled = 'ORDER_ALREADY_CANCELLED_OR_FILLED', + OrderCancelled = 'ORDER_CANCELLED', OrderFillAmountZero = 'ORDER_FILL_AMOUNT_ZERO', OrderRemainingFillAmountZero = 'ORDER_REMAINING_FILL_AMOUNT_ZERO', OrderFillRoundingError = 'ORDER_FILL_ROUNDING_ERROR', diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts index 39bbd404c..32b07473c 100644 --- a/packages/website/ts/utils/utils.ts +++ b/packages/website/ts/utils/utils.ts @@ -247,12 +247,9 @@ export const utils = { } = { [ExchangeContractErrs.OrderFillExpired]: 'This order has expired', [ExchangeContractErrs.OrderCancelExpired]: 'This order has expired', - [ExchangeContractErrs.OrderCancelAmountZero]: "Order cancel amount can't be 0", - [ExchangeContractErrs.OrderAlreadyCancelledOrFilled]: - 'This order has already been completely filled or cancelled', + [ExchangeContractErrs.OrderCancelled]: 'This order has been cancelled', [ExchangeContractErrs.OrderFillAmountZero]: "Order fill amount can't be 0", - [ExchangeContractErrs.OrderRemainingFillAmountZero]: - 'This order has already been completely filled or cancelled', + [ExchangeContractErrs.OrderRemainingFillAmountZero]: 'This order has already been completely filled', [ExchangeContractErrs.OrderFillRoundingError]: 'Rounding error will occur when filling this order. Please try filling a different amount.', [ExchangeContractErrs.InsufficientTakerBalance]: -- cgit v1.2.3