aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorBrandon Millman <brandon.millman@gmail.com>2018-09-15 19:56:20 +0800
committerBrandon Millman <brandon.millman@gmail.com>2018-09-15 20:14:55 +0800
commit190bf2599c1327fffd03d8a9d50bc7568190cf33 (patch)
tree587e65fdeda7067bf3f2980c309990a60804aae8 /packages
parentf1a22e9bd7943bc9cb8d8308daca0c60af6e0039 (diff)
downloaddexon-0x-contracts-190bf2599c1327fffd03d8a9d50bc7568190cf33.tar.gz
dexon-0x-contracts-190bf2599c1327fffd03d8a9d50bc7568190cf33.tar.zst
dexon-0x-contracts-190bf2599c1327fffd03d8a9d50bc7568190cf33.zip
Implement StandardRelayerAPIOrderFetcher
Diffstat (limited to 'packages')
-rw-r--r--packages/asset-buyer/src/forwarder_helper_factory.ts262
-rw-r--r--packages/asset-buyer/src/order_fetchers/standard_relayer_api_order_fetcher.ts80
-rw-r--r--packages/asset-buyer/src/utils/order_fetcher_response_processor.ts4
3 files changed, 84 insertions, 262 deletions
diff --git a/packages/asset-buyer/src/forwarder_helper_factory.ts b/packages/asset-buyer/src/forwarder_helper_factory.ts
deleted file mode 100644
index 4c4adfda0..000000000
--- a/packages/asset-buyer/src/forwarder_helper_factory.ts
+++ /dev/null
@@ -1,262 +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 '@0xproject/asset-buyer/src/asset_buyer';
-// 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<ForwarderHelper> {
-// 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/asset-buyer/src/order_fetchers/standard_relayer_api_order_fetcher.ts b/packages/asset-buyer/src/order_fetchers/standard_relayer_api_order_fetcher.ts
new file mode 100644
index 000000000..bf177b93b
--- /dev/null
+++ b/packages/asset-buyer/src/order_fetchers/standard_relayer_api_order_fetcher.ts
@@ -0,0 +1,80 @@
+import { APIOrder, HttpClient, OrderbookResponse } from '@0xproject/connect';
+import { SignedOrder } from '@0xproject/types';
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
+
+import { constants } from '../constants';
+import {
+ AssetBuyerError,
+ OrderFetcher,
+ OrderFetcherRequest,
+ OrderFetcherResponse,
+ SignedOrderWithRemainingFillableMakerAssetAmount,
+} from '../types';
+import { assert } from '../utils/assert';
+import { orderUtils } from '../utils/order_utils';
+
+export class StandardRelayerAPIOrderFetcher implements OrderFetcher {
+ public readonly apiUrl: string;
+ private _sraClient: HttpClient;
+ /**
+ * Given an array of APIOrder objects from a standard relayer api, return an array
+ * of SignedOrderWithRemainingFillableMakerAssetAmounts
+ */
+ private static _getSignedOrderWithRemainingFillableMakerAssetAmountFromApi(
+ apiOrders: APIOrder[],
+ ): SignedOrderWithRemainingFillableMakerAssetAmount[] {
+ const result = _.map(apiOrders, apiOrder => {
+ const { order, metaData } = apiOrder;
+ // calculate remainingFillableMakerAssetAmount from api metadata, else assume order is completely fillable
+ const remainingFillableTakerAssetAmount = _.get(
+ metaData,
+ 'remainingTakerAssetAmount',
+ order.takerAssetAmount,
+ );
+ const remainingFillableMakerAssetAmount = orderUtils.calculateRemainingMakerAssetAmount(
+ order,
+ remainingFillableTakerAssetAmount,
+ );
+ const newOrder = {
+ ...order,
+ remainingFillableMakerAssetAmount,
+ };
+ return newOrder;
+ });
+ return result;
+ }
+ /**
+ * Instantiates a new StandardRelayerAPIOrderFetcher instance
+ * @param apiUrl The relayer API base HTTP url you would like to interact with.
+ * @return An instance of StandardRelayerAPIOrderFetcher
+ */
+ constructor(apiUrl: string) {
+ assert.isWebUri('apiUrl', apiUrl);
+ this.apiUrl = apiUrl;
+ this._sraClient = new HttpClient(apiUrl);
+ }
+ /**
+ * Given an object that conforms to OrderFetcherRequest, return the corresponding OrderFetcherResponse that satisfies the request.
+ * @param orderFetchRequest An instance of OrderFetcherRequest. See type for more information.
+ * @return An instance of OrderFetcherResponse. See type for more information.
+ */
+ public async fetchOrdersAsync(orderFetchRequest: OrderFetcherRequest): Promise<OrderFetcherResponse> {
+ const { makerAssetData, takerAssetData, networkId } = orderFetchRequest;
+ const orderbookRequest = { baseAssetData: makerAssetData, quoteAssetData: takerAssetData };
+ const requestOpts = { networkId };
+ let orderbook: OrderbookResponse;
+ try {
+ orderbook = await this._sraClient.getOrderbookAsync(orderbookRequest, requestOpts);
+ } catch (err) {
+ throw new Error(AssetBuyerError.StandardRelayerApiError);
+ }
+ const apiOrders = orderbook.asks.records;
+ const orders = StandardRelayerAPIOrderFetcher._getSignedOrderWithRemainingFillableMakerAssetAmountFromApi(
+ apiOrders,
+ );
+ return {
+ orders,
+ };
+ }
+}
diff --git a/packages/asset-buyer/src/utils/order_fetcher_response_processor.ts b/packages/asset-buyer/src/utils/order_fetcher_response_processor.ts
index 04c5355eb..f1116a80f 100644
--- a/packages/asset-buyer/src/utils/order_fetcher_response_processor.ts
+++ b/packages/asset-buyer/src/utils/order_fetcher_response_processor.ts
@@ -165,6 +165,10 @@ function unbundleOrdersWithAmounts(
const { remainingFillableMakerAssetAmount, ...order } = orderWithAmount;
// if we are still missing a remainingFillableMakerAssetAmount, assume the order is completely fillable
const newRemainingAmount = remainingFillableMakerAssetAmount || order.makerAssetAmount;
+ // if remaining amount is less than or equal to zero, do not add it
+ if (newRemainingAmount.lte(constants.ZERO_AMOUNT)) {
+ return acc;
+ }
const newAcc = {
orders: _.concat(orders, order),
remainingFillableMakerAssetAmounts: _.concat(remainingFillableMakerAssetAmounts, newRemainingAmount),