aboutsummaryrefslogtreecommitdiffstats
path: root/packages/asset-buyer/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/asset-buyer/src')
-rw-r--r--packages/asset-buyer/src/asset_buyer.ts51
-rw-r--r--packages/asset-buyer/src/constants.ts3
-rw-r--r--packages/asset-buyer/src/order_providers/basic_order_provider.ts9
-rw-r--r--packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts36
-rw-r--r--packages/asset-buyer/src/types.ts5
-rw-r--r--packages/asset-buyer/src/utils/assert.ts17
-rw-r--r--packages/asset-buyer/src/utils/buy_quote_calculator.ts2
7 files changed, 78 insertions, 45 deletions
diff --git a/packages/asset-buyer/src/asset_buyer.ts b/packages/asset-buyer/src/asset_buyer.ts
index 74f3cb471..934410c55 100644
--- a/packages/asset-buyer/src/asset_buyer.ts
+++ b/packages/asset-buyer/src/asset_buyer.ts
@@ -52,16 +52,12 @@ export class AssetBuyer {
public static getAssetBuyerForProvidedOrders(
provider: Provider,
orders: SignedOrder[],
- feeOrders: SignedOrder[] = [],
options: Partial<AssetBuyerOpts> = {},
): AssetBuyer {
assert.isWeb3Provider('provider', provider);
assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
- assert.doesConformToSchema('feeOrders', feeOrders, schemas.signedOrdersSchema);
- assert.areValidProvidedOrders('orders', orders);
- assert.areValidProvidedOrders('feeOrders', feeOrders);
assert.assert(orders.length !== 0, `Expected orders to contain at least one order`);
- const orderProvider = new BasicOrderProvider(_.concat(orders, feeOrders));
+ const orderProvider = new BasicOrderProvider(orders);
const assetBuyer = new AssetBuyer(provider, orderProvider, options);
return assetBuyer;
}
@@ -80,7 +76,8 @@ export class AssetBuyer {
): AssetBuyer {
assert.isWeb3Provider('provider', provider);
assert.isWebUri('sraApiUrl', sraApiUrl);
- const orderProvider = new StandardRelayerAPIOrderProvider(sraApiUrl);
+ const networkId = options.networkId || constants.DEFAULT_ASSET_BUYER_OPTS.networkId;
+ const orderProvider = new StandardRelayerAPIOrderProvider(sraApiUrl, networkId);
const assetBuyer = new AssetBuyer(provider, orderProvider, options);
return assetBuyer;
}
@@ -93,10 +90,11 @@ export class AssetBuyer {
* @return An instance of AssetBuyer
*/
constructor(provider: Provider, orderProvider: OrderProvider, options: Partial<AssetBuyerOpts> = {}) {
- const { networkId, orderRefreshIntervalMs, expiryBufferSeconds } = {
- ...constants.DEFAULT_ASSET_BUYER_OPTS,
- ...options,
- };
+ const { networkId, orderRefreshIntervalMs, expiryBufferSeconds } = _.merge(
+ {},
+ constants.DEFAULT_ASSET_BUYER_OPTS,
+ options,
+ );
assert.isWeb3Provider('provider', provider);
assert.isValidOrderProvider('orderProvider', orderProvider);
assert.isNumber('networkId', networkId);
@@ -125,10 +123,11 @@ export class AssetBuyer {
assetBuyAmount: BigNumber,
options: Partial<BuyQuoteRequestOpts> = {},
): Promise<BuyQuote> {
- const { feePercentage, shouldForceOrderRefresh, slippagePercentage } = {
- ...constants.DEFAULT_BUY_QUOTE_REQUEST_OPTS,
- ...options,
- };
+ const { feePercentage, shouldForceOrderRefresh, slippagePercentage } = _.merge(
+ {},
+ constants.DEFAULT_BUY_QUOTE_REQUEST_OPTS,
+ options,
+ );
assert.isString('assetData', assetData);
assert.isBigNumber('assetBuyAmount', assetBuyAmount);
assert.isValidPercentage('feePercentage', feePercentage);
@@ -189,10 +188,11 @@ export class AssetBuyer {
buyQuote: BuyQuote,
options: Partial<BuyQuoteExecutionOpts> = {},
): Promise<string> {
- const { ethAmount, takerAddress, feeRecipient, gasLimit, gasPrice } = {
- ...constants.DEFAULT_BUY_QUOTE_EXECUTION_OPTS,
- ...options,
- };
+ const { ethAmount, takerAddress, feeRecipient, gasLimit, gasPrice } = _.merge(
+ {},
+ constants.DEFAULT_BUY_QUOTE_EXECUTION_OPTS,
+ options,
+ );
assert.isValidBuyQuote('buyQuote', buyQuote);
if (!_.isUndefined(ethAmount)) {
assert.isBigNumber('ethAmount', ethAmount);
@@ -201,6 +201,12 @@ export class AssetBuyer {
assert.isETHAddressHex('takerAddress', takerAddress);
}
assert.isETHAddressHex('feeRecipient', feeRecipient);
+ if (!_.isUndefined(gasLimit)) {
+ assert.isNumber('gasLimit', gasLimit);
+ }
+ if (!_.isUndefined(gasPrice)) {
+ assert.isBigNumber('gasPrice', gasPrice);
+ }
const { orders, feeOrders, feePercentage, assetBuyAmount, worstCaseQuoteInfo } = buyQuote;
// if no takerAddress is provided, try to get one from the provider
let finalTakerAddress;
@@ -244,6 +250,15 @@ export class AssetBuyer {
}
}
/**
+ * Get the asset data of all assets that are purchaseable with ether token (wETH) in the order provider passed in at init.
+ *
+ * @return An array of asset data strings that can be purchased using wETH.
+ */
+ public async getAvailableAssetDatasAsync(): Promise<string[]> {
+ const etherTokenAssetData = this._getEtherTokenAssetDataOrThrow();
+ return this.orderProvider.getAvailableMakerAssetDatasAsync(etherTokenAssetData);
+ }
+ /**
* Grab orders from the map, if there is a miss or it is time to refresh, fetch and process the orders
*/
private async _getOrdersAndFillableAmountsAsync(
diff --git a/packages/asset-buyer/src/constants.ts b/packages/asset-buyer/src/constants.ts
index c912253bd..c0e1bf27d 100644
--- a/packages/asset-buyer/src/constants.ts
+++ b/packages/asset-buyer/src/constants.ts
@@ -9,7 +9,7 @@ const MAINNET_NETWORK_ID = 1;
const DEFAULT_ASSET_BUYER_OPTS: AssetBuyerOpts = {
networkId: MAINNET_NETWORK_ID,
orderRefreshIntervalMs: 10000, // 10 seconds
- expiryBufferSeconds: 300, // 5 minutes
+ expiryBufferSeconds: 120, // 2 minutes
};
const DEFAULT_BUY_QUOTE_REQUEST_OPTS: BuyQuoteRequestOpts = {
@@ -36,6 +36,5 @@ export const constants = {
DEFAULT_ASSET_BUYER_OPTS,
DEFAULT_BUY_QUOTE_EXECUTION_OPTS,
DEFAULT_BUY_QUOTE_REQUEST_OPTS,
- MAX_PER_PAGE: 10000,
EMPTY_ORDERS_AND_FILLABLE_AMOUNTS,
};
diff --git a/packages/asset-buyer/src/order_providers/basic_order_provider.ts b/packages/asset-buyer/src/order_providers/basic_order_provider.ts
index 68406f19b..76685f27a 100644
--- a/packages/asset-buyer/src/order_providers/basic_order_provider.ts
+++ b/packages/asset-buyer/src/order_providers/basic_order_provider.ts
@@ -29,4 +29,13 @@ export class BasicOrderProvider implements OrderProvider {
});
return { orders };
}
+ /**
+ * Given a taker asset data string, return all availabled paired maker asset data strings.
+ * @param takerAssetData A string representing the taker asset data.
+ * @return An array of asset data strings that can be purchased using takerAssetData.
+ */
+ public async getAvailableMakerAssetDatasAsync(takerAssetData: string): Promise<string[]> {
+ const ordersWithTakerAssetData = _.filter(this.orders, { takerAssetData });
+ return _.map(ordersWithTakerAssetData, order => order.makerAssetData);
+ }
}
diff --git a/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts b/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts
index 41fd1fb30..be1fc55d6 100644
--- a/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts
+++ b/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts
@@ -1,5 +1,5 @@
import { HttpClient } from '@0x/connect';
-import { APIOrder, OrderbookResponse } from '@0x/types';
+import { APIOrder, AssetPairsResponse, OrderbookResponse } from '@0x/types';
import * as _ from 'lodash';
import {
@@ -14,6 +14,7 @@ import { orderUtils } from '../utils/order_utils';
export class StandardRelayerAPIOrderProvider implements OrderProvider {
public readonly apiUrl: string;
+ public readonly networkId: number;
private readonly _sraClient: HttpClient;
/**
* Given an array of APIOrder objects from a standard relayer api, return an array
@@ -44,12 +45,15 @@ export class StandardRelayerAPIOrderProvider implements OrderProvider {
}
/**
* Instantiates a new StandardRelayerAPIOrderProvider instance
- * @param apiUrl The standard relayer API base HTTP url you would like to source orders from.
+ * @param apiUrl The standard relayer API base HTTP url you would like to source orders from.
+ * @param networkId The ethereum network id.
* @return An instance of StandardRelayerAPIOrderProvider
*/
- constructor(apiUrl: string) {
+ constructor(apiUrl: string, networkId: number) {
assert.isWebUri('apiUrl', apiUrl);
+ assert.isNumber('networkId', networkId);
this.apiUrl = apiUrl;
+ this.networkId = networkId;
this._sraClient = new HttpClient(apiUrl);
}
/**
@@ -59,9 +63,9 @@ export class StandardRelayerAPIOrderProvider implements OrderProvider {
*/
public async getOrdersAsync(orderProviderRequest: OrderProviderRequest): Promise<OrderProviderResponse> {
assert.isValidOrderProviderRequest('orderProviderRequest', orderProviderRequest);
- const { makerAssetData, takerAssetData, networkId } = orderProviderRequest;
+ const { makerAssetData, takerAssetData } = orderProviderRequest;
const orderbookRequest = { baseAssetData: makerAssetData, quoteAssetData: takerAssetData };
- const requestOpts = { networkId };
+ const requestOpts = { networkId: this.networkId };
let orderbook: OrderbookResponse;
try {
orderbook = await this._sraClient.getOrderbookAsync(orderbookRequest, requestOpts);
@@ -76,4 +80,26 @@ export class StandardRelayerAPIOrderProvider implements OrderProvider {
orders,
};
}
+ /**
+ * Given a taker asset data string, return all availabled paired maker asset data strings.
+ * @param takerAssetData A string representing the taker asset data.
+ * @return An array of asset data strings that can be purchased using takerAssetData.
+ */
+ public async getAvailableMakerAssetDatasAsync(takerAssetData: string): Promise<string[]> {
+ // Return a maximum of 1000 asset datas
+ const maxPerPage = 1000;
+ const requestOpts = { networkId: this.networkId, perPage: maxPerPage };
+ const assetPairsRequest = { assetDataA: takerAssetData };
+ const fullRequest = {
+ ...requestOpts,
+ ...assetPairsRequest,
+ };
+ let response: AssetPairsResponse;
+ try {
+ response = await this._sraClient.getAssetPairsAsync(fullRequest);
+ } catch (err) {
+ throw new Error(AssetBuyerError.StandardRelayerApiError);
+ }
+ return _.map(response.records, item => item.assetDataB.assetData);
+ }
}
diff --git a/packages/asset-buyer/src/types.ts b/packages/asset-buyer/src/types.ts
index f15e7e934..3f1e6ff21 100644
--- a/packages/asset-buyer/src/types.ts
+++ b/packages/asset-buyer/src/types.ts
@@ -9,7 +9,6 @@ import { BigNumber } from '@0x/utils';
export interface OrderProviderRequest {
makerAssetData: string;
takerAssetData: string;
- networkId: number;
}
/**
@@ -27,10 +26,12 @@ export interface SignedOrderWithRemainingFillableMakerAssetAmount extends Signed
remainingFillableMakerAssetAmount?: BigNumber;
}
/**
- * Given an OrderProviderRequest, get an OrderProviderResponse.
+ * gerOrdersAsync: Given an OrderProviderRequest, get an OrderProviderResponse.
+ * getAvailableMakerAssetDatasAsync: Given a taker asset data string, return all availabled paired maker asset data strings.
*/
export interface OrderProvider {
getOrdersAsync: (orderProviderRequest: OrderProviderRequest) => Promise<OrderProviderResponse>;
+ getAvailableMakerAssetDatasAsync: (takerAssetData: string) => Promise<string[]>;
}
/**
diff --git a/packages/asset-buyer/src/utils/assert.ts b/packages/asset-buyer/src/utils/assert.ts
index e8cb7f763..2466f53a4 100644
--- a/packages/asset-buyer/src/utils/assert.ts
+++ b/packages/asset-buyer/src/utils/assert.ts
@@ -1,6 +1,5 @@
import { assert as sharedAssert } from '@0x/assert';
import { schemas } from '@0x/json-schemas';
-import { SignedOrder } from '@0x/types';
import * as _ from 'lodash';
import { BuyQuote, BuyQuoteInfo, OrderProvider, OrderProviderRequest } from '../types';
@@ -29,22 +28,6 @@ export const assert = {
isValidOrderProviderRequest(variableName: string, orderFetcherRequest: OrderProviderRequest): void {
sharedAssert.isHexString(`${variableName}.makerAssetData`, orderFetcherRequest.makerAssetData);
sharedAssert.isHexString(`${variableName}.takerAssetData`, orderFetcherRequest.takerAssetData);
- sharedAssert.isNumber(`${variableName}.networkId`, orderFetcherRequest.networkId);
- },
- areValidProvidedOrders(variableName: string, orders: SignedOrder[]): void {
- if (orders.length === 0) {
- return;
- }
- const makerAssetData = orders[0].makerAssetData;
- const takerAssetData = orders[0].takerAssetData;
- const filteredOrders = _.filter(
- orders,
- order => order.makerAssetData === makerAssetData && order.takerAssetData === takerAssetData,
- );
- sharedAssert.assert(
- orders.length === filteredOrders.length,
- `Expected all orders in ${variableName} to have the same makerAssetData and takerAssetData.`,
- );
},
isValidPercentage(variableName: string, percentage: number): void {
assert.isNumber(variableName, percentage);
diff --git a/packages/asset-buyer/src/utils/buy_quote_calculator.ts b/packages/asset-buyer/src/utils/buy_quote_calculator.ts
index f94ab3fa4..6a67ed1ed 100644
--- a/packages/asset-buyer/src/utils/buy_quote_calculator.ts
+++ b/packages/asset-buyer/src/utils/buy_quote_calculator.ts
@@ -119,7 +119,7 @@ function calculateQuoteInfo(
ethAmountToBuyZrx = findEthAmountNeededToBuyZrx(feeOrdersAndFillableAmounts, zrxAmountToBuyAsset);
}
/// find the eth amount needed to buy the affiliate fee
- const ethAmountToBuyAffiliateFee = ethAmountToBuyAsset.mul(feePercentage);
+ const ethAmountToBuyAffiliateFee = ethAmountToBuyAsset.mul(feePercentage).ceil();
const totalEthAmountWithoutAffiliateFee = ethAmountToBuyAsset.plus(ethAmountToBuyZrx);
const ethAmountTotal = totalEthAmountWithoutAffiliateFee.plus(ethAmountToBuyAffiliateFee);
// divide into the assetBuyAmount in order to find rate of makerAsset / WETH