mppx 0.8.12 → 0.8.14
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 +34 -0
- package/README.md +16 -1
- package/dist/Errors.d.ts +10 -0
- package/dist/Errors.d.ts.map +1 -1
- package/dist/Errors.js +11 -2
- package/dist/Errors.js.map +1 -1
- package/dist/Method.d.ts +105 -3
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +102 -2
- package/dist/Method.js.map +1 -1
- package/dist/cli/account.d.ts +88 -0
- package/dist/cli/account.d.ts.map +1 -1
- package/dist/cli/account.js +39 -9
- package/dist/cli/account.js.map +1 -1
- package/dist/cli/cli.d.ts +2 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +59 -2
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/sessions/Manager.d.ts +31 -0
- package/dist/cli/sessions/Manager.d.ts.map +1 -0
- package/dist/cli/sessions/Manager.js +56 -0
- package/dist/cli/sessions/Manager.js.map +1 -0
- package/dist/cli/sessions/commands.d.ts +36 -0
- package/dist/cli/sessions/commands.d.ts.map +1 -0
- package/dist/cli/sessions/commands.js +407 -0
- package/dist/cli/sessions/commands.js.map +1 -0
- package/dist/cli/sessions/request.d.ts +35 -0
- package/dist/cli/sessions/request.d.ts.map +1 -0
- package/dist/cli/sessions/request.js +271 -0
- package/dist/cli/sessions/request.js.map +1 -0
- package/dist/cli/sessions/store.d.ts +134 -0
- package/dist/cli/sessions/store.d.ts.map +1 -0
- package/dist/cli/sessions/store.js +723 -0
- package/dist/cli/sessions/store.js.map +1 -0
- package/dist/cli/utils.d.ts +2 -0
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js +12 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/cli/validate/index.d.ts.map +1 -1
- package/dist/cli/validate/index.js +12 -6
- package/dist/cli/validate/index.js.map +1 -1
- package/dist/cli/validate/messages.d.ts +2 -0
- package/dist/cli/validate/messages.d.ts.map +1 -0
- package/dist/cli/validate/messages.js +8 -0
- package/dist/cli/validate/messages.js.map +1 -0
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +12 -2
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/client/internal/MethodChallenge.d.ts +17 -0
- package/dist/client/internal/MethodChallenge.d.ts.map +1 -0
- package/dist/client/internal/MethodChallenge.js +11 -0
- package/dist/client/internal/MethodChallenge.js.map +1 -0
- package/dist/client/node.d.ts +29 -0
- package/dist/client/node.d.ts.map +1 -0
- package/dist/client/node.js +177 -0
- package/dist/client/node.js.map +1 -0
- package/dist/internal/types.d.ts +24 -0
- package/dist/internal/types.d.ts.map +1 -1
- package/dist/server/Mppx.d.ts +23 -4
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +91 -82
- package/dist/server/Mppx.js.map +1 -1
- package/dist/stripe/server/Charge.d.ts +8 -4
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/stripe/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/client/Methods.d.ts +2 -1
- package/dist/tempo/client/Methods.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts +1 -0
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js +7 -2
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/internal/types.d.ts +10 -1
- package/dist/tempo/internal/types.d.ts.map +1 -1
- package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -1
- package/dist/tempo/legacy/client/ChannelOps.js +2 -1
- package/dist/tempo/legacy/client/ChannelOps.js.map +1 -1
- package/dist/tempo/legacy/client/Session.d.ts +2 -2
- package/dist/tempo/legacy/server/Session.d.ts +3 -3
- package/dist/tempo/legacy/server/Session.d.ts.map +1 -1
- package/dist/tempo/legacy/server/Session.js.map +1 -1
- package/dist/tempo/server/Charge.d.ts +40 -78
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +289 -209
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +13 -23
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +6 -2
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Relay.d.ts +48 -0
- package/dist/tempo/server/Relay.d.ts.map +1 -0
- package/dist/tempo/server/Relay.js +177 -0
- package/dist/tempo/server/Relay.js.map +1 -0
- package/dist/tempo/server/SponsorBudget.d.ts +59 -0
- package/dist/tempo/server/SponsorBudget.d.ts.map +1 -0
- package/dist/tempo/server/SponsorBudget.js +144 -0
- package/dist/tempo/server/SponsorBudget.js.map +1 -0
- package/dist/tempo/server/Subscription.d.ts +3 -2
- package/dist/tempo/server/Subscription.d.ts.map +1 -1
- package/dist/tempo/server/Subscription.js.map +1 -1
- package/dist/tempo/server/index.d.ts +1 -1
- package/dist/tempo/server/index.d.ts.map +1 -1
- package/dist/tempo/server/index.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/session/Snapshot.d.ts +9 -0
- package/dist/tempo/session/Snapshot.d.ts.map +1 -1
- package/dist/tempo/session/Snapshot.js +6 -0
- package/dist/tempo/session/Snapshot.js.map +1 -1
- package/dist/tempo/session/client/ChannelOps.d.ts +7 -1
- package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -1
- package/dist/tempo/session/client/ChannelOps.js +17 -3
- package/dist/tempo/session/client/ChannelOps.js.map +1 -1
- package/dist/tempo/session/client/CredentialState.d.ts +26 -2
- package/dist/tempo/session/client/CredentialState.d.ts.map +1 -1
- package/dist/tempo/session/client/CredentialState.js +99 -16
- package/dist/tempo/session/client/CredentialState.js.map +1 -1
- package/dist/tempo/session/client/Runtime.d.ts +8 -0
- package/dist/tempo/session/client/Runtime.d.ts.map +1 -1
- package/dist/tempo/session/client/Runtime.js +17 -0
- package/dist/tempo/session/client/Runtime.js.map +1 -1
- package/dist/tempo/session/client/Session.d.ts +16 -6
- package/dist/tempo/session/client/Session.d.ts.map +1 -1
- package/dist/tempo/session/client/Session.js +93 -36
- package/dist/tempo/session/client/Session.js.map +1 -1
- package/dist/tempo/session/client/SessionManager.d.ts +10 -3
- package/dist/tempo/session/client/SessionManager.d.ts.map +1 -1
- package/dist/tempo/session/client/SessionManager.js +176 -50
- package/dist/tempo/session/client/SessionManager.js.map +1 -1
- package/dist/tempo/session/client/Transports.d.ts +18 -7
- package/dist/tempo/session/client/Transports.d.ts.map +1 -1
- package/dist/tempo/session/client/Transports.js +81 -33
- package/dist/tempo/session/client/Transports.js.map +1 -1
- package/dist/tempo/session/client/internal/SessionManager.d.ts +19 -0
- package/dist/tempo/session/client/internal/SessionManager.d.ts.map +1 -0
- package/dist/tempo/session/client/internal/SessionManager.js +13 -0
- package/dist/tempo/session/client/internal/SessionManager.js.map +1 -0
- package/dist/tempo/session/precompile/Chain.d.ts.map +1 -1
- package/dist/tempo/session/precompile/Chain.js +109 -12
- package/dist/tempo/session/precompile/Chain.js.map +1 -1
- package/dist/tempo/session/precompile/Channel.d.ts +2 -0
- package/dist/tempo/session/precompile/Channel.d.ts.map +1 -1
- package/dist/tempo/session/precompile/Channel.js +4 -0
- package/dist/tempo/session/precompile/Channel.js.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.d.ts +3 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.js +14 -0
- package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
- package/dist/tempo/session/server/MeteredStream.d.ts +7 -1
- package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -1
- package/dist/tempo/session/server/MeteredStream.js +5 -4
- package/dist/tempo/session/server/MeteredStream.js.map +1 -1
- package/dist/tempo/session/server/RequestState.d.ts +5 -1
- package/dist/tempo/session/server/RequestState.d.ts.map +1 -1
- package/dist/tempo/session/server/RequestState.js +13 -5
- package/dist/tempo/session/server/RequestState.js.map +1 -1
- package/dist/tempo/session/server/Session.d.ts +21 -6
- package/dist/tempo/session/server/Session.d.ts.map +1 -1
- package/dist/tempo/session/server/Session.js +4 -1
- package/dist/tempo/session/server/Session.js.map +1 -1
- package/dist/tempo/session/server/Settlement.d.ts +20 -0
- package/dist/tempo/session/server/Settlement.d.ts.map +1 -1
- package/dist/tempo/session/server/Settlement.js +20 -0
- package/dist/tempo/session/server/Settlement.js.map +1 -1
- package/dist/tempo/session/server/Ws.d.ts +2 -0
- package/dist/tempo/session/server/Ws.d.ts.map +1 -1
- package/dist/tempo/session/server/Ws.js.map +1 -1
- package/dist/tempo/session/server/index.d.ts +1 -1
- package/dist/tempo/session/server/index.d.ts.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.d.ts +21 -21
- package/dist/validation/core.d.ts.map +1 -1
- package/dist/validation/core.js +6 -2
- package/dist/validation/core.js.map +1 -1
- package/dist/viem/Client.d.ts.map +1 -1
- package/dist/viem/Client.js +24 -17
- package/dist/viem/Client.js.map +1 -1
- package/package.json +6 -1
- package/src/Errors.test.ts +23 -0
- package/src/Errors.ts +21 -2
- package/src/Method.test.ts +102 -1
- package/src/Method.ts +241 -5
- package/src/cli/account.ts +45 -10
- package/src/cli/cli.test.ts +165 -70
- package/src/cli/cli.ts +67 -2
- package/src/cli/mcp.test.ts +11 -0
- package/src/cli/sessions/Manager.test.ts +249 -0
- package/src/cli/sessions/Manager.ts +93 -0
- package/src/cli/sessions/commands.ts +444 -0
- package/src/cli/sessions/request.test.ts +51 -0
- package/src/cli/sessions/request.ts +353 -0
- package/src/cli/sessions/store.test.ts +581 -0
- package/src/cli/sessions/store.ts +940 -0
- package/src/cli/utils.test.ts +23 -0
- package/src/cli/utils.ts +10 -0
- package/src/cli/validate/index.ts +12 -14
- package/src/cli/validate/messages.ts +7 -0
- package/src/cli/validate.test.ts +38 -5
- package/src/client/Mppx.test-d.ts +3 -3
- package/src/client/internal/Fetch.ts +16 -7
- package/src/client/internal/MethodChallenge.ts +30 -0
- package/src/client/node.test.ts +115 -0
- package/src/client/node.ts +247 -0
- package/src/internal/types.test-d.ts +21 -0
- package/src/internal/types.ts +33 -0
- package/src/server/Mppx.test-d.ts +44 -0
- package/src/server/Mppx.test.ts +205 -0
- package/src/server/Mppx.ts +167 -103
- package/src/stripe/Methods.test.ts +10 -0
- package/src/stripe/server/Charge.test-d.ts +66 -0
- package/src/stripe/server/Charge.ts +8 -5
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/PublicExports.test-d.ts +20 -0
- package/src/tempo/internal/fee-payer.ts +7 -3
- package/src/tempo/internal/types.ts +13 -2
- package/src/tempo/legacy/client/ChannelOps.test.ts +7 -0
- package/src/tempo/legacy/client/ChannelOps.ts +2 -1
- package/src/tempo/legacy/server/Defaults.test-d.ts +9 -0
- package/src/tempo/legacy/server/Session.ts +6 -5
- package/src/tempo/server/Charge.test.ts +337 -63
- package/src/tempo/server/Charge.ts +440 -270
- package/src/tempo/server/Methods.ts +16 -4
- package/src/tempo/server/Relay.test.ts +523 -0
- package/src/tempo/server/Relay.ts +288 -0
- package/src/tempo/server/SponsorBudget.test.ts +125 -0
- package/src/tempo/server/SponsorBudget.ts +213 -0
- package/src/tempo/server/Subscription.ts +6 -4
- package/src/tempo/server/index.ts +5 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/session/README.md +201 -0
- package/src/tempo/session/Snapshot.ts +21 -0
- package/src/tempo/session/client/ChannelOps.test.ts +55 -0
- package/src/tempo/session/client/ChannelOps.ts +21 -3
- package/src/tempo/session/client/CredentialState.test.ts +2 -2
- package/src/tempo/session/client/CredentialState.ts +159 -16
- package/src/tempo/session/client/Runtime.test.ts +12 -0
- package/src/tempo/session/client/Runtime.ts +22 -0
- package/src/tempo/session/client/Session.test.ts +238 -5
- package/src/tempo/session/client/Session.ts +130 -41
- package/src/tempo/session/client/SessionManager.test.ts +239 -8
- package/src/tempo/session/client/SessionManager.ts +204 -54
- package/src/tempo/session/client/Transports.test.ts +181 -8
- package/src/tempo/session/client/Transports.ts +127 -45
- package/src/tempo/session/client/internal/SessionManager.ts +36 -0
- package/src/tempo/session/precompile/Chain.integration.test.ts +19 -1
- package/src/tempo/session/precompile/Chain.test.ts +223 -10
- package/src/tempo/session/precompile/Chain.ts +119 -12
- package/src/tempo/session/precompile/Channel.test.ts +9 -0
- package/src/tempo/session/precompile/Channel.ts +5 -0
- package/src/tempo/session/server/CredentialVerification.ts +18 -1
- package/src/tempo/session/server/MeteredStream.ts +12 -5
- package/src/tempo/session/server/RequestState.test.ts +47 -4
- package/src/tempo/session/server/RequestState.ts +15 -8
- package/src/tempo/session/server/Session.test.ts +461 -0
- package/src/tempo/session/server/Session.ts +31 -8
- package/src/tempo/session/server/Settlement.ts +45 -0
- package/src/tempo/session/server/Ws.test.ts +113 -0
- package/src/tempo/session/server/Ws.ts +2 -0
- package/src/tempo/session/server/index.ts +2 -0
- package/src/validation/core.ts +7 -1
- package/src/viem/Client.test.ts +44 -1
- package/src/viem/Client.ts +31 -17
|
@@ -316,7 +316,11 @@ describe('SessionSnapshotHints', () => {
|
|
|
316
316
|
escrowContract,
|
|
317
317
|
expiringNonceHash: descriptor.expiringNonceHash,
|
|
318
318
|
finalized: false,
|
|
319
|
-
highestVoucher:
|
|
319
|
+
highestVoucher: {
|
|
320
|
+
channelId,
|
|
321
|
+
cumulativeAmount: 500n,
|
|
322
|
+
signature: `0x${'44'.repeat(64)}`,
|
|
323
|
+
},
|
|
320
324
|
highestVoucherAmount: 500n,
|
|
321
325
|
operator: descriptor.operator,
|
|
322
326
|
payee: descriptor.payee,
|
|
@@ -451,6 +455,11 @@ describe('SessionSnapshotHints', () => {
|
|
|
451
455
|
deposit: '1000',
|
|
452
456
|
descriptor,
|
|
453
457
|
escrow: escrowContract,
|
|
458
|
+
highestVoucher: {
|
|
459
|
+
channelId,
|
|
460
|
+
cumulativeAmount: '500',
|
|
461
|
+
signature: `0x${'44'.repeat(64)}`,
|
|
462
|
+
},
|
|
454
463
|
requiredCumulative: '350',
|
|
455
464
|
settled: '100',
|
|
456
465
|
spent: '300',
|
|
@@ -458,7 +467,7 @@ describe('SessionSnapshotHints', () => {
|
|
|
458
467
|
})
|
|
459
468
|
})
|
|
460
469
|
|
|
461
|
-
test('
|
|
470
|
+
test('keeps accepted cumulative at the signed voucher when the next request needs more', async () => {
|
|
462
471
|
const snapshot = await resolveSessionSnapshot({
|
|
463
472
|
amount: 300n,
|
|
464
473
|
channelId,
|
|
@@ -466,7 +475,34 @@ describe('SessionSnapshotHints', () => {
|
|
|
466
475
|
})
|
|
467
476
|
|
|
468
477
|
expect(snapshot?.requiredCumulative).toBe('600')
|
|
469
|
-
expect(snapshot?.acceptedCumulative).toBe('
|
|
478
|
+
expect(snapshot?.acceptedCumulative).toBe('500')
|
|
479
|
+
expect(snapshot?.highestVoucher?.cumulativeAmount).toBe('500')
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
test('omits reusable channel hints without a matching signed highest voucher', async () => {
|
|
483
|
+
await expect(
|
|
484
|
+
resolveSessionSnapshot({
|
|
485
|
+
amount: 50n,
|
|
486
|
+
channelId,
|
|
487
|
+
store: store(channel({ highestVoucher: null })),
|
|
488
|
+
}),
|
|
489
|
+
).resolves.toBeUndefined()
|
|
490
|
+
|
|
491
|
+
await expect(
|
|
492
|
+
resolveSessionSnapshot({
|
|
493
|
+
amount: 50n,
|
|
494
|
+
channelId,
|
|
495
|
+
store: store(
|
|
496
|
+
channel({
|
|
497
|
+
highestVoucher: {
|
|
498
|
+
channelId,
|
|
499
|
+
cumulativeAmount: 499n,
|
|
500
|
+
signature: `0x${'44'.repeat(64)}`,
|
|
501
|
+
},
|
|
502
|
+
}),
|
|
503
|
+
),
|
|
504
|
+
}),
|
|
505
|
+
).resolves.toBeUndefined()
|
|
470
506
|
})
|
|
471
507
|
|
|
472
508
|
test('omits reusable channel hints when payment fields do not match', async () => {
|
|
@@ -508,10 +544,17 @@ describe('SessionSnapshotHints', () => {
|
|
|
508
544
|
}
|
|
509
545
|
})
|
|
510
546
|
|
|
511
|
-
test('omits hints for missing, non-precompile, or finalized channels', async () => {
|
|
547
|
+
test('omits hints for missing, non-precompile, closing, or finalized channels', async () => {
|
|
512
548
|
await expect(
|
|
513
549
|
resolveSessionSnapshot({ amount: 1n, channelId, store: store(null) }),
|
|
514
550
|
).resolves.toBe(undefined)
|
|
551
|
+
await expect(
|
|
552
|
+
resolveSessionSnapshot({
|
|
553
|
+
amount: 1n,
|
|
554
|
+
channelId,
|
|
555
|
+
store: store(channel({ closeRequestedAt: 1n })),
|
|
556
|
+
}),
|
|
557
|
+
).resolves.toBe(undefined)
|
|
515
558
|
await expect(
|
|
516
559
|
resolveSessionSnapshot({
|
|
517
560
|
amount: 1n,
|
|
@@ -80,7 +80,11 @@ export type ResolveSessionChannelIdParameters = {
|
|
|
80
80
|
store: ChannelStore.ChannelStore
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Application-owned lookup from authenticated identity and payment scope to an existing session
|
|
85
|
+
* channel. MPPx does not derive a storage key or scan the channel store; the returned channel ID is
|
|
86
|
+
* loaded and independently validated before its snapshot is advertised.
|
|
87
|
+
*/
|
|
84
88
|
export type ResolveSessionChannelId = (
|
|
85
89
|
parameters: ResolveSessionChannelIdParameters,
|
|
86
90
|
) => Promise<string | null | undefined> | string | null | undefined
|
|
@@ -139,21 +143,24 @@ export async function resolveSessionSnapshot(
|
|
|
139
143
|
const channel = await store.getChannel(ChannelStore.normalizeChannelId(channelId))
|
|
140
144
|
if (!channel || !ChannelStore.isPrecompileState(channel)) return undefined
|
|
141
145
|
if (channel.finalized) return undefined
|
|
146
|
+
if (channel.closeRequestedAt !== 0n) return undefined
|
|
147
|
+
if (!channel.highestVoucher) return undefined
|
|
148
|
+
if (channel.highestVoucher.cumulativeAmount !== channel.highestVoucherAmount) return undefined
|
|
142
149
|
if (expected && !matchesSnapshotPaymentFields(channel, expected)) return undefined
|
|
143
150
|
const requiredCumulative = channel.spent + amount
|
|
144
|
-
const acceptedCumulative =
|
|
145
|
-
channel.highestVoucherAmount > requiredCumulative
|
|
146
|
-
? channel.highestVoucherAmount
|
|
147
|
-
: requiredCumulative
|
|
148
151
|
return {
|
|
149
|
-
acceptedCumulative:
|
|
152
|
+
acceptedCumulative: channel.highestVoucherAmount.toString(),
|
|
150
153
|
chainId: channel.chainId,
|
|
151
154
|
channelId: channel.channelId,
|
|
152
|
-
closeRequestedAt:
|
|
153
|
-
channel.closeRequestedAt === 0n ? undefined : channel.closeRequestedAt.toString(),
|
|
155
|
+
closeRequestedAt: undefined,
|
|
154
156
|
deposit: channel.deposit.toString(),
|
|
155
157
|
descriptor: channel.descriptor,
|
|
156
158
|
escrow: channel.escrowContract,
|
|
159
|
+
highestVoucher: {
|
|
160
|
+
channelId: channel.highestVoucher.channelId,
|
|
161
|
+
cumulativeAmount: channel.highestVoucher.cumulativeAmount.toString(),
|
|
162
|
+
signature: channel.highestVoucher.signature,
|
|
163
|
+
},
|
|
157
164
|
requiredCumulative: requiredCumulative.toString(),
|
|
158
165
|
settled: channel.settledOnChain.toString(),
|
|
159
166
|
spent: channel.spent.toString(),
|
|
@@ -556,8 +556,21 @@ describe('precompile server session unit guardrails', () => {
|
|
|
556
556
|
test('request returns a server session snapshot for a known precompile channel', async () => {
|
|
557
557
|
const { method, store } = createServer()
|
|
558
558
|
const openPayload = await createOpenPayload({ initialAmount: 100n })
|
|
559
|
+
const highestVoucher = await ClientOps.createVoucherPayload(
|
|
560
|
+
createSigningClient(),
|
|
561
|
+
payer,
|
|
562
|
+
openPayload.descriptor,
|
|
563
|
+
Types.uint96(250n),
|
|
564
|
+
chainId,
|
|
565
|
+
)
|
|
566
|
+
if (highestVoucher.action !== 'voucher') throw new Error('expected voucher payload')
|
|
559
567
|
await persistPrecompileChannel(store, openPayload, {
|
|
560
568
|
highestVoucherAmount: 250n,
|
|
569
|
+
highestVoucher: {
|
|
570
|
+
channelId: openPayload.channelId,
|
|
571
|
+
cumulativeAmount: 250n,
|
|
572
|
+
signature: highestVoucher.signature,
|
|
573
|
+
},
|
|
561
574
|
spent: 200n,
|
|
562
575
|
units: 2,
|
|
563
576
|
})
|
|
@@ -585,6 +598,11 @@ describe('precompile server session unit guardrails', () => {
|
|
|
585
598
|
deposit: '1000',
|
|
586
599
|
descriptor: openPayload.descriptor,
|
|
587
600
|
escrow: tip20ChannelEscrow,
|
|
601
|
+
highestVoucher: {
|
|
602
|
+
channelId: openPayload.channelId,
|
|
603
|
+
cumulativeAmount: '250',
|
|
604
|
+
signature: highestVoucher.signature,
|
|
605
|
+
},
|
|
588
606
|
requiredCumulative: '201',
|
|
589
607
|
settled: '0',
|
|
590
608
|
spent: '200',
|
|
@@ -594,6 +612,14 @@ describe('precompile server session unit guardrails', () => {
|
|
|
594
612
|
|
|
595
613
|
test('request can resolve a server session snapshot from request identity', async () => {
|
|
596
614
|
const openPayload = await createOpenPayload({ initialAmount: 100n })
|
|
615
|
+
const highestVoucher = await ClientOps.createVoucherPayload(
|
|
616
|
+
createSigningClient(),
|
|
617
|
+
payer,
|
|
618
|
+
openPayload.descriptor,
|
|
619
|
+
Types.uint96(250n),
|
|
620
|
+
chainId,
|
|
621
|
+
)
|
|
622
|
+
if (highestVoucher.action !== 'voucher') throw new Error('expected voucher payload')
|
|
597
623
|
const { method, store } = createServer({
|
|
598
624
|
resolveChannelId({ request, credential, paymentRequest, store: hookStore }) {
|
|
599
625
|
expect(request?.headers.get('cookie')).toBe('sid=session-1')
|
|
@@ -605,6 +631,11 @@ describe('precompile server session unit guardrails', () => {
|
|
|
605
631
|
})
|
|
606
632
|
await persistPrecompileChannel(store, openPayload, {
|
|
607
633
|
highestVoucherAmount: 250n,
|
|
634
|
+
highestVoucher: {
|
|
635
|
+
channelId: openPayload.channelId,
|
|
636
|
+
cumulativeAmount: 250n,
|
|
637
|
+
signature: highestVoucher.signature,
|
|
638
|
+
},
|
|
608
639
|
spent: 200n,
|
|
609
640
|
units: 2,
|
|
610
641
|
})
|
|
@@ -661,8 +692,21 @@ describe('precompile server session unit guardrails', () => {
|
|
|
661
692
|
test('request uses zero effective amount for non-content snapshot hints', async () => {
|
|
662
693
|
const { method, store } = createServer()
|
|
663
694
|
const openPayload = await createOpenPayload({ initialAmount: 100n })
|
|
695
|
+
const highestVoucher = await ClientOps.createVoucherPayload(
|
|
696
|
+
createSigningClient(),
|
|
697
|
+
payer,
|
|
698
|
+
openPayload.descriptor,
|
|
699
|
+
Types.uint96(250n),
|
|
700
|
+
chainId,
|
|
701
|
+
)
|
|
702
|
+
if (highestVoucher.action !== 'voucher') throw new Error('expected voucher payload')
|
|
664
703
|
await persistPrecompileChannel(store, openPayload, {
|
|
665
704
|
highestVoucherAmount: 250n,
|
|
705
|
+
highestVoucher: {
|
|
706
|
+
channelId: openPayload.channelId,
|
|
707
|
+
cumulativeAmount: 250n,
|
|
708
|
+
signature: highestVoucher.signature,
|
|
709
|
+
},
|
|
666
710
|
spent: 250n,
|
|
667
711
|
units: 2,
|
|
668
712
|
})
|
|
@@ -2032,8 +2076,21 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2032
2076
|
const rawStore = Store.memory()
|
|
2033
2077
|
const store = channelStore(rawStore)
|
|
2034
2078
|
const openPayload = await createOpenPayload({ initialAmount: 1n })
|
|
2079
|
+
const highestVoucher = await ClientOps.createVoucherPayload(
|
|
2080
|
+
createSigningClient(),
|
|
2081
|
+
payer,
|
|
2082
|
+
openPayload.descriptor,
|
|
2083
|
+
Types.uint96(5n),
|
|
2084
|
+
chainId,
|
|
2085
|
+
)
|
|
2086
|
+
if (highestVoucher.action !== 'voucher') throw new Error('expected voucher payload')
|
|
2035
2087
|
await persistPrecompileChannel(store, openPayload, {
|
|
2036
2088
|
highestVoucherAmount: 5n,
|
|
2089
|
+
highestVoucher: {
|
|
2090
|
+
channelId: openPayload.channelId,
|
|
2091
|
+
cumulativeAmount: 5n,
|
|
2092
|
+
signature: highestVoucher.signature,
|
|
2093
|
+
},
|
|
2037
2094
|
spent: 3n,
|
|
2038
2095
|
units: 3,
|
|
2039
2096
|
})
|
|
@@ -2056,6 +2113,10 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2056
2113
|
expect(snapshot).toMatchObject({
|
|
2057
2114
|
channelId: openPayload.channelId,
|
|
2058
2115
|
acceptedCumulative: '5',
|
|
2116
|
+
highestVoucher: {
|
|
2117
|
+
channelId: openPayload.channelId,
|
|
2118
|
+
cumulativeAmount: '5',
|
|
2119
|
+
},
|
|
2059
2120
|
requiredCumulative: '3',
|
|
2060
2121
|
spent: '3',
|
|
2061
2122
|
})
|
|
@@ -3337,3 +3398,403 @@ describe('precompile server session unit guardrails', () => {
|
|
|
3337
3398
|
).rejects.toThrow(/tx sender .* is not the channel payee/)
|
|
3338
3399
|
})
|
|
3339
3400
|
})
|
|
3401
|
+
|
|
3402
|
+
describe('onSessionSettlement', () => {
|
|
3403
|
+
function createSettleClient(channelId: Hex, settledAmount: bigint) {
|
|
3404
|
+
return createClient({
|
|
3405
|
+
account: payer,
|
|
3406
|
+
chain: testChain,
|
|
3407
|
+
transport: custom({
|
|
3408
|
+
async request(args) {
|
|
3409
|
+
if (args.method === 'eth_chainId') return `0x${chainId.toString(16)}`
|
|
3410
|
+
if (args.method === 'eth_getTransactionCount') return '0x0'
|
|
3411
|
+
if (args.method === 'eth_estimateGas') return '0x5208'
|
|
3412
|
+
if (args.method === 'eth_maxPriorityFeePerGas') return '0x1'
|
|
3413
|
+
if (args.method === 'eth_getBlockByNumber') return { baseFeePerGas: '0x1' }
|
|
3414
|
+
if (args.method === 'eth_sendRawTransaction') return `0x${'cc'.repeat(32)}`
|
|
3415
|
+
if (args.method === 'eth_sendTransaction') return `0x${'cc'.repeat(32)}`
|
|
3416
|
+
if (args.method === 'eth_getTransactionReceipt')
|
|
3417
|
+
return transactionReceipt([settledLog(channelId, settledAmount)])
|
|
3418
|
+
if (args.method === 'eth_call') {
|
|
3419
|
+
return encodeFunctionResult({
|
|
3420
|
+
abi: escrowAbi,
|
|
3421
|
+
functionName: 'getChannelState',
|
|
3422
|
+
result: { settled: settledAmount, deposit: 1_000n, closeRequestedAt: 0 },
|
|
3423
|
+
})
|
|
3424
|
+
}
|
|
3425
|
+
throw new Error(`unexpected rpc request: ${args.method}`)
|
|
3426
|
+
},
|
|
3427
|
+
}),
|
|
3428
|
+
})
|
|
3429
|
+
}
|
|
3430
|
+
|
|
3431
|
+
test('fires onSessionSettlement for explicit settle() calls', async () => {
|
|
3432
|
+
const events: { trigger: string; txHash: string; amount: bigint; delta: bigint }[] = []
|
|
3433
|
+
const store = Store.memory()
|
|
3434
|
+
const openPayload = await createOpenPayload()
|
|
3435
|
+
await persistPrecompileChannel(channelStore(store), openPayload, {
|
|
3436
|
+
payee: payer.address,
|
|
3437
|
+
spent: 100n,
|
|
3438
|
+
highestVoucherAmount: 100n,
|
|
3439
|
+
highestVoucher: {
|
|
3440
|
+
channelId: openPayload.channelId,
|
|
3441
|
+
cumulativeAmount: 100n,
|
|
3442
|
+
signature: '0x1234',
|
|
3443
|
+
},
|
|
3444
|
+
})
|
|
3445
|
+
|
|
3446
|
+
const { settle } = await import('./Session.js')
|
|
3447
|
+
const client = createSettleClient(openPayload.channelId, 100n)
|
|
3448
|
+
await settle(store, client, openPayload.channelId, {
|
|
3449
|
+
onSessionSettlement: (ctx) => {
|
|
3450
|
+
events.push({
|
|
3451
|
+
trigger: ctx.trigger,
|
|
3452
|
+
txHash: ctx.txHash,
|
|
3453
|
+
amount: ctx.amount,
|
|
3454
|
+
delta: ctx.delta,
|
|
3455
|
+
})
|
|
3456
|
+
},
|
|
3457
|
+
})
|
|
3458
|
+
|
|
3459
|
+
expect(events).toHaveLength(1)
|
|
3460
|
+
expect(events[0]).toMatchObject({
|
|
3461
|
+
trigger: 'settle',
|
|
3462
|
+
txHash: `0x${'cc'.repeat(32)}`,
|
|
3463
|
+
amount: 100n,
|
|
3464
|
+
delta: 100n,
|
|
3465
|
+
})
|
|
3466
|
+
})
|
|
3467
|
+
|
|
3468
|
+
test('fires onSessionSettlement for auto-scheduled settlements', async () => {
|
|
3469
|
+
const events: { trigger: string; channelId: string; amount: bigint; delta: bigint }[] = []
|
|
3470
|
+
const rawStore = Store.memory()
|
|
3471
|
+
const openPayload = await createOpenPayload()
|
|
3472
|
+
const store = channelStore(rawStore)
|
|
3473
|
+
await persistPrecompileChannel(store, openPayload, {
|
|
3474
|
+
payee: payer.address,
|
|
3475
|
+
spent: 500n,
|
|
3476
|
+
units: 10,
|
|
3477
|
+
highestVoucherAmount: 500n,
|
|
3478
|
+
highestVoucher: {
|
|
3479
|
+
channelId: openPayload.channelId,
|
|
3480
|
+
cumulativeAmount: 500n,
|
|
3481
|
+
signature: '0x1234',
|
|
3482
|
+
},
|
|
3483
|
+
})
|
|
3484
|
+
|
|
3485
|
+
const { maybeSettleScheduled } = await import('./Settlement.js')
|
|
3486
|
+
const client = createSettleClient(openPayload.channelId, 500n)
|
|
3487
|
+
const channel = await store.getChannel(openPayload.channelId)
|
|
3488
|
+
|
|
3489
|
+
await maybeSettleScheduled({
|
|
3490
|
+
account: payer,
|
|
3491
|
+
channel: channel!,
|
|
3492
|
+
client,
|
|
3493
|
+
schedule: { units: 5 },
|
|
3494
|
+
store,
|
|
3495
|
+
onSessionSettlement: (ctx) => {
|
|
3496
|
+
events.push({
|
|
3497
|
+
trigger: ctx.trigger,
|
|
3498
|
+
channelId: ctx.channelId,
|
|
3499
|
+
amount: ctx.amount,
|
|
3500
|
+
delta: ctx.delta,
|
|
3501
|
+
})
|
|
3502
|
+
},
|
|
3503
|
+
})
|
|
3504
|
+
|
|
3505
|
+
expect(events).toHaveLength(1)
|
|
3506
|
+
expect(events[0]).toMatchObject({
|
|
3507
|
+
trigger: 'scheduled',
|
|
3508
|
+
channelId: openPayload.channelId,
|
|
3509
|
+
amount: 500n,
|
|
3510
|
+
delta: 500n,
|
|
3511
|
+
})
|
|
3512
|
+
})
|
|
3513
|
+
|
|
3514
|
+
test('delta reflects incremental scheduled settlement with prior on-chain settlement', async () => {
|
|
3515
|
+
const events: { trigger: string; amount: bigint; delta: bigint }[] = []
|
|
3516
|
+
const rawStore = Store.memory()
|
|
3517
|
+
const openPayload = await createOpenPayload()
|
|
3518
|
+
const store = channelStore(rawStore)
|
|
3519
|
+
await persistPrecompileChannel(store, openPayload, {
|
|
3520
|
+
payee: payer.address,
|
|
3521
|
+
spent: 500n,
|
|
3522
|
+
units: 10,
|
|
3523
|
+
settledOnChain: 200n,
|
|
3524
|
+
highestVoucherAmount: 500n,
|
|
3525
|
+
highestVoucher: {
|
|
3526
|
+
channelId: openPayload.channelId,
|
|
3527
|
+
cumulativeAmount: 500n,
|
|
3528
|
+
signature: '0x1234',
|
|
3529
|
+
},
|
|
3530
|
+
})
|
|
3531
|
+
|
|
3532
|
+
const { maybeSettleScheduled } = await import('./Settlement.js')
|
|
3533
|
+
const client = createSettleClient(openPayload.channelId, 500n)
|
|
3534
|
+
const channel = await store.getChannel(openPayload.channelId)
|
|
3535
|
+
|
|
3536
|
+
await maybeSettleScheduled({
|
|
3537
|
+
account: payer,
|
|
3538
|
+
channel: channel!,
|
|
3539
|
+
client,
|
|
3540
|
+
schedule: { units: 5 },
|
|
3541
|
+
store,
|
|
3542
|
+
onSessionSettlement: (ctx) => {
|
|
3543
|
+
events.push({ trigger: ctx.trigger, amount: ctx.amount, delta: ctx.delta })
|
|
3544
|
+
},
|
|
3545
|
+
})
|
|
3546
|
+
|
|
3547
|
+
expect(events).toHaveLength(1)
|
|
3548
|
+
expect(events[0]).toMatchObject({
|
|
3549
|
+
trigger: 'scheduled',
|
|
3550
|
+
amount: 500n,
|
|
3551
|
+
delta: 300n,
|
|
3552
|
+
})
|
|
3553
|
+
})
|
|
3554
|
+
|
|
3555
|
+
test('fires onSessionSettlement for cooperative close', async () => {
|
|
3556
|
+
const events: { trigger: string; txHash: string; amount: bigint; delta: bigint }[] = []
|
|
3557
|
+
const openPayload = await createOpenPayload()
|
|
3558
|
+
const closedAmount = 100n
|
|
3559
|
+
const refundedAmount = 900n
|
|
3560
|
+
const rawStore = Store.memory()
|
|
3561
|
+
|
|
3562
|
+
const closeClient = createClient({
|
|
3563
|
+
account: payer,
|
|
3564
|
+
chain: testChain,
|
|
3565
|
+
transport: custom({
|
|
3566
|
+
async request(args) {
|
|
3567
|
+
if (args.method === 'eth_chainId') return `0x${chainId.toString(16)}`
|
|
3568
|
+
if (args.method === 'eth_getTransactionCount') return '0x0'
|
|
3569
|
+
if (args.method === 'eth_estimateGas') return '0x5208'
|
|
3570
|
+
if (args.method === 'eth_maxPriorityFeePerGas') return '0x1'
|
|
3571
|
+
if (args.method === 'eth_getBlockByNumber') return { baseFeePerGas: '0x1' }
|
|
3572
|
+
if (args.method === 'eth_sendRawTransaction') return `0x${'dd'.repeat(32)}`
|
|
3573
|
+
if (args.method === 'eth_sendTransaction') return `0x${'dd'.repeat(32)}`
|
|
3574
|
+
if (args.method === 'eth_getTransactionReceipt')
|
|
3575
|
+
return transactionReceipt([
|
|
3576
|
+
closedLog(openPayload.channelId, closedAmount, refundedAmount),
|
|
3577
|
+
])
|
|
3578
|
+
if (args.method === 'eth_call') {
|
|
3579
|
+
return encodeFunctionResult({
|
|
3580
|
+
abi: escrowAbi,
|
|
3581
|
+
functionName: 'getChannelState',
|
|
3582
|
+
result: { settled: 0n, deposit: 1_000n, closeRequestedAt: 0 },
|
|
3583
|
+
})
|
|
3584
|
+
}
|
|
3585
|
+
throw new Error(`unexpected rpc request: ${args.method}`)
|
|
3586
|
+
},
|
|
3587
|
+
}),
|
|
3588
|
+
})
|
|
3589
|
+
|
|
3590
|
+
const method = session({
|
|
3591
|
+
amount: '1',
|
|
3592
|
+
chainId,
|
|
3593
|
+
currency: token,
|
|
3594
|
+
decimals: 0,
|
|
3595
|
+
recipient: payee,
|
|
3596
|
+
store: rawStore,
|
|
3597
|
+
unitType: 'request',
|
|
3598
|
+
getClient: () => closeClient,
|
|
3599
|
+
onSessionSettlement: (ctx) => {
|
|
3600
|
+
events.push({
|
|
3601
|
+
trigger: ctx.trigger,
|
|
3602
|
+
txHash: ctx.txHash,
|
|
3603
|
+
amount: ctx.amount,
|
|
3604
|
+
delta: ctx.delta,
|
|
3605
|
+
})
|
|
3606
|
+
},
|
|
3607
|
+
})
|
|
3608
|
+
|
|
3609
|
+
await persistPrecompileChannel(channelStore(rawStore), openPayload, {
|
|
3610
|
+
payee: payer.address,
|
|
3611
|
+
spent: 100n,
|
|
3612
|
+
highestVoucherAmount: 100n,
|
|
3613
|
+
highestVoucher: {
|
|
3614
|
+
channelId: openPayload.channelId,
|
|
3615
|
+
cumulativeAmount: 100n,
|
|
3616
|
+
signature: '0x1234',
|
|
3617
|
+
},
|
|
3618
|
+
})
|
|
3619
|
+
|
|
3620
|
+
const closeSignature = await Voucher.signVoucher(
|
|
3621
|
+
createSigningClient(),
|
|
3622
|
+
payer,
|
|
3623
|
+
{ channelId: openPayload.channelId, cumulativeAmount: 100n },
|
|
3624
|
+
tip20ChannelEscrow,
|
|
3625
|
+
chainId,
|
|
3626
|
+
)
|
|
3627
|
+
|
|
3628
|
+
await method.verify({
|
|
3629
|
+
credential: {
|
|
3630
|
+
challenge: makeChallenge(openPayload.channelId),
|
|
3631
|
+
payload: {
|
|
3632
|
+
action: 'close',
|
|
3633
|
+
channelId: openPayload.channelId,
|
|
3634
|
+
descriptor: openPayload.descriptor,
|
|
3635
|
+
cumulativeAmount: '100',
|
|
3636
|
+
signature: closeSignature,
|
|
3637
|
+
},
|
|
3638
|
+
},
|
|
3639
|
+
request: verifyRequest(openPayload.channelId),
|
|
3640
|
+
})
|
|
3641
|
+
|
|
3642
|
+
expect(events).toHaveLength(1)
|
|
3643
|
+
expect(events[0]).toMatchObject({
|
|
3644
|
+
trigger: 'close',
|
|
3645
|
+
txHash: `0x${'dd'.repeat(32)}`,
|
|
3646
|
+
amount: closedAmount,
|
|
3647
|
+
delta: closedAmount,
|
|
3648
|
+
})
|
|
3649
|
+
})
|
|
3650
|
+
|
|
3651
|
+
test('delta reflects incremental settlement when channel has prior on-chain settlement', async () => {
|
|
3652
|
+
const events: { trigger: string; amount: bigint; delta: bigint }[] = []
|
|
3653
|
+
const store = Store.memory()
|
|
3654
|
+
const openPayload = await createOpenPayload()
|
|
3655
|
+
await persistPrecompileChannel(channelStore(store), openPayload, {
|
|
3656
|
+
payee: payer.address,
|
|
3657
|
+
spent: 300n,
|
|
3658
|
+
settledOnChain: 200n,
|
|
3659
|
+
highestVoucherAmount: 300n,
|
|
3660
|
+
highestVoucher: {
|
|
3661
|
+
channelId: openPayload.channelId,
|
|
3662
|
+
cumulativeAmount: 300n,
|
|
3663
|
+
signature: '0x1234',
|
|
3664
|
+
},
|
|
3665
|
+
})
|
|
3666
|
+
|
|
3667
|
+
const { settle } = await import('./Session.js')
|
|
3668
|
+
const client = createSettleClient(openPayload.channelId, 300n)
|
|
3669
|
+
await settle(store, client, openPayload.channelId, {
|
|
3670
|
+
onSessionSettlement: (ctx) => {
|
|
3671
|
+
events.push({ trigger: ctx.trigger, amount: ctx.amount, delta: ctx.delta })
|
|
3672
|
+
},
|
|
3673
|
+
})
|
|
3674
|
+
|
|
3675
|
+
expect(events).toHaveLength(1)
|
|
3676
|
+
expect(events[0]).toMatchObject({
|
|
3677
|
+
trigger: 'settle',
|
|
3678
|
+
amount: 300n,
|
|
3679
|
+
delta: 100n,
|
|
3680
|
+
})
|
|
3681
|
+
})
|
|
3682
|
+
|
|
3683
|
+
test('delta reflects incremental close when channel has prior on-chain settlement', async () => {
|
|
3684
|
+
const events: { trigger: string; amount: bigint; delta: bigint }[] = []
|
|
3685
|
+
const openPayload = await createOpenPayload()
|
|
3686
|
+
const priorSettled = 50n
|
|
3687
|
+
const closedAmount = 100n
|
|
3688
|
+
const refundedAmount = 900n
|
|
3689
|
+
const rawStore = Store.memory()
|
|
3690
|
+
|
|
3691
|
+
const closeClient = createClient({
|
|
3692
|
+
account: payer,
|
|
3693
|
+
chain: testChain,
|
|
3694
|
+
transport: custom({
|
|
3695
|
+
async request(args) {
|
|
3696
|
+
if (args.method === 'eth_chainId') return `0x${chainId.toString(16)}`
|
|
3697
|
+
if (args.method === 'eth_getTransactionCount') return '0x0'
|
|
3698
|
+
if (args.method === 'eth_estimateGas') return '0x5208'
|
|
3699
|
+
if (args.method === 'eth_maxPriorityFeePerGas') return '0x1'
|
|
3700
|
+
if (args.method === 'eth_getBlockByNumber') return { baseFeePerGas: '0x1' }
|
|
3701
|
+
if (args.method === 'eth_sendRawTransaction') return `0x${'dd'.repeat(32)}`
|
|
3702
|
+
if (args.method === 'eth_sendTransaction') return `0x${'dd'.repeat(32)}`
|
|
3703
|
+
if (args.method === 'eth_getTransactionReceipt')
|
|
3704
|
+
return transactionReceipt([
|
|
3705
|
+
closedLog(openPayload.channelId, closedAmount, refundedAmount),
|
|
3706
|
+
])
|
|
3707
|
+
if (args.method === 'eth_call') {
|
|
3708
|
+
return encodeFunctionResult({
|
|
3709
|
+
abi: escrowAbi,
|
|
3710
|
+
functionName: 'getChannelState',
|
|
3711
|
+
result: { settled: priorSettled, deposit: 1_000n, closeRequestedAt: 0 },
|
|
3712
|
+
})
|
|
3713
|
+
}
|
|
3714
|
+
throw new Error(`unexpected rpc request: ${args.method}`)
|
|
3715
|
+
},
|
|
3716
|
+
}),
|
|
3717
|
+
})
|
|
3718
|
+
|
|
3719
|
+
const method = session({
|
|
3720
|
+
amount: '1',
|
|
3721
|
+
chainId,
|
|
3722
|
+
currency: token,
|
|
3723
|
+
decimals: 0,
|
|
3724
|
+
recipient: payee,
|
|
3725
|
+
store: rawStore,
|
|
3726
|
+
unitType: 'request',
|
|
3727
|
+
getClient: () => closeClient,
|
|
3728
|
+
onSessionSettlement: (ctx) => {
|
|
3729
|
+
events.push({ trigger: ctx.trigger, amount: ctx.amount, delta: ctx.delta })
|
|
3730
|
+
},
|
|
3731
|
+
})
|
|
3732
|
+
|
|
3733
|
+
await persistPrecompileChannel(channelStore(rawStore), openPayload, {
|
|
3734
|
+
payee: payer.address,
|
|
3735
|
+
spent: 100n,
|
|
3736
|
+
settledOnChain: priorSettled,
|
|
3737
|
+
highestVoucherAmount: 100n,
|
|
3738
|
+
highestVoucher: {
|
|
3739
|
+
channelId: openPayload.channelId,
|
|
3740
|
+
cumulativeAmount: 100n,
|
|
3741
|
+
signature: '0x1234',
|
|
3742
|
+
},
|
|
3743
|
+
})
|
|
3744
|
+
|
|
3745
|
+
const closeSignature = await Voucher.signVoucher(
|
|
3746
|
+
createSigningClient(),
|
|
3747
|
+
payer,
|
|
3748
|
+
{ channelId: openPayload.channelId, cumulativeAmount: 100n },
|
|
3749
|
+
tip20ChannelEscrow,
|
|
3750
|
+
chainId,
|
|
3751
|
+
)
|
|
3752
|
+
|
|
3753
|
+
await method.verify({
|
|
3754
|
+
credential: {
|
|
3755
|
+
challenge: makeChallenge(openPayload.channelId),
|
|
3756
|
+
payload: {
|
|
3757
|
+
action: 'close',
|
|
3758
|
+
channelId: openPayload.channelId,
|
|
3759
|
+
descriptor: openPayload.descriptor,
|
|
3760
|
+
cumulativeAmount: '100',
|
|
3761
|
+
signature: closeSignature,
|
|
3762
|
+
},
|
|
3763
|
+
},
|
|
3764
|
+
request: verifyRequest(openPayload.channelId),
|
|
3765
|
+
})
|
|
3766
|
+
|
|
3767
|
+
expect(events).toHaveLength(1)
|
|
3768
|
+
expect(events[0]).toMatchObject({
|
|
3769
|
+
trigger: 'close',
|
|
3770
|
+
amount: closedAmount,
|
|
3771
|
+
delta: closedAmount - priorSettled,
|
|
3772
|
+
})
|
|
3773
|
+
})
|
|
3774
|
+
|
|
3775
|
+
test('isolates errors in onSessionSettlement handler', async () => {
|
|
3776
|
+
const store = Store.memory()
|
|
3777
|
+
const openPayload = await createOpenPayload()
|
|
3778
|
+
await persistPrecompileChannel(channelStore(store), openPayload, {
|
|
3779
|
+
payee: payer.address,
|
|
3780
|
+
spent: 100n,
|
|
3781
|
+
highestVoucherAmount: 100n,
|
|
3782
|
+
highestVoucher: {
|
|
3783
|
+
channelId: openPayload.channelId,
|
|
3784
|
+
cumulativeAmount: 100n,
|
|
3785
|
+
signature: '0x1234',
|
|
3786
|
+
},
|
|
3787
|
+
})
|
|
3788
|
+
|
|
3789
|
+
const { settle } = await import('./Session.js')
|
|
3790
|
+
const client = createSettleClient(openPayload.channelId, 100n)
|
|
3791
|
+
|
|
3792
|
+
await expect(
|
|
3793
|
+
settle(store, client, openPayload.channelId, {
|
|
3794
|
+
onSessionSettlement: () => {
|
|
3795
|
+
throw new Error('observer exploded')
|
|
3796
|
+
},
|
|
3797
|
+
}),
|
|
3798
|
+
).resolves.toBe(`0x${'cc'.repeat(32)}`)
|
|
3799
|
+
})
|
|
3800
|
+
})
|