@solana/mpp 0.1.1 → 0.2.0

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.
Files changed (91) hide show
  1. package/dist/Methods.d.ts +1 -213
  2. package/dist/Methods.d.ts.map +1 -1
  3. package/dist/Methods.js +1 -158
  4. package/dist/Methods.js.map +1 -1
  5. package/dist/client/Methods.d.ts +0 -2
  6. package/dist/client/Methods.d.ts.map +1 -1
  7. package/dist/client/Methods.js +0 -2
  8. package/dist/client/Methods.js.map +1 -1
  9. package/dist/client/index.d.ts +0 -1
  10. package/dist/client/index.d.ts.map +1 -1
  11. package/dist/client/index.js +0 -1
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/index.d.ts +0 -3
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +0 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/server/Charge.d.ts +2 -2
  18. package/dist/server/Charge.d.ts.map +1 -1
  19. package/dist/server/Charge.js +4 -0
  20. package/dist/server/Charge.js.map +1 -1
  21. package/dist/server/Methods.d.ts +0 -2
  22. package/dist/server/Methods.d.ts.map +1 -1
  23. package/dist/server/Methods.js +0 -2
  24. package/dist/server/Methods.js.map +1 -1
  25. package/dist/server/index.d.ts +0 -1
  26. package/dist/server/index.d.ts.map +1 -1
  27. package/dist/server/index.js +0 -1
  28. package/dist/server/index.js.map +1 -1
  29. package/package.json +1 -9
  30. package/src/Methods.ts +1 -171
  31. package/src/client/Methods.ts +0 -3
  32. package/src/client/index.ts +0 -1
  33. package/src/index.ts +0 -29
  34. package/src/server/Charge.ts +7 -2
  35. package/src/server/Methods.ts +0 -3
  36. package/src/server/index.ts +0 -1
  37. package/dist/client/Session.d.ts +0 -195
  38. package/dist/client/Session.d.ts.map +0 -1
  39. package/dist/client/Session.js +0 -411
  40. package/dist/client/Session.js.map +0 -1
  41. package/dist/server/Session.d.ts +0 -171
  42. package/dist/server/Session.d.ts.map +0 -1
  43. package/dist/server/Session.js +0 -430
  44. package/dist/server/Session.js.map +0 -1
  45. package/dist/session/ChannelStore.d.ts +0 -12
  46. package/dist/session/ChannelStore.d.ts.map +0 -1
  47. package/dist/session/ChannelStore.js +0 -88
  48. package/dist/session/ChannelStore.js.map +0 -1
  49. package/dist/session/Types.d.ts +0 -179
  50. package/dist/session/Types.d.ts.map +0 -1
  51. package/dist/session/Types.js +0 -2
  52. package/dist/session/Types.js.map +0 -1
  53. package/dist/session/Voucher.d.ts +0 -7
  54. package/dist/session/Voucher.d.ts.map +0 -1
  55. package/dist/session/Voucher.js +0 -118
  56. package/dist/session/Voucher.js.map +0 -1
  57. package/dist/session/authorizers/BudgetAuthorizer.d.ts +0 -90
  58. package/dist/session/authorizers/BudgetAuthorizer.d.ts.map +0 -1
  59. package/dist/session/authorizers/BudgetAuthorizer.js +0 -398
  60. package/dist/session/authorizers/BudgetAuthorizer.js.map +0 -1
  61. package/dist/session/authorizers/SwigSessionAuthorizer.d.ts +0 -104
  62. package/dist/session/authorizers/SwigSessionAuthorizer.d.ts.map +0 -1
  63. package/dist/session/authorizers/SwigSessionAuthorizer.js +0 -522
  64. package/dist/session/authorizers/SwigSessionAuthorizer.js.map +0 -1
  65. package/dist/session/authorizers/UnboundedAuthorizer.d.ts +0 -36
  66. package/dist/session/authorizers/UnboundedAuthorizer.d.ts.map +0 -1
  67. package/dist/session/authorizers/UnboundedAuthorizer.js +0 -204
  68. package/dist/session/authorizers/UnboundedAuthorizer.js.map +0 -1
  69. package/dist/session/authorizers/index.d.ts +0 -5
  70. package/dist/session/authorizers/index.d.ts.map +0 -1
  71. package/dist/session/authorizers/index.js +0 -5
  72. package/dist/session/authorizers/index.js.map +0 -1
  73. package/dist/session/authorizers/makeSessionAuthorizer.d.ts +0 -19
  74. package/dist/session/authorizers/makeSessionAuthorizer.d.ts.map +0 -1
  75. package/dist/session/authorizers/makeSessionAuthorizer.js +0 -72
  76. package/dist/session/authorizers/makeSessionAuthorizer.js.map +0 -1
  77. package/dist/session/index.d.ts +0 -5
  78. package/dist/session/index.d.ts.map +0 -1
  79. package/dist/session/index.js +0 -5
  80. package/dist/session/index.js.map +0 -1
  81. package/src/client/Session.ts +0 -630
  82. package/src/server/Session.ts +0 -687
  83. package/src/session/ChannelStore.ts +0 -128
  84. package/src/session/Types.ts +0 -189
  85. package/src/session/Voucher.ts +0 -158
  86. package/src/session/authorizers/BudgetAuthorizer.ts +0 -574
  87. package/src/session/authorizers/SwigSessionAuthorizer.ts +0 -767
  88. package/src/session/authorizers/UnboundedAuthorizer.ts +0 -284
  89. package/src/session/authorizers/index.ts +0 -4
  90. package/src/session/authorizers/makeSessionAuthorizer.ts +0 -104
  91. package/src/session/index.ts +0 -4
@@ -1,630 +0,0 @@
1
- import type { TransactionSigner } from '@solana/kit';
2
- import { type Challenge, Credential, Method, z } from 'mppx';
3
-
4
- import * as Methods from '../Methods.js';
5
- import type { SessionAuthorizer, SessionCredentialPayload } from '../session/Types.js';
6
-
7
- type SessionAsset = {
8
- decimals: number;
9
- kind: 'sol' | 'spl';
10
- mint?: string;
11
- symbol?: string;
12
- };
13
-
14
- type SessionPricing = {
15
- amountPerUnit: string;
16
- meter: string;
17
- minDebit?: string;
18
- unit: string;
19
- };
20
-
21
- type SessionChallengeRequest = {
22
- asset: SessionAsset;
23
- channelProgram: string;
24
- network?: string;
25
- pricing?: SessionPricing;
26
- recipient: string;
27
- sessionDefaults?: {
28
- closeBehavior?: 'payer_must_close' | 'server_may_finalize';
29
- settleInterval?: { kind: string; minIncrement?: string; seconds?: number };
30
- suggestedDeposit?: string;
31
- ttlSeconds?: number;
32
- };
33
- };
34
-
35
- type ActiveChannel = {
36
- asset: SessionAsset;
37
- channelId: string;
38
- channelProgram: string;
39
- cumulativeAmount: bigint;
40
- depositAmount: bigint;
41
- network: string;
42
- recipient: string;
43
- sequence: number;
44
- serverNonce: string;
45
- };
46
-
47
- export const sessionContextSchema = z.object({
48
- action: z.optional(z.enum(['open', 'update', 'topup', 'close'])),
49
- additionalAmount: z.optional(z.string()),
50
- channelId: z.optional(z.string()),
51
- cumulativeAmount: z.optional(z.string()),
52
- depositAmount: z.optional(z.string()),
53
- openTx: z.optional(z.string()),
54
- sequence: z.optional(z.number()),
55
- topupTx: z.optional(z.string()),
56
- });
57
-
58
- export type SessionContext = z.infer<typeof sessionContextSchema>;
59
-
60
- export function session(parameters: session.Parameters) {
61
- const { signer, authorizer, autoOpen = true, autoTopup = false, settleOnLimitHit = false, onProgress } = parameters;
62
-
63
- let activeChannel: ActiveChannel | null = null;
64
-
65
- return Method.toClient(Methods.session, {
66
- context: sessionContextSchema,
67
-
68
- async createCredential({ challenge, context }) {
69
- const request = challenge.request as SessionChallengeRequest;
70
- const recipient = request.recipient;
71
- const network = request.network ?? 'mainnet-beta';
72
- const asset = request.asset;
73
- const channelProgram = request.channelProgram;
74
- const pricing = request.pricing;
75
- const sessionDefaults = request.sessionDefaults;
76
-
77
- onProgress?.({
78
- asset,
79
- network,
80
- recipient,
81
- type: 'challenge',
82
- });
83
-
84
- if (context?.action === 'topup') {
85
- return await handleTopupAction(challenge, context, authorizer, activeChannel, channelProgram, network);
86
- }
87
-
88
- if (context?.action === 'close') {
89
- const credential = await handleCloseAction(
90
- challenge,
91
- context,
92
- authorizer,
93
- activeChannel,
94
- channelProgram,
95
- recipient,
96
- network,
97
- onProgress,
98
- );
99
-
100
- activeChannel = null;
101
- return credential;
102
- }
103
-
104
- if (context?.action === 'open') {
105
- if (!context.channelId) {
106
- throw new Error('channelId is required for open action');
107
- }
108
-
109
- if (!context.depositAmount) {
110
- throw new Error('depositAmount is required for open action');
111
- }
112
-
113
- const channelId = context.channelId;
114
- const depositAmount = context.depositAmount;
115
- const parsedDepositAmount = parseNonNegativeAmount(depositAmount, 'context.depositAmount');
116
- const serverNonce = crypto.randomUUID();
117
-
118
- onProgress?.({ channelId, type: 'opening' });
119
-
120
- const openResult = await authorizer.authorizeOpen({
121
- asset,
122
- channelId,
123
- channelProgram,
124
- depositAmount,
125
- network,
126
- pricing,
127
- recipient,
128
- serverNonce,
129
- });
130
-
131
- const payer = resolveOpenPayer(openResult.voucher.voucher.payer, signer);
132
-
133
- const payload: SessionCredentialPayload = {
134
- action: 'open',
135
- authorizationMode: authorizer.getMode(),
136
- channelId,
137
- depositAmount,
138
- openTx: context.openTx ?? openResult.openTx,
139
- payer,
140
- ...(openResult.expiresAt ? { expiresAt: openResult.expiresAt } : {}),
141
- capabilities: {
142
- ...(openResult.capabilities.maxCumulativeAmount
143
- ? {
144
- maxCumulativeAmount: openResult.capabilities.maxCumulativeAmount,
145
- }
146
- : {}),
147
- ...(openResult.capabilities.allowedActions
148
- ? { allowedActions: openResult.capabilities.allowedActions }
149
- : {}),
150
- },
151
- voucher: openResult.voucher,
152
- };
153
-
154
- activeChannel = {
155
- asset: normalizeAsset(asset),
156
- channelId,
157
- channelProgram,
158
- cumulativeAmount: parseNonNegativeAmount(
159
- openResult.voucher.voucher.cumulativeAmount,
160
- 'voucher.cumulativeAmount',
161
- ),
162
- depositAmount: parsedDepositAmount,
163
- network,
164
- recipient,
165
- sequence: assertNonNegativeSequence(openResult.voucher.voucher.sequence),
166
- serverNonce: openResult.voucher.voucher.serverNonce,
167
- };
168
-
169
- onProgress?.({ channelId, type: 'opened' });
170
-
171
- return Credential.serialize({
172
- challenge,
173
- payload,
174
- });
175
- }
176
-
177
- if (context?.action === 'update') {
178
- const channelId = context.channelId ?? activeChannel?.channelId;
179
- if (!channelId) {
180
- throw new Error('channelId is required for update action');
181
- }
182
-
183
- if (!activeChannel || activeChannel.channelId !== channelId) {
184
- throw new Error('Cannot update a channel that is not active');
185
- }
186
-
187
- if (!context.cumulativeAmount) {
188
- throw new Error('cumulativeAmount is required for update action');
189
- }
190
-
191
- if (context.sequence === undefined) {
192
- throw new Error('sequence is required for update action');
193
- }
194
-
195
- const nextCumulativeAmount = parseNonNegativeAmount(
196
- context.cumulativeAmount,
197
- 'context.cumulativeAmount',
198
- );
199
- const nextSequence = assertNonNegativeSequence(context.sequence);
200
-
201
- onProgress?.({
202
- channelId,
203
- cumulativeAmount: nextCumulativeAmount.toString(),
204
- type: 'updating',
205
- });
206
-
207
- const updateResult = await authorizer.authorizeUpdate({
208
- channelId,
209
- channelProgram,
210
- cumulativeAmount: nextCumulativeAmount.toString(),
211
- meter: pricing?.meter ?? 'session',
212
- network,
213
- recipient,
214
- sequence: nextSequence,
215
- serverNonce: activeChannel.serverNonce,
216
- units: pricing ? '1' : '0',
217
- });
218
-
219
- const payload: SessionCredentialPayload = {
220
- action: 'update',
221
- channelId,
222
- voucher: updateResult.voucher,
223
- };
224
-
225
- activeChannel.cumulativeAmount = parseNonNegativeAmount(
226
- updateResult.voucher.voucher.cumulativeAmount,
227
- 'voucher.cumulativeAmount',
228
- );
229
- activeChannel.sequence = assertNonNegativeSequence(updateResult.voucher.voucher.sequence);
230
- activeChannel.serverNonce = updateResult.voucher.voucher.serverNonce;
231
-
232
- onProgress?.({
233
- channelId,
234
- cumulativeAmount: activeChannel.cumulativeAmount.toString(),
235
- type: 'updated',
236
- });
237
-
238
- return Credential.serialize({
239
- challenge,
240
- payload,
241
- });
242
- }
243
-
244
- const scopedActiveChannel =
245
- activeChannel &&
246
- matchesScope(activeChannel, {
247
- asset,
248
- channelProgram,
249
- network,
250
- recipient,
251
- })
252
- ? activeChannel
253
- : null;
254
-
255
- if (!scopedActiveChannel) {
256
- if (!autoOpen) {
257
- throw new Error('No active session channel for challenge scope and autoOpen is disabled');
258
- }
259
-
260
- const channelId = crypto.randomUUID();
261
- const serverNonce = crypto.randomUUID();
262
- const depositAmount = sessionDefaults?.suggestedDeposit ?? '0';
263
- const parsedDepositAmount = parseNonNegativeAmount(depositAmount, 'sessionDefaults.suggestedDeposit');
264
-
265
- onProgress?.({ channelId, type: 'opening' });
266
-
267
- const openResult = await authorizer.authorizeOpen({
268
- asset,
269
- channelId,
270
- channelProgram,
271
- depositAmount,
272
- network,
273
- pricing,
274
- recipient,
275
- serverNonce,
276
- });
277
-
278
- const payer = resolveOpenPayer(openResult.voucher.voucher.payer, signer);
279
-
280
- const payload: SessionCredentialPayload = {
281
- action: 'open',
282
- authorizationMode: authorizer.getMode(),
283
- channelId,
284
- depositAmount,
285
- openTx: openResult.openTx,
286
- payer,
287
- ...(openResult.expiresAt ? { expiresAt: openResult.expiresAt } : {}),
288
- capabilities: {
289
- ...(openResult.capabilities.maxCumulativeAmount
290
- ? {
291
- maxCumulativeAmount: openResult.capabilities.maxCumulativeAmount,
292
- }
293
- : {}),
294
- ...(openResult.capabilities.allowedActions
295
- ? { allowedActions: openResult.capabilities.allowedActions }
296
- : {}),
297
- },
298
- voucher: openResult.voucher,
299
- };
300
-
301
- activeChannel = {
302
- asset: normalizeAsset(asset),
303
- channelId,
304
- channelProgram,
305
- cumulativeAmount: parseNonNegativeAmount(
306
- openResult.voucher.voucher.cumulativeAmount,
307
- 'voucher.cumulativeAmount',
308
- ),
309
- depositAmount: parsedDepositAmount,
310
- network,
311
- recipient,
312
- sequence: assertNonNegativeSequence(openResult.voucher.voucher.sequence),
313
- serverNonce: openResult.voucher.voucher.serverNonce,
314
- };
315
-
316
- onProgress?.({ channelId, type: 'opened' });
317
-
318
- return Credential.serialize({
319
- challenge,
320
- payload,
321
- });
322
- }
323
-
324
- const debitIncrement = resolveDebitIncrement(pricing);
325
- const nextCumulativeAmount = scopedActiveChannel.cumulativeAmount + debitIncrement;
326
- const nextSequence = scopedActiveChannel.sequence + 1;
327
-
328
- if (nextCumulativeAmount > scopedActiveChannel.depositAmount) {
329
- if (!autoTopup) {
330
- if (!settleOnLimitHit) {
331
- throw new Error('Voucher cumulative amount exceeds tracked deposit and autoTopup is disabled');
332
- }
333
-
334
- const closeCredential = await handleCloseAction(
335
- challenge,
336
- {
337
- action: 'close',
338
- channelId: scopedActiveChannel.channelId,
339
- },
340
- authorizer,
341
- scopedActiveChannel,
342
- channelProgram,
343
- recipient,
344
- network,
345
- onProgress,
346
- );
347
-
348
- activeChannel = null;
349
- return closeCredential;
350
- }
351
-
352
- const additionalAmount = resolveAutoTopupAmount(
353
- sessionDefaults?.suggestedDeposit,
354
- nextCumulativeAmount,
355
- scopedActiveChannel.depositAmount,
356
- );
357
-
358
- const topupResult = await authorizer.authorizeTopup({
359
- additionalAmount: additionalAmount.toString(),
360
- channelId: scopedActiveChannel.channelId,
361
- channelProgram,
362
- network,
363
- });
364
-
365
- scopedActiveChannel.depositAmount += additionalAmount;
366
-
367
- const payload: SessionCredentialPayload = {
368
- action: 'topup',
369
- additionalAmount: additionalAmount.toString(),
370
- channelId: scopedActiveChannel.channelId,
371
- topupTx: topupResult.topupTx,
372
- };
373
-
374
- return Credential.serialize({
375
- challenge,
376
- payload,
377
- });
378
- }
379
-
380
- onProgress?.({
381
- channelId: scopedActiveChannel.channelId,
382
- cumulativeAmount: nextCumulativeAmount.toString(),
383
- type: 'updating',
384
- });
385
-
386
- const updateResult = await authorizer.authorizeUpdate({
387
- channelId: scopedActiveChannel.channelId,
388
- channelProgram,
389
- cumulativeAmount: nextCumulativeAmount.toString(),
390
- meter: pricing?.meter ?? 'session',
391
- network,
392
- recipient,
393
- sequence: nextSequence,
394
- serverNonce: scopedActiveChannel.serverNonce,
395
- units: pricing ? '1' : '0',
396
- });
397
-
398
- const payload: SessionCredentialPayload = {
399
- action: 'update',
400
- channelId: scopedActiveChannel.channelId,
401
- voucher: updateResult.voucher,
402
- };
403
-
404
- scopedActiveChannel.cumulativeAmount = parseNonNegativeAmount(
405
- updateResult.voucher.voucher.cumulativeAmount,
406
- 'voucher.cumulativeAmount',
407
- );
408
- scopedActiveChannel.sequence = assertNonNegativeSequence(updateResult.voucher.voucher.sequence);
409
- scopedActiveChannel.serverNonce = updateResult.voucher.voucher.serverNonce;
410
-
411
- onProgress?.({
412
- channelId: scopedActiveChannel.channelId,
413
- cumulativeAmount: scopedActiveChannel.cumulativeAmount.toString(),
414
- type: 'updated',
415
- });
416
-
417
- return Credential.serialize({
418
- challenge,
419
- payload,
420
- });
421
- },
422
- });
423
- }
424
-
425
- async function handleTopupAction(
426
- challenge: Challenge.Challenge,
427
- context: SessionContext,
428
- authorizer: SessionAuthorizer,
429
- activeChannel: ActiveChannel | null,
430
- channelProgram: string,
431
- network: string,
432
- ): Promise<string> {
433
- const channelId = context.channelId ?? activeChannel?.channelId;
434
- if (!channelId) {
435
- throw new Error('channelId is required for topup action');
436
- }
437
- if (!context.additionalAmount) {
438
- throw new Error('additionalAmount is required for topup action');
439
- }
440
-
441
- const additionalAmount = parseNonNegativeAmount(context.additionalAmount, 'context.additionalAmount');
442
-
443
- const topupResult = await authorizer.authorizeTopup({
444
- additionalAmount: additionalAmount.toString(),
445
- channelId,
446
- channelProgram,
447
- network,
448
- });
449
-
450
- if (activeChannel && activeChannel.channelId === channelId) {
451
- activeChannel.depositAmount += additionalAmount;
452
- }
453
-
454
- const payload: SessionCredentialPayload = {
455
- action: 'topup',
456
- additionalAmount: additionalAmount.toString(),
457
- channelId,
458
- topupTx: topupResult.topupTx,
459
- };
460
-
461
- return Credential.serialize({ challenge, payload });
462
- }
463
-
464
- async function handleCloseAction(
465
- challenge: Challenge.Challenge,
466
- context: SessionContext,
467
- authorizer: SessionAuthorizer,
468
- activeChannel: ActiveChannel | null,
469
- channelProgram: string,
470
- recipient: string,
471
- network: string,
472
- onProgress?: session.Parameters['onProgress'],
473
- ): Promise<string> {
474
- const channelId = context.channelId ?? activeChannel?.channelId;
475
- if (!channelId) {
476
- throw new Error('channelId is required for close action');
477
- }
478
-
479
- if (!activeChannel || activeChannel.channelId !== channelId) {
480
- throw new Error('Cannot close a channel that is not active');
481
- }
482
-
483
- const finalSequence = activeChannel.sequence + 1;
484
-
485
- onProgress?.({ channelId, type: 'closing' });
486
-
487
- const closeResult = await authorizer.authorizeClose({
488
- channelId,
489
- channelProgram,
490
- finalCumulativeAmount: activeChannel.cumulativeAmount.toString(),
491
- network,
492
- recipient,
493
- sequence: finalSequence,
494
- serverNonce: activeChannel.serverNonce,
495
- });
496
-
497
- const payload: SessionCredentialPayload = {
498
- action: 'close',
499
- channelId,
500
- ...(closeResult.closeTx ? { closeTx: closeResult.closeTx } : {}),
501
- voucher: closeResult.voucher,
502
- };
503
-
504
- onProgress?.({ channelId, type: 'closed' });
505
-
506
- return Credential.serialize({ challenge, payload });
507
- }
508
-
509
- function resolveDebitIncrement(pricing?: SessionPricing): bigint {
510
- if (pricing?.minDebit !== undefined) {
511
- return parseNonNegativeAmount(pricing.minDebit, 'pricing.minDebit');
512
- }
513
-
514
- if (pricing?.amountPerUnit !== undefined) {
515
- return parseNonNegativeAmount(pricing.amountPerUnit, 'pricing.amountPerUnit');
516
- }
517
-
518
- return 0n;
519
- }
520
-
521
- function resolveAutoTopupAmount(
522
- suggestedDeposit: string | undefined,
523
- nextCumulativeAmount: bigint,
524
- depositAmount: bigint,
525
- ): bigint {
526
- const shortfall = nextCumulativeAmount - depositAmount;
527
- if (shortfall <= 0n) {
528
- return 0n;
529
- }
530
-
531
- if (suggestedDeposit === undefined) {
532
- return shortfall;
533
- }
534
-
535
- const parsedSuggestedDeposit = parseNonNegativeAmount(suggestedDeposit, 'sessionDefaults.suggestedDeposit');
536
- return parsedSuggestedDeposit > shortfall ? parsedSuggestedDeposit : shortfall;
537
- }
538
-
539
- function matchesScope(
540
- active: ActiveChannel,
541
- scope: {
542
- asset: SessionAsset;
543
- channelProgram: string;
544
- network: string;
545
- recipient: string;
546
- },
547
- ): boolean {
548
- if (active.recipient !== scope.recipient) {
549
- return false;
550
- }
551
-
552
- if (active.network !== scope.network) {
553
- return false;
554
- }
555
-
556
- if (active.channelProgram !== scope.channelProgram) {
557
- return false;
558
- }
559
-
560
- return sameAsset(active.asset, scope.asset);
561
- }
562
-
563
- function sameAsset(left: SessionAsset, right: SessionAsset): boolean {
564
- return (
565
- left.kind === right.kind &&
566
- left.decimals === right.decimals &&
567
- (left.mint ?? '') === (right.mint ?? '') &&
568
- (left.symbol ?? '') === (right.symbol ?? '')
569
- );
570
- }
571
-
572
- function normalizeAsset(asset: SessionAsset): SessionAsset {
573
- return {
574
- decimals: asset.decimals,
575
- kind: asset.kind,
576
- ...(asset.mint ? { mint: asset.mint } : {}),
577
- ...(asset.symbol ? { symbol: asset.symbol } : {}),
578
- };
579
- }
580
-
581
- function assertNonNegativeSequence(value: number): number {
582
- if (!Number.isInteger(value) || value < 0) {
583
- throw new Error('voucher.sequence must be a non-negative integer');
584
- }
585
-
586
- return value;
587
- }
588
-
589
- function parseNonNegativeAmount(value: string, field: string): bigint {
590
- let amount: bigint;
591
- try {
592
- amount = BigInt(value);
593
- } catch {
594
- throw new Error(`${field} must be a valid integer string`);
595
- }
596
-
597
- if (amount < 0n) {
598
- throw new Error(`${field} must be non-negative`);
599
- }
600
-
601
- return amount;
602
- }
603
-
604
- function resolveOpenPayer(voucherPayer: string, signer?: TransactionSigner): string {
605
- if (signer && signer.address !== voucherPayer) {
606
- throw new Error(`Open voucher payer ${voucherPayer} does not match signer address ${signer.address}`);
607
- }
608
-
609
- return voucherPayer;
610
- }
611
-
612
- export declare namespace session {
613
- type Parameters = {
614
- authorizer: SessionAuthorizer;
615
- autoOpen?: boolean;
616
- autoTopup?: boolean;
617
- onProgress?: (event: ProgressEvent) => void;
618
- settleOnLimitHit?: boolean;
619
- signer?: TransactionSigner;
620
- };
621
-
622
- type ProgressEvent =
623
- | { asset: SessionAsset; network: string; recipient: string; type: 'challenge' }
624
- | { channelId: string; cumulativeAmount: string; type: 'updated' }
625
- | { channelId: string; cumulativeAmount: string; type: 'updating' }
626
- | { channelId: string; type: 'closed' }
627
- | { channelId: string; type: 'closing' }
628
- | { channelId: string; type: 'opened' }
629
- | { channelId: string; type: 'opening' };
630
- }