mppx 0.6.25 → 0.6.27
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 +15 -0
- package/dist/Method.d.ts +6 -4
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +2 -1
- package/dist/Method.js.map +1 -1
- package/dist/cli/cli.js +1 -1
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/utils.js +2 -2
- package/dist/cli/utils.js.map +1 -1
- package/dist/middlewares/internal/mppx.d.ts +3 -2
- package/dist/middlewares/internal/mppx.d.ts.map +1 -1
- package/dist/middlewares/internal/mppx.js +1 -0
- package/dist/middlewares/internal/mppx.js.map +1 -1
- package/dist/server/Mppx.d.ts +8 -3
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +4 -1
- package/dist/server/Mppx.js.map +1 -1
- package/dist/stripe/server/Charge.d.ts +1 -1
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Methods.d.ts +1 -1
- package/dist/stripe/server/Methods.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/tempo/Methods.d.ts +3 -2
- package/dist/tempo/Methods.d.ts.map +1 -1
- package/dist/tempo/Methods.js +13 -4
- package/dist/tempo/Methods.js.map +1 -1
- package/dist/tempo/client/ChannelOps.d.ts.map +1 -1
- package/dist/tempo/client/ChannelOps.js +7 -2
- 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 +6 -4
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/client/Session.js +1 -1
- package/dist/tempo/client/Session.js.map +1 -1
- package/dist/tempo/client/Subscription.d.ts +3 -2
- package/dist/tempo/client/Subscription.d.ts.map +1 -1
- package/dist/tempo/client/Subscription.js +1 -1
- package/dist/tempo/client/Subscription.js.map +1 -1
- package/dist/tempo/server/Charge.d.ts +1 -1
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +1 -1
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +2 -2
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Session.d.ts +1 -1
- package/dist/tempo/server/Session.d.ts.map +1 -1
- package/dist/tempo/server/Session.js +1 -1
- package/dist/tempo/server/Session.js.map +1 -1
- package/dist/tempo/server/Subscription.d.ts +28 -12
- package/dist/tempo/server/Subscription.d.ts.map +1 -1
- package/dist/tempo/server/Subscription.js +83 -31
- 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.map +1 -1
- package/dist/tempo/session/Chain.js +6 -1
- package/dist/tempo/session/Chain.js.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.d.ts +3 -14
- package/dist/tempo/subscription/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.js +11 -20
- package/dist/tempo/subscription/KeyAuthorization.js.map +1 -1
- package/dist/tempo/subscription/Types.d.ts +2 -2
- package/dist/tempo/subscription/Types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/Method.ts +21 -5
- package/src/cli/cli.ts +1 -1
- package/src/cli/utils.test.ts +1 -1
- package/src/cli/utils.ts +2 -2
- package/src/middlewares/internal/mppx.test.ts +24 -0
- package/src/middlewares/internal/mppx.ts +6 -2
- package/src/server/Mppx.ts +17 -4
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/Methods.test.ts +17 -0
- package/src/tempo/Methods.ts +12 -4
- package/src/tempo/client/ChannelOps.ts +6 -2
- package/src/tempo/client/Charge.ts +5 -4
- package/src/tempo/client/Session.ts +1 -1
- package/src/tempo/client/Subscription.test.ts +5 -7
- package/src/tempo/client/Subscription.ts +1 -1
- package/src/tempo/server/Charge.ts +1 -1
- package/src/tempo/server/Session.ts +1 -1
- package/src/tempo/server/Subscription.test.ts +2 -5
- package/src/tempo/server/Subscription.ts +157 -68
- package/src/tempo/server/internal/html/main.ts +1 -1
- package/src/tempo/server/internal/html/package.json +2 -2
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/session/Chain.test.ts +16 -8
- package/src/tempo/session/Chain.ts +6 -1
- package/src/tempo/subscription/KeyAuthorization.test.ts +13 -4
- package/src/tempo/subscription/KeyAuthorization.ts +11 -20
- package/src/tempo/subscription/Types.ts +2 -2
- package/src/viem/Account.test.ts +1 -1
- package/src/viem/Client.test.ts +1 -1
|
@@ -498,10 +498,12 @@ describe.runIf(isLocalnet)('on-chain', () => {
|
|
|
498
498
|
{ to: currency, data: approveData },
|
|
499
499
|
{ to: escrowContract, data: openData },
|
|
500
500
|
],
|
|
501
|
-
feePayer: true,
|
|
502
501
|
feeToken: currency,
|
|
502
|
+
nonceKey: 'expiring',
|
|
503
|
+
validBefore: Math.floor(Date.now() / 1_000) + 25,
|
|
503
504
|
} as never)
|
|
504
|
-
prepared.gas = prepared.gas
|
|
505
|
+
prepared.gas = (prepared.gas ?? 0n) + 5_000n
|
|
506
|
+
;(prepared as Record<string, unknown>).feePayer = true
|
|
505
507
|
const serializedTransaction = await signTransaction(client, prepared as never)
|
|
506
508
|
|
|
507
509
|
await broadcastOpenTransaction({
|
|
@@ -561,10 +563,12 @@ describe.runIf(isLocalnet)('on-chain', () => {
|
|
|
561
563
|
{ to: escrowContract, data: openData },
|
|
562
564
|
{ to: escrowContract, data: smuggledOpenData },
|
|
563
565
|
],
|
|
564
|
-
feePayer: true,
|
|
565
566
|
feeToken: currency,
|
|
567
|
+
nonceKey: 'expiring',
|
|
568
|
+
validBefore: Math.floor(Date.now() / 1_000) + 25,
|
|
566
569
|
} as never)
|
|
567
|
-
prepared.gas = prepared.gas
|
|
570
|
+
prepared.gas = (prepared.gas ?? 0n) + 5_000n
|
|
571
|
+
;(prepared as Record<string, unknown>).feePayer = true
|
|
568
572
|
|
|
569
573
|
const serializedTransaction = await signTransaction(client, prepared as never)
|
|
570
574
|
|
|
@@ -1006,10 +1010,12 @@ describe.runIf(isLocalnet)('on-chain', () => {
|
|
|
1006
1010
|
{ to: currency, data: approveData },
|
|
1007
1011
|
{ to: escrowContract, data: topUpData },
|
|
1008
1012
|
],
|
|
1009
|
-
feePayer: true,
|
|
1010
1013
|
feeToken: currency,
|
|
1014
|
+
nonceKey: 'expiring',
|
|
1015
|
+
validBefore: Math.floor(Date.now() / 1_000) + 25,
|
|
1011
1016
|
} as never)
|
|
1012
|
-
prepared.gas = prepared.gas
|
|
1017
|
+
prepared.gas = (prepared.gas ?? 0n) + 5_000n
|
|
1018
|
+
;(prepared as Record<string, unknown>).feePayer = true
|
|
1013
1019
|
const serializedTransaction = await signTransaction(client, prepared as never)
|
|
1014
1020
|
|
|
1015
1021
|
await broadcastTopUpTransaction({
|
|
@@ -1069,10 +1075,12 @@ describe.runIf(isLocalnet)('on-chain', () => {
|
|
|
1069
1075
|
{ to: escrowContract, data: topUpData },
|
|
1070
1076
|
{ to: escrowContract, data: smuggledTopUpData },
|
|
1071
1077
|
],
|
|
1072
|
-
feePayer: true,
|
|
1073
1078
|
feeToken: currency,
|
|
1079
|
+
nonceKey: 'expiring',
|
|
1080
|
+
validBefore: Math.floor(Date.now() / 1_000) + 25,
|
|
1074
1081
|
} as never)
|
|
1075
|
-
prepared.gas = prepared.gas
|
|
1082
|
+
prepared.gas = (prepared.gas ?? 0n) + 5_000n
|
|
1083
|
+
;(prepared as Record<string, unknown>).feePayer = true
|
|
1076
1084
|
|
|
1077
1085
|
const serializedTransaction = await signTransaction(client, prepared as never)
|
|
1078
1086
|
|
|
@@ -258,9 +258,14 @@ async function sendFeePayerTx(
|
|
|
258
258
|
const prepared = await prepareTransactionRequest(client, {
|
|
259
259
|
account,
|
|
260
260
|
calls: [{ to, data }],
|
|
261
|
-
feePayer: true,
|
|
262
261
|
...(feeToken ? { feeToken } : {}),
|
|
262
|
+
nonceKey: 'expiring',
|
|
263
|
+
validBefore: Math.floor(Date.now() / 1_000) + 25,
|
|
263
264
|
} as never)
|
|
265
|
+
// Estimate before enabling fee-payer mode so Tempo includes sender
|
|
266
|
+
// signature verification costs in the gas budget.
|
|
267
|
+
prepared.gas = (prepared.gas ?? 0n) + 5_000n
|
|
268
|
+
;(prepared as Record<string, unknown>).feePayer = true
|
|
264
269
|
|
|
265
270
|
const serialized = (await signTransaction(client, {
|
|
266
271
|
...prepared,
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
toSubscriptionExpiryDate,
|
|
12
12
|
toSubscriptionExpirySeconds,
|
|
13
13
|
toSubscriptionPeriodSeconds,
|
|
14
|
+
transferSelector,
|
|
15
|
+
transferWithMemoSelector,
|
|
14
16
|
verifySubscriptionKeyAuthorization,
|
|
15
17
|
} from './KeyAuthorization.js'
|
|
16
18
|
import type { SubscriptionAccessKey } from './Types.js'
|
|
@@ -89,13 +91,12 @@ describe('tempo subscription key authorization', () => {
|
|
|
89
91
|
const request = parseRequest()
|
|
90
92
|
|
|
91
93
|
expect(getSubscriptionScopes(request)).toMatchObject([
|
|
92
|
-
{ address: currency, recipients: [recipient] },
|
|
93
|
-
{ address: currency, recipients: [recipient] },
|
|
94
|
+
{ address: currency, recipients: [recipient], selector: transferWithMemoSelector },
|
|
94
95
|
])
|
|
95
96
|
expect(getSubscriptionRpcAllowedCalls(request)).toMatchObject([
|
|
96
97
|
{
|
|
97
98
|
target: currency,
|
|
98
|
-
selectorRules: [{ recipients: [recipient]
|
|
99
|
+
selectorRules: [{ recipients: [recipient], selector: transferWithMemoSelector }],
|
|
99
100
|
},
|
|
100
101
|
])
|
|
101
102
|
})
|
|
@@ -158,7 +159,10 @@ describe('tempo subscription key authorization', () => {
|
|
|
158
159
|
const authorization = KeyAuthorization.deserialize(payload.signature)
|
|
159
160
|
const transferOnly = KeyAuthorization.serialize({
|
|
160
161
|
...authorization,
|
|
161
|
-
scopes: authorization.scopes?.
|
|
162
|
+
scopes: authorization.scopes?.map((scope) => ({
|
|
163
|
+
...scope,
|
|
164
|
+
selector: transferSelector,
|
|
165
|
+
})),
|
|
162
166
|
})
|
|
163
167
|
|
|
164
168
|
expect(() =>
|
|
@@ -183,6 +187,11 @@ describe('tempo subscription key authorization', () => {
|
|
|
183
187
|
).toThrow('subscription period cannot be represented exactly by this Tempo client')
|
|
184
188
|
})
|
|
185
189
|
|
|
190
|
+
test('accepts dev-prefixed subscription periods for development and tests', () => {
|
|
191
|
+
expect(toSubscriptionPeriodSeconds({ periodCount: '15', periodUnit: 'dev_second' })).toBe(15)
|
|
192
|
+
expect(toSubscriptionPeriodSeconds({ periodCount: '120', periodUnit: 'dev_second' })).toBe(120)
|
|
193
|
+
})
|
|
194
|
+
|
|
186
195
|
test('rejects subscription expiries that cannot be represented by Tempo key authorizations', () => {
|
|
187
196
|
expect(() =>
|
|
188
197
|
toSubscriptionExpirySeconds(toSubscriptionExpiryDate('2026-01-01T00:00:00.500Z')),
|
|
@@ -12,12 +12,15 @@ import type {
|
|
|
12
12
|
/** 4-byte selector for TIP-20 `transfer(address,uint256)`. */
|
|
13
13
|
export const transferSelector = '0xa9059cbb'
|
|
14
14
|
|
|
15
|
-
/** 4-byte selector for TIP-20 `transferWithMemo(address,uint256,
|
|
15
|
+
/** 4-byte selector for TIP-20 `transferWithMemo(address,uint256,bytes32)`. */
|
|
16
16
|
export const transferWithMemoSelector = '0x95777d59'
|
|
17
17
|
|
|
18
18
|
const uint64Max = (1n << 64n) - 1n
|
|
19
|
-
const
|
|
20
|
-
|
|
19
|
+
const subscriptionPeriodUnitSeconds = {
|
|
20
|
+
dev_second: 1n,
|
|
21
|
+
day: 86_400n,
|
|
22
|
+
week: 604_800n,
|
|
23
|
+
} satisfies Record<SubscriptionPeriodUnit, bigint>
|
|
21
24
|
|
|
22
25
|
type SubscriptionRequest = ReturnType<typeof Methods.subscription.schema.request.parse>
|
|
23
26
|
type Authorization = KeyAuthorization.KeyAuthorization
|
|
@@ -63,11 +66,11 @@ export function toSubscriptionPeriodSeconds(request: {
|
|
|
63
66
|
if (!/^[1-9]\d*$/.test(request.periodCount)) {
|
|
64
67
|
throw new VerificationFailedError({ reason: 'periodCount is invalid' })
|
|
65
68
|
}
|
|
66
|
-
|
|
69
|
+
const unitSeconds = subscriptionPeriodUnitSeconds[request.periodUnit]
|
|
70
|
+
if (unitSeconds === undefined) {
|
|
67
71
|
throw new VerificationFailedError({ reason: 'periodUnit is invalid' })
|
|
68
72
|
}
|
|
69
73
|
|
|
70
|
-
const unitSeconds = request.periodUnit === 'day' ? secondsPerDay : secondsPerWeek
|
|
71
74
|
const value = BigInt(request.periodCount) * unitSeconds
|
|
72
75
|
if (value > uint64Max) {
|
|
73
76
|
throw new VerificationFailedError({
|
|
@@ -113,11 +116,6 @@ export function getSubscriptionScopes(
|
|
|
113
116
|
const currency = normalizeAddress(request.currency, 'currency')
|
|
114
117
|
const recipient = normalizeAddress(request.recipient, 'recipient')
|
|
115
118
|
return [
|
|
116
|
-
{
|
|
117
|
-
address: currency,
|
|
118
|
-
selector: transferSelector,
|
|
119
|
-
recipients: [recipient],
|
|
120
|
-
},
|
|
121
119
|
{
|
|
122
120
|
address: currency,
|
|
123
121
|
selector: transferWithMemoSelector,
|
|
@@ -130,15 +128,11 @@ export function getSubscriptionScopes(
|
|
|
130
128
|
export function getSubscriptionRpcAllowedCalls(
|
|
131
129
|
request: Pick<SubscriptionRequest, 'currency' | 'recipient'>,
|
|
132
130
|
) {
|
|
133
|
-
const [
|
|
131
|
+
const [transferWithMemo] = getSubscriptionScopes(request)
|
|
134
132
|
return [
|
|
135
133
|
{
|
|
136
134
|
target: normalizeAddress(request.currency, 'currency'),
|
|
137
135
|
selectorRules: [
|
|
138
|
-
{
|
|
139
|
-
selector: transfer.selector,
|
|
140
|
-
recipients: transfer.recipients,
|
|
141
|
-
},
|
|
142
136
|
{
|
|
143
137
|
selector: transferWithMemo.selector,
|
|
144
138
|
recipients: transferWithMemo.recipients,
|
|
@@ -325,9 +319,9 @@ function assertAuthorizationScopes(
|
|
|
325
319
|
scopes: readonly KeyAuthorization.Scope[] | undefined,
|
|
326
320
|
request: Pick<SubscriptionRequest, 'currency' | 'recipient'>,
|
|
327
321
|
) {
|
|
328
|
-
if (!scopes || scopes.length
|
|
322
|
+
if (!scopes || scopes.length !== 1) {
|
|
329
323
|
throw new VerificationFailedError({
|
|
330
|
-
reason: 'keyAuthorization must contain recipient-scoped
|
|
324
|
+
reason: 'keyAuthorization must contain a recipient-scoped transferWithMemo call',
|
|
331
325
|
})
|
|
332
326
|
}
|
|
333
327
|
|
|
@@ -353,9 +347,6 @@ function assertAuthorizationScopes(
|
|
|
353
347
|
}
|
|
354
348
|
}
|
|
355
349
|
|
|
356
|
-
if (!seen.has(transferSelector)) {
|
|
357
|
-
throw new VerificationFailedError({ reason: 'keyAuthorization must allow transfer' })
|
|
358
|
-
}
|
|
359
350
|
if (!seen.has(transferWithMemoSelector)) {
|
|
360
351
|
throw new VerificationFailedError({ reason: 'keyAuthorization must allow transferWithMemo' })
|
|
361
352
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Address } from 'viem'
|
|
2
2
|
|
|
3
|
-
/** Tempo-supported subscription period units.
|
|
4
|
-
export type SubscriptionPeriodUnit = 'day' | 'week'
|
|
3
|
+
/** Tempo-supported subscription period units. Use `day` or `week` in production; `dev_*` units are for development and tests. */
|
|
4
|
+
export type SubscriptionPeriodUnit = 'dev_second' | 'day' | 'week'
|
|
5
5
|
|
|
6
6
|
/** Access key information used to authorize recurring Tempo payments. */
|
|
7
7
|
export type SubscriptionAccessKey = {
|
package/src/viem/Account.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createClient, http } from 'viem'
|
|
2
2
|
import { privateKeyToAccount } from 'viem/accounts'
|
|
3
|
-
import { mainnet } from 'viem/chains'
|
|
3
|
+
import { tempo as mainnet } from 'viem/tempo/chains'
|
|
4
4
|
import { describe, expect, test } from 'vp/test'
|
|
5
5
|
|
|
6
6
|
import * as Account from './Account.js'
|
package/src/viem/Client.test.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createClient, custom, defineChain, type Hex } from 'viem'
|
|
2
2
|
import { privateKeyToAccount } from 'viem/accounts'
|
|
3
3
|
import { signTransaction } from 'viem/actions'
|
|
4
|
-
import { tempoLocalnet } from 'viem/chains'
|
|
5
4
|
import { Account as TempoAccount, Transaction } from 'viem/tempo'
|
|
5
|
+
import { tempoLocalnet } from 'viem/tempo/chains'
|
|
6
6
|
import { describe, expect, test } from 'vp/test'
|
|
7
7
|
|
|
8
8
|
import * as Client from './Client.js'
|