Skip to content

Commit ba13b29

Browse files
committed
pool: determine order type based on Pool version
1 parent 31ae6ab commit ba13b29

File tree

4 files changed

+105
-10
lines changed

4 files changed

+105
-10
lines changed

app/src/__tests__/components/pool/OrderFormSection.spec.tsx

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
/* eslint-disable @typescript-eslint/no-non-null-assertion */
22
import React from 'react';
33
import * as POOL from 'types/generated/trader_pb';
4+
import { grpc } from '@improbable-eng/grpc-web';
45
import { fireEvent, waitFor } from '@testing-library/react';
5-
import { injectIntoGrpcUnary, renderWithProviders } from 'util/tests';
6+
import { injectIntoGrpcUnary, renderWithProviders, sampleGrpcResponse } from 'util/tests';
67
import { createStore, Store } from 'store';
78
import OrderFormSection from 'components/pool/OrderFormSection';
89

10+
const grpcMock = grpc as jest.Mocked<typeof grpc>;
11+
912
describe('OrderFormSection', () => {
1013
let store: Store;
1114

@@ -64,14 +67,21 @@ describe('OrderFormSection', () => {
6467
changeInput('Max Batch Fee Rate', '1');
6568
await changeSelect('Min Node Tier', 'T0 - All Nodes');
6669

67-
let bid: Required<POOL.Bid.AsObject>;
70+
// handle the GetInfo call
71+
grpcMock.unary.mockImplementationOnce((desc, opts) => {
72+
opts.onEnd(sampleGrpcResponse(desc));
73+
return undefined as any;
74+
});
75+
let bid: Required<POOL.Bid.AsObject> = {} as any;
6876
// capture the rate that is sent to the API
6977
injectIntoGrpcUnary((_, props) => {
7078
bid = (props.request.toObject() as any).bid;
7179
});
7280

7381
fireEvent.click(getByText('Place Bid Order'));
74-
expect(bid!.details.amt).toBe('1000000');
82+
await waitFor(() => {
83+
expect(bid!.details.amt).toBe('1000000');
84+
});
7585
expect(bid!.details.rateFixed).toBe(4960);
7686
expect(bid!.details.minUnitsMatch).toBe(1);
7787
expect(bid!.leaseDurationBlocks).toBe(2016);
@@ -88,14 +98,21 @@ describe('OrderFormSection', () => {
8898
changeInput('Minimum Channel Size', '100000');
8999
changeInput('Max Batch Fee Rate', '1');
90100

101+
// handle the GetInfo call
102+
grpcMock.unary.mockImplementationOnce((desc, opts) => {
103+
opts.onEnd(sampleGrpcResponse(desc));
104+
return undefined as any;
105+
});
91106
let ask: Required<POOL.Ask.AsObject>;
92107
// capture the rate that is sent to the API
93108
injectIntoGrpcUnary((_, props) => {
94109
ask = (props.request.toObject() as any).ask;
95110
});
96111

97112
fireEvent.click(getByText('Place Ask Order'));
98-
expect(ask!.details.amt).toBe('1000000');
113+
await waitFor(() => {
114+
expect(ask!.details.amt).toBe('1000000');
115+
});
99116
expect(ask!.details.rateFixed).toBe(4960);
100117
expect(ask!.details.minUnitsMatch).toBe(1);
101118
expect(ask!.leaseDurationBlocks).toBe(2016);
@@ -112,14 +129,21 @@ describe('OrderFormSection', () => {
112129
await changeSelect('Channel Duration', '1 month (open)');
113130
await changeSelect('Min Node Tier', 'T0 - All Nodes');
114131

132+
// handle the GetInfo call
133+
grpcMock.unary.mockImplementationOnce((desc, opts) => {
134+
opts.onEnd(sampleGrpcResponse(desc));
135+
return undefined as any;
136+
});
115137
let bid: Required<POOL.Bid.AsObject>;
116138
// capture the rate that is sent to the API
117139
injectIntoGrpcUnary((_, props) => {
118140
bid = (props.request.toObject() as any).bid;
119141
});
120142

121143
fireEvent.click(getByText('Place Bid Order'));
122-
expect(bid!.details.amt).toBe('1000000');
144+
await waitFor(() => {
145+
expect(bid!.details.amt).toBe('1000000');
146+
});
123147
expect(bid!.details.rateFixed).toBe(2480);
124148
expect(bid!.details.minUnitsMatch).toBe(1);
125149
expect(bid!.leaseDurationBlocks).toBe(4032);

app/src/__tests__/store/orderStore.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { grpc } from '@improbable-eng/grpc-web';
55
import { waitFor } from '@testing-library/react';
66
import Big from 'big.js';
77
import { hex } from 'util/strings';
8+
import { sampleGrpcResponse } from 'util/tests';
89
import { poolInvalidOrder, poolListOrders, poolSubmitOrder } from 'util/tests/sampleData';
910
import { createStore, OrderStore, Store } from 'store';
1011
import { Order } from 'store/models';
@@ -101,6 +102,12 @@ describe('OrderStore', () => {
101102

102103
it('should handle invalid orders', async () => {
103104
await rootStore.accountStore.fetchAccounts();
105+
// handle the GetInfo call
106+
grpcMock.unary.mockImplementationOnce((desc, opts) => {
107+
opts.onEnd(sampleGrpcResponse(desc));
108+
return undefined as any;
109+
});
110+
// mock the SubmitOrder response
104111
grpcMock.unary.mockImplementationOnce((desc, opts) => {
105112
if (desc.methodName === 'SubmitOrder') {
106113
const res = {

app/src/api/pool.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as POOL from 'types/generated/trader_pb';
33
import { Trader } from 'types/generated/trader_pb_service';
44
import Big from 'big.js';
55
import { Buffer } from 'buffer';
6+
import { coerce, satisfies } from 'semver';
67
import { b64 } from 'util/strings';
78
import { OrderType, Tier } from 'store/models/order';
89
import BaseApi from './base';
@@ -20,9 +21,17 @@ export const ONE_UNIT = 100000;
2021
// The minimum batch fee rate in sats/kw
2122
export const MIN_FEE_RATE_KW = 253;
2223

23-
// The latest order version. This should be updated along with pool CLI
24-
// see: https://github.com/lightninglabs/pool/blob/master/order/interface.go#L35
25-
export const ORDER_VERSION = 4;
24+
// The default order version to use if the Pool version cannot be detected
25+
export const DEFAULT_ORDER_VERSION = 2;
26+
27+
// maps from the Pool version semver condition to a compatible order version
28+
// see: https://github.com/lightninglabs/pool/blob/master/order/interfaces.go#L42
29+
export const ORDER_VERSION_COMPAT: Record<string, number> = {
30+
'>=0.5.2-alpha': 5,
31+
'>=0.5.0-alpha': 4,
32+
'>=0.4.0-alpha': 2,
33+
'>=0.2.7-alpha': 1,
34+
};
2635

2736
const POOL_INITIATOR = 'lit-ui';
2837

@@ -41,6 +50,15 @@ class PoolApi extends BaseApi<PoolEvents> {
4150
this._grpc = grpc;
4251
}
4352

53+
/**
54+
* call the pool `GetInfo` RPC and return the response
55+
*/
56+
async getInfo(): Promise<POOL.GetInfoResponse.AsObject> {
57+
const req = new POOL.GetInfoRequest();
58+
const res = await this._grpc.request(Trader.GetInfo, req, this._meta);
59+
return res.toObject();
60+
}
61+
4462
/**
4563
* call the pool `QuoteAccount` RPC and return the response
4664
*/
@@ -201,6 +219,9 @@ class PoolApi extends BaseApi<PoolEvents> {
201219
throw new Error(`The rate is too low. it must equate to at least 1 sat per block`);
202220
}
203221

222+
const info = await this.getInfo();
223+
const orderVersion = this.getOrderVersion(info.version);
224+
204225
const req = new POOL.SubmitOrderRequest();
205226
req.setInitiator(POOL_INITIATOR);
206227

@@ -215,15 +236,15 @@ class PoolApi extends BaseApi<PoolEvents> {
215236
case OrderType.Bid:
216237
const bid = new POOL.Bid();
217238
bid.setLeaseDurationBlocks(duration);
218-
bid.setVersion(ORDER_VERSION);
239+
bid.setVersion(orderVersion);
219240
if (minNodeTier !== undefined) bid.setMinNodeTier(minNodeTier);
220241
bid.setDetails(order);
221242
req.setBid(bid);
222243
break;
223244
case OrderType.Ask:
224245
const ask = new POOL.Ask();
225246
ask.setLeaseDurationBlocks(duration);
226-
ask.setVersion(ORDER_VERSION);
247+
ask.setVersion(orderVersion);
227248
ask.setDetails(order);
228249
req.setAsk(ask);
229250
break;
@@ -358,6 +379,26 @@ class PoolApi extends BaseApi<PoolEvents> {
358379
calcPctRate(fixedRate: Big, duration: Big) {
359380
return +fixedRate.mul(duration).div(FEE_RATE_TOTAL_PARTS);
360381
}
382+
383+
/**
384+
* Determines which order version to use based on the provided version string
385+
* @param version the version of pool
386+
* (ex: 0.5.4-alpha commit=v0.5.4-alpha.0.20220114202858-525fe156d240)
387+
*/
388+
getOrderVersion(version: string): number {
389+
// try to convert the pool version string to a SemVer object (ex: 0.5.4)
390+
const verNum = coerce(version);
391+
if (!verNum) return DEFAULT_ORDER_VERSION;
392+
393+
// find the first key which the pool version satisfies
394+
const matchedKey = Object.keys(ORDER_VERSION_COMPAT).find(condition =>
395+
satisfies(verNum, condition),
396+
);
397+
if (!matchedKey) return DEFAULT_ORDER_VERSION;
398+
399+
// return the order version that was matched
400+
return ORDER_VERSION_COMPAT[matchedKey];
401+
}
361402
}
362403

363404
export default PoolApi;

app/src/util/tests/sampleData.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ export const lndPendingChannel: LND.PendingChannelsResponse.PendingChannel.AsObj
157157
remoteChanReserveSat: '5000',
158158
remoteNodePub: '03bb934930cdcd25576aa61d08cc95214e0036f1219c435c06976e561558703290',
159159
numForwardingPackages: '7',
160+
chanStatusFlags: '',
160161
};
161162

162163
export const lndPendingChannels: LND.PendingChannelsResponse.AsObject = {
@@ -197,6 +198,7 @@ export const lndPendingChannels: LND.PendingChannelsResponse.AsObject = {
197198
remoteTxid: '9850a4b1cfcfbf972f8541b26b8061ed3091ee8cbed5875167080be4be9524e7',
198199
},
199200
limboBalance: '0',
201+
closingTxid: '6c151252215b73547a5415051c82dd25c725c4309b93fed4f38c4c5b610c3fb0',
200202
},
201203
],
202204
pendingForceClosingChannelsList: [
@@ -392,6 +394,26 @@ export const poolRenewAccount: POOL.RenewAccountResponse.AsObject = {
392394
account: poolInitAccount,
393395
};
394396

397+
export const poolGetInfo: POOL.GetInfoResponse.AsObject = {
398+
version: '0.5.4-alpha commit=v0.5.4-alpha.0.20220114202858-525fe156d240',
399+
accountsTotal: 5,
400+
accountsActive: 1,
401+
accountsActiveExpired: 0,
402+
accountsArchived: 4,
403+
ordersTotal: 16,
404+
ordersActive: 0,
405+
ordersArchived: 16,
406+
currentBlockHeight: 2164104,
407+
batchesInvolved: 8,
408+
nodeRating: {
409+
nodePubkey: '027433f335bbea5f5631bda2bcf45f57d069a084c800aa80148909bc392b99103c',
410+
nodeTier: AUCT.NodeTier.TIER_1,
411+
},
412+
lsatTokens: 1,
413+
subscribedToAuctioneer: true,
414+
newNodesOnly: false,
415+
};
416+
395417
export const poolListAccounts: POOL.ListAccountsResponse.AsObject = {
396418
accountsList: [
397419
poolInitAccount,
@@ -859,6 +881,7 @@ export const sampleApiResponses: Record<string, any> = {
859881
'looprpc.SwapClient.GetLoopInQuote': loopInQuote,
860882
'looprpc.SwapClient.LoopIn': loopSwapResponse,
861883
'looprpc.SwapClient.LoopOut': loopSwapResponse,
884+
'poolrpc.Trader.GetInfo': poolGetInfo,
862885
'poolrpc.Trader.ListAccounts': poolListAccounts,
863886
'poolrpc.Trader.QuoteAccount': poolQuoteAccount,
864887
'poolrpc.Trader.InitAccount': poolInitAccount,

0 commit comments

Comments
 (0)