Make OrderStore async for use in db adapter

CHANGELOGS
This commit is contained in:
Jacob Evans
2019-12-10 20:19:25 -08:00
parent 6b0f3570b9
commit c324fe204e
13 changed files with 63 additions and 36 deletions

View File

@@ -1,4 +1,13 @@
[ [
{
"version": "3.0.2",
"changes": [
{
"note": "Fix gasPrice from `ethgasstation` to be in WEI instead of GWEI",
"pr": 2393
}
]
},
{ {
"timestamp": 1575931811, "timestamp": 1575931811,
"version": "3.0.1", "version": "3.0.1",

View File

@@ -18,7 +18,11 @@ export class ProtocolFeeUtils {
const gasInfo = await res.json(); const gasInfo = await res.json();
// Eth Gas Station result is gwei * 10 // Eth Gas Station result is gwei * 10
// tslint:disable-next-line:custom-no-magic-numbers // tslint:disable-next-line:custom-no-magic-numbers
return new BigNumber(gasInfo.fast / 10); const BASE_TEN = 10;
const gasPriceGwei = new BigNumber(gasInfo.fast / BASE_TEN);
const unit = new BigNumber(BASE_TEN).pow(BASE_TEN);
const gasPriceWei = unit.times(gasPriceGwei);
return gasPriceWei;
} catch (e) { } catch (e) {
throw new Error(SwapQuoterError.NoGasPriceProvidedOrEstimated); throw new Error(SwapQuoterError.NoGasPriceProvidedOrEstimated);
} }

View File

@@ -1,4 +1,13 @@
[ [
{
"version": "2.0.0",
"changes": [
{
"note": "Change OrderStore functions to be async, allowing for Database adapters",
"pr": 2393
}
]
},
{ {
"timestamp": 1575931811, "timestamp": 1575931811,
"version": "1.0.1", "version": "1.0.1",

View File

@@ -27,8 +27,6 @@ export abstract class BaseOrderProvider {
public abstract async addOrdersAsync(orders: SignedOrder[]): Promise<AcceptedRejectedOrders>; public abstract async addOrdersAsync(orders: SignedOrder[]): Promise<AcceptedRejectedOrders>;
protected async _updateStoreAsync(addedRemoved: AddedRemovedOrders): Promise<void> { protected async _updateStoreAsync(addedRemoved: AddedRemovedOrders): Promise<void> {
const orderSet = this._orderStore.getOrderSetForAssetPair(addedRemoved.assetPairKey); await this._orderStore.updateAsync(addedRemoved);
await orderSet.addManyAsync(addedRemoved.added);
await orderSet.deleteManyAsync(addedRemoved.removed);
} }
} }

View File

@@ -23,7 +23,7 @@ export class CustomOrderProvider extends BaseOrderProvider {
const minAmount = new BigNumber(0); const minAmount = new BigNumber(0);
const maxAmount = new BigNumber(2).pow(256).minus(1); const maxAmount = new BigNumber(2).pow(256).minus(1);
const precision = DEFAULT_TOKEN_PRECISION; const precision = DEFAULT_TOKEN_PRECISION;
for (const assetPairKey of this._orderStore.keys()) { for (const assetPairKey of await this._orderStore.keysAsync()) {
const [assetA, assetB] = OrderStore.assetPairKeyToAssets(assetPairKey); const [assetA, assetB] = OrderStore.assetPairKeyToAssets(assetPairKey);
const assetDataA: Asset = { assetData: assetA, minAmount, maxAmount, precision }; const assetDataA: Asset = { assetData: assetA, minAmount, maxAmount, precision };
const assetDataB: Asset = { assetData: assetB, minAmount, maxAmount, precision }; const assetDataB: Asset = { assetData: assetB, minAmount, maxAmount, precision };
@@ -40,13 +40,19 @@ export class CustomOrderProvider extends BaseOrderProvider {
public async addOrdersAsync(orders: SignedOrder[]): Promise<AcceptedRejectedOrders> { public async addOrdersAsync(orders: SignedOrder[]): Promise<AcceptedRejectedOrders> {
for (const order of orders) { for (const order of orders) {
const orderSet = this._orderStore.getOrderSetForAssets(order.makerAssetData, order.takerAssetData); const assetPairKey = OrderStore.getKeyForAssetPair(order.makerAssetData, order.takerAssetData);
await orderSet.addAsync({ await this._orderStore.updateAsync({
order, added: [
metaData: { {
remainingFillableTakerAssetAmount: order.takerAssetAmount, order,
orderHash: await utils.getOrderHashAsync(order), metaData: {
}, remainingFillableTakerAssetAmount: order.takerAssetAmount,
orderHash: await utils.getOrderHashAsync(order),
},
},
],
removed: [],
assetPairKey,
}); });
} }
return { accepted: orders, rejected: [] }; return { accepted: orders, rejected: [] };

View File

@@ -65,7 +65,7 @@ export class MeshOrderProvider extends BaseOrderProvider {
const minAmount = new BigNumber(0); const minAmount = new BigNumber(0);
const maxAmount = new BigNumber(2).pow(256).minus(1); const maxAmount = new BigNumber(2).pow(256).minus(1);
const precision = DEFAULT_TOKEN_PRECISION; const precision = DEFAULT_TOKEN_PRECISION;
for (const assetPairKey of this._orderStore.keys()) { for (const assetPairKey of await this._orderStore.keysAsync()) {
const [assetA, assetB] = OrderStore.assetPairKeyToAssets(assetPairKey); const [assetA, assetB] = OrderStore.assetPairKeyToAssets(assetPairKey);
const assetDataA: Asset = { assetData: assetA, minAmount, maxAmount, precision }; const assetDataA: Asset = { assetData: assetA, minAmount, maxAmount, precision };
const assetDataB: Asset = { assetData: assetB, minAmount, maxAmount, precision }; const assetDataB: Asset = { assetData: assetB, minAmount, maxAmount, precision };
@@ -127,8 +127,8 @@ export class MeshOrderProvider extends BaseOrderProvider {
* for every known asset pair. * for every known asset pair.
*/ */
private async _syncOrdersInOrderStoreAsync(): Promise<void> { private async _syncOrdersInOrderStoreAsync(): Promise<void> {
for (const assetPairKey of this._orderStore.keys()) { for (const assetPairKey of await this._orderStore.keysAsync()) {
const currentOrders = this._orderStore.getOrderSetForAssetPair(assetPairKey); const currentOrders = await this._orderStore.getOrderSetForAssetPairAsync(assetPairKey);
const { rejected } = await utils.attemptAsync(() => const { rejected } = await utils.attemptAsync(() =>
this._wsClient.addOrdersAsync(Array.from(currentOrders.values()).map(o => o.order)), this._wsClient.addOrdersAsync(Array.from(currentOrders.values()).map(o => o.order)),
); );

View File

@@ -69,7 +69,7 @@ export class SRAPollingOrderProvider extends BaseSRAOrderProvider {
const assetPairKey = OrderStore.getKeyForAssetPair(makerAssetData, takerAssetData); const assetPairKey = OrderStore.getKeyForAssetPair(makerAssetData, takerAssetData);
const pollingIntervalId = intervalUtils.setAsyncExcludingInterval( const pollingIntervalId = intervalUtils.setAsyncExcludingInterval(
async () => { async () => {
const previousOrderSet = this._orderStore.getOrderSetForAssetPair(assetPairKey); const previousOrderSet = await this._orderStore.getOrderSetForAssetPairAsync(assetPairKey);
const orders = await this._fetchLatestOrdersAsync(makerAssetData, takerAssetData); const orders = await this._fetchLatestOrdersAsync(makerAssetData, takerAssetData);
const orderSet = new OrderSet(); const orderSet = new OrderSet();
await orderSet.addManyAsync(orders); await orderSet.addManyAsync(orders);

View File

@@ -101,7 +101,7 @@ export class SRAWebsocketOrderProvider extends BaseSRAOrderProvider {
// first time we have had this request, preload the local storage // first time we have had this request, preload the local storage
const orders = await this._fetchLatestOrdersAsync(makerAssetData, takerAssetData); const orders = await this._fetchLatestOrdersAsync(makerAssetData, takerAssetData);
const assetPairKey = OrderStore.getKeyForAssetPair(makerAssetData, takerAssetData); const assetPairKey = OrderStore.getKeyForAssetPair(makerAssetData, takerAssetData);
const currentOrders = this._orderStore.getOrderSetForAssetPair(assetPairKey); const currentOrders = await this._orderStore.getOrderSetForAssetPairAsync(assetPairKey);
const newOrders = new OrderSet(); const newOrders = new OrderSet();
await newOrders.addManyAsync(orders); await newOrders.addManyAsync(orders);
const diff = await currentOrders.diffAsync(newOrders); const diff = await currentOrders.diffAsync(newOrders);
@@ -113,7 +113,7 @@ export class SRAWebsocketOrderProvider extends BaseSRAOrderProvider {
} }
private async _syncOrdersInOrderStoreAsync(): Promise<void> { private async _syncOrdersInOrderStoreAsync(): Promise<void> {
for (const assetPairKey of this._orderStore.keys()) { for (const assetPairKey of await this._orderStore.keysAsync()) {
const [assetDataA, assetDataB] = OrderStore.assetPairKeyToAssets(assetPairKey); const [assetDataA, assetDataB] = OrderStore.assetPairKeyToAssets(assetPairKey);
await this._fetchAndCreateSubscriptionAsync(assetDataA, assetDataB); await this._fetchAndCreateSubscriptionAsync(assetDataA, assetDataB);
} }

View File

@@ -12,11 +12,11 @@ export class OrderStore {
public static assetPairKeyToAssets(assetPairKey: string): string[] { public static assetPairKeyToAssets(assetPairKey: string): string[] {
return assetPairKey.split('-'); return assetPairKey.split('-');
} }
public getOrderSetForAssets(makerAssetData: string, takerAssetData: string): OrderSet { public async getOrderSetForAssetsAsync(makerAssetData: string, takerAssetData: string): Promise<OrderSet> {
const assetPairKey = OrderStore.getKeyForAssetPair(makerAssetData, takerAssetData); const assetPairKey = OrderStore.getKeyForAssetPair(makerAssetData, takerAssetData);
return this.getOrderSetForAssetPair(assetPairKey); return this.getOrderSetForAssetPairAsync(assetPairKey);
} }
public getOrderSetForAssetPair(assetPairKey: string): OrderSet { public async getOrderSetForAssetPairAsync(assetPairKey: string): Promise<OrderSet> {
const orderSet = this._orders.get(assetPairKey); const orderSet = this._orders.get(assetPairKey);
if (!orderSet) { if (!orderSet) {
const newOrderSet = new OrderSet(); const newOrderSet = new OrderSet();
@@ -27,17 +27,17 @@ export class OrderStore {
} }
public async updateAsync(addedRemoved: AddedRemovedOrders): Promise<void> { public async updateAsync(addedRemoved: AddedRemovedOrders): Promise<void> {
const { added, removed, assetPairKey } = addedRemoved; const { added, removed, assetPairKey } = addedRemoved;
const orders = this.getOrderSetForAssetPair(assetPairKey); const orders = await this.getOrderSetForAssetPairAsync(assetPairKey);
await orders.addManyAsync(added); await orders.addManyAsync(added);
await orders.deleteManyAsync(removed); await orders.deleteManyAsync(removed);
} }
public has(assetPairKey: string): boolean { public async hasAsync(assetPairKey: string): Promise<boolean> {
return this._orders.has(assetPairKey); return this._orders.has(assetPairKey);
} }
public values(assetPairKey: string): APIOrder[] { public async valuesAsync(assetPairKey: string): Promise<APIOrder[]> {
return Array.from(this.getOrderSetForAssetPair(assetPairKey).values()); return Array.from((await this.getOrderSetForAssetPairAsync(assetPairKey)).values());
} }
public keys(): IterableIterator<string> { public async keysAsync(): Promise<IterableIterator<string>> {
return this._orders.keys(); return this._orders.keys();
} }
} }

View File

@@ -76,10 +76,10 @@ export class Orderbook {
assert.isString('makerAssetData', makerAssetData); assert.isString('makerAssetData', makerAssetData);
assert.isString('takerAssetData', takerAssetData); assert.isString('takerAssetData', takerAssetData);
const assetPairKey = OrderStore.getKeyForAssetPair(makerAssetData, takerAssetData); const assetPairKey = OrderStore.getKeyForAssetPair(makerAssetData, takerAssetData);
if (!this._orderStore.has(assetPairKey)) { if (!(await this._orderStore.hasAsync(assetPairKey))) {
await this._orderProvider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData); await this._orderProvider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData);
} }
const orders = this._orderStore.values(assetPairKey); const orders = await this._orderStore.valuesAsync(assetPairKey);
return orders.filter( return orders.filter(
o => o.order.makerAssetData === makerAssetData && o.order.takerAssetData === takerAssetData, o => o.order.makerAssetData === makerAssetData && o.order.takerAssetData === takerAssetData,
); );

View File

@@ -142,7 +142,7 @@ describe('MeshOrderProvider', () => {
); );
provider = new MeshOrderProvider({ websocketEndpoint }, orderStore); provider = new MeshOrderProvider({ websocketEndpoint }, orderStore);
await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData); await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData);
const orders = orderStore.getOrderSetForAssets(makerAssetData, takerAssetData); const orders = await orderStore.getOrderSetForAssetsAsync(makerAssetData, takerAssetData);
expect(orders.size()).toBe(1); expect(orders.size()).toBe(1);
}); });
test('stores the orders from a subscription update', async () => { test('stores the orders from a subscription update', async () => {
@@ -152,7 +152,7 @@ describe('MeshOrderProvider', () => {
await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData); await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData);
connection.sendUTF(eventResponse); connection.sendUTF(eventResponse);
await utils.delayAsync(100); await utils.delayAsync(100);
const orders = orderStore.getOrderSetForAssets(makerAssetData, takerAssetData); const orders = await orderStore.getOrderSetForAssetsAsync(makerAssetData, takerAssetData);
expect(orders.size()).toBe(1); expect(orders.size()).toBe(1);
}); });
test('removes orders on a subscription update', async () => { test('removes orders on a subscription update', async () => {
@@ -163,7 +163,7 @@ describe('MeshOrderProvider', () => {
await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData); await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData);
connection.sendUTF(added); connection.sendUTF(added);
await utils.delayAsync(100); await utils.delayAsync(100);
const orders = orderStore.getOrderSetForAssets(makerAssetData, takerAssetData); const orders = await orderStore.getOrderSetForAssetsAsync(makerAssetData, takerAssetData);
expect(orders.size()).toBe(1); expect(orders.size()).toBe(1);
connection.sendUTF(removed); connection.sendUTF(removed);
await utils.delayAsync(100); await utils.delayAsync(100);
@@ -224,7 +224,7 @@ describe('MeshOrderProvider', () => {
orderStore, orderStore,
); );
await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData); await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData);
const orders = orderStore.getOrderSetForAssets(makerAssetData, takerAssetData); const orders = await orderStore.getOrderSetForAssetsAsync(makerAssetData, takerAssetData);
expect(getOrdersStub.callCount).toBe(1); expect(getOrdersStub.callCount).toBe(1);
// Orders are not added on a subscription, only during reconnnect // Orders are not added on a subscription, only during reconnnect
expect(addOrdersStub.callCount).toBe(0); expect(addOrdersStub.callCount).toBe(0);

View File

@@ -71,7 +71,7 @@ describe('SRAPollingOrderProvider', () => {
); );
provider = new SRAPollingOrderProvider({ httpEndpoint, pollingIntervalMs: 30000 }, orderStore); provider = new SRAPollingOrderProvider({ httpEndpoint, pollingIntervalMs: 30000 }, orderStore);
await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData); await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData);
const orders = orderStore.getOrderSetForAssets(makerAssetData, takerAssetData); const orders = await orderStore.getOrderSetForAssetsAsync(makerAssetData, takerAssetData);
expect(orders.size()).toBe(1); expect(orders.size()).toBe(1);
}); });
test('removes the order from the set when the API response no longer returns the order', async () => { test('removes the order from the set when the API response no longer returns the order', async () => {
@@ -88,7 +88,7 @@ describe('SRAPollingOrderProvider', () => {
); );
provider = new SRAPollingOrderProvider({ httpEndpoint, pollingIntervalMs: 1 }, orderStore); provider = new SRAPollingOrderProvider({ httpEndpoint, pollingIntervalMs: 1 }, orderStore);
await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData); await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData);
const orders = orderStore.getOrderSetForAssets(makerAssetData, takerAssetData); const orders = await orderStore.getOrderSetForAssetsAsync(makerAssetData, takerAssetData);
expect(orders.size()).toBe(1); expect(orders.size()).toBe(1);
// Delete the record from the API response // Delete the record from the API response
records.splice(0, 1); records.splice(0, 1);

View File

@@ -87,7 +87,7 @@ describe('SRAWebsocketOrderProvider', () => {
expect(stub.callCount).toBe(2); expect(stub.callCount).toBe(2);
expect(wsStub.callCount).toBe(1); expect(wsStub.callCount).toBe(1);
await utils.delayAsync(5); await utils.delayAsync(5);
const storedOrders = orderStore.getOrderSetForAssets(makerAssetData, takerAssetData); const storedOrders = await orderStore.getOrderSetForAssetsAsync(makerAssetData, takerAssetData);
expect(storedOrders.size()).toBe(1); expect(storedOrders.size()).toBe(1);
}); });
test('stores the orders', async () => { test('stores the orders', async () => {
@@ -108,7 +108,7 @@ describe('SRAWebsocketOrderProvider', () => {
); );
provider = new SRAWebsocketOrderProvider({ httpEndpoint, websocketEndpoint }, orderStore); provider = new SRAWebsocketOrderProvider({ httpEndpoint, websocketEndpoint }, orderStore);
await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData); await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData);
const orders = orderStore.getOrderSetForAssets(makerAssetData, takerAssetData); const orders = await orderStore.getOrderSetForAssetsAsync(makerAssetData, takerAssetData);
expect(orders.size()).toBe(1); expect(orders.size()).toBe(1);
}); });
test('reconnects on channel close', async () => { test('reconnects on channel close', async () => {
@@ -134,6 +134,7 @@ describe('SRAWebsocketOrderProvider', () => {
await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData); await provider.createSubscriptionForAssetPairAsync(makerAssetData, takerAssetData);
expect(handler).not.toBe(undefined); expect(handler).not.toBe(undefined);
(handler as OrdersChannelHandler).onClose(undefined as any); (handler as OrdersChannelHandler).onClose(undefined as any);
await utils.delayAsync(5);
// Creates the new connection // Creates the new connection
expect(wsStub.callCount).toBe(2); expect(wsStub.callCount).toBe(2);
}); });