Add expiry buffer

This commit is contained in:
fragosti
2018-09-24 13:17:38 +02:00
parent 7a5376621f
commit e4b664bafa
4 changed files with 51 additions and 14 deletions

View File

@@ -29,6 +29,7 @@ export class AssetBuyer {
public readonly orderProvider: OrderProvider; public readonly orderProvider: OrderProvider;
public readonly networkId: number; public readonly networkId: number;
public readonly orderRefreshIntervalMs: number; public readonly orderRefreshIntervalMs: number;
public readonly expiryBufferSeconds: number;
private readonly _contractWrappers: ContractWrappers; private readonly _contractWrappers: ContractWrappers;
private _lastRefreshTimeIfExists?: number; private _lastRefreshTimeIfExists?: number;
private _currentOrdersAndFillableAmountsIfExists?: AssetBuyerOrdersAndFillableAmounts; private _currentOrdersAndFillableAmountsIfExists?: AssetBuyerOrdersAndFillableAmounts;
@@ -38,8 +39,9 @@ export class AssetBuyer {
* @param orders A non-empty array of objects that conform to SignedOrder. All orders must have the same makerAssetData and takerAssetData (WETH). * @param orders A non-empty array of objects that conform to SignedOrder. All orders must have the same makerAssetData and takerAssetData (WETH).
* @param feeOrders A array of objects that conform to SignedOrder. All orders must have the same makerAssetData (ZRX) and takerAssetData (WETH). Defaults to an empty array. * @param feeOrders A array of objects that conform to SignedOrder. All orders must have the same makerAssetData (ZRX) and takerAssetData (WETH). Defaults to an empty array.
* @param networkId The ethereum network id. Defaults to 1 (mainnet). * @param networkId The ethereum network id. Defaults to 1 (mainnet).
* @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. * @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. Defaults to 10000ms (10s).
* Defaults to 10000ms (10s). * @param expiryBufferSeconds The number of seconds to add when calculating whether an order is expired or not. Defaults to 15s.
*
* @return An instance of AssetBuyer * @return An instance of AssetBuyer
*/ */
public static getAssetBuyerForProvidedOrders( public static getAssetBuyerForProvidedOrders(
@@ -48,6 +50,7 @@ export class AssetBuyer {
feeOrders: SignedOrder[] = [], feeOrders: SignedOrder[] = [],
networkId: number = constants.MAINNET_NETWORK_ID, networkId: number = constants.MAINNET_NETWORK_ID,
orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS, orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS,
expiryBufferSeconds: number = constants.DEFAULT_EXPIRY_BUFFER_SECONDS,
): AssetBuyer { ): AssetBuyer {
assert.isWeb3Provider('provider', provider); assert.isWeb3Provider('provider', provider);
assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema); assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
@@ -59,7 +62,14 @@ export class AssetBuyer {
assert.assert(orders.length !== 0, `Expected orders to contain at least one order`); assert.assert(orders.length !== 0, `Expected orders to contain at least one order`);
const assetData = orders[0].makerAssetData; const assetData = orders[0].makerAssetData;
const orderProvider = new BasicOrderProvider(_.concat(orders, feeOrders)); const orderProvider = new BasicOrderProvider(_.concat(orders, feeOrders));
const assetBuyer = new AssetBuyer(provider, assetData, orderProvider, networkId, orderRefreshIntervalMs); const assetBuyer = new AssetBuyer(
provider,
assetData,
orderProvider,
networkId,
orderRefreshIntervalMs,
expiryBufferSeconds,
);
return assetBuyer; return assetBuyer;
} }
/** /**
@@ -68,8 +78,9 @@ export class AssetBuyer {
* @param assetData The assetData that identifies the desired asset to buy. * @param assetData The assetData that identifies the desired asset to buy.
* @param sraApiUrl The standard relayer API base HTTP url you would like to source orders from. * @param sraApiUrl The standard relayer API base HTTP url you would like to source orders from.
* @param networkId The ethereum network id. Defaults to 1 (mainnet). * @param networkId The ethereum network id. Defaults to 1 (mainnet).
* @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. * @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. Defaults to 10000ms (10s).
* Defaults to 10000ms (10s). * @param expiryBufferSeconds The number of seconds to add when calculating whether an order is expired or not. Defaults to 15s.
*
* @return An instance of AssetBuyer * @return An instance of AssetBuyer
*/ */
public static getAssetBuyerForAssetData( public static getAssetBuyerForAssetData(
@@ -78,6 +89,7 @@ export class AssetBuyer {
sraApiUrl: string, sraApiUrl: string,
networkId: number = constants.MAINNET_NETWORK_ID, networkId: number = constants.MAINNET_NETWORK_ID,
orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS, orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS,
expiryBufferSeconds: number = constants.DEFAULT_EXPIRY_BUFFER_SECONDS,
): AssetBuyer { ): AssetBuyer {
assert.isWeb3Provider('provider', provider); assert.isWeb3Provider('provider', provider);
assert.isHexString('assetData', assetData); assert.isHexString('assetData', assetData);
@@ -85,7 +97,14 @@ export class AssetBuyer {
assert.isNumber('networkId', networkId); assert.isNumber('networkId', networkId);
assert.isNumber('orderRefreshIntervalMs', orderRefreshIntervalMs); assert.isNumber('orderRefreshIntervalMs', orderRefreshIntervalMs);
const orderProvider = new StandardRelayerAPIOrderProvider(sraApiUrl); const orderProvider = new StandardRelayerAPIOrderProvider(sraApiUrl);
const assetBuyer = new AssetBuyer(provider, assetData, orderProvider, networkId, orderRefreshIntervalMs); const assetBuyer = new AssetBuyer(
provider,
assetData,
orderProvider,
networkId,
orderRefreshIntervalMs,
expiryBufferSeconds,
);
return assetBuyer; return assetBuyer;
} }
/** /**
@@ -94,8 +113,8 @@ export class AssetBuyer {
* @param tokenAddress The ERC20 token address that identifies the desired asset to buy. * @param tokenAddress The ERC20 token address that identifies the desired asset to buy.
* @param sraApiUrl The standard relayer API base HTTP url you would like to source orders from. * @param sraApiUrl The standard relayer API base HTTP url you would like to source orders from.
* @param networkId The ethereum network id. Defaults to 1 (mainnet). * @param networkId The ethereum network id. Defaults to 1 (mainnet).
* @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. * @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. Defaults to 10000ms (10s).
* Defaults to 10000ms (10s). * @param expiryBufferSeconds The number of seconds to add when calculating whether an order is expired or not. Defaults to 15s.
* @return An instance of AssetBuyer * @return An instance of AssetBuyer
*/ */
public static getAssetBuyerForERC20TokenAddress( public static getAssetBuyerForERC20TokenAddress(
@@ -104,6 +123,7 @@ export class AssetBuyer {
sraApiUrl: string, sraApiUrl: string,
networkId: number = constants.MAINNET_NETWORK_ID, networkId: number = constants.MAINNET_NETWORK_ID,
orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS, orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS,
expiryBufferSeconds: number = constants.DEFAULT_EXPIRY_BUFFER_SECONDS,
): AssetBuyer { ): AssetBuyer {
assert.isWeb3Provider('provider', provider); assert.isWeb3Provider('provider', provider);
assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('tokenAddress', tokenAddress);
@@ -117,6 +137,7 @@ export class AssetBuyer {
sraApiUrl, sraApiUrl,
networkId, networkId,
orderRefreshIntervalMs, orderRefreshIntervalMs,
expiryBufferSeconds,
); );
return assetBuyer; return assetBuyer;
} }
@@ -126,8 +147,9 @@ export class AssetBuyer {
* @param assetData The assetData of the desired asset to buy (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md). * @param assetData The assetData of the desired asset to buy (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* @param orderProvider An object that conforms to OrderProvider, see type for definition. * @param orderProvider An object that conforms to OrderProvider, see type for definition.
* @param networkId The ethereum network id. Defaults to 1 (mainnet). * @param networkId The ethereum network id. Defaults to 1 (mainnet).
* @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. * @param orderRefreshIntervalMs The interval in ms that getBuyQuoteAsync should trigger an refresh of orders and order states. Defaults to 10000ms (10s).
* Defaults to 10000ms (10s). * @param expiryBufferSeconds The number of seconds to add when calculating whether an order is expired or not. Defaults to 15s.
*
* @return An instance of AssetBuyer * @return An instance of AssetBuyer
*/ */
constructor( constructor(
@@ -136,6 +158,7 @@ export class AssetBuyer {
orderProvider: OrderProvider, orderProvider: OrderProvider,
networkId: number = constants.MAINNET_NETWORK_ID, networkId: number = constants.MAINNET_NETWORK_ID,
orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS, orderRefreshIntervalMs: number = constants.DEFAULT_ORDER_REFRESH_INTERVAL_MS,
expiryBufferSeconds: number = constants.DEFAULT_EXPIRY_BUFFER_SECONDS,
) { ) {
assert.isWeb3Provider('provider', provider); assert.isWeb3Provider('provider', provider);
assert.isString('assetData', assetData); assert.isString('assetData', assetData);
@@ -146,6 +169,7 @@ export class AssetBuyer {
this.assetData = assetData; this.assetData = assetData;
this.orderProvider = orderProvider; this.orderProvider = orderProvider;
this.networkId = networkId; this.networkId = networkId;
this.expiryBufferSeconds = expiryBufferSeconds;
this.orderRefreshIntervalMs = orderRefreshIntervalMs; this.orderRefreshIntervalMs = orderRefreshIntervalMs;
this._contractWrappers = new ContractWrappers(this.provider, { this._contractWrappers = new ContractWrappers(this.provider, {
networkId, networkId,
@@ -278,6 +302,7 @@ export class AssetBuyer {
targetOrderProviderResponse, targetOrderProviderResponse,
feeOrderProviderResponse, feeOrderProviderResponse,
zrxTokenAssetData, zrxTokenAssetData,
this.expiryBufferSeconds,
this._contractWrappers.orderValidator, this._contractWrappers.orderValidator,
); );
return ordersAndFillableAmounts; return ordersAndFillableAmounts;

View File

@@ -16,4 +16,5 @@ export const constants = {
ETHER_TOKEN_DECIMALS: 18, ETHER_TOKEN_DECIMALS: 18,
DEFAULT_BUY_QUOTE_REQUEST_OPTS, DEFAULT_BUY_QUOTE_REQUEST_OPTS,
MAX_PER_PAGE: 10000, MAX_PER_PAGE: 10000,
DEFAULT_EXPIRY_BUFFER_SECONDS: 15,
}; };

View File

@@ -41,11 +41,18 @@ export const orderProviderResponseProcessor = {
targetOrderProviderResponse: OrderProviderResponse, targetOrderProviderResponse: OrderProviderResponse,
feeOrderProviderResponse: OrderProviderResponse, feeOrderProviderResponse: OrderProviderResponse,
zrxTokenAssetData: string, zrxTokenAssetData: string,
expiryBufferSeconds: number,
orderValidator?: OrderValidatorWrapper, orderValidator?: OrderValidatorWrapper,
): Promise<AssetBuyerOrdersAndFillableAmounts> { ): Promise<AssetBuyerOrdersAndFillableAmounts> {
// drop orders that are expired or not open // drop orders that are expired or not open
const filteredTargetOrders = filterOutExpiredAndNonOpenOrders(targetOrderProviderResponse.orders); const filteredTargetOrders = filterOutExpiredAndNonOpenOrders(
const filteredFeeOrders = filterOutExpiredAndNonOpenOrders(feeOrderProviderResponse.orders); targetOrderProviderResponse.orders,
expiryBufferSeconds,
);
const filteredFeeOrders = filterOutExpiredAndNonOpenOrders(
feeOrderProviderResponse.orders,
expiryBufferSeconds,
);
// set the orders to be sorted equal to the filtered orders // set the orders to be sorted equal to the filtered orders
let unsortedTargetOrders = filteredTargetOrders; let unsortedTargetOrders = filteredTargetOrders;
let unsortedFeeOrders = filteredFeeOrders; let unsortedFeeOrders = filteredFeeOrders;
@@ -98,9 +105,10 @@ export const orderProviderResponseProcessor = {
*/ */
function filterOutExpiredAndNonOpenOrders( function filterOutExpiredAndNonOpenOrders(
orders: SignedOrderWithRemainingFillableMakerAssetAmount[], orders: SignedOrderWithRemainingFillableMakerAssetAmount[],
expiryBufferSeconds: number,
): SignedOrderWithRemainingFillableMakerAssetAmount[] { ): SignedOrderWithRemainingFillableMakerAssetAmount[] {
const result = _.filter(orders, order => { const result = _.filter(orders, order => {
return orderUtils.isOpenOrder(order) && !orderUtils.isOrderExpired(order); return orderUtils.isOpenOrder(order) && !orderUtils.willOrderExpire(order, expiryBufferSeconds);
}); });
return result; return result;
} }

View File

@@ -5,9 +5,12 @@ import { constants } from '../constants';
export const orderUtils = { export const orderUtils = {
isOrderExpired(order: SignedOrder): boolean { isOrderExpired(order: SignedOrder): boolean {
return orderUtils.willOrderExpire(order, 0);
},
willOrderExpire(order: SignedOrder, secondsFromNow: number): boolean {
const millisecondsInSecond = 1000; const millisecondsInSecond = 1000;
const currentUnixTimestampSec = new BigNumber(Date.now() / millisecondsInSecond).round(); const currentUnixTimestampSec = new BigNumber(Date.now() / millisecondsInSecond).round();
return order.expirationTimeSeconds.lessThan(currentUnixTimestampSec); return order.expirationTimeSeconds.lessThan(currentUnixTimestampSec.minus(secondsFromNow));
}, },
calculateRemainingMakerAssetAmount(order: SignedOrder, remainingTakerAssetAmount: BigNumber): BigNumber { calculateRemainingMakerAssetAmount(order: SignedOrder, remainingTakerAssetAmount: BigNumber): BigNumber {
if (remainingTakerAssetAmount.eq(0)) { if (remainingTakerAssetAmount.eq(0)) {