mppx 0.6.27 → 0.6.29
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 +25 -0
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +16 -10
- package/dist/Challenge.js.map +1 -1
- package/dist/Method.d.ts +1 -1
- package/dist/Method.d.ts.map +1 -1
- package/dist/Store.d.ts +32 -9
- package/dist/Store.d.ts.map +1 -1
- package/dist/Store.js +42 -10
- package/dist/Store.js.map +1 -1
- package/dist/client/Methods.d.ts +1 -0
- package/dist/client/Methods.d.ts.map +1 -1
- package/dist/client/Methods.js +1 -0
- package/dist/client/Methods.js.map +1 -1
- package/dist/client/Mppx.d.ts +3 -3
- package/dist/client/Mppx.d.ts.map +1 -1
- package/dist/client/Mppx.js +1 -0
- package/dist/client/Mppx.js.map +1 -1
- package/dist/client/Transport.d.ts +10 -3
- package/dist/client/Transport.d.ts.map +1 -1
- package/dist/client/Transport.js +60 -7
- package/dist/client/Transport.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal/Fetch.d.ts +3 -0
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +12 -20
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/evm/Assets.d.ts +2 -0
- package/dist/evm/Assets.d.ts.map +1 -0
- package/dist/evm/Assets.js +2 -0
- package/dist/evm/Assets.js.map +1 -0
- package/dist/evm/Chains.d.ts +5 -0
- package/dist/evm/Chains.d.ts.map +1 -0
- package/dist/evm/Chains.js +5 -0
- package/dist/evm/Chains.js.map +1 -0
- package/dist/evm/Methods.d.ts +68 -0
- package/dist/evm/Methods.d.ts.map +1 -0
- package/dist/evm/Methods.js +28 -0
- package/dist/evm/Methods.js.map +1 -0
- package/dist/evm/Types.d.ts +143 -0
- package/dist/evm/Types.d.ts.map +1 -0
- package/dist/evm/Types.js +102 -0
- package/dist/evm/Types.js.map +1 -0
- package/dist/evm/client/Charge.d.ts +102 -0
- package/dist/evm/client/Charge.d.ts.map +1 -0
- package/dist/evm/client/Charge.js +141 -0
- package/dist/evm/client/Charge.js.map +1 -0
- package/dist/evm/client/Methods.d.ts +81 -0
- package/dist/evm/client/Methods.d.ts.map +1 -0
- package/dist/evm/client/Methods.js +16 -0
- package/dist/evm/client/Methods.js.map +1 -0
- package/dist/evm/client/index.d.ts +6 -0
- package/dist/evm/client/index.d.ts.map +1 -0
- package/dist/evm/client/index.js +6 -0
- package/dist/evm/client/index.js.map +1 -0
- package/dist/evm/index.d.ts +9 -0
- package/dist/evm/index.d.ts.map +1 -0
- package/dist/evm/index.js +8 -0
- package/dist/evm/index.js.map +1 -0
- package/dist/evm/server/Charge.d.ts +62 -0
- package/dist/evm/server/Charge.d.ts.map +1 -0
- package/dist/evm/server/Charge.js +172 -0
- package/dist/evm/server/Charge.js.map +1 -0
- package/dist/evm/server/Methods.d.ts +80 -0
- package/dist/evm/server/Methods.d.ts.map +1 -0
- package/dist/evm/server/Methods.js +16 -0
- package/dist/evm/server/Methods.js.map +1 -0
- package/dist/evm/server/index.d.ts +6 -0
- package/dist/evm/server/index.d.ts.map +1 -0
- package/dist/evm/server/index.js +6 -0
- package/dist/evm/server/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/HeaderCodec.d.ts +18 -0
- package/dist/internal/HeaderCodec.d.ts.map +1 -0
- package/dist/internal/HeaderCodec.js +31 -0
- package/dist/internal/HeaderCodec.js.map +1 -0
- package/dist/middlewares/elysia.d.ts.map +1 -1
- package/dist/middlewares/elysia.js +2 -3
- package/dist/middlewares/elysia.js.map +1 -1
- package/dist/middlewares/express.js +2 -1
- package/dist/middlewares/express.js.map +1 -1
- package/dist/proxy/internal/Headers.d.ts +13 -1
- package/dist/proxy/internal/Headers.d.ts.map +1 -1
- package/dist/proxy/internal/Headers.js +25 -2
- package/dist/proxy/internal/Headers.js.map +1 -1
- package/dist/proxy/services/openai.d.ts.map +1 -1
- package/dist/proxy/services/openai.js +2 -0
- package/dist/proxy/services/openai.js.map +1 -1
- package/dist/server/Methods.d.ts +1 -0
- package/dist/server/Methods.d.ts.map +1 -1
- package/dist/server/Methods.js +1 -0
- package/dist/server/Methods.js.map +1 -1
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +90 -12
- package/dist/server/Mppx.js.map +1 -1
- package/dist/server/Transport.d.ts +10 -0
- package/dist/server/Transport.d.ts.map +1 -1
- package/dist/server/Transport.js +9 -0
- package/dist/server/Transport.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/stripe/server/Charge.d.ts +31 -1
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js +88 -11
- 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/ChannelOps.d.ts +3 -3
- package/dist/tempo/client/ChannelOps.d.ts.map +1 -1
- package/dist/tempo/client/ChannelOps.js +13 -6
- package/dist/tempo/client/ChannelOps.js.map +1 -1
- package/dist/tempo/client/Charge.d.ts.map +1 -1
- package/dist/tempo/client/Charge.js +8 -5
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/client/Methods.d.ts +0 -1
- package/dist/tempo/client/Methods.d.ts.map +1 -1
- package/dist/tempo/client/Session.d.ts +2 -4
- package/dist/tempo/client/Session.d.ts.map +1 -1
- package/dist/tempo/client/Session.js +10 -12
- package/dist/tempo/client/Session.js.map +1 -1
- package/dist/tempo/client/SessionManager.d.ts +3 -3
- package/dist/tempo/client/SessionManager.d.ts.map +1 -1
- package/dist/tempo/client/SessionManager.js +1 -1
- package/dist/tempo/client/SessionManager.js.map +1 -1
- package/dist/tempo/internal/account.d.ts +5 -0
- package/dist/tempo/internal/account.d.ts.map +1 -1
- package/dist/tempo/internal/account.js +8 -0
- package/dist/tempo/internal/account.js.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js +5 -2
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/server/Charge.d.ts +6 -0
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +30 -3
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Session.d.ts +6 -0
- package/dist/tempo/server/Session.d.ts.map +1 -1
- package/dist/tempo/server/Session.js +14 -13
- package/dist/tempo/server/Session.js.map +1 -1
- package/dist/tempo/server/Subscription.d.ts +6 -0
- package/dist/tempo/server/Subscription.d.ts.map +1 -1
- package/dist/tempo/server/Subscription.js +1 -1
- package/dist/tempo/server/Subscription.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/Chain.d.ts +2 -0
- package/dist/tempo/session/Chain.d.ts.map +1 -1
- package/dist/tempo/session/Chain.js +8 -8
- package/dist/tempo/session/Chain.js.map +1 -1
- package/dist/tempo/session/Voucher.d.ts +4 -3
- package/dist/tempo/session/Voucher.d.ts.map +1 -1
- package/dist/tempo/session/Voucher.js +71 -44
- package/dist/tempo/session/Voucher.js.map +1 -1
- package/dist/tempo/session/Ws.d.ts.map +1 -1
- package/dist/tempo/session/Ws.js +15 -0
- package/dist/tempo/session/Ws.js.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.d.ts +2 -2
- package/dist/x402/Assets.d.ts +29 -0
- package/dist/x402/Assets.d.ts.map +1 -0
- package/dist/x402/Assets.js +46 -0
- package/dist/x402/Assets.js.map +1 -0
- package/dist/x402/Header.d.ts +14 -0
- package/dist/x402/Header.d.ts.map +1 -0
- package/dist/x402/Header.js +18 -0
- package/dist/x402/Header.js.map +1 -0
- package/dist/x402/Types.d.ts +289 -0
- package/dist/x402/Types.d.ts.map +1 -0
- package/dist/x402/Types.js +139 -0
- package/dist/x402/Types.js.map +1 -0
- package/dist/x402/client/Exact.d.ts +38 -0
- package/dist/x402/client/Exact.d.ts.map +1 -0
- package/dist/x402/client/Exact.js +141 -0
- package/dist/x402/client/Exact.js.map +1 -0
- package/dist/x402/index.d.ts +6 -0
- package/dist/x402/index.d.ts.map +1 -0
- package/dist/x402/index.js +6 -0
- package/dist/x402/index.js.map +1 -0
- package/dist/x402/internal/ChallengeBrand.d.ts +5 -0
- package/dist/x402/internal/ChallengeBrand.d.ts.map +1 -0
- package/dist/x402/internal/ChallengeBrand.js +13 -0
- package/dist/x402/internal/ChallengeBrand.js.map +1 -0
- package/dist/x402/internal/RouteBinding.d.ts +8 -0
- package/dist/x402/internal/RouteBinding.d.ts.map +1 -0
- package/dist/x402/internal/RouteBinding.js +12 -0
- package/dist/x402/internal/RouteBinding.js.map +1 -0
- package/dist/x402/server/EvmCharge.d.ts +50 -0
- package/dist/x402/server/EvmCharge.d.ts.map +1 -0
- package/dist/x402/server/EvmCharge.js +301 -0
- package/dist/x402/server/EvmCharge.js.map +1 -0
- package/dist/x402/server/Facilitator.d.ts +12 -0
- package/dist/x402/server/Facilitator.d.ts.map +1 -0
- package/dist/x402/server/Facilitator.js +42 -0
- package/dist/x402/server/Facilitator.js.map +1 -0
- package/package.json +41 -21
- package/src/Challenge.test.ts +28 -0
- package/src/Challenge.ts +17 -10
- package/src/Method.ts +1 -1
- package/src/Store.test-d.ts +58 -0
- package/src/Store.test.ts +77 -0
- package/src/Store.ts +155 -74
- package/src/client/Methods.ts +1 -0
- package/src/client/Mppx.ts +4 -3
- package/src/client/Transport.test.ts +165 -30
- package/src/client/Transport.ts +76 -8
- package/src/client/index.ts +1 -1
- package/src/client/internal/Fetch.test.ts +31 -2
- package/src/client/internal/Fetch.ts +26 -19
- package/src/evm/Assets.ts +1 -0
- package/src/evm/Chains.ts +5 -0
- package/src/evm/Methods.ts +44 -0
- package/src/evm/PublicInterface.test-d.ts +109 -0
- package/src/evm/Types.ts +140 -0
- package/src/evm/client/Charge.test.ts +99 -0
- package/src/evm/client/Charge.ts +198 -0
- package/src/evm/client/Methods.ts +19 -0
- package/src/evm/client/index.ts +5 -0
- package/src/evm/index.ts +13 -0
- package/src/evm/server/Charge.test.ts +199 -0
- package/src/evm/server/Charge.ts +283 -0
- package/src/evm/server/Methods.ts +22 -0
- package/src/evm/server/index.ts +5 -0
- package/src/index.ts +2 -0
- package/src/internal/HeaderCodec.ts +36 -0
- package/src/middlewares/elysia.test.ts +25 -0
- package/src/middlewares/elysia.ts +1 -2
- package/src/middlewares/express.test.ts +28 -0
- package/src/middlewares/express.ts +1 -1
- package/src/middlewares/hono.test.ts +138 -2
- package/src/middlewares/nextjs.test.ts +22 -0
- package/src/proxy/internal/Headers.test.ts +38 -0
- package/src/proxy/internal/Headers.ts +26 -2
- package/src/proxy/services/openai.test.ts +57 -1
- package/src/proxy/services/openai.ts +2 -0
- package/src/server/Methods.ts +1 -0
- package/src/server/Mppx.test.ts +244 -1
- package/src/server/Mppx.ts +124 -11
- package/src/server/NodeListener.test.ts +28 -1
- package/src/server/Transport.test.ts +19 -0
- package/src/server/Transport.ts +20 -0
- package/src/server/index.ts +1 -1
- package/src/stripe/server/Charge.test.ts +215 -1
- package/src/stripe/server/Charge.ts +150 -20
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/AccessKeyAuthorization.test.ts +231 -0
- package/src/tempo/client/ChannelOps.test.ts +61 -7
- package/src/tempo/client/ChannelOps.ts +18 -7
- package/src/tempo/client/Charge.test.ts +126 -0
- package/src/tempo/client/Charge.ts +10 -6
- package/src/tempo/client/Session.test.ts +130 -1
- package/src/tempo/client/Session.ts +12 -19
- package/src/tempo/client/SessionManager.test.ts +69 -2
- package/src/tempo/client/SessionManager.ts +4 -4
- package/src/tempo/internal/account.ts +13 -0
- package/src/tempo/internal/fee-payer.test.ts +32 -2
- package/src/tempo/internal/fee-payer.ts +6 -2
- package/src/tempo/server/Charge.test.ts +91 -1
- package/src/tempo/server/Charge.ts +48 -2
- package/src/tempo/server/Session.test.ts +30 -0
- package/src/tempo/server/Session.ts +24 -17
- package/src/tempo/server/Subscription.ts +7 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/session/Chain.test.ts +4 -4
- package/src/tempo/session/Chain.ts +10 -6
- package/src/tempo/session/ChannelStore.test.ts +21 -0
- package/src/tempo/session/Voucher.test.ts +230 -1
- package/src/tempo/session/Voucher.ts +96 -48
- package/src/tempo/session/Ws.test.ts +71 -0
- package/src/tempo/session/Ws.ts +13 -0
- package/src/tempo/subscription/Store.test.ts +55 -0
- package/src/x402/Assets.ts +65 -0
- package/src/x402/Exact.e2e.test.ts +448 -0
- package/src/x402/Header.test.ts +73 -0
- package/src/x402/Header.ts +34 -0
- package/src/x402/PublicInterface.test-d.ts +39 -0
- package/src/x402/Types.ts +248 -0
- package/src/x402/client/Exact.test.ts +180 -0
- package/src/x402/client/Exact.ts +198 -0
- package/src/x402/index.ts +5 -0
- package/src/x402/internal/ChallengeBrand.ts +14 -0
- package/src/x402/internal/RouteBinding.ts +18 -0
- package/src/x402/server/EvmCharge.ts +394 -0
- package/src/x402/server/Facilitator.test.ts +111 -0
- package/src/x402/server/Facilitator.ts +56 -0
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { createClient, type Hex, http } from 'viem'
|
|
2
|
+
import { privateKeyToAccount } from 'viem/accounts'
|
|
3
|
+
import { Account as TempoAccount } from 'viem/tempo'
|
|
2
4
|
import { describe, expect, test, vi } from 'vp/test'
|
|
3
5
|
|
|
4
6
|
import * as Challenge from '../../Challenge.js'
|
|
7
|
+
import * as PaymentCredential from '../../Credential.js'
|
|
5
8
|
import { formatNeedVoucherEvent, parseEvent } from '../session/Sse.js'
|
|
6
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
NeedVoucherEvent,
|
|
11
|
+
SessionCredentialPayload,
|
|
12
|
+
SessionReceipt,
|
|
13
|
+
} from '../session/Types.js'
|
|
7
14
|
import { sessionManager } from './SessionManager.js'
|
|
8
15
|
|
|
9
16
|
const channelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
|
|
@@ -82,6 +89,66 @@ describe('Session', () => {
|
|
|
82
89
|
expect(s.cumulative).toBe(0n)
|
|
83
90
|
expect(s.opened).toBe(false)
|
|
84
91
|
})
|
|
92
|
+
|
|
93
|
+
test('uses voucherSigner for managed open credentials', async () => {
|
|
94
|
+
vi.resetModules()
|
|
95
|
+
vi.doMock('viem/actions', () => ({
|
|
96
|
+
prepareTransactionRequest: vi.fn(async () => ({})),
|
|
97
|
+
sendCallsSync: vi.fn(),
|
|
98
|
+
signTransaction: vi.fn(async () => '0xdeadbeef'),
|
|
99
|
+
signTypedData: vi.fn(),
|
|
100
|
+
}))
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const { sessionManager: sessionManagerWithMocks } = await import('./SessionManager.js')
|
|
104
|
+
const account = privateKeyToAccount(
|
|
105
|
+
'0x0000000000000000000000000000000000000000000000000000000000000001',
|
|
106
|
+
)
|
|
107
|
+
const voucherSigner = TempoAccount.fromSecp256k1(
|
|
108
|
+
'0x0000000000000000000000000000000000000000000000000000000000000002',
|
|
109
|
+
{ access: account },
|
|
110
|
+
)
|
|
111
|
+
const client = createClient({
|
|
112
|
+
account,
|
|
113
|
+
transport: http('http://127.0.0.1'),
|
|
114
|
+
})
|
|
115
|
+
const challenge = makeChallenge({
|
|
116
|
+
recipient: '0x742d35cc6634c0532925a3b844bc9e7595f8fe00',
|
|
117
|
+
methodDetails: {
|
|
118
|
+
escrowContract: '0x9d136eea063ede5418a6bc7beaff009bbb6cfa70',
|
|
119
|
+
chainId: 4217,
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
const mockFetch = vi
|
|
123
|
+
.fn()
|
|
124
|
+
.mockResolvedValueOnce(make402Response(challenge))
|
|
125
|
+
.mockResolvedValueOnce(makeOkResponse())
|
|
126
|
+
|
|
127
|
+
const manager = sessionManagerWithMocks({
|
|
128
|
+
account,
|
|
129
|
+
client,
|
|
130
|
+
fetch: mockFetch as typeof globalThis.fetch,
|
|
131
|
+
maxDeposit: '10',
|
|
132
|
+
voucherSigner,
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const response = await manager.fetch('https://api.example.com/data')
|
|
136
|
+
const authorization = new Headers((mockFetch.mock.calls[1]![1] as RequestInit).headers).get(
|
|
137
|
+
'Authorization',
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
expect(response.status).toBe(200)
|
|
141
|
+
expect(authorization).toBeDefined()
|
|
142
|
+
if (!authorization) throw new Error('missing authorization header')
|
|
143
|
+
const credential = PaymentCredential.deserialize<SessionCredentialPayload>(authorization)
|
|
144
|
+
expect(credential.payload.action).toBe('open')
|
|
145
|
+
if (credential.payload.action !== 'open') throw new Error('unexpected action')
|
|
146
|
+
expect(credential.payload.authorizedSigner).toBe(voucherSigner.accessKeyAddress)
|
|
147
|
+
} finally {
|
|
148
|
+
vi.doUnmock('viem/actions')
|
|
149
|
+
vi.resetModules()
|
|
150
|
+
}
|
|
151
|
+
})
|
|
85
152
|
})
|
|
86
153
|
|
|
87
154
|
describe('.fetch()', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Hex } from 'ox'
|
|
2
|
-
import { parseUnits, type Address } from 'viem'
|
|
2
|
+
import { parseUnits, type Account as viem_Account, type Address } from 'viem'
|
|
3
3
|
|
|
4
4
|
import * as Challenge from '../../Challenge.js'
|
|
5
5
|
import * as Fetch from '../../client/internal/Fetch.js'
|
|
@@ -124,7 +124,7 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
124
124
|
|
|
125
125
|
const method = sessionPlugin({
|
|
126
126
|
account: parameters.account,
|
|
127
|
-
|
|
127
|
+
voucherSigner: parameters.voucherSigner,
|
|
128
128
|
getClient: parameters.client ? () => parameters.client! : parameters.getClient,
|
|
129
129
|
escrowContract: parameters.escrowContract,
|
|
130
130
|
decimals: parameters.decimals,
|
|
@@ -853,8 +853,8 @@ export function sessionManager(parameters: sessionManager.Parameters): SessionMa
|
|
|
853
853
|
export declare namespace sessionManager {
|
|
854
854
|
type Parameters = Account.getResolver.Parameters &
|
|
855
855
|
Client.getResolver.Parameters & {
|
|
856
|
-
/**
|
|
857
|
-
|
|
856
|
+
/** Account that signs voucher digests. Defaults to `account`; access-key accounts sign raw vouchers as their access-key address. */
|
|
857
|
+
voucherSigner?: viem_Account | undefined
|
|
858
858
|
/** Viem client instance. Shorthand for `getClient: () => client`. */
|
|
859
859
|
client?: import('viem').Client | undefined
|
|
860
860
|
/** Token decimals used to convert `maxDeposit` to raw units. Defaults to `6`. */
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import type { Account, Address } from 'viem'
|
|
2
|
+
import type { Account as TempoAccount } from 'viem/tempo'
|
|
3
|
+
|
|
4
|
+
/** Returns whether an account is a Tempo access-key account. */
|
|
5
|
+
export function isAccessKeyAccount(
|
|
6
|
+
account: Account,
|
|
7
|
+
): account is Account & TempoAccount.AccessKeyAccount {
|
|
8
|
+
return 'accessKeyAddress' in account
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Returns the address that should authorize direct account signatures. */
|
|
12
|
+
export function getAccountSignerAddress(account: Account): Address {
|
|
13
|
+
return isAccessKeyAccount(account) ? account.accessKeyAddress : account.address
|
|
14
|
+
}
|
|
2
15
|
|
|
3
16
|
/**
|
|
4
17
|
* Resolves a recipient address and optional fee payer from flexible input parameters.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { encodeFunctionData } from 'viem'
|
|
1
|
+
import { encodeFunctionData, maxUint256 } from 'viem'
|
|
2
2
|
import { Abis, Addresses } from 'viem/tempo'
|
|
3
3
|
import { describe, expect, test } from 'vp/test'
|
|
4
4
|
|
|
@@ -443,7 +443,7 @@ describe('prepareSponsoredTransaction', () => {
|
|
|
443
443
|
maxFeePerGas: 1_000_000_000n,
|
|
444
444
|
maxPriorityFeePerGas: 1_000_000_000n,
|
|
445
445
|
nonce: 1n,
|
|
446
|
-
nonceKey:
|
|
446
|
+
nonceKey: 'expiring',
|
|
447
447
|
signature: { r: 1n, s: 1n, yParity: 0 } as any,
|
|
448
448
|
validBefore: Math.floor(Date.now() / 1_000) + 300,
|
|
449
449
|
} as const
|
|
@@ -460,6 +460,36 @@ describe('prepareSponsoredTransaction', () => {
|
|
|
460
460
|
).not.toThrow()
|
|
461
461
|
})
|
|
462
462
|
|
|
463
|
+
test('accepts serialized expiring nonce key', () => {
|
|
464
|
+
expect(() =>
|
|
465
|
+
prepareSponsoredTransaction({
|
|
466
|
+
account: sponsor,
|
|
467
|
+
chainId: 42431,
|
|
468
|
+
details,
|
|
469
|
+
expectedFeeToken: bogus,
|
|
470
|
+
transaction: {
|
|
471
|
+
...baseTransaction,
|
|
472
|
+
nonceKey: maxUint256,
|
|
473
|
+
} as any,
|
|
474
|
+
}),
|
|
475
|
+
).not.toThrow()
|
|
476
|
+
})
|
|
477
|
+
|
|
478
|
+
test('error: rejects non-expiring nonce keys', () => {
|
|
479
|
+
expect(() =>
|
|
480
|
+
prepareSponsoredTransaction({
|
|
481
|
+
account: sponsor,
|
|
482
|
+
chainId: 42431,
|
|
483
|
+
details,
|
|
484
|
+
expectedFeeToken: bogus,
|
|
485
|
+
transaction: {
|
|
486
|
+
...baseTransaction,
|
|
487
|
+
nonceKey: 1n,
|
|
488
|
+
} as any,
|
|
489
|
+
}),
|
|
490
|
+
).toThrow('must use an expiring nonce')
|
|
491
|
+
})
|
|
492
|
+
|
|
463
493
|
test('accepts higher Moderato priority fees by default', () => {
|
|
464
494
|
expect(() =>
|
|
465
495
|
prepareSponsoredTransaction({
|
|
@@ -2,7 +2,7 @@ import type { TempoAddress } from 'ox/tempo'
|
|
|
2
2
|
import { TxEnvelopeTempo } from 'ox/tempo'
|
|
3
3
|
import type { Hex } from 'viem'
|
|
4
4
|
import type { Account } from 'viem'
|
|
5
|
-
import { decodeFunctionData } from 'viem'
|
|
5
|
+
import { decodeFunctionData, maxUint256 } from 'viem'
|
|
6
6
|
import { Abis, Addresses, Transaction } from 'viem/tempo'
|
|
7
7
|
|
|
8
8
|
import * as TempoAddress_internal from './address.js'
|
|
@@ -126,6 +126,10 @@ function getPolicy(chainId: number, overrides: Partial<Policy> | undefined): Pol
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
function isExpiringNonceKey(nonceKey: SponsoredTransaction['nonceKey']): boolean {
|
|
130
|
+
return nonceKey === 'expiring' || nonceKey === maxUint256
|
|
131
|
+
}
|
|
132
|
+
|
|
129
133
|
/** Validates that a set of transaction calls matches an allowed fee-payer pattern. */
|
|
130
134
|
export function validateCalls(
|
|
131
135
|
calls: readonly { data?: `0x${string}` | undefined; to?: TempoAddress.Address | undefined }[],
|
|
@@ -358,7 +362,7 @@ export function prepareSponsoredTransaction(parameters: {
|
|
|
358
362
|
maxPriorityFeePerGas: maxPriorityFeePerGas.toString(),
|
|
359
363
|
})
|
|
360
364
|
|
|
361
|
-
if (nonceKey
|
|
365
|
+
if (!isExpiringNonceKey(nonceKey)) fail('fee-sponsored transaction must use an expiring nonce')
|
|
362
366
|
if (validBefore === undefined)
|
|
363
367
|
fail('fee-sponsored transaction must declare validBefore for the expiring nonce')
|
|
364
368
|
const validBeforeValue = validBefore
|
|
@@ -286,6 +286,7 @@ describe('tempo', () => {
|
|
|
286
286
|
})
|
|
287
287
|
|
|
288
288
|
test('behavior: rejects replayed transaction hash', async () => {
|
|
289
|
+
const dedupStore = Store.memory()
|
|
289
290
|
const dedupServer = Mppx_server.create({
|
|
290
291
|
methods: [
|
|
291
292
|
tempo_server.charge({
|
|
@@ -294,7 +295,8 @@ describe('tempo', () => {
|
|
|
294
295
|
},
|
|
295
296
|
currency: asset,
|
|
296
297
|
account: accounts[0],
|
|
297
|
-
store:
|
|
298
|
+
store: dedupStore,
|
|
299
|
+
storeKeyPrefix: 'tenant:',
|
|
298
300
|
}),
|
|
299
301
|
],
|
|
300
302
|
realm,
|
|
@@ -336,6 +338,8 @@ describe('tempo', () => {
|
|
|
336
338
|
})
|
|
337
339
|
expect(response.status).toBe(200)
|
|
338
340
|
}
|
|
341
|
+
expect(await dedupStore.get(`tenant:mppx:charge:${receipt.transactionHash}`)).not.toBeNull()
|
|
342
|
+
expect(await dedupStore.get(`mppx:charge:${receipt.transactionHash}`)).toBeNull()
|
|
339
343
|
|
|
340
344
|
const response2 = await fetch(httpServer.url)
|
|
341
345
|
expect(response2.status).toBe(402)
|
|
@@ -1616,6 +1620,7 @@ describe('tempo', () => {
|
|
|
1616
1620
|
currency: asset,
|
|
1617
1621
|
account: accounts[0],
|
|
1618
1622
|
store: sponsoredStore,
|
|
1623
|
+
storeKeyPrefix: 'tenant:',
|
|
1619
1624
|
}),
|
|
1620
1625
|
],
|
|
1621
1626
|
realm,
|
|
@@ -1661,6 +1666,16 @@ describe('tempo', () => {
|
|
|
1661
1666
|
|
|
1662
1667
|
const first = fetch(httpServer.url, { headers: { Authorization: credential1 } })
|
|
1663
1668
|
await simulationStarted
|
|
1669
|
+
expect(
|
|
1670
|
+
await sponsoredStore.get(
|
|
1671
|
+
`tenant:mppx:charge:sponsor:${chain.id}:${accounts[1].address.toLowerCase()}`,
|
|
1672
|
+
),
|
|
1673
|
+
).not.toBeNull()
|
|
1674
|
+
expect(
|
|
1675
|
+
await sponsoredStore.get(
|
|
1676
|
+
`mppx:charge:sponsor:${chain.id}:${accounts[1].address.toLowerCase()}`,
|
|
1677
|
+
),
|
|
1678
|
+
).toBeNull()
|
|
1664
1679
|
const second = fetch(httpServer.url, { headers: { Authorization: credential2 } })
|
|
1665
1680
|
|
|
1666
1681
|
try {
|
|
@@ -2870,6 +2885,7 @@ describe('tempo', () => {
|
|
|
2870
2885
|
|
|
2871
2886
|
test('behavior: store keys proof replay protection by challenge ID', async () => {
|
|
2872
2887
|
const replayStore = Store.memory()
|
|
2888
|
+
const storeKeyPrefix = 'tenant:'
|
|
2873
2889
|
const server_ = Mppx_server.create({
|
|
2874
2890
|
methods: [
|
|
2875
2891
|
tempo_server.charge({
|
|
@@ -2879,6 +2895,7 @@ describe('tempo', () => {
|
|
|
2879
2895
|
currency: asset,
|
|
2880
2896
|
account: accounts[0],
|
|
2881
2897
|
store: replayStore,
|
|
2898
|
+
storeKeyPrefix,
|
|
2882
2899
|
}),
|
|
2883
2900
|
],
|
|
2884
2901
|
realm,
|
|
@@ -2918,6 +2935,10 @@ describe('tempo', () => {
|
|
|
2918
2935
|
headers: { Authorization: Credential.serialize(credential1) },
|
|
2919
2936
|
})
|
|
2920
2937
|
expect(response2.status).toBe(200)
|
|
2938
|
+
expect(
|
|
2939
|
+
await replayStore.get(`${storeKeyPrefix}mppx:charge:proof:${challenge1.id}`),
|
|
2940
|
+
).not.toBeNull()
|
|
2941
|
+
expect(await replayStore.get(`mppx:charge:proof:${challenge1.id}`)).toBeNull()
|
|
2921
2942
|
|
|
2922
2943
|
const response3 = await fetch(httpServer.url)
|
|
2923
2944
|
expect(response3.status).toBe(402)
|
|
@@ -3633,6 +3654,75 @@ describe('tempo', () => {
|
|
|
3633
3654
|
})
|
|
3634
3655
|
expect(challenge.request.methodDetails?.supportedModes).toEqual(['pull'])
|
|
3635
3656
|
})
|
|
3657
|
+
|
|
3658
|
+
test('challenge contains supportedModes from method defaults', async () => {
|
|
3659
|
+
const handler = Mppx_server.create({
|
|
3660
|
+
methods: [
|
|
3661
|
+
tempo_server.charge({
|
|
3662
|
+
getClient: () => client,
|
|
3663
|
+
account: accounts[0].address,
|
|
3664
|
+
currency: asset,
|
|
3665
|
+
supportedModes: ['pull'],
|
|
3666
|
+
}),
|
|
3667
|
+
],
|
|
3668
|
+
realm,
|
|
3669
|
+
secretKey,
|
|
3670
|
+
})
|
|
3671
|
+
|
|
3672
|
+
const result = await handler.charge({ amount: '1' })(new Request('https://example.com'))
|
|
3673
|
+
expect(result.status).toBe(402)
|
|
3674
|
+
if (result.status !== 402) throw new Error()
|
|
3675
|
+
|
|
3676
|
+
const challenge = Challenge.fromResponse(result.challenge, {
|
|
3677
|
+
methods: [tempo_client.charge()],
|
|
3678
|
+
})
|
|
3679
|
+
expect(challenge.request.methodDetails?.supportedModes).toEqual(['pull'])
|
|
3680
|
+
})
|
|
3681
|
+
|
|
3682
|
+
test('stable binding contains supportedModes', () => {
|
|
3683
|
+
const method = tempo_server.charge({
|
|
3684
|
+
getClient: () => client,
|
|
3685
|
+
account: accounts[0].address,
|
|
3686
|
+
currency: asset,
|
|
3687
|
+
})
|
|
3688
|
+
const request = method.schema.request.parse({
|
|
3689
|
+
amount: '1',
|
|
3690
|
+
currency: asset,
|
|
3691
|
+
decimals: 6,
|
|
3692
|
+
supportedModes: ['pull'],
|
|
3693
|
+
})
|
|
3694
|
+
|
|
3695
|
+
expect(method.stableBinding?.(request)).toMatchObject({
|
|
3696
|
+
supportedModes: ['pull'],
|
|
3697
|
+
})
|
|
3698
|
+
})
|
|
3699
|
+
|
|
3700
|
+
test('challenge contains splits from method defaults', async () => {
|
|
3701
|
+
const split = { amount: '0.2', recipient: accounts[2].address }
|
|
3702
|
+
const handler = Mppx_server.create({
|
|
3703
|
+
methods: [
|
|
3704
|
+
tempo_server.charge({
|
|
3705
|
+
getClient: () => client,
|
|
3706
|
+
account: accounts[0].address,
|
|
3707
|
+
currency: asset,
|
|
3708
|
+
splits: [split],
|
|
3709
|
+
}),
|
|
3710
|
+
],
|
|
3711
|
+
realm,
|
|
3712
|
+
secretKey,
|
|
3713
|
+
})
|
|
3714
|
+
|
|
3715
|
+
const result = await handler.charge({ amount: '1' })(new Request('https://example.com'))
|
|
3716
|
+
expect(result.status).toBe(402)
|
|
3717
|
+
if (result.status !== 402) throw new Error()
|
|
3718
|
+
|
|
3719
|
+
const challenge = Challenge.fromResponse(result.challenge, {
|
|
3720
|
+
methods: [tempo_client.charge()],
|
|
3721
|
+
})
|
|
3722
|
+
expect(challenge.request.methodDetails?.splits).toEqual([
|
|
3723
|
+
{ amount: '200000', recipient: split.recipient },
|
|
3724
|
+
])
|
|
3725
|
+
})
|
|
3636
3726
|
})
|
|
3637
3727
|
|
|
3638
3728
|
describe('attribution memo', () => {
|
|
@@ -63,11 +63,21 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
63
63
|
feePayerPolicy,
|
|
64
64
|
html,
|
|
65
65
|
memo,
|
|
66
|
+
splits,
|
|
67
|
+
supportedModes,
|
|
66
68
|
validateSender,
|
|
67
69
|
waitForConfirmation = true,
|
|
68
70
|
} = parameters
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
+
const storeKeyPrefix = parameters.storeKeyPrefix ?? ''
|
|
72
|
+
const store = Store.from(
|
|
73
|
+
(parameters.store ?? Store.memory()) as Store.AtomicStore<charge.StoreItemMap>,
|
|
74
|
+
{ keyPrefix: storeKeyPrefix },
|
|
75
|
+
)
|
|
76
|
+
const proofStore = parameters.store
|
|
77
|
+
? Store.from(parameters.store as Store.AtomicStore<charge.StoreItemMap>, {
|
|
78
|
+
keyPrefix: storeKeyPrefix,
|
|
79
|
+
})
|
|
80
|
+
: undefined
|
|
71
81
|
|
|
72
82
|
const { recipient, feePayer, feePayerUrl } = Account.resolve(parameters)
|
|
73
83
|
|
|
@@ -88,8 +98,12 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
88
98
|
externalId,
|
|
89
99
|
memo,
|
|
90
100
|
recipient,
|
|
101
|
+
splits,
|
|
102
|
+
supportedModes,
|
|
91
103
|
} as unknown as Defaults,
|
|
92
104
|
|
|
105
|
+
stableBinding: chargeBinding,
|
|
106
|
+
|
|
93
107
|
html: html
|
|
94
108
|
? {
|
|
95
109
|
config: {},
|
|
@@ -539,6 +553,12 @@ export declare namespace charge {
|
|
|
539
553
|
* memo binding, transaction success, and replay protection.
|
|
540
554
|
*/
|
|
541
555
|
validateSender?: ValidateSender | undefined
|
|
556
|
+
/**
|
|
557
|
+
* Prefix prepended to charge replay-protection store keys.
|
|
558
|
+
*
|
|
559
|
+
* By default, no prefix is applied.
|
|
560
|
+
*/
|
|
561
|
+
storeKeyPrefix?: string | undefined
|
|
542
562
|
/**
|
|
543
563
|
* Whether to wait for the charge transaction to confirm on-chain before
|
|
544
564
|
* responding. @default true
|
|
@@ -565,6 +585,32 @@ export declare namespace charge {
|
|
|
565
585
|
type FeePayerPolicy = Partial<FeePayer.Policy>
|
|
566
586
|
}
|
|
567
587
|
|
|
588
|
+
type ChargeRequest = z.output<typeof Methods.charge.schema.request>
|
|
589
|
+
|
|
590
|
+
function chargeBinding(request: ChargeRequest) {
|
|
591
|
+
// Exhaustively destructure so new charge request fields require an explicit binding decision.
|
|
592
|
+
const { amount, currency, description, externalId, methodDetails, recipient, ...requestRest } =
|
|
593
|
+
request
|
|
594
|
+
requestRest satisfies Record<string, never>
|
|
595
|
+
|
|
596
|
+
const { chainId, feePayer, memo, splits, supportedModes, ...methodDetailsRest } =
|
|
597
|
+
methodDetails ?? {}
|
|
598
|
+
methodDetailsRest satisfies Record<string, never>
|
|
599
|
+
void feePayer
|
|
600
|
+
|
|
601
|
+
return {
|
|
602
|
+
amount,
|
|
603
|
+
chainId,
|
|
604
|
+
currency,
|
|
605
|
+
description,
|
|
606
|
+
externalId,
|
|
607
|
+
memo,
|
|
608
|
+
recipient,
|
|
609
|
+
splits,
|
|
610
|
+
supportedModes,
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
568
614
|
type ExpectedTransfer = {
|
|
569
615
|
amount: string
|
|
570
616
|
allowAnyMemo?: boolean | undefined
|
|
@@ -668,6 +668,36 @@ describe.runIf(isLocalnet)('session', () => {
|
|
|
668
668
|
expect(ch!.highestVoucherAmount).toBe(2000000n)
|
|
669
669
|
})
|
|
670
670
|
|
|
671
|
+
test('rejects voucher signed for route escrow instead of stored channel escrow', async () => {
|
|
672
|
+
const { channelId, serializedTransaction } = await createSignedOpenTransaction(10000000n)
|
|
673
|
+
const server = createServer()
|
|
674
|
+
await openServerChannel(server, channelId, serializedTransaction)
|
|
675
|
+
|
|
676
|
+
const routeEscrow = '0x0000000000000000000000000000000000000999' as Address
|
|
677
|
+
const signature = await signVoucher(
|
|
678
|
+
client,
|
|
679
|
+
payer,
|
|
680
|
+
{ channelId, cumulativeAmount: 2000000n },
|
|
681
|
+
routeEscrow,
|
|
682
|
+
chain.id,
|
|
683
|
+
)
|
|
684
|
+
|
|
685
|
+
await expect(
|
|
686
|
+
server.verify({
|
|
687
|
+
credential: {
|
|
688
|
+
challenge: makeChallenge({ id: 'route-escrow-replay', channelId }),
|
|
689
|
+
payload: {
|
|
690
|
+
action: 'voucher' as const,
|
|
691
|
+
channelId,
|
|
692
|
+
cumulativeAmount: '2000000',
|
|
693
|
+
signature,
|
|
694
|
+
},
|
|
695
|
+
},
|
|
696
|
+
request: makeRequest({ escrowContract: routeEscrow }),
|
|
697
|
+
}),
|
|
698
|
+
).rejects.toThrow(InvalidSignatureError)
|
|
699
|
+
})
|
|
700
|
+
|
|
671
701
|
test('rejects non-increasing voucher replay', async () => {
|
|
672
702
|
const { channelId, serializedTransaction } = await createSignedOpenTransaction(10000000n)
|
|
673
703
|
const server = createServer()
|
|
@@ -104,7 +104,9 @@ export function session<const parameters extends session.Parameters>(
|
|
|
104
104
|
|
|
105
105
|
const lastOnChainVerified = new Map<Hex, number>()
|
|
106
106
|
|
|
107
|
-
const store = ChannelStore.fromStore(
|
|
107
|
+
const store = ChannelStore.fromStore(
|
|
108
|
+
Store.from(rawStore, { keyPrefix: parameters.storeKeyPrefix }),
|
|
109
|
+
)
|
|
108
110
|
|
|
109
111
|
const { account, recipient, feePayer, feePayerUrl } = Account.resolve(parameters)
|
|
110
112
|
|
|
@@ -139,7 +141,7 @@ export function session<const parameters extends session.Parameters>(
|
|
|
139
141
|
unitType,
|
|
140
142
|
} as unknown as Defaults,
|
|
141
143
|
|
|
142
|
-
transport
|
|
144
|
+
transport,
|
|
143
145
|
|
|
144
146
|
// TODO: dedupe `{charge,session}.request`
|
|
145
147
|
async request({ credential, request }) {
|
|
@@ -224,6 +226,7 @@ export function session<const parameters extends session.Parameters>(
|
|
|
224
226
|
payload,
|
|
225
227
|
methodDetails,
|
|
226
228
|
resolvedFeePayer,
|
|
229
|
+
methodDetails.feePayer === true,
|
|
227
230
|
feePayerPolicy,
|
|
228
231
|
waitForConfirmation,
|
|
229
232
|
)
|
|
@@ -238,6 +241,7 @@ export function session<const parameters extends session.Parameters>(
|
|
|
238
241
|
payload,
|
|
239
242
|
methodDetails,
|
|
240
243
|
resolvedFeePayer,
|
|
244
|
+
methodDetails.feePayer === true,
|
|
241
245
|
feePayerPolicy,
|
|
242
246
|
)
|
|
243
247
|
lastOnChainVerified.set(sessionReceipt.channelId, Date.now())
|
|
@@ -357,6 +361,12 @@ export declare namespace session {
|
|
|
357
361
|
* local single-process usage.
|
|
358
362
|
*/
|
|
359
363
|
store?: Store.AtomicStore | undefined
|
|
364
|
+
/**
|
|
365
|
+
* Prefix prepended to channel state store keys.
|
|
366
|
+
*
|
|
367
|
+
* By default, no prefix is applied.
|
|
368
|
+
*/
|
|
369
|
+
storeKeyPrefix?: string | undefined
|
|
360
370
|
/**
|
|
361
371
|
* Enable SSE streaming.
|
|
362
372
|
*
|
|
@@ -522,10 +532,8 @@ async function verifyAndAcceptVoucher(parameters: {
|
|
|
522
532
|
channelId: Hex
|
|
523
533
|
voucher: SignedVoucher
|
|
524
534
|
onChain: OnChainChannel
|
|
525
|
-
methodDetails: SessionMethodDetails
|
|
526
535
|
}): Promise<SessionReceipt> {
|
|
527
|
-
const { store, minVoucherDelta, challenge, channel, channelId, voucher, onChain
|
|
528
|
-
parameters
|
|
536
|
+
const { store, minVoucherDelta, challenge, channel, channelId, voucher, onChain } = parameters
|
|
529
537
|
|
|
530
538
|
if (onChain.finalized) {
|
|
531
539
|
throw new ChannelClosedError({ reason: 'channel is finalized on-chain' })
|
|
@@ -560,8 +568,8 @@ async function verifyAndAcceptVoucher(parameters: {
|
|
|
560
568
|
}
|
|
561
569
|
|
|
562
570
|
const isValid = await verifyVoucher(
|
|
563
|
-
|
|
564
|
-
|
|
571
|
+
channel.escrowContract,
|
|
572
|
+
channel.chainId,
|
|
565
573
|
voucher,
|
|
566
574
|
channel.authorizedSigner,
|
|
567
575
|
)
|
|
@@ -627,6 +635,7 @@ async function handleOpen(
|
|
|
627
635
|
payload: SessionCredentialPayload & { action: 'open' },
|
|
628
636
|
methodDetails: SessionMethodDetails,
|
|
629
637
|
feePayer: viem_Account | undefined,
|
|
638
|
+
isSponsored: boolean,
|
|
630
639
|
feePayerPolicy: session.FeePayerPolicy | undefined,
|
|
631
640
|
waitForConfirmation: boolean,
|
|
632
641
|
): Promise<SessionReceipt> {
|
|
@@ -679,6 +688,7 @@ async function handleOpen(
|
|
|
679
688
|
challengeExpires: challenge.expires,
|
|
680
689
|
feePayerPolicy,
|
|
681
690
|
feePayer,
|
|
691
|
+
isSponsored,
|
|
682
692
|
beforeBroadcast: async (pendingOnChain) => {
|
|
683
693
|
await validateOpenVoucher(pendingOnChain)
|
|
684
694
|
},
|
|
@@ -764,6 +774,7 @@ async function handleTopUp(
|
|
|
764
774
|
payload: SessionCredentialPayload & { action: 'topUp' },
|
|
765
775
|
methodDetails: SessionMethodDetails,
|
|
766
776
|
feePayer: viem_Account | undefined,
|
|
777
|
+
isSponsored: boolean,
|
|
767
778
|
feePayerPolicy: session.FeePayerPolicy | undefined,
|
|
768
779
|
): Promise<SessionReceipt> {
|
|
769
780
|
const channelId = ChannelStore.normalizeChannelId(payload.channelId)
|
|
@@ -785,6 +796,7 @@ async function handleTopUp(
|
|
|
785
796
|
challengeExpires: challenge.expires,
|
|
786
797
|
feePayerPolicy,
|
|
787
798
|
feePayer,
|
|
799
|
+
isSponsored,
|
|
788
800
|
})
|
|
789
801
|
|
|
790
802
|
const updated = await store.updateChannel(channelId, (current) => {
|
|
@@ -840,11 +852,7 @@ async function handleVoucher(
|
|
|
840
852
|
|
|
841
853
|
const onChain = await (async () => {
|
|
842
854
|
if (isStale) {
|
|
843
|
-
const onChainChannel = await getOnChainChannel(
|
|
844
|
-
client,
|
|
845
|
-
methodDetails.escrowContract,
|
|
846
|
-
channelId,
|
|
847
|
-
)
|
|
855
|
+
const onChainChannel = await getOnChainChannel(client, channel.escrowContract, channelId)
|
|
848
856
|
lastOnChainVerified.set(channelId, Date.now())
|
|
849
857
|
// Persist closeRequestedAt so the cached path detects force-close
|
|
850
858
|
// between re-queries.
|
|
@@ -875,7 +883,6 @@ async function handleVoucher(
|
|
|
875
883
|
channelId,
|
|
876
884
|
voucher,
|
|
877
885
|
onChain,
|
|
878
|
-
methodDetails,
|
|
879
886
|
})
|
|
880
887
|
}
|
|
881
888
|
|
|
@@ -902,7 +909,7 @@ async function handleClose(
|
|
|
902
909
|
|
|
903
910
|
const voucher = parseVoucherFromPayload(channelId, payload.cumulativeAmount, payload.signature)
|
|
904
911
|
|
|
905
|
-
const onChain = await getOnChainChannel(client,
|
|
912
|
+
const onChain = await getOnChainChannel(client, channel.escrowContract, channelId)
|
|
906
913
|
|
|
907
914
|
if (onChain.finalized) {
|
|
908
915
|
throw new ChannelClosedError({ reason: 'channel is finalized on-chain' })
|
|
@@ -928,8 +935,8 @@ async function handleClose(
|
|
|
928
935
|
}
|
|
929
936
|
|
|
930
937
|
const isValid = await verifyVoucher(
|
|
931
|
-
|
|
932
|
-
|
|
938
|
+
channel.escrowContract,
|
|
939
|
+
channel.chainId,
|
|
933
940
|
voucher,
|
|
934
941
|
channel.authorizedSigner,
|
|
935
942
|
)
|
|
@@ -964,7 +971,7 @@ async function handleClose(
|
|
|
964
971
|
sender: account?.address ?? client.account?.address,
|
|
965
972
|
})
|
|
966
973
|
|
|
967
|
-
txHash = await closeOnChain(client,
|
|
974
|
+
txHash = await closeOnChain(client, channel.escrowContract, voucher, {
|
|
968
975
|
...(feePayer && account ? { feePayer, account } : { account }),
|
|
969
976
|
candidateFeeTokens: [channel.token],
|
|
970
977
|
})
|
|
@@ -72,7 +72,7 @@ export function subscription<const parameters extends subscription.Parameters>(
|
|
|
72
72
|
|
|
73
73
|
const { recipient } = Account.resolve(parameters)
|
|
74
74
|
const context = createContext(parameters, {
|
|
75
|
-
store: rawStore,
|
|
75
|
+
store: Store.from(rawStore, { keyPrefix: parameters.storeKeyPrefix }),
|
|
76
76
|
options: {
|
|
77
77
|
activationTimeoutMs: parameters.activationTimeoutMs,
|
|
78
78
|
renewalTimeoutMs: parameters.renewalTimeoutMs,
|
|
@@ -1110,6 +1110,12 @@ export declare namespace subscription {
|
|
|
1110
1110
|
subscription: SubscriptionRecord
|
|
1111
1111
|
}) => Promise<RenewalResult>
|
|
1112
1112
|
store?: Store.AtomicStore<Record<string, unknown>> | undefined
|
|
1113
|
+
/**
|
|
1114
|
+
* Prefix prepended to all subscription store keys.
|
|
1115
|
+
*
|
|
1116
|
+
* By default, no prefix is applied.
|
|
1117
|
+
*/
|
|
1118
|
+
storeKeyPrefix?: string | undefined
|
|
1113
1119
|
testnet?: boolean | undefined
|
|
1114
1120
|
waitForConfirmation?: boolean | undefined
|
|
1115
1121
|
} & Defaults
|