@lightsparkdev/lightspark-sdk 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/{chunk-5RDIWPBE.js → chunk-D32EWIPX.js} +3 -1
- package/dist/{chunk-VTPDR6P4.js → chunk-GLL4KTUT.js} +353 -15
- package/dist/env.cjs +3 -1
- package/dist/env.d.cts +17 -0
- package/dist/env.js +2 -2
- package/dist/{index-f040db9f.d.ts → index-eb604025.d.ts} +1377 -15
- package/dist/index.cjs +682 -94
- package/dist/index.d.cts +41 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +290 -37
- package/dist/objects/index.cjs +345 -5
- package/dist/objects/index.d.cts +4 -0
- package/dist/objects/index.d.ts +1 -1
- package/dist/objects/index.js +10 -2
- package/dist/{text-encoding-MDIPJAHL.js → text-encoding-26SMKBAQ.js} +3 -1
- package/package.json +4 -4
- package/src/auth/AccountTokenAuthProvider.ts +15 -11
- package/src/client.ts +201 -7
- package/src/graphql/ClaimUmaInvitation.ts +21 -0
- package/src/graphql/ClaimUmaInvitationWithIncentives.ts +25 -0
- package/src/graphql/CreateUmaInvitation.ts +19 -0
- package/src/graphql/CreateUmaInvitationWithIncentives.ts +23 -0
- package/src/graphql/FetchUmaInvitation.ts +15 -0
- package/src/helpers.ts +3 -1
- package/src/objects/Account.ts +8 -0
- package/src/objects/AccountToChannelsConnection.ts +5 -0
- package/src/objects/Channel.ts +31 -0
- package/src/objects/ClaimUmaInvitationInput.ts +26 -0
- package/src/objects/ClaimUmaInvitationOutput.ts +30 -0
- package/src/objects/ClaimUmaInvitationWithIncentivesInput.ts +44 -0
- package/src/objects/ClaimUmaInvitationWithIncentivesOutput.ts +33 -0
- package/src/objects/CreateInvitationWithIncentivesInput.ts +37 -0
- package/src/objects/CreateInvitationWithIncentivesOutput.ts +32 -0
- package/src/objects/CreateUmaInvitationInput.ts +22 -0
- package/src/objects/CreateUmaInvitationOutput.ts +30 -0
- package/src/objects/Entity.ts +13 -0
- package/src/objects/GraphNode.ts +28 -0
- package/src/objects/IncentivesIneligibilityReason.ts +24 -0
- package/src/objects/IncentivesStatus.ts +18 -0
- package/src/objects/IncomingPayment.ts +17 -0
- package/src/objects/LightsparkNodeWithOSK.ts +61 -0
- package/src/objects/LightsparkNodeWithRemoteSigning.ts +60 -0
- package/src/objects/OutgoingPayment.ts +20 -0
- package/src/objects/OutgoingPaymentAttempt.ts +31 -0
- package/src/objects/RegionCode.ts +510 -0
- package/src/objects/UmaInvitation.ts +113 -0
- package/src/objects/Wallet.ts +12 -0
- package/src/objects/WebhookEventType.ts +4 -0
- package/src/objects/WithdrawalRequest.ts +17 -0
- package/src/objects/index.ts +15 -0
- package/src/tests/integration/constants.ts +10 -0
- package/src/tests/integration/general-regtest.test.ts +633 -0
- package/src/tests/serialization.test.ts +5 -2
- package/src/webhooks.ts +1 -1
- package/src/tests/integration/client.test.ts +0 -207
- /package/dist/{chunk-NIMBE7W3.js → chunk-BMTV3EA2.js} +0 -0
|
@@ -0,0 +1,633 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* To run test properly:
|
|
3
|
+
* 1. Create LIGHTSPARK_API_TOKEN_CLIENT_ID and LIGHTSPARK_API_TOKEN_CLIENT_SECRET in https://app.lightspark.com/api-config
|
|
4
|
+
* 2. lightspark-wallet init-env
|
|
5
|
+
* 3. yarn workspace @lightsparkdev/wallet-sdk test
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, expect, test } from "@jest/globals";
|
|
9
|
+
import { mapCurrencyAmount, pollUntil, round } from "@lightsparkdev/core";
|
|
10
|
+
import dayjs from "dayjs";
|
|
11
|
+
import LightsparkClient from "../../client.js";
|
|
12
|
+
import { getCredentialsFromEnvOrThrow } from "../../env.js";
|
|
13
|
+
import { DecodeInvoice } from "../../graphql/DecodeInvoice.js";
|
|
14
|
+
import {
|
|
15
|
+
AccountTokenAuthProvider,
|
|
16
|
+
BitcoinNetwork,
|
|
17
|
+
InvoiceType,
|
|
18
|
+
OutgoingPayment,
|
|
19
|
+
PaymentRequestStatus,
|
|
20
|
+
TransactionStatus,
|
|
21
|
+
WithdrawalMode,
|
|
22
|
+
WithdrawalRequestStatus,
|
|
23
|
+
type AccountToNodesConnection,
|
|
24
|
+
} from "../../index.js";
|
|
25
|
+
import { logger } from "../../logger.js";
|
|
26
|
+
import WithdrawalRequest from "../../objects/WithdrawalRequest.js";
|
|
27
|
+
import {
|
|
28
|
+
DAY_IN_MS,
|
|
29
|
+
ENCODED_REGTEST_REQUEST_FOR_TESTS,
|
|
30
|
+
INVOICE_EXPIRY,
|
|
31
|
+
LONG_TEST_TIMEOUT,
|
|
32
|
+
PAGINATION_STEP,
|
|
33
|
+
REGTEST_SIGNING_KEY_PASSWORD,
|
|
34
|
+
TESTS_TIMEOUT,
|
|
35
|
+
TRANSACTION_WAIT_TIME,
|
|
36
|
+
} from "./constants.js";
|
|
37
|
+
|
|
38
|
+
const TEST_MODE_L1_WITHDRAWAL_ADDRESS =
|
|
39
|
+
"bcrt1qnuyejmm2l4kavspq0jqaw0fv07lg6zv3z9z3te";
|
|
40
|
+
|
|
41
|
+
const unauthorizedLightsparkClient = new LightsparkClient();
|
|
42
|
+
|
|
43
|
+
const { apiTokenClientId, apiTokenClientSecret, baseUrl } =
|
|
44
|
+
getCredentialsFromEnvOrThrow();
|
|
45
|
+
|
|
46
|
+
const accountAuthProvider = new AccountTokenAuthProvider(
|
|
47
|
+
apiTokenClientId,
|
|
48
|
+
apiTokenClientSecret,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const lightsparkClient = new LightsparkClient(accountAuthProvider, baseUrl);
|
|
52
|
+
|
|
53
|
+
let paymentInvoice: string | undefined;
|
|
54
|
+
let regtestNodeId: string | undefined;
|
|
55
|
+
let invoicePayment: OutgoingPayment | undefined;
|
|
56
|
+
|
|
57
|
+
const pollIgnoreErrors = false;
|
|
58
|
+
|
|
59
|
+
let nodesConnection: AccountToNodesConnection | undefined;
|
|
60
|
+
|
|
61
|
+
const testModeInvoices: Record<string, string | null> = {
|
|
62
|
+
withMemo: null,
|
|
63
|
+
withoutMemo: null,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const initSuiteName = "initialization";
|
|
67
|
+
const p0SuiteName = "p0";
|
|
68
|
+
const p1SuiteName = "p1";
|
|
69
|
+
const p2SuiteName = "p2";
|
|
70
|
+
function log(msg: string, ...args: unknown[]) {
|
|
71
|
+
logger.info(
|
|
72
|
+
`${expect
|
|
73
|
+
.getState()
|
|
74
|
+
.currentTestName?.replace(
|
|
75
|
+
new RegExp(`^(${initSuiteName}|p[0-2])\\s`, "g"),
|
|
76
|
+
"",
|
|
77
|
+
)}: ${msg}`,
|
|
78
|
+
...args,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getRegtestNodeId() {
|
|
83
|
+
expect(regtestNodeId).toBeDefined();
|
|
84
|
+
if (!regtestNodeId) {
|
|
85
|
+
throw new TypeError("No regtest nodes in account");
|
|
86
|
+
}
|
|
87
|
+
return regtestNodeId;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function getAccount() {
|
|
91
|
+
const account = await lightsparkClient.getCurrentAccount();
|
|
92
|
+
if (!account) {
|
|
93
|
+
throw new TypeError("No account");
|
|
94
|
+
}
|
|
95
|
+
return account;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function getRegtestNode() {
|
|
99
|
+
const account = await getAccount();
|
|
100
|
+
const regtestNodeId = getRegtestNodeId();
|
|
101
|
+
const nodesConnection = await account.getNodes(
|
|
102
|
+
lightsparkClient,
|
|
103
|
+
1,
|
|
104
|
+
[BitcoinNetwork.REGTEST],
|
|
105
|
+
[regtestNodeId],
|
|
106
|
+
);
|
|
107
|
+
const regtestNode = nodesConnection.entities[0];
|
|
108
|
+
if (!regtestNode) {
|
|
109
|
+
throw new TypeError(`No regtest node found for account ${account.id}`);
|
|
110
|
+
}
|
|
111
|
+
return regtestNode;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const createTestModePayment = async () => {
|
|
115
|
+
const regtestNodeId = getRegtestNodeId();
|
|
116
|
+
const testInvoice = await lightsparkClient.createInvoice(
|
|
117
|
+
regtestNodeId,
|
|
118
|
+
10_000,
|
|
119
|
+
"hi there!",
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
if (!testInvoice) {
|
|
123
|
+
throw new TypeError("Test invoice wasn't created");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const payment = await lightsparkClient.createTestModePayment(
|
|
127
|
+
regtestNodeId,
|
|
128
|
+
testInvoice,
|
|
129
|
+
);
|
|
130
|
+
if (!payment) {
|
|
131
|
+
throw new TypeError("Test mode payment wasn't created");
|
|
132
|
+
}
|
|
133
|
+
return payment;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
async function fundNode(satsToFund: number) {
|
|
137
|
+
let regtestNode = await getRegtestNode();
|
|
138
|
+
|
|
139
|
+
const initialSendBalance = mapCurrencyAmount(
|
|
140
|
+
regtestNode?.balances?.availableToSendBalance,
|
|
141
|
+
);
|
|
142
|
+
log("initialSendBalance.sats", initialSendBalance.sats);
|
|
143
|
+
|
|
144
|
+
const nodeId = getRegtestNodeId();
|
|
145
|
+
|
|
146
|
+
log(`Funding node ${nodeId} with ${satsToFund} sats`);
|
|
147
|
+
await lightsparkClient.fundNode(nodeId, satsToFund);
|
|
148
|
+
|
|
149
|
+
regtestNode = await pollUntil(
|
|
150
|
+
() => {
|
|
151
|
+
return getRegtestNode();
|
|
152
|
+
},
|
|
153
|
+
(current, response) => {
|
|
154
|
+
if (
|
|
155
|
+
current &&
|
|
156
|
+
!mapCurrencyAmount(current.balances?.availableToSendBalance).isEqualTo(
|
|
157
|
+
initialSendBalance,
|
|
158
|
+
)
|
|
159
|
+
) {
|
|
160
|
+
return {
|
|
161
|
+
stopPolling: true,
|
|
162
|
+
value: current,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return response;
|
|
166
|
+
},
|
|
167
|
+
(10 * 60 * 1000) / 3000 /* can take several minutes */,
|
|
168
|
+
3000,
|
|
169
|
+
pollIgnoreErrors,
|
|
170
|
+
() => new Error("Timeout waiting for node to be funded"),
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const balances = regtestNode?.balances;
|
|
174
|
+
if (!balances) {
|
|
175
|
+
throw new Error("No balances property on node");
|
|
176
|
+
}
|
|
177
|
+
log(
|
|
178
|
+
"regtestNode.balances.availableToSend sats",
|
|
179
|
+
mapCurrencyAmount(balances.availableToSendBalance).sats,
|
|
180
|
+
);
|
|
181
|
+
log(
|
|
182
|
+
"regtestNode.balances.ownedBalance sats",
|
|
183
|
+
mapCurrencyAmount(balances.ownedBalance).sats,
|
|
184
|
+
);
|
|
185
|
+
log(
|
|
186
|
+
"regtestNode.balances.withdrawableBalance sats",
|
|
187
|
+
mapCurrencyAmount(balances.availableToWithdrawBalance).sats,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
expect(
|
|
191
|
+
mapCurrencyAmount(regtestNode.balances?.availableToSendBalance).isEqualTo(
|
|
192
|
+
initialSendBalance,
|
|
193
|
+
),
|
|
194
|
+
).toBe(false);
|
|
195
|
+
|
|
196
|
+
return regtestNode;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
describe(initSuiteName, () => {
|
|
200
|
+
test("Should get env vars and construct the client successfully", () => {
|
|
201
|
+
expect(lightsparkClient).toBeDefined();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test(
|
|
205
|
+
"Should successfully get the current account regtest node and use it for the current test suite",
|
|
206
|
+
async () => {
|
|
207
|
+
const account = await getAccount();
|
|
208
|
+
nodesConnection = await account.getNodes(lightsparkClient, 1, [
|
|
209
|
+
BitcoinNetwork.REGTEST,
|
|
210
|
+
]);
|
|
211
|
+
|
|
212
|
+
if (!nodesConnection?.entities) {
|
|
213
|
+
throw new TypeError("No connections in account");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const [regtestNode] = nodesConnection?.entities;
|
|
217
|
+
regtestNodeId = regtestNode?.id;
|
|
218
|
+
log("regtestNodeId", regtestNode?.id);
|
|
219
|
+
|
|
220
|
+
await lightsparkClient.loadNodeSigningKey(getRegtestNodeId(), {
|
|
221
|
+
password: REGTEST_SIGNING_KEY_PASSWORD,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
expect(regtestNode).toBeDefined();
|
|
225
|
+
},
|
|
226
|
+
TESTS_TIMEOUT,
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe(p0SuiteName, () => {
|
|
231
|
+
test("Should create a normal payment invoice", async () => {
|
|
232
|
+
paymentInvoice = await lightsparkClient.createInvoice(
|
|
233
|
+
getRegtestNodeId(),
|
|
234
|
+
10_000,
|
|
235
|
+
"hi there!",
|
|
236
|
+
);
|
|
237
|
+
expect(paymentInvoice).toBeDefined();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test("Should create a AMP type invoice", async () => {
|
|
241
|
+
const AmpPaymentInvoice = await lightsparkClient.createInvoice(
|
|
242
|
+
getRegtestNodeId(),
|
|
243
|
+
10_000,
|
|
244
|
+
"hi there!",
|
|
245
|
+
InvoiceType.AMP,
|
|
246
|
+
);
|
|
247
|
+
expect(AmpPaymentInvoice).toBeDefined();
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test("Should create a invoice with custom expiration", async () => {
|
|
251
|
+
const AmpPaymentInvoiceWithExpiration =
|
|
252
|
+
await lightsparkClient.createInvoice(
|
|
253
|
+
getRegtestNodeId(),
|
|
254
|
+
10_000,
|
|
255
|
+
"hi there!",
|
|
256
|
+
InvoiceType.STANDARD,
|
|
257
|
+
INVOICE_EXPIRY,
|
|
258
|
+
);
|
|
259
|
+
expect(AmpPaymentInvoiceWithExpiration).toBeDefined();
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test("Should create an invoice that allows the payer to specify any amount", async () => {
|
|
263
|
+
const AnyPaymentAmountInvoice = await lightsparkClient.createInvoice(
|
|
264
|
+
getRegtestNodeId(),
|
|
265
|
+
0,
|
|
266
|
+
"hi there!",
|
|
267
|
+
InvoiceType.STANDARD,
|
|
268
|
+
INVOICE_EXPIRY,
|
|
269
|
+
);
|
|
270
|
+
expect(AnyPaymentAmountInvoice).toBeDefined();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test("Should throw an error on create an unauthorized invoice", async () => {
|
|
274
|
+
await expect(
|
|
275
|
+
unauthorizedLightsparkClient.createInvoice(
|
|
276
|
+
getRegtestNodeId(),
|
|
277
|
+
0,
|
|
278
|
+
"hi there!",
|
|
279
|
+
),
|
|
280
|
+
).rejects.toThrowError();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
test(
|
|
284
|
+
"Should withdraw all funds from the node, also causing all channels to be closed",
|
|
285
|
+
async () => {
|
|
286
|
+
// first make sure we have a balance to withdraw
|
|
287
|
+
let regtestNode = await getRegtestNode();
|
|
288
|
+
|
|
289
|
+
const initialSendBalance = mapCurrencyAmount(
|
|
290
|
+
regtestNode?.balances?.availableToSendBalance,
|
|
291
|
+
);
|
|
292
|
+
log("initialSendBalance.sats", initialSendBalance.sats);
|
|
293
|
+
|
|
294
|
+
if (initialSendBalance.sats < 100_000) {
|
|
295
|
+
regtestNode = await fundNode(100_000);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const withdrawalRequest = await lightsparkClient.requestWithdrawal(
|
|
299
|
+
getRegtestNodeId(),
|
|
300
|
+
-1,
|
|
301
|
+
TEST_MODE_L1_WITHDRAWAL_ADDRESS,
|
|
302
|
+
WithdrawalMode.WALLET_THEN_CHANNELS,
|
|
303
|
+
);
|
|
304
|
+
expect(withdrawalRequest).toBeDefined();
|
|
305
|
+
const completedWithdrawalRequest: WithdrawalRequest = await pollUntil(
|
|
306
|
+
() =>
|
|
307
|
+
lightsparkClient.executeRawQuery(
|
|
308
|
+
WithdrawalRequest.getWithdrawalRequestQuery(withdrawalRequest.id),
|
|
309
|
+
),
|
|
310
|
+
(current, response) => {
|
|
311
|
+
if (
|
|
312
|
+
current &&
|
|
313
|
+
![
|
|
314
|
+
WithdrawalRequestStatus.IN_PROGRESS,
|
|
315
|
+
WithdrawalRequestStatus.CREATED,
|
|
316
|
+
].includes(current.status)
|
|
317
|
+
) {
|
|
318
|
+
return {
|
|
319
|
+
stopPolling: true,
|
|
320
|
+
value: current,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return response;
|
|
324
|
+
},
|
|
325
|
+
(10 * 60 * 1000) / 3000 /* can take several minutes */,
|
|
326
|
+
3000,
|
|
327
|
+
pollIgnoreErrors,
|
|
328
|
+
() => new Error("Timeout waiting for payment to be received"),
|
|
329
|
+
);
|
|
330
|
+
expect(completedWithdrawalRequest.status).toBe(
|
|
331
|
+
WithdrawalRequestStatus.SUCCESSFUL,
|
|
332
|
+
);
|
|
333
|
+
},
|
|
334
|
+
10 * 60 * 1000 /* can take several minutes */,
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
const satsToFund = 10_000_000;
|
|
338
|
+
test(
|
|
339
|
+
"Should deposit funds to node with a defined amount of sats",
|
|
340
|
+
async () => {
|
|
341
|
+
await fundNode(10_000_000);
|
|
342
|
+
},
|
|
343
|
+
10 * 60 * 1000 /* can take several minutes */,
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
test("Should pay an invoice", async () => {
|
|
347
|
+
const node = await getRegtestNode();
|
|
348
|
+
log(
|
|
349
|
+
"node.balances.availableToSendBalance",
|
|
350
|
+
node.balances?.availableToSendBalance,
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
const testInvoice = await lightsparkClient.createTestModeInvoice(
|
|
354
|
+
getRegtestNodeId(),
|
|
355
|
+
round(satsToFund / 4), // should be some small fraction of the sats we know we have from earlier funding test
|
|
356
|
+
"hi there!",
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
if (!testInvoice) {
|
|
360
|
+
throw new TypeError("Test invoice doesn't created");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
invoicePayment = await lightsparkClient.payInvoice(
|
|
364
|
+
getRegtestNodeId(),
|
|
365
|
+
testInvoice,
|
|
366
|
+
10_000_000,
|
|
367
|
+
TESTS_TIMEOUT,
|
|
368
|
+
);
|
|
369
|
+
expect(invoicePayment).toBeDefined();
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test(
|
|
373
|
+
"Should open just-in-time channel from inbound payment",
|
|
374
|
+
async () => {
|
|
375
|
+
const payment = await createTestModePayment();
|
|
376
|
+
const { status } = await lightsparkClient.waitForTransactionComplete(
|
|
377
|
+
payment.id,
|
|
378
|
+
TRANSACTION_WAIT_TIME,
|
|
379
|
+
);
|
|
380
|
+
expect(status).toBe(TransactionStatus.SUCCESS);
|
|
381
|
+
},
|
|
382
|
+
TESTS_TIMEOUT,
|
|
383
|
+
);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
describe(p1SuiteName, () => {
|
|
387
|
+
test(
|
|
388
|
+
"Should fetch the current account",
|
|
389
|
+
async () => {
|
|
390
|
+
const wallet = await lightsparkClient.getCurrentAccount();
|
|
391
|
+
expect(wallet?.id).toBeDefined();
|
|
392
|
+
},
|
|
393
|
+
TESTS_TIMEOUT,
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
test(
|
|
397
|
+
"Should fetch the current account from unauthorized client",
|
|
398
|
+
async () => {
|
|
399
|
+
await expect(
|
|
400
|
+
unauthorizedLightsparkClient.getCurrentAccount(),
|
|
401
|
+
).rejects.toThrowError();
|
|
402
|
+
},
|
|
403
|
+
TESTS_TIMEOUT,
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
test(
|
|
407
|
+
"Should listen current payment requests",
|
|
408
|
+
async () => {
|
|
409
|
+
for (let i = 0; i < PAGINATION_STEP; i++) {
|
|
410
|
+
await createTestModePayment();
|
|
411
|
+
}
|
|
412
|
+
const requests = await lightsparkClient.getRecentPaymentRequests(
|
|
413
|
+
getRegtestNodeId(),
|
|
414
|
+
PAGINATION_STEP,
|
|
415
|
+
BitcoinNetwork.REGTEST,
|
|
416
|
+
);
|
|
417
|
+
expect(requests.length).toBe(PAGINATION_STEP);
|
|
418
|
+
},
|
|
419
|
+
LONG_TEST_TIMEOUT,
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
test(
|
|
423
|
+
"Should listen current payment requests after some date",
|
|
424
|
+
async () => {
|
|
425
|
+
const requestsAfterDate = dayjs(Date.now() - DAY_IN_MS).format();
|
|
426
|
+
const requests = await lightsparkClient.getRecentPaymentRequests(
|
|
427
|
+
getRegtestNodeId(),
|
|
428
|
+
PAGINATION_STEP,
|
|
429
|
+
BitcoinNetwork.REGTEST,
|
|
430
|
+
requestsAfterDate,
|
|
431
|
+
);
|
|
432
|
+
expect(requests.length).toBe(PAGINATION_STEP);
|
|
433
|
+
},
|
|
434
|
+
TESTS_TIMEOUT,
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
test(
|
|
438
|
+
"Should listen current payment requests from unauthorized client",
|
|
439
|
+
async () => {
|
|
440
|
+
await expect(
|
|
441
|
+
unauthorizedLightsparkClient.getRecentPaymentRequests(
|
|
442
|
+
getRegtestNodeId(),
|
|
443
|
+
PAGINATION_STEP,
|
|
444
|
+
BitcoinNetwork.REGTEST,
|
|
445
|
+
),
|
|
446
|
+
).rejects.toThrowError();
|
|
447
|
+
},
|
|
448
|
+
TESTS_TIMEOUT,
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
test(
|
|
452
|
+
"Should list recent transactions",
|
|
453
|
+
async () => {
|
|
454
|
+
const transactions = await lightsparkClient.getRecentTransactions(
|
|
455
|
+
getRegtestNodeId(),
|
|
456
|
+
undefined,
|
|
457
|
+
BitcoinNetwork.REGTEST,
|
|
458
|
+
);
|
|
459
|
+
expect(transactions.length > 0).toBe(true);
|
|
460
|
+
},
|
|
461
|
+
TESTS_TIMEOUT,
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
test("Should fetch an invoices payment by IDs", () => {
|
|
465
|
+
if (!invoicePayment?.id) throw new TypeError("invoicePayment is null");
|
|
466
|
+
|
|
467
|
+
const payment = OutgoingPayment.getOutgoingPaymentQuery(invoicePayment?.id);
|
|
468
|
+
|
|
469
|
+
expect(payment.queryPayload).not.toBeNull();
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
test(
|
|
473
|
+
"Should decode an invoice",
|
|
474
|
+
async () => {
|
|
475
|
+
const decodedInvoice = await lightsparkClient.decodeInvoice(
|
|
476
|
+
ENCODED_REGTEST_REQUEST_FOR_TESTS,
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
expect(decodedInvoice).not.toBeNull();
|
|
480
|
+
expect(decodedInvoice?.memo).toBe("hi there!");
|
|
481
|
+
expect(decodedInvoice?.paymentHash).toBe(
|
|
482
|
+
"7806a0f8acd5385f9dd13d0aaa14922a7349afc5ba5d4b2bbbaaab5abd7f93ca",
|
|
483
|
+
);
|
|
484
|
+
},
|
|
485
|
+
TESTS_TIMEOUT,
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
test(
|
|
489
|
+
"Should create STANDARD a test mode invoice",
|
|
490
|
+
async () => {
|
|
491
|
+
testModeInvoices.withMemo = await lightsparkClient.createTestModeInvoice(
|
|
492
|
+
getRegtestNodeId(),
|
|
493
|
+
10_000,
|
|
494
|
+
"hi there!",
|
|
495
|
+
);
|
|
496
|
+
expect(testModeInvoices.withMemo).not.toBeNull();
|
|
497
|
+
},
|
|
498
|
+
TESTS_TIMEOUT,
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
test(
|
|
502
|
+
"Should create an AMP a test mode invoice",
|
|
503
|
+
async () => {
|
|
504
|
+
const testInvoice = await lightsparkClient.createTestModeInvoice(
|
|
505
|
+
getRegtestNodeId(),
|
|
506
|
+
0,
|
|
507
|
+
"",
|
|
508
|
+
InvoiceType.AMP,
|
|
509
|
+
);
|
|
510
|
+
expect(testInvoice).not.toBeNull();
|
|
511
|
+
},
|
|
512
|
+
TESTS_TIMEOUT,
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
test(
|
|
516
|
+
"Should create a clear memo test mode invoice",
|
|
517
|
+
async () => {
|
|
518
|
+
testModeInvoices.withoutMemo =
|
|
519
|
+
await lightsparkClient.createTestModeInvoice(getRegtestNodeId(), 0);
|
|
520
|
+
expect(testModeInvoices.withoutMemo).not.toBeNull();
|
|
521
|
+
},
|
|
522
|
+
TESTS_TIMEOUT,
|
|
523
|
+
);
|
|
524
|
+
|
|
525
|
+
test(
|
|
526
|
+
"Should create a test mode payment",
|
|
527
|
+
async () => {
|
|
528
|
+
const regtestNodeId = getRegtestNodeId();
|
|
529
|
+
|
|
530
|
+
const invoiceForTestPayment = await lightsparkClient.createInvoice(
|
|
531
|
+
regtestNodeId,
|
|
532
|
+
10_000,
|
|
533
|
+
"hi there!",
|
|
534
|
+
);
|
|
535
|
+
|
|
536
|
+
if (!invoiceForTestPayment) {
|
|
537
|
+
throw new TypeError("Invoice for test payment wasn't created");
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const payment = await lightsparkClient.createTestModePayment(
|
|
541
|
+
regtestNodeId,
|
|
542
|
+
invoiceForTestPayment,
|
|
543
|
+
);
|
|
544
|
+
|
|
545
|
+
if (!payment) {
|
|
546
|
+
throw new TypeError("Test mode payment wasn't created");
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const transaction = await lightsparkClient.waitForTransactionComplete(
|
|
550
|
+
payment.id,
|
|
551
|
+
TRANSACTION_WAIT_TIME,
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
expect(transaction?.status).toBe(TransactionStatus.SUCCESS);
|
|
555
|
+
},
|
|
556
|
+
TESTS_TIMEOUT,
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
test(
|
|
560
|
+
"Should successfully create an uma invoice",
|
|
561
|
+
async () => {
|
|
562
|
+
const nodeId = getRegtestNodeId();
|
|
563
|
+
|
|
564
|
+
const metadata = JSON.stringify([
|
|
565
|
+
["text/plain", "Pay to vasp2.com user $bob"],
|
|
566
|
+
["text/identifier", "$bob@vasp2.com"],
|
|
567
|
+
]);
|
|
568
|
+
|
|
569
|
+
const umaInvoice = await lightsparkClient.createUmaInvoice(
|
|
570
|
+
nodeId,
|
|
571
|
+
1000,
|
|
572
|
+
metadata,
|
|
573
|
+
);
|
|
574
|
+
expect(umaInvoice?.status).toEqual(PaymentRequestStatus.OPEN);
|
|
575
|
+
},
|
|
576
|
+
TESTS_TIMEOUT,
|
|
577
|
+
);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
describe(p2SuiteName, () => {
|
|
581
|
+
test(
|
|
582
|
+
"Should get a bitcoin fee estimate",
|
|
583
|
+
async () => {
|
|
584
|
+
const fee = await lightsparkClient.getBitcoinFeeEstimate();
|
|
585
|
+
expect(fee).not.toBeNull();
|
|
586
|
+
},
|
|
587
|
+
TESTS_TIMEOUT,
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
test(
|
|
591
|
+
"Should execute a raw graphql query",
|
|
592
|
+
async () => {
|
|
593
|
+
type DecodeInvoiceQueryResult = {
|
|
594
|
+
decoded_payment_request: {
|
|
595
|
+
__typename: "InvoiceData";
|
|
596
|
+
invoice_data_payment_hash: string;
|
|
597
|
+
invoice_data_amount: {
|
|
598
|
+
currency_amount_original_value: number;
|
|
599
|
+
};
|
|
600
|
+
invoice_data_memo: string;
|
|
601
|
+
};
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
const result = await lightsparkClient.executeRawQuery<
|
|
605
|
+
DecodeInvoiceQueryResult["decoded_payment_request"]
|
|
606
|
+
>({
|
|
607
|
+
queryPayload: DecodeInvoice,
|
|
608
|
+
variables: {
|
|
609
|
+
encoded_payment_request: ENCODED_REGTEST_REQUEST_FOR_TESTS,
|
|
610
|
+
},
|
|
611
|
+
constructObject: (data) =>
|
|
612
|
+
(data as DecodeInvoiceQueryResult)?.decoded_payment_request,
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
expect({
|
|
616
|
+
invoice_data_payment_hash: result?.invoice_data_payment_hash,
|
|
617
|
+
invoice_data_amount: {
|
|
618
|
+
currency_amount_original_value:
|
|
619
|
+
result?.invoice_data_amount.currency_amount_original_value,
|
|
620
|
+
},
|
|
621
|
+
invoice_data_memo: result?.invoice_data_memo,
|
|
622
|
+
}).toEqual({
|
|
623
|
+
invoice_data_payment_hash:
|
|
624
|
+
"7806a0f8acd5385f9dd13d0aaa14922a7349afc5ba5d4b2bbbaaab5abd7f93ca",
|
|
625
|
+
invoice_data_amount: {
|
|
626
|
+
currency_amount_original_value: 0,
|
|
627
|
+
},
|
|
628
|
+
invoice_data_memo: "hi there!",
|
|
629
|
+
});
|
|
630
|
+
},
|
|
631
|
+
TESTS_TIMEOUT,
|
|
632
|
+
);
|
|
633
|
+
});
|
|
@@ -4,10 +4,13 @@ import {
|
|
|
4
4
|
} from "../objects/InvoiceData.js";
|
|
5
5
|
|
|
6
6
|
describe("Serialization", () => {
|
|
7
|
-
test("should serialize and deserialize InvoiceData to the same object",
|
|
7
|
+
test("should serialize and deserialize InvoiceData to the same object", () => {
|
|
8
8
|
const serialized = `{"__typename": "InvoiceData", "invoice_data_encoded_payment_request":"lnbcrt34170n1pj5vdn4pp56jhw0672v566u4rvl333v8hwwuvavvu9gx4a2mqag4pkrvm0hwkqhp5xaz278y6cejcvpqnndl4wfq3slgthjduwlfksg778aevn23v2pdscqzpgxqyz5vqsp5ee5jezfvjqvvz7hfwta3ekk8hs6dq36szkgp40qh7twa8upquxlq9qyyssqjg2slc95falxf2t67y0wu2w43qwfcvfflwl8tn4ppqw9tumwqxk36qkfct9p2w8c3yy2ld7c6nacy4ssv2gl6qyqfpmhl4jmarnjf8cpvjlxek","invoice_data_bitcoin_network":"REGTEST","invoice_data_payment_hash":"d4aee7ebca6535ae546cfc63161eee7719d6338541abd56c1d454361b36fbbac","invoice_data_amount":{"currency_amount_original_value":3417,"currency_amount_original_unit":"SATOSHI","currency_amount_preferred_currency_unit":"USD","currency_amount_preferred_currency_value_rounded":118,"currency_amount_preferred_currency_value_approx":118.89352818371607},"invoice_data_created_at":"2023-11-04T12:17:57Z","invoice_data_expires_at":"2023-11-05T12:17:57Z","invoice_data_memo":null,"invoice_data_destination":{"graph_node_id":"GraphNode:0189a572-6dba-cf00-0000-ac0908d34ea6","graph_node_created_at":"2023-07-30T06:18:07.162759Z","graph_node_updated_at":"2023-11-04T12:01:04.015414Z","graph_node_alias":"ls_test_vSViIQitob_SE","graph_node_bitcoin_network":"REGTEST","graph_node_color":"#3399ff","graph_node_conductivity":null,"graph_node_display_name":"ls_test_vSViIQitob_SE","graph_node_public_key":"02253935a5703a6f0429081e08d2defce0faa15f4d75305302284751d53a4e0608", "__typename":"GraphNode"}}`;
|
|
9
9
|
const deserialized = InvoiceDataFromJson(JSON.parse(serialized));
|
|
10
|
-
const reserialized = InvoiceDataToJson(deserialized)
|
|
10
|
+
const reserialized = InvoiceDataToJson(deserialized) as Record<
|
|
11
|
+
string,
|
|
12
|
+
unknown
|
|
13
|
+
>;
|
|
11
14
|
expect(reserialized).toEqual(JSON.parse(serialized));
|
|
12
15
|
|
|
13
16
|
const deserializedAgain = InvoiceDataFromJson(reserialized);
|
package/src/webhooks.ts
CHANGED
|
@@ -78,7 +78,7 @@ export class RemoteSigningWebhookHandler {
|
|
|
78
78
|
this.validator,
|
|
79
79
|
);
|
|
80
80
|
const variables = JSON.parse(response.variables);
|
|
81
|
-
this.client.executeRawQuery({
|
|
81
|
+
return this.client.executeRawQuery({
|
|
82
82
|
queryPayload: response.query,
|
|
83
83
|
variables,
|
|
84
84
|
constructObject: (rawData: unknown) => rawData,
|