From 8687b9533c67a551df928b28a776bfdbe6e3e84f Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Fri, 24 Aug 2018 11:11:29 -0700 Subject: Add getForwarderHelperForMakerAssetDataAsync method to forwarderHelperFactory --- .../src/forwarder_helper_factory.ts | 229 ++++++++++++++++++++- packages/forwarder-helper/src/types.ts | 5 + packages/forwarder-helper/src/utils/order_utils.ts | 16 ++ 3 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 packages/forwarder-helper/src/utils/order_utils.ts (limited to 'packages/forwarder-helper/src') diff --git a/packages/forwarder-helper/src/forwarder_helper_factory.ts b/packages/forwarder-helper/src/forwarder_helper_factory.ts index 95f11f555..e3ef59388 100644 --- a/packages/forwarder-helper/src/forwarder_helper_factory.ts +++ b/packages/forwarder-helper/src/forwarder_helper_factory.ts @@ -1,13 +1,22 @@ import { assert } from '@0xproject/assert'; +import { APIOrder, HttpClient } from '@0xproject/connect'; +import { ContractWrappers, OrderAndTraderInfo, OrderStatus } from '@0xproject/contract-wrappers'; import { schemas } from '@0xproject/json-schemas'; +import { assetDataUtils } from '@0xproject/order-utils'; +import { RemainingFillableCalculator } from '@0xproject/order-utils/lib/src/remaining_fillable_calculator'; +import { RPCSubprovider, Web3ProviderEngine } from '@0xproject/subproviders'; import { SignedOrder } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import { constants } from './constants'; import { ForwarderHelperImpl, ForwarderHelperImplConfig } from './forwarder_helper_impl'; -import { ForwarderHelper } from './types'; +import { ForwarderHelper, ForwarderHelperFactoryError } from './types'; +import { orderUtils } from './utils/order_utils'; export const forwarderHelperFactory = { /** - * Given an array of orders and an array of feeOrders + * Given an array of orders and an array of feeOrders, get a ForwarderHelper * @param orders An array of objects conforming to SignedOrder. Each order should specify the same makerAssetData and takerAssetData * @param feeOrders An array of objects conforming to SignedOrder. Each order should specify ZRX as makerAssetData WETH as takerAssetData * @return A ForwarderHelper, see type for definition @@ -22,4 +31,220 @@ export const forwarderHelperFactory = { const helper = new ForwarderHelperImpl(config); return helper; }, + /** + * Given a desired makerAsset and SRA url, get a ForwarderHelper + * @param makerAssetData An array of objects conforming to SignedOrder. Each order should specify the same makerAssetData and takerAssetData + * @param sraUrl A url pointing to an SRA v2 compliant endpoint. + * @param rpcUrl A url pointing to an ethereum node. + * @param networkId The ethereum networkId, defaults to 1 (mainnet). + * @return A ForwarderHelper, see type for definition + */ + async getForwarderHelperForMakerAssetDataAsync( + makerAssetData: string, + takerAddress: string, + sraUrl: string, + rpcUrl?: string, + networkId: number = 1, + ): Promise { + assert.isHexString('makerAssetData', makerAssetData); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.isWebUri('sraUrl', sraUrl); + if (!_.isUndefined(rpcUrl)) { + assert.isWebUri('rpcUrl', rpcUrl); + } + assert.isNumber('networkId', networkId); + // create provider + const providerEngine = new Web3ProviderEngine(); + if (!_.isUndefined(rpcUrl)) { + providerEngine.addProvider(new RPCSubprovider(rpcUrl)); + } + providerEngine.start(); + // create contract wrappers given provider and networkId + const contractWrappers = new ContractWrappers(providerEngine, { networkId }); + // find ether token asset data + const etherTokenAddressIfExists = contractWrappers.etherToken.getContractAddressIfExists(); + if (_.isUndefined(etherTokenAddressIfExists)) { + throw new Error(ForwarderHelperFactoryError.NoEtherTokenContractFound); + } + const etherTokenAssetData = assetDataUtils.encodeERC20AssetData(etherTokenAddressIfExists); + // find zrx token asset data + let zrxTokenAssetData: string; + try { + zrxTokenAssetData = contractWrappers.exchange.getZRXAssetData(); + } catch (err) { + throw new Error(ForwarderHelperFactoryError.NoZrxTokenContractFound); + } + // get orderbooks for makerAsset/WETH and ZRX/WETH + const sraClient = new HttpClient(sraUrl); + const orderbookRequests = [ + { baseAssetData: makerAssetData, quoteAssetData: etherTokenAssetData }, + { baseAssetData: zrxTokenAssetData, quoteAssetData: etherTokenAssetData }, + ]; + const requestOpts = { networkId }; + // TODO: try catch these requests and throw a more domain specific error + const [makerAssetOrderbook, zrxOrderbook] = await Promise.all( + _.map(orderbookRequests, request => sraClient.getOrderbookAsync(request, requestOpts)), + ); + // validate orders and find remaining fillable from on chain state or sra api + let ordersAndRemainingFillableMakerAssetAmounts: OrdersAndRemainingFillableMakerAssetAmounts; + let feeOrdersAndRemainingFillableMakerAssetAmounts: OrdersAndRemainingFillableMakerAssetAmounts; + if (!_.isUndefined(rpcUrl)) { + // if we do have an rpc url, get on-chain orders and traders info via the OrderValidatorWrapper + const ordersFromSra = _.map(makerAssetOrderbook.asks.records, apiOrder => apiOrder.order); + const feeOrdersFromSra = _.map(zrxOrderbook.asks.records, apiOrder => apiOrder.order); + // TODO: try catch these requests and throw a more domain specific error + const [makerAssetOrdersAndTradersInfo, feeOrdersAndTradersInfo] = await Promise.all( + _.map([ordersFromSra, feeOrdersFromSra], ordersToBeValidated => { + const takerAddresses = _.map(ordersToBeValidated, () => takerAddress); + return contractWrappers.orderValidator.getOrdersAndTradersInfoAsync( + ordersToBeValidated, + takerAddresses, + ); + }), + ); + // take maker asset orders from SRA + on chain information and find the valid orders and remaining fillable maker asset amounts + ordersAndRemainingFillableMakerAssetAmounts = getValidOrdersAndRemainingFillableMakerAssetAmountsFromOnChain( + ordersFromSra, + makerAssetOrdersAndTradersInfo, + zrxTokenAssetData, + ); + // take fee orders from SRA + on chain information and find the valid orders and remaining fillable maker asset amounts + feeOrdersAndRemainingFillableMakerAssetAmounts = getValidOrdersAndRemainingFillableMakerAssetAmountsFromOnChain( + feeOrdersFromSra, + feeOrdersAndTradersInfo, + zrxTokenAssetData, + ); + } else { + // if we don't have an rpc url, assume all orders are valid and fallback to optional fill amounts from SRA + // if fill amounts are not available from the SRA, assume all orders are completely fillable + const apiOrdersFromSra = makerAssetOrderbook.asks.records; + const feeApiOrdersFromSra = zrxOrderbook.asks.records; + // take maker asset orders from SRA and the valid orders and remaining fillable maker asset amounts + ordersAndRemainingFillableMakerAssetAmounts = getValidOrdersAndRemainingFillableMakerAssetAmountsFromApi( + apiOrdersFromSra, + ); + // take fee orders from SRA and find the valid orders and remaining fillable maker asset amounts + feeOrdersAndRemainingFillableMakerAssetAmounts = getValidOrdersAndRemainingFillableMakerAssetAmountsFromApi( + feeApiOrdersFromSra, + ); + } + // compile final config + const config: ForwarderHelperImplConfig = { + orders: ordersAndRemainingFillableMakerAssetAmounts.orders, + feeOrders: feeOrdersAndRemainingFillableMakerAssetAmounts.orders, + remainingFillableMakerAssetAmounts: + ordersAndRemainingFillableMakerAssetAmounts.remainingFillableMakerAssetAmounts, + remainingFillableFeeAmounts: + feeOrdersAndRemainingFillableMakerAssetAmounts.remainingFillableMakerAssetAmounts, + }; + const helper = new ForwarderHelperImpl(config); + return helper; + }, }; + +interface OrdersAndRemainingFillableMakerAssetAmounts { + orders: SignedOrder[]; + remainingFillableMakerAssetAmounts: BigNumber[]; +} + +/** + * Given an array of APIOrder objects from a standard relayer api, return an array + * of fillable orders with their corresponding remainingFillableMakerAssetAmounts + */ +function getValidOrdersAndRemainingFillableMakerAssetAmountsFromApi( + apiOrders: APIOrder[], +): OrdersAndRemainingFillableMakerAssetAmounts { + const result = _.reduce( + apiOrders, + (acc, apiOrder, index) => { + // get current accumulations + const { orders, remainingFillableMakerAssetAmounts } = acc; + // get order and metadata + const { order, metaData } = apiOrder; + // if the order is expired, move on + if (orderUtils.isOrderExpired(order)) { + return acc; + } + // calculate remainingFillableMakerAssetAmount from api metadata + const remainingFillableTakerAssetAmount = _.get( + metaData, + 'remainingTakerAssetAmount', + order.takerAssetAmount, + ); + const remainingFillableMakerAssetAmount = orderUtils.calculateRemainingMakerAssetAmount( + order, + remainingFillableTakerAssetAmount, + ); + // if there is some amount of maker asset left to fill and add the order and remaining amount to the accumulations + // if there is not any maker asset left to fill, do not add + if (remainingFillableMakerAssetAmount.gt(constants.ZERO_AMOUNT)) { + return { + orders: _.concat(orders, order), + remainingFillableMakerAssetAmounts: _.concat( + remainingFillableMakerAssetAmounts, + remainingFillableMakerAssetAmount, + ), + }; + } else { + return acc; + } + }, + { orders: [] as SignedOrder[], remainingFillableMakerAssetAmounts: [] as BigNumber[] }, + ); + return result; +} + +/** + * Given an array of orders and corresponding on-chain infos, return a subset of the orders + * that are still fillable orders with their corresponding remainingFillableMakerAssetAmounts + */ +function getValidOrdersAndRemainingFillableMakerAssetAmountsFromOnChain( + inputOrders: SignedOrder[], + ordersAndTradersInfo: OrderAndTraderInfo[], + zrxAssetData: string, +): OrdersAndRemainingFillableMakerAssetAmounts { + // iterate through the input orders and find the ones that are still fillable + // for the orders that are still fillable, calculate the remaining fillable maker asset amount + const result = _.reduce( + inputOrders, + (acc, order, index) => { + // get current accumulations + const { orders, remainingFillableMakerAssetAmounts } = acc; + // get corresponding on-chain state for the order + const { orderInfo, traderInfo } = ordersAndTradersInfo[index]; + // if the order IS NOT fillable, do not add anything and continue iterating + if (orderInfo.orderStatus !== OrderStatus.FILLABLE) { + return acc; + } + // if the order IS fillable, add the order and calculate the remaining fillable amount + const transferrableAssetAmount = BigNumber.min([traderInfo.makerAllowance, traderInfo.makerBalance]); + const transferrableFeeAssetAmount = BigNumber.min([ + traderInfo.makerZrxAllowance, + traderInfo.makerZrxBalance, + ]); + const remainingTakerAssetAmount = order.takerAssetAmount.minus(orderInfo.orderTakerAssetFilledAmount); + const remainingMakerAssetAmount = orderUtils.calculateRemainingMakerAssetAmount( + order, + remainingTakerAssetAmount, + ); + const remainingFillableCalculator = new RemainingFillableCalculator( + order.makerFee, + order.makerAssetAmount, + order.makerAssetData === zrxAssetData, + transferrableAssetAmount, + transferrableFeeAssetAmount, + remainingMakerAssetAmount, + ); + const remainingFillableAmount = remainingFillableCalculator.computeRemainingFillable(); + return { + orders: _.concat(orders, order), + remainingFillableMakerAssetAmounts: _.concat( + remainingFillableMakerAssetAmounts, + remainingFillableAmount, + ), + }; + }, + { orders: [] as SignedOrder[], remainingFillableMakerAssetAmounts: [] as BigNumber[] }, + ); + return result; +} diff --git a/packages/forwarder-helper/src/types.ts b/packages/forwarder-helper/src/types.ts index fb171cc90..5a8439257 100644 --- a/packages/forwarder-helper/src/types.ts +++ b/packages/forwarder-helper/src/types.ts @@ -1,6 +1,11 @@ import { SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; +export enum ForwarderHelperFactoryError { + NoEtherTokenContractFound = 'NO_ETHER_TOKEN_CONTRACT_FOUND', + NoZrxTokenContractFound = 'NO_ZRX_TOKEN_CONTRACT_FOUND', +} + export interface ForwarderHelper { /** * Given a MarketBuyOrdersInfoRequest, returns a MarketBuyOrdersInfo containing all information relevant to fulfilling the request diff --git a/packages/forwarder-helper/src/utils/order_utils.ts b/packages/forwarder-helper/src/utils/order_utils.ts new file mode 100644 index 000000000..d14c6a6d7 --- /dev/null +++ b/packages/forwarder-helper/src/utils/order_utils.ts @@ -0,0 +1,16 @@ +import { SignedOrder } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; + +export const orderUtils = { + isOrderExpired(order: SignedOrder): boolean { + const millisecondsInSecond = 1000; + const currentUnixTimestampSec = new BigNumber(Date.now() / millisecondsInSecond).round(); + return order.expirationTimeSeconds.lessThan(currentUnixTimestampSec); + }, + calculateRemainingMakerAssetAmount(order: SignedOrder, remainingTakerAssetAmount: BigNumber): BigNumber { + const result = remainingTakerAssetAmount.eq(0) + ? new BigNumber(0) + : remainingTakerAssetAmount.times(order.makerAssetAmount).dividedToIntegerBy(order.takerAssetAmount); + return result; + }, +}; -- cgit v1.2.3 From 8d6132736bfd57d08448cbde538c13072df80256 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 13 Sep 2018 14:39:06 +0200 Subject: Remove taker address as param and filter out non-open orders --- packages/forwarder-helper/src/constants.ts | 1 + .../forwarder-helper/src/forwarder_helper_factory.ts | 20 ++++++++++++-------- packages/forwarder-helper/src/utils/order_utils.ts | 5 +++++ 3 files changed, 18 insertions(+), 8 deletions(-) (limited to 'packages/forwarder-helper/src') diff --git a/packages/forwarder-helper/src/constants.ts b/packages/forwarder-helper/src/constants.ts index 0ad30e4c0..c0a1b090e 100644 --- a/packages/forwarder-helper/src/constants.ts +++ b/packages/forwarder-helper/src/constants.ts @@ -2,4 +2,5 @@ import { BigNumber } from '@0xproject/utils'; export const constants = { ZERO_AMOUNT: new BigNumber(0), + NULL_ADDRESS: '0x0000000000000000000000000000000000000000', }; diff --git a/packages/forwarder-helper/src/forwarder_helper_factory.ts b/packages/forwarder-helper/src/forwarder_helper_factory.ts index e3ef59388..ab8eaeeaf 100644 --- a/packages/forwarder-helper/src/forwarder_helper_factory.ts +++ b/packages/forwarder-helper/src/forwarder_helper_factory.ts @@ -1,5 +1,5 @@ import { assert } from '@0xproject/assert'; -import { APIOrder, HttpClient } from '@0xproject/connect'; +import { APIOrder, HttpClient, OrderbookResponse } from '@0xproject/connect'; import { ContractWrappers, OrderAndTraderInfo, OrderStatus } from '@0xproject/contract-wrappers'; import { schemas } from '@0xproject/json-schemas'; import { assetDataUtils } from '@0xproject/order-utils'; @@ -41,13 +41,11 @@ export const forwarderHelperFactory = { */ async getForwarderHelperForMakerAssetDataAsync( makerAssetData: string, - takerAddress: string, sraUrl: string, rpcUrl?: string, networkId: number = 1, ): Promise { assert.isHexString('makerAssetData', makerAssetData); - assert.isETHAddressHex('takerAddress', takerAddress); assert.isWebUri('sraUrl', sraUrl); if (!_.isUndefined(rpcUrl)) { assert.isWebUri('rpcUrl', rpcUrl); @@ -90,12 +88,12 @@ export const forwarderHelperFactory = { let feeOrdersAndRemainingFillableMakerAssetAmounts: OrdersAndRemainingFillableMakerAssetAmounts; if (!_.isUndefined(rpcUrl)) { // if we do have an rpc url, get on-chain orders and traders info via the OrderValidatorWrapper - const ordersFromSra = _.map(makerAssetOrderbook.asks.records, apiOrder => apiOrder.order); - const feeOrdersFromSra = _.map(zrxOrderbook.asks.records, apiOrder => apiOrder.order); + const ordersFromSra = getOpenAsksFromOrderbook(makerAssetOrderbook); + const feeOrdersFromSra = getOpenAsksFromOrderbook(zrxOrderbook); // TODO: try catch these requests and throw a more domain specific error const [makerAssetOrdersAndTradersInfo, feeOrdersAndTradersInfo] = await Promise.all( _.map([ordersFromSra, feeOrdersFromSra], ordersToBeValidated => { - const takerAddresses = _.map(ordersToBeValidated, () => takerAddress); + const takerAddresses = _.map(ordersToBeValidated, () => constants.NULL_ADDRESS); return contractWrappers.orderValidator.getOrdersAndTradersInfoAsync( ordersToBeValidated, takerAddresses, @@ -161,8 +159,8 @@ function getValidOrdersAndRemainingFillableMakerAssetAmountsFromApi( const { orders, remainingFillableMakerAssetAmounts } = acc; // get order and metadata const { order, metaData } = apiOrder; - // if the order is expired, move on - if (orderUtils.isOrderExpired(order)) { + // if the order is expired or not open, move on + if (orderUtils.isOrderExpired(order) || !orderUtils.isOpenOrder(order)) { return acc; } // calculate remainingFillableMakerAssetAmount from api metadata @@ -248,3 +246,9 @@ function getValidOrdersAndRemainingFillableMakerAssetAmountsFromOnChain( ); return result; } + +function getOpenAsksFromOrderbook(orderbookResponse: OrderbookResponse): SignedOrder[] { + const asks = _.map(orderbookResponse.asks.records, apiOrder => apiOrder.order); + const result = _.filter(asks, ask => orderUtils.isOpenOrder(ask)); + return result; +} diff --git a/packages/forwarder-helper/src/utils/order_utils.ts b/packages/forwarder-helper/src/utils/order_utils.ts index d14c6a6d7..482006bf1 100644 --- a/packages/forwarder-helper/src/utils/order_utils.ts +++ b/packages/forwarder-helper/src/utils/order_utils.ts @@ -1,6 +1,8 @@ import { SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; +import { constants } from '../constants'; + export const orderUtils = { isOrderExpired(order: SignedOrder): boolean { const millisecondsInSecond = 1000; @@ -13,4 +15,7 @@ export const orderUtils = { : remainingTakerAssetAmount.times(order.makerAssetAmount).dividedToIntegerBy(order.takerAssetAmount); return result; }, + isOpenOrder(order: SignedOrder): boolean { + return order.takerAddress === constants.NULL_ADDRESS; + }, }; -- cgit v1.2.3 From c0a14a4a4110f3fedea6624376eae4c86c02cda8 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 13 Sep 2018 14:44:53 +0200 Subject: Catch standard relayer api errors --- packages/forwarder-helper/src/forwarder_helper_factory.ts | 13 +++++++++---- packages/forwarder-helper/src/types.ts | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'packages/forwarder-helper/src') diff --git a/packages/forwarder-helper/src/forwarder_helper_factory.ts b/packages/forwarder-helper/src/forwarder_helper_factory.ts index ab8eaeeaf..be38f2bd5 100644 --- a/packages/forwarder-helper/src/forwarder_helper_factory.ts +++ b/packages/forwarder-helper/src/forwarder_helper_factory.ts @@ -79,10 +79,15 @@ export const forwarderHelperFactory = { { baseAssetData: zrxTokenAssetData, quoteAssetData: etherTokenAssetData }, ]; const requestOpts = { networkId }; - // TODO: try catch these requests and throw a more domain specific error - const [makerAssetOrderbook, zrxOrderbook] = await Promise.all( - _.map(orderbookRequests, request => sraClient.getOrderbookAsync(request, requestOpts)), - ); + let makerAssetOrderbook: OrderbookResponse; + let zrxOrderbook: OrderbookResponse; + try { + [makerAssetOrderbook, zrxOrderbook] = await Promise.all( + _.map(orderbookRequests, request => sraClient.getOrderbookAsync(request, requestOpts)), + ); + } catch (err) { + throw new Error(ForwarderHelperFactoryError.StandardRelayerApiError); + } // validate orders and find remaining fillable from on chain state or sra api let ordersAndRemainingFillableMakerAssetAmounts: OrdersAndRemainingFillableMakerAssetAmounts; let feeOrdersAndRemainingFillableMakerAssetAmounts: OrdersAndRemainingFillableMakerAssetAmounts; diff --git a/packages/forwarder-helper/src/types.ts b/packages/forwarder-helper/src/types.ts index 5a8439257..a7f02ff8d 100644 --- a/packages/forwarder-helper/src/types.ts +++ b/packages/forwarder-helper/src/types.ts @@ -4,6 +4,7 @@ import { BigNumber } from '@0xproject/utils'; export enum ForwarderHelperFactoryError { NoEtherTokenContractFound = 'NO_ETHER_TOKEN_CONTRACT_FOUND', NoZrxTokenContractFound = 'NO_ZRX_TOKEN_CONTRACT_FOUND', + StandardRelayerApiError = 'STANDARD_RELAYER_API_ERROR', } export interface ForwarderHelper { -- cgit v1.2.3 From 90674d9038b45644e82545558d9937b9eec498f9 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Fri, 14 Sep 2018 13:42:37 +0200 Subject: Various clean up --- packages/forwarder-helper/src/forwarder_helper_factory.ts | 8 +++++--- packages/forwarder-helper/src/utils/order_utils.ts | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'packages/forwarder-helper/src') diff --git a/packages/forwarder-helper/src/forwarder_helper_factory.ts b/packages/forwarder-helper/src/forwarder_helper_factory.ts index be38f2bd5..2b37ac98f 100644 --- a/packages/forwarder-helper/src/forwarder_helper_factory.ts +++ b/packages/forwarder-helper/src/forwarder_helper_factory.ts @@ -24,6 +24,7 @@ export const forwarderHelperFactory = { getForwarderHelperForOrders(orders: SignedOrder[], feeOrders: SignedOrder[] = []): ForwarderHelper { assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema); assert.doesConformToSchema('feeOrders', orders, schemas.signedOrdersSchema); + // TODO: Add assertion here for orders all having the same makerAsset and takerAsset const config: ForwarderHelperImplConfig = { orders, feeOrders, @@ -96,6 +97,7 @@ export const forwarderHelperFactory = { const ordersFromSra = getOpenAsksFromOrderbook(makerAssetOrderbook); const feeOrdersFromSra = getOpenAsksFromOrderbook(zrxOrderbook); // TODO: try catch these requests and throw a more domain specific error + // TODO: optimization, reduce this to once RPC call buy combining orders into one array and then splitting up the response const [makerAssetOrdersAndTradersInfo, feeOrdersAndTradersInfo] = await Promise.all( _.map([ordersFromSra, feeOrdersFromSra], ordersToBeValidated => { const takerAddresses = _.map(ordersToBeValidated, () => constants.NULL_ADDRESS); @@ -159,7 +161,7 @@ function getValidOrdersAndRemainingFillableMakerAssetAmountsFromApi( ): OrdersAndRemainingFillableMakerAssetAmounts { const result = _.reduce( apiOrders, - (acc, apiOrder, index) => { + (acc, apiOrder) => { // get current accumulations const { orders, remainingFillableMakerAssetAmounts } = acc; // get order and metadata @@ -168,7 +170,7 @@ function getValidOrdersAndRemainingFillableMakerAssetAmountsFromApi( if (orderUtils.isOrderExpired(order) || !orderUtils.isOpenOrder(order)) { return acc; } - // calculate remainingFillableMakerAssetAmount from api metadata + // calculate remainingFillableMakerAssetAmount from api metadata, else assume order is completely fillable const remainingFillableTakerAssetAmount = _.get( metaData, 'remainingTakerAssetAmount', @@ -215,7 +217,7 @@ function getValidOrdersAndRemainingFillableMakerAssetAmountsFromOnChain( const { orders, remainingFillableMakerAssetAmounts } = acc; // get corresponding on-chain state for the order const { orderInfo, traderInfo } = ordersAndTradersInfo[index]; - // if the order IS NOT fillable, do not add anything and continue iterating + // if the order IS NOT fillable, do not add anything to the accumulations and continue iterating if (orderInfo.orderStatus !== OrderStatus.FILLABLE) { return acc; } diff --git a/packages/forwarder-helper/src/utils/order_utils.ts b/packages/forwarder-helper/src/utils/order_utils.ts index 482006bf1..bb0bdb80f 100644 --- a/packages/forwarder-helper/src/utils/order_utils.ts +++ b/packages/forwarder-helper/src/utils/order_utils.ts @@ -11,7 +11,7 @@ export const orderUtils = { }, calculateRemainingMakerAssetAmount(order: SignedOrder, remainingTakerAssetAmount: BigNumber): BigNumber { const result = remainingTakerAssetAmount.eq(0) - ? new BigNumber(0) + ? constants.ZERO_AMOUNT : remainingTakerAssetAmount.times(order.makerAssetAmount).dividedToIntegerBy(order.takerAssetAmount); return result; }, -- cgit v1.2.3 From 91702bbae214f56e7ff66156fa799fcfb83f6e42 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Fri, 14 Sep 2018 13:45:14 +0200 Subject: Move packages/forwarder-helper into packages/asset-buyer --- packages/forwarder-helper/src/constants.ts | 6 - .../src/forwarder_helper_factory.ts | 261 --------------------- .../forwarder-helper/src/forwarder_helper_impl.ts | 64 ----- packages/forwarder-helper/src/globals.d.ts | 6 - packages/forwarder-helper/src/index.ts | 2 - packages/forwarder-helper/src/types.ts | 49 ---- .../utils/forwarder_helper_impl_config_utils.ts | 92 -------- packages/forwarder-helper/src/utils/order_utils.ts | 21 -- 8 files changed, 501 deletions(-) delete mode 100644 packages/forwarder-helper/src/constants.ts delete mode 100644 packages/forwarder-helper/src/forwarder_helper_factory.ts delete mode 100644 packages/forwarder-helper/src/forwarder_helper_impl.ts delete mode 100644 packages/forwarder-helper/src/globals.d.ts delete mode 100644 packages/forwarder-helper/src/index.ts delete mode 100644 packages/forwarder-helper/src/types.ts delete mode 100644 packages/forwarder-helper/src/utils/forwarder_helper_impl_config_utils.ts delete mode 100644 packages/forwarder-helper/src/utils/order_utils.ts (limited to 'packages/forwarder-helper/src') diff --git a/packages/forwarder-helper/src/constants.ts b/packages/forwarder-helper/src/constants.ts deleted file mode 100644 index c0a1b090e..000000000 --- a/packages/forwarder-helper/src/constants.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { BigNumber } from '@0xproject/utils'; - -export const constants = { - ZERO_AMOUNT: new BigNumber(0), - NULL_ADDRESS: '0x0000000000000000000000000000000000000000', -}; diff --git a/packages/forwarder-helper/src/forwarder_helper_factory.ts b/packages/forwarder-helper/src/forwarder_helper_factory.ts deleted file mode 100644 index 2b37ac98f..000000000 --- a/packages/forwarder-helper/src/forwarder_helper_factory.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { assert } from '@0xproject/assert'; -import { APIOrder, HttpClient, OrderbookResponse } from '@0xproject/connect'; -import { ContractWrappers, OrderAndTraderInfo, OrderStatus } from '@0xproject/contract-wrappers'; -import { schemas } from '@0xproject/json-schemas'; -import { assetDataUtils } from '@0xproject/order-utils'; -import { RemainingFillableCalculator } from '@0xproject/order-utils/lib/src/remaining_fillable_calculator'; -import { RPCSubprovider, Web3ProviderEngine } from '@0xproject/subproviders'; -import { SignedOrder } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; -import * as _ from 'lodash'; - -import { constants } from './constants'; -import { ForwarderHelperImpl, ForwarderHelperImplConfig } from './forwarder_helper_impl'; -import { ForwarderHelper, ForwarderHelperFactoryError } from './types'; -import { orderUtils } from './utils/order_utils'; - -export const forwarderHelperFactory = { - /** - * Given an array of orders and an array of feeOrders, get a ForwarderHelper - * @param orders An array of objects conforming to SignedOrder. Each order should specify the same makerAssetData and takerAssetData - * @param feeOrders An array of objects conforming to SignedOrder. Each order should specify ZRX as makerAssetData WETH as takerAssetData - * @return A ForwarderHelper, see type for definition - */ - getForwarderHelperForOrders(orders: SignedOrder[], feeOrders: SignedOrder[] = []): ForwarderHelper { - assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema); - assert.doesConformToSchema('feeOrders', orders, schemas.signedOrdersSchema); - // TODO: Add assertion here for orders all having the same makerAsset and takerAsset - const config: ForwarderHelperImplConfig = { - orders, - feeOrders, - }; - const helper = new ForwarderHelperImpl(config); - return helper; - }, - /** - * Given a desired makerAsset and SRA url, get a ForwarderHelper - * @param makerAssetData An array of objects conforming to SignedOrder. Each order should specify the same makerAssetData and takerAssetData - * @param sraUrl A url pointing to an SRA v2 compliant endpoint. - * @param rpcUrl A url pointing to an ethereum node. - * @param networkId The ethereum networkId, defaults to 1 (mainnet). - * @return A ForwarderHelper, see type for definition - */ - async getForwarderHelperForMakerAssetDataAsync( - makerAssetData: string, - sraUrl: string, - rpcUrl?: string, - networkId: number = 1, - ): Promise { - assert.isHexString('makerAssetData', makerAssetData); - assert.isWebUri('sraUrl', sraUrl); - if (!_.isUndefined(rpcUrl)) { - assert.isWebUri('rpcUrl', rpcUrl); - } - assert.isNumber('networkId', networkId); - // create provider - const providerEngine = new Web3ProviderEngine(); - if (!_.isUndefined(rpcUrl)) { - providerEngine.addProvider(new RPCSubprovider(rpcUrl)); - } - providerEngine.start(); - // create contract wrappers given provider and networkId - const contractWrappers = new ContractWrappers(providerEngine, { networkId }); - // find ether token asset data - const etherTokenAddressIfExists = contractWrappers.etherToken.getContractAddressIfExists(); - if (_.isUndefined(etherTokenAddressIfExists)) { - throw new Error(ForwarderHelperFactoryError.NoEtherTokenContractFound); - } - const etherTokenAssetData = assetDataUtils.encodeERC20AssetData(etherTokenAddressIfExists); - // find zrx token asset data - let zrxTokenAssetData: string; - try { - zrxTokenAssetData = contractWrappers.exchange.getZRXAssetData(); - } catch (err) { - throw new Error(ForwarderHelperFactoryError.NoZrxTokenContractFound); - } - // get orderbooks for makerAsset/WETH and ZRX/WETH - const sraClient = new HttpClient(sraUrl); - const orderbookRequests = [ - { baseAssetData: makerAssetData, quoteAssetData: etherTokenAssetData }, - { baseAssetData: zrxTokenAssetData, quoteAssetData: etherTokenAssetData }, - ]; - const requestOpts = { networkId }; - let makerAssetOrderbook: OrderbookResponse; - let zrxOrderbook: OrderbookResponse; - try { - [makerAssetOrderbook, zrxOrderbook] = await Promise.all( - _.map(orderbookRequests, request => sraClient.getOrderbookAsync(request, requestOpts)), - ); - } catch (err) { - throw new Error(ForwarderHelperFactoryError.StandardRelayerApiError); - } - // validate orders and find remaining fillable from on chain state or sra api - let ordersAndRemainingFillableMakerAssetAmounts: OrdersAndRemainingFillableMakerAssetAmounts; - let feeOrdersAndRemainingFillableMakerAssetAmounts: OrdersAndRemainingFillableMakerAssetAmounts; - if (!_.isUndefined(rpcUrl)) { - // if we do have an rpc url, get on-chain orders and traders info via the OrderValidatorWrapper - const ordersFromSra = getOpenAsksFromOrderbook(makerAssetOrderbook); - const feeOrdersFromSra = getOpenAsksFromOrderbook(zrxOrderbook); - // TODO: try catch these requests and throw a more domain specific error - // TODO: optimization, reduce this to once RPC call buy combining orders into one array and then splitting up the response - const [makerAssetOrdersAndTradersInfo, feeOrdersAndTradersInfo] = await Promise.all( - _.map([ordersFromSra, feeOrdersFromSra], ordersToBeValidated => { - const takerAddresses = _.map(ordersToBeValidated, () => constants.NULL_ADDRESS); - return contractWrappers.orderValidator.getOrdersAndTradersInfoAsync( - ordersToBeValidated, - takerAddresses, - ); - }), - ); - // take maker asset orders from SRA + on chain information and find the valid orders and remaining fillable maker asset amounts - ordersAndRemainingFillableMakerAssetAmounts = getValidOrdersAndRemainingFillableMakerAssetAmountsFromOnChain( - ordersFromSra, - makerAssetOrdersAndTradersInfo, - zrxTokenAssetData, - ); - // take fee orders from SRA + on chain information and find the valid orders and remaining fillable maker asset amounts - feeOrdersAndRemainingFillableMakerAssetAmounts = getValidOrdersAndRemainingFillableMakerAssetAmountsFromOnChain( - feeOrdersFromSra, - feeOrdersAndTradersInfo, - zrxTokenAssetData, - ); - } else { - // if we don't have an rpc url, assume all orders are valid and fallback to optional fill amounts from SRA - // if fill amounts are not available from the SRA, assume all orders are completely fillable - const apiOrdersFromSra = makerAssetOrderbook.asks.records; - const feeApiOrdersFromSra = zrxOrderbook.asks.records; - // take maker asset orders from SRA and the valid orders and remaining fillable maker asset amounts - ordersAndRemainingFillableMakerAssetAmounts = getValidOrdersAndRemainingFillableMakerAssetAmountsFromApi( - apiOrdersFromSra, - ); - // take fee orders from SRA and find the valid orders and remaining fillable maker asset amounts - feeOrdersAndRemainingFillableMakerAssetAmounts = getValidOrdersAndRemainingFillableMakerAssetAmountsFromApi( - feeApiOrdersFromSra, - ); - } - // compile final config - const config: ForwarderHelperImplConfig = { - orders: ordersAndRemainingFillableMakerAssetAmounts.orders, - feeOrders: feeOrdersAndRemainingFillableMakerAssetAmounts.orders, - remainingFillableMakerAssetAmounts: - ordersAndRemainingFillableMakerAssetAmounts.remainingFillableMakerAssetAmounts, - remainingFillableFeeAmounts: - feeOrdersAndRemainingFillableMakerAssetAmounts.remainingFillableMakerAssetAmounts, - }; - const helper = new ForwarderHelperImpl(config); - return helper; - }, -}; - -interface OrdersAndRemainingFillableMakerAssetAmounts { - orders: SignedOrder[]; - remainingFillableMakerAssetAmounts: BigNumber[]; -} - -/** - * Given an array of APIOrder objects from a standard relayer api, return an array - * of fillable orders with their corresponding remainingFillableMakerAssetAmounts - */ -function getValidOrdersAndRemainingFillableMakerAssetAmountsFromApi( - apiOrders: APIOrder[], -): OrdersAndRemainingFillableMakerAssetAmounts { - const result = _.reduce( - apiOrders, - (acc, apiOrder) => { - // get current accumulations - const { orders, remainingFillableMakerAssetAmounts } = acc; - // get order and metadata - const { order, metaData } = apiOrder; - // if the order is expired or not open, move on - if (orderUtils.isOrderExpired(order) || !orderUtils.isOpenOrder(order)) { - return acc; - } - // calculate remainingFillableMakerAssetAmount from api metadata, else assume order is completely fillable - const remainingFillableTakerAssetAmount = _.get( - metaData, - 'remainingTakerAssetAmount', - order.takerAssetAmount, - ); - const remainingFillableMakerAssetAmount = orderUtils.calculateRemainingMakerAssetAmount( - order, - remainingFillableTakerAssetAmount, - ); - // if there is some amount of maker asset left to fill and add the order and remaining amount to the accumulations - // if there is not any maker asset left to fill, do not add - if (remainingFillableMakerAssetAmount.gt(constants.ZERO_AMOUNT)) { - return { - orders: _.concat(orders, order), - remainingFillableMakerAssetAmounts: _.concat( - remainingFillableMakerAssetAmounts, - remainingFillableMakerAssetAmount, - ), - }; - } else { - return acc; - } - }, - { orders: [] as SignedOrder[], remainingFillableMakerAssetAmounts: [] as BigNumber[] }, - ); - return result; -} - -/** - * Given an array of orders and corresponding on-chain infos, return a subset of the orders - * that are still fillable orders with their corresponding remainingFillableMakerAssetAmounts - */ -function getValidOrdersAndRemainingFillableMakerAssetAmountsFromOnChain( - inputOrders: SignedOrder[], - ordersAndTradersInfo: OrderAndTraderInfo[], - zrxAssetData: string, -): OrdersAndRemainingFillableMakerAssetAmounts { - // iterate through the input orders and find the ones that are still fillable - // for the orders that are still fillable, calculate the remaining fillable maker asset amount - const result = _.reduce( - inputOrders, - (acc, order, index) => { - // get current accumulations - const { orders, remainingFillableMakerAssetAmounts } = acc; - // get corresponding on-chain state for the order - const { orderInfo, traderInfo } = ordersAndTradersInfo[index]; - // if the order IS NOT fillable, do not add anything to the accumulations and continue iterating - if (orderInfo.orderStatus !== OrderStatus.FILLABLE) { - return acc; - } - // if the order IS fillable, add the order and calculate the remaining fillable amount - const transferrableAssetAmount = BigNumber.min([traderInfo.makerAllowance, traderInfo.makerBalance]); - const transferrableFeeAssetAmount = BigNumber.min([ - traderInfo.makerZrxAllowance, - traderInfo.makerZrxBalance, - ]); - const remainingTakerAssetAmount = order.takerAssetAmount.minus(orderInfo.orderTakerAssetFilledAmount); - const remainingMakerAssetAmount = orderUtils.calculateRemainingMakerAssetAmount( - order, - remainingTakerAssetAmount, - ); - const remainingFillableCalculator = new RemainingFillableCalculator( - order.makerFee, - order.makerAssetAmount, - order.makerAssetData === zrxAssetData, - transferrableAssetAmount, - transferrableFeeAssetAmount, - remainingMakerAssetAmount, - ); - const remainingFillableAmount = remainingFillableCalculator.computeRemainingFillable(); - return { - orders: _.concat(orders, order), - remainingFillableMakerAssetAmounts: _.concat( - remainingFillableMakerAssetAmounts, - remainingFillableAmount, - ), - }; - }, - { orders: [] as SignedOrder[], remainingFillableMakerAssetAmounts: [] as BigNumber[] }, - ); - return result; -} - -function getOpenAsksFromOrderbook(orderbookResponse: OrderbookResponse): SignedOrder[] { - const asks = _.map(orderbookResponse.asks.records, apiOrder => apiOrder.order); - const result = _.filter(asks, ask => orderUtils.isOpenOrder(ask)); - return result; -} diff --git a/packages/forwarder-helper/src/forwarder_helper_impl.ts b/packages/forwarder-helper/src/forwarder_helper_impl.ts deleted file mode 100644 index a90edb0bb..000000000 --- a/packages/forwarder-helper/src/forwarder_helper_impl.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { marketUtils } from '@0xproject/order-utils'; -import { SignedOrder } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; -import * as _ from 'lodash'; - -import { constants } from './constants'; -import { ForwarderHelper, ForwarderHelperError, MarketBuyOrdersInfo, MarketBuyOrdersInfoRequest } from './types'; -import { forwarderHelperImplConfigUtils } from './utils/forwarder_helper_impl_config_utils'; - -const SLIPPAGE_PERCENTAGE = new BigNumber(0.2); // 20% slippage protection, possibly move this into request interface - -export interface ForwarderHelperImplConfig { - orders: SignedOrder[]; - feeOrders: SignedOrder[]; - remainingFillableMakerAssetAmounts?: BigNumber[]; - remainingFillableFeeAmounts?: BigNumber[]; -} - -export class ForwarderHelperImpl implements ForwarderHelper { - public readonly config: ForwarderHelperImplConfig; - constructor(config: ForwarderHelperImplConfig) { - this.config = forwarderHelperImplConfigUtils.sortedConfig(config); - } - public getMarketBuyOrdersInfo(request: MarketBuyOrdersInfoRequest): MarketBuyOrdersInfo { - const { makerAssetFillAmount, feePercentage } = request; - const { orders, feeOrders, remainingFillableMakerAssetAmounts, remainingFillableFeeAmounts } = this.config; - // TODO: make the slippage percentage customizable - const slippageBufferAmount = makerAssetFillAmount.mul(SLIPPAGE_PERCENTAGE).round(); - const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount( - orders, - makerAssetFillAmount, - { - remainingFillableMakerAssetAmounts, - slippageBufferAmount, - }, - ); - if (remainingFillAmount.gt(constants.ZERO_AMOUNT)) { - throw new Error(ForwarderHelperError.InsufficientMakerAssetLiquidity); - } - // TODO: update this logic to find the minimum amount of feeOrders to cover the worst case as opposed to - // finding order that cover all fees, this will help with estimating ETH and minimizing gas usage - const { resultFeeOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders( - resultOrders, - feeOrders, - { - remainingFillableMakerAssetAmounts, - remainingFillableFeeAmounts, - }, - ); - if (remainingFeeAmount.gt(constants.ZERO_AMOUNT)) { - throw new Error(ForwarderHelperError.InsufficientZrxLiquidity); - } - // TODO: calculate min and max eth usage - // TODO: optimize orders call data - return { - makerAssetFillAmount, - orders: resultOrders, - feeOrders: resultFeeOrders, - minEthAmount: constants.ZERO_AMOUNT, - maxEthAmount: constants.ZERO_AMOUNT, - feePercentage, - }; - } -} diff --git a/packages/forwarder-helper/src/globals.d.ts b/packages/forwarder-helper/src/globals.d.ts deleted file mode 100644 index 94e63a32d..000000000 --- a/packages/forwarder-helper/src/globals.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module '*.json' { - const json: any; - /* tslint:disable */ - export default json; - /* tslint:enable */ -} diff --git a/packages/forwarder-helper/src/index.ts b/packages/forwarder-helper/src/index.ts deleted file mode 100644 index eb3a34bd5..000000000 --- a/packages/forwarder-helper/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { forwarderHelperFactory } from './forwarder_helper_factory'; -export { ForwarderHelper, ForwarderHelperError, MarketBuyOrdersInfoRequest, MarketBuyOrdersInfo } from './types'; diff --git a/packages/forwarder-helper/src/types.ts b/packages/forwarder-helper/src/types.ts deleted file mode 100644 index a7f02ff8d..000000000 --- a/packages/forwarder-helper/src/types.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { SignedOrder } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; - -export enum ForwarderHelperFactoryError { - NoEtherTokenContractFound = 'NO_ETHER_TOKEN_CONTRACT_FOUND', - NoZrxTokenContractFound = 'NO_ZRX_TOKEN_CONTRACT_FOUND', - StandardRelayerApiError = 'STANDARD_RELAYER_API_ERROR', -} - -export interface ForwarderHelper { - /** - * Given a MarketBuyOrdersInfoRequest, returns a MarketBuyOrdersInfo containing all information relevant to fulfilling the request - * using the ForwarderContract marketBuyOrdersWithEth function. - * @param request An object that conforms to MarketBuyOrdersInfoRequest. See type definition for more information. - * @return An object that conforms to MarketBuyOrdersInfo that satisfies the request. See type definition for more information. - */ - getMarketBuyOrdersInfo: (request: MarketBuyOrdersInfoRequest) => MarketBuyOrdersInfo; -} - -export enum ForwarderHelperError { - InsufficientMakerAssetLiquidity = 'INSUFFICIENT_MAKER_ASSET_LIQUIDITY', - InsufficientZrxLiquidity = 'INSUFFICIENT_ZRX_LIQUIDITY', -} - -/** - * makerAssetFillAmount: The amount of makerAsset requesting to be filled - * feePercentage: Optional affiliate percentage amount factoring into eth amount calculations - */ -export interface MarketBuyOrdersInfoRequest { - makerAssetFillAmount: BigNumber; - feePercentage?: BigNumber; -} - -/** - * makerAssetFillAmount: The amount of makerAsset requesting to be filled - * orders: An array of objects conforming to SignedOrder. These orders can be used to cover the requested makerAssetFillAmount plus slippage - * feeOrders: An array of objects conforming to SignedOrder. These orders can be used to cover the fees for the orders param above - * minEthAmount: Amount of eth in wei to send with the tx for the most optimistic case - * maxEthAmount: Amount of eth in wei to send with the tx for the worst case - * feePercentage: Affiliate fee percentage used to calculate the eth amounts above. Passed thru directly from the request - */ -export interface MarketBuyOrdersInfo { - makerAssetFillAmount: BigNumber; - orders: SignedOrder[]; - feeOrders: SignedOrder[]; - minEthAmount: BigNumber; - maxEthAmount: BigNumber; - feePercentage?: BigNumber; -} diff --git a/packages/forwarder-helper/src/utils/forwarder_helper_impl_config_utils.ts b/packages/forwarder-helper/src/utils/forwarder_helper_impl_config_utils.ts deleted file mode 100644 index 253384f65..000000000 --- a/packages/forwarder-helper/src/utils/forwarder_helper_impl_config_utils.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { sortingUtils } from '@0xproject/order-utils'; -import { SignedOrder } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; -import * as _ from 'lodash'; - -import { ForwarderHelperImplConfig } from '../forwarder_helper_impl'; - -interface SignedOrderWithAmount extends SignedOrder { - remainingFillAmount: BigNumber; -} - -export const forwarderHelperImplConfigUtils = { - sortedConfig(config: ForwarderHelperImplConfig): ForwarderHelperImplConfig { - const { orders, feeOrders, remainingFillableMakerAssetAmounts, remainingFillableFeeAmounts } = config; - // TODO: provide a feeRate to the sorting function to more accurately sort based on the current market for ZRX tokens - const orderSorter = (ordersToSort: SignedOrder[]) => { - return sortingUtils.sortOrdersByFeeAdjustedRate(ordersToSort); - }; - const sortOrdersResult = sortOrdersAndRemainingFillAmounts( - orderSorter, - orders, - remainingFillableMakerAssetAmounts, - ); - const feeOrderSorter = (ordersToSort: SignedOrder[]) => { - return sortingUtils.sortFeeOrdersByFeeAdjustedRate(ordersToSort); - }; - const sortFeeOrdersResult = sortOrdersAndRemainingFillAmounts( - feeOrderSorter, - feeOrders, - remainingFillableFeeAmounts, - ); - return { - orders: sortOrdersResult.orders, - feeOrders: sortFeeOrdersResult.orders, - remainingFillableMakerAssetAmounts: sortOrdersResult.remainingFillAmounts, - remainingFillableFeeAmounts: sortFeeOrdersResult.remainingFillAmounts, - }; - }, -}; - -type OrderSorter = (orders: SignedOrder[]) => SignedOrder[]; - -function sortOrdersAndRemainingFillAmounts( - orderSorter: OrderSorter, - orders: SignedOrder[], - remainingFillAmounts?: BigNumber[], -): { orders: SignedOrder[]; remainingFillAmounts?: BigNumber[] } { - if (!_.isUndefined(remainingFillAmounts)) { - // Bundle orders together with their remainingFillAmounts so that we can sort them together - const orderWithAmounts = bundleSignedOrderWithAmounts(orders, remainingFillAmounts); - // Sort - const sortedOrderWithAmounts = orderSorter(orderWithAmounts) as SignedOrderWithAmount[]; - // Unbundle after sorting - const unbundledSortedOrderWithAmounts = unbundleSignedOrderWithAmounts(sortedOrderWithAmounts); - return { - orders: unbundledSortedOrderWithAmounts.orders, - remainingFillAmounts: unbundledSortedOrderWithAmounts.amounts, - }; - } else { - const sortedOrders = orderSorter(orders); - return { - orders: sortedOrders, - }; - } -} - -function bundleSignedOrderWithAmounts(orders: SignedOrder[], amounts: BigNumber[]): SignedOrderWithAmount[] { - const ordersAndAmounts = _.map(orders, (order, index) => { - return { - ...order, - remainingFillAmount: amounts[index], - }; - }); - return ordersAndAmounts; -} - -function unbundleSignedOrderWithAmounts( - signedOrderWithAmounts: SignedOrderWithAmount[], -): { orders: SignedOrder[]; amounts: BigNumber[] } { - const orders = _.map(signedOrderWithAmounts, order => { - const { remainingFillAmount, ...rest } = order; - return rest; - }); - const amounts = _.map(signedOrderWithAmounts, order => { - const { remainingFillAmount } = order; - return remainingFillAmount; - }); - return { - orders, - amounts, - }; -} diff --git a/packages/forwarder-helper/src/utils/order_utils.ts b/packages/forwarder-helper/src/utils/order_utils.ts deleted file mode 100644 index bb0bdb80f..000000000 --- a/packages/forwarder-helper/src/utils/order_utils.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { SignedOrder } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; - -import { constants } from '../constants'; - -export const orderUtils = { - isOrderExpired(order: SignedOrder): boolean { - const millisecondsInSecond = 1000; - const currentUnixTimestampSec = new BigNumber(Date.now() / millisecondsInSecond).round(); - return order.expirationTimeSeconds.lessThan(currentUnixTimestampSec); - }, - calculateRemainingMakerAssetAmount(order: SignedOrder, remainingTakerAssetAmount: BigNumber): BigNumber { - const result = remainingTakerAssetAmount.eq(0) - ? constants.ZERO_AMOUNT - : remainingTakerAssetAmount.times(order.makerAssetAmount).dividedToIntegerBy(order.takerAssetAmount); - return result; - }, - isOpenOrder(order: SignedOrder): boolean { - return order.takerAddress === constants.NULL_ADDRESS; - }, -}; -- cgit v1.2.3