mppx 0.17.3 → 0.17.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/Errors.d.ts +94 -0
  3. package/dist/Errors.js +83 -0
  4. package/dist/Store.d.ts +199 -11
  5. package/dist/Store.js +527 -48
  6. package/dist/cli/cli.js +141 -137
  7. package/dist/cli/internal.js +28 -6
  8. package/dist/cli/plugins/index.js +16 -12
  9. package/dist/cli/validate/challenge.d.ts +4 -0
  10. package/dist/cli/validate/challenge.js +9 -6
  11. package/dist/cloudflare/ChannelStore.d.ts +97 -0
  12. package/dist/cloudflare/ChannelStore.js +304 -0
  13. package/dist/cloudflare/Channels.d.ts +92 -0
  14. package/dist/cloudflare/Channels.js +325 -0
  15. package/dist/cloudflare/index.d.ts +5 -0
  16. package/dist/cloudflare/index.js +5 -0
  17. package/dist/internal/sse.js +32 -15
  18. package/dist/internal/version.d.ts +2 -2
  19. package/dist/internal/version.js +1 -1
  20. package/dist/stripe/server/Methods.d.ts +2 -0
  21. package/dist/stripe/server/Methods.js +2 -1
  22. package/dist/stripe/server/internal/record-payment.d.ts +49 -0
  23. package/dist/stripe/server/internal/record-payment.js +75 -18
  24. package/dist/tempo/Methods.d.ts +8 -0
  25. package/dist/tempo/Methods.js +18 -2
  26. package/dist/tempo/client/Charge.d.ts +32 -1
  27. package/dist/tempo/client/Charge.js +201 -3
  28. package/dist/tempo/client/Methods.d.ts +16 -0
  29. package/dist/tempo/internal/fee-payer.d.ts +0 -25
  30. package/dist/tempo/internal/fee-payer.js +50 -3
  31. package/dist/tempo/internal/zone.d.ts +79 -0
  32. package/dist/tempo/internal/zone.js +133 -0
  33. package/dist/tempo/server/Charge.d.ts +7 -3
  34. package/dist/tempo/server/Charge.js +98 -4
  35. package/dist/tempo/server/Methods.d.ts +40 -0
  36. package/dist/tempo/server/internal/html.gen.js +1 -1
  37. package/dist/tempo/session/server/ChannelStore.d.ts +5 -0
  38. package/dist/tempo/session/server/ChannelStore.js +2 -2
  39. package/dist/tempo/session/server/CredentialVerification.js +1 -1
  40. package/dist/validation/core.js +2 -0
  41. package/package.json +5 -1
@@ -0,0 +1,79 @@
1
+ import { type Address, type Client, type Hex, type TransactionReceipt } from 'viem';
2
+ /** Default time a payer waits for a Zone withdrawal to settle on Tempo. */
3
+ export declare const defaultSettlementTimeoutMs = 60000;
4
+ /** A withdrawal as `ZonePortal.processWithdrawals` receives it on Tempo. */
5
+ export type Withdrawal = {
6
+ token: Address;
7
+ senderTag: Hex;
8
+ to: Address;
9
+ amount: bigint;
10
+ memo: Hex;
11
+ gasLimit: bigint;
12
+ fallbackNonce: bigint;
13
+ callbackData: Hex;
14
+ encryptedSender: Hex;
15
+ };
16
+ /** A `ZonePortal.WithdrawalProcessed` event. */
17
+ export type ProcessedEvent = {
18
+ to: Address;
19
+ senderTag: Hex;
20
+ token: Address;
21
+ amount: bigint;
22
+ callbackSuccess: boolean;
23
+ };
24
+ /** Zones a challenge accepts: a list of Zone IDs, or `true` for any Zone. */
25
+ export type Accepted = readonly number[] | true;
26
+ /** Returns whether a value is a valid Zone ID: a positive integer below the Zone chain ID ranges. */
27
+ export declare function isId(zoneId: number): boolean;
28
+ /** Returns whether a challenge's `zones` accepts withdrawals from a Zone. */
29
+ export declare function isAccepted(zones: Accepted | undefined, zoneId: number): boolean;
30
+ /** Returns the Tempo portal address of a Zone. */
31
+ export declare function portalAddress(zoneId: number): Address;
32
+ /**
33
+ * Derives a Zone ID from a Zone chain ID.
34
+ *
35
+ * Zones on Tempo mainnet and Moderato use reserved bases (`421700000` and
36
+ * `1424310000`). Zones on any other parent chain use `(parentChainId << 32) | zoneId`.
37
+ */
38
+ export declare function idFromChainId(chainId: number): number;
39
+ /**
40
+ * Derives the parent Tempo chain ID of a Zone chain ID, or `undefined` when
41
+ * the chain ID doesn't follow a known Zone scheme.
42
+ */
43
+ export declare function parentChainIdFromChainId(chainId: number): number | undefined;
44
+ /**
45
+ * Derives a withdrawal's sender tag, which identifies it in the
46
+ * `WithdrawalProcessed` event on Tempo.
47
+ */
48
+ export declare function senderTag(parameters: {
49
+ fallbackNonce: bigint;
50
+ sender: Address;
51
+ transactionHash: Hex;
52
+ }): Hex;
53
+ /** Returns the `WithdrawalProcessed` event a portal emitted for a sender tag. */
54
+ export declare function findProcessedEvent(receipt: Pick<TransactionReceipt, 'logs'>, parameters: {
55
+ portal: Address;
56
+ senderTag: Hex;
57
+ }): ProcessedEvent | undefined;
58
+ /**
59
+ * Finds the withdrawal for a sender tag in the calldata of a settlement
60
+ * transaction's top-level `processWithdrawals` calls to the portal.
61
+ */
62
+ export declare function findWithdrawal(calls: readonly {
63
+ to?: Address | null | undefined;
64
+ data?: Hex | undefined;
65
+ }[], parameters: {
66
+ portal: Address;
67
+ senderTag: Hex;
68
+ }): Withdrawal | undefined;
69
+ /**
70
+ * Waits until a portal emits `WithdrawalProcessed` for a sender tag and
71
+ * returns the Tempo transaction hash that settled it.
72
+ */
73
+ export declare function waitForSettlement(client: Client, parameters: {
74
+ portal: Address;
75
+ senderTag: Hex;
76
+ to?: Address | undefined;
77
+ timeoutMs?: number | undefined;
78
+ }): Promise<Hex>;
79
+ //# sourceMappingURL=zone.d.ts.map
@@ -0,0 +1,133 @@
1
+ import { AbiParameters, Hash } from 'ox';
2
+ import { decodeFunctionData, getAbiItem, parseEventLogs, } from 'viem';
3
+ import { getBlockNumber, getLogs } from 'viem/actions';
4
+ import { Abis, Addresses } from 'viem/tempo';
5
+ import * as TempoAddress from './address.js';
6
+ /** Default time a payer waits for a Zone withdrawal to settle on Tempo. */
7
+ export const defaultSettlementTimeoutMs = 60_000;
8
+ /** Number of Tempo blocks searched back for a settled Zone withdrawal. */
9
+ const lookbackBlocks = 7200n;
10
+ /** Time between polls for a settled Zone withdrawal. */
11
+ const pollingIntervalMs = 500;
12
+ const withdrawalProcessed = getAbiItem({ abi: Abis.zonePortal, name: 'WithdrawalProcessed' });
13
+ /**
14
+ * Zone IDs from here up read as Zone chain IDs in viem's portal lookup, which
15
+ * would map them to another Zone's portal.
16
+ */
17
+ const maxIdExclusive = 421_700_000;
18
+ /** Returns whether a value is a valid Zone ID: a positive integer below the Zone chain ID ranges. */
19
+ export function isId(zoneId) {
20
+ return Number.isInteger(zoneId) && zoneId > 0 && zoneId < maxIdExclusive;
21
+ }
22
+ /** Returns whether a challenge's `zones` accepts withdrawals from a Zone. */
23
+ export function isAccepted(zones, zoneId) {
24
+ if (!isId(zoneId))
25
+ return false;
26
+ return zones === true || (zones?.includes(zoneId) ?? false);
27
+ }
28
+ /** Returns the Tempo portal address of a Zone. */
29
+ export function portalAddress(zoneId) {
30
+ return Addresses.zonePortal(zoneId);
31
+ }
32
+ /**
33
+ * Derives a Zone ID from a Zone chain ID.
34
+ *
35
+ * Zones on Tempo mainnet and Moderato use reserved bases (`421700000` and
36
+ * `1424310000`). Zones on any other parent chain use `(parentChainId << 32) | zoneId`.
37
+ */
38
+ export function idFromChainId(chainId) {
39
+ if (chainId >= 2 ** 32)
40
+ return chainId % 2 ** 32;
41
+ if (chainId > 1_424_310_000 && chainId < 1_424_320_000)
42
+ return chainId - 1_424_310_000;
43
+ if (chainId > 421_700_000 && chainId < 421_710_000)
44
+ return chainId - 421_700_000;
45
+ throw new Error(`Cannot derive a Zone ID from chain ID ${chainId}. Pass \`zoneId\`.`);
46
+ }
47
+ /**
48
+ * Derives the parent Tempo chain ID of a Zone chain ID, or `undefined` when
49
+ * the chain ID doesn't follow a known Zone scheme.
50
+ */
51
+ export function parentChainIdFromChainId(chainId) {
52
+ if (chainId >= 2 ** 32)
53
+ return Math.floor(chainId / 2 ** 32);
54
+ if (chainId > 1_424_310_000 && chainId < 1_424_320_000)
55
+ return 42_431;
56
+ if (chainId > 421_700_000 && chainId < 421_710_000)
57
+ return 4_217;
58
+ return undefined;
59
+ }
60
+ /**
61
+ * Derives a withdrawal's sender tag, which identifies it in the
62
+ * `WithdrawalProcessed` event on Tempo.
63
+ */
64
+ export function senderTag(parameters) {
65
+ return Hash.keccak256(AbiParameters.encodePacked(['address', 'bytes32', 'uint64'], [parameters.sender, parameters.transactionHash, parameters.fallbackNonce]));
66
+ }
67
+ /** Returns the `WithdrawalProcessed` event a portal emitted for a sender tag. */
68
+ export function findProcessedEvent(receipt, parameters) {
69
+ const logs = parseEventLogs({ abi: [withdrawalProcessed], logs: receipt.logs });
70
+ const log = logs.find((log) => TempoAddress.isEqual(log.address, parameters.portal) &&
71
+ log.args.senderTag.toLowerCase() === parameters.senderTag.toLowerCase());
72
+ return log?.args;
73
+ }
74
+ /**
75
+ * Finds the withdrawal for a sender tag in the calldata of a settlement
76
+ * transaction's top-level `processWithdrawals` calls to the portal.
77
+ */
78
+ export function findWithdrawal(calls, parameters) {
79
+ for (const call of calls) {
80
+ if (!call.to || !call.data || !TempoAddress.isEqual(call.to, parameters.portal))
81
+ continue;
82
+ let decoded;
83
+ try {
84
+ decoded = decodeFunctionData({ abi: Abis.zonePortal, data: call.data });
85
+ }
86
+ catch {
87
+ continue;
88
+ }
89
+ if (decoded.functionName !== 'processWithdrawals')
90
+ continue;
91
+ const [withdrawals] = decoded.args;
92
+ const withdrawal = withdrawals.find((withdrawal) => withdrawal.senderTag.toLowerCase() === parameters.senderTag.toLowerCase());
93
+ if (withdrawal)
94
+ return withdrawal;
95
+ }
96
+ return undefined;
97
+ }
98
+ /**
99
+ * Waits until a portal emits `WithdrawalProcessed` for a sender tag and
100
+ * returns the Tempo transaction hash that settled it.
101
+ */
102
+ export async function waitForSettlement(client, parameters) {
103
+ const { timeoutMs = defaultSettlementTimeoutMs } = parameters;
104
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0)
105
+ throw new Error('Zone settlement timeout must be a finite, non-negative number.');
106
+ let latest = await getBlockNumber(client, { cacheTime: 0 });
107
+ // Scan the lookback window once, then only blocks added since the previous poll.
108
+ let fromBlock = latest > lookbackBlocks ? latest - lookbackBlocks : 0n;
109
+ const deadline = Date.now() + timeoutMs;
110
+ while (true) {
111
+ if (fromBlock <= latest) {
112
+ const logs = await getLogs(client, {
113
+ address: parameters.portal,
114
+ event: withdrawalProcessed,
115
+ args: {
116
+ senderTag: parameters.senderTag,
117
+ ...(parameters.to ? { to: parameters.to } : {}),
118
+ },
119
+ fromBlock,
120
+ toBlock: latest,
121
+ });
122
+ const hash = logs[0]?.transactionHash;
123
+ if (hash)
124
+ return hash;
125
+ fromBlock = latest + 1n;
126
+ }
127
+ if (Date.now() + pollingIntervalMs > deadline)
128
+ throw new Error(`Zone withdrawal ${parameters.senderTag} did not settle on Tempo within ${timeoutMs}ms.`);
129
+ await new Promise((resolve) => setTimeout(resolve, pollingIntervalMs));
130
+ latest = await getBlockNumber(client, { cacheTime: 0 });
131
+ }
132
+ }
133
+ //# sourceMappingURL=zone.js.map
@@ -61,8 +61,10 @@ export declare namespace charge {
61
61
  * two thirds of this budget. If it fails with an unknown outcome (e.g. a
62
62
  * timeout, a lost connection, or "already known"), mppx polls for the
63
63
  * receipt until the deadline, or until 2 seconds after the transaction's
64
- * `validBefore` followed by one final lookup, before surfacing the broadcast
65
- * error. Definitive rejections fail immediately.
64
+ * `validBefore` followed by one final lookup, before throwing
65
+ * `Errors.BroadcastOutcomeUnknownError` with the transaction hash and
66
+ * `validBefore`, and the broadcast error as `cause`. Definitive rejections
67
+ * fail immediately with the RPC error.
66
68
  * @default 30_000
67
69
  */
68
70
  confirmationTimeoutMs?: number | undefined;
@@ -143,7 +145,9 @@ export declare namespace charge {
143
145
  * report `status: 'success'` based on simulation alone — if the
144
146
  * transaction reverts on-chain after broadcast (e.g. due to a state
145
147
  * change between simulation and inclusion), the receipt will not reflect
146
- * the failure.
148
+ * the failure. An ambiguous broadcast failure (a timeout, a lost
149
+ * connection, a 5xx) throws `Errors.BroadcastOutcomeUnknownError` without
150
+ * polling for a receipt.
147
151
  */
148
152
  waitForConfirmation?: boolean | undefined;
149
153
  } & Client.getResolver.Parameters & Account.resolve.Parameters & Defaults & Method.ComposableHooks<typeof Methods.charge>;
@@ -3,7 +3,7 @@ import { decodeFunctionData, formatUnits, keccak256, parseEventLogs, WaitForTran
3
3
  import { getTransaction, getTransactionReceipt, sendRawTransaction, sendRawTransactionSync, signTransaction, verifyTypedData, waitForTransactionReceipt, call as viem_call, } from 'viem/actions';
4
4
  import { Abis, Actions, Transaction } from 'viem/tempo';
5
5
  import { tempo as tempo_chain } from 'viem/tempo/chains';
6
- import { CredentialReplayedError, PaymentError, VerificationFailedError } from '../../Errors.js';
6
+ import { BroadcastOutcomeUnknownError, CredentialReplayedError, PaymentError, VerificationFailedError, } from '../../Errors.js';
7
7
  import * as Expires from '../../Expires.js';
8
8
  import * as Method from '../../Method.js';
9
9
  import * as Store from '../../Store.js';
@@ -18,6 +18,7 @@ import { resolveFeeToken } from '../internal/fee-token.js';
18
18
  import * as MachineTokenCharge from '../internal/machine-token-charge.js';
19
19
  import * as Proof from '../internal/proof.js';
20
20
  import * as Selectors from '../internal/selectors.js';
21
+ import * as Zone from '../internal/zone.js';
21
22
  import * as Methods from '../Methods.js';
22
23
  import { fallbackStore } from './internal/fallback-store.js';
23
24
  import * as Relay from './Relay.js';
@@ -33,7 +34,7 @@ import * as SponsorBudget from './SponsorBudget.js';
33
34
  * ```
34
35
  */
35
36
  export function charge(parameters = {}) {
36
- const { machineTokenEnabled, allowedFeeTokens: configuredAllowedFeeTokens, amount, confirmationTimeoutMs = 30_000, currency = defaults.resolveCurrency(parameters), decimals = defaults.decimals, description, externalId, feeToken: configuredFeeToken, feePayerPolicy, html, relay, sponsorBudget, splits, supportedModes, validateSender, waitForConfirmation = true, } = parameters;
37
+ const { machineTokenEnabled, allowedFeeTokens: configuredAllowedFeeTokens, amount, confirmationTimeoutMs = 30_000, currency = defaults.resolveCurrency(parameters), decimals = defaults.decimals, description, externalId, feeToken: configuredFeeToken, feePayerPolicy, html, relay, sponsorBudget, splits, supportedModes, validateSender, waitForConfirmation = true, zones, } = parameters;
37
38
  if (configuredAllowedFeeTokens?.length === 0)
38
39
  throw new Error('`allowedFeeTokens` must contain at least one token.');
39
40
  const storeKeyPrefix = parameters.storeKeyPrefix ?? '';
@@ -187,6 +188,55 @@ export function charge(parameters = {}) {
187
188
  const payer = payers.size === 1 ? [...payers][0] : undefined;
188
189
  return { payer, receipt, sender, transfers };
189
190
  }
191
+ /**
192
+ * Validates a payment that a Zone withdrawal settled on Tempo: the portal's
193
+ * `WithdrawalProcessed` event pays the recipient, and the withdrawal's memo in
194
+ * the `processWithdrawals` calldata binds it to this challenge.
195
+ */
196
+ async function validateZoneCredential(payload, context) {
197
+ const { amount, challenge, client, currency, methodDetails, recipient, supportedModes } = context;
198
+ if (supportedModes && !supportedModes.includes('push'))
199
+ throw new MismatchError('Zone credentials are not supported for this challenge.', {});
200
+ if (!Zone.isAccepted(methodDetails?.zones, payload.zoneId))
201
+ throw new MismatchError('Zone is not accepted for this challenge.', {
202
+ zoneId: String(payload.zoneId),
203
+ });
204
+ if (methodDetails?.splits)
205
+ throw new MismatchError('Zone credentials do not support split payments.', {});
206
+ const portal = Zone.portalAddress(payload.zoneId);
207
+ const senderTag = payload.senderTag;
208
+ const hash = payload.hash;
209
+ const receipt = await getTransactionReceipt(client, { hash });
210
+ if (receipt.status !== 'success')
211
+ throw new MismatchError('Payment verification failed: settlement transaction reverted.', {
212
+ hash,
213
+ });
214
+ const event = Zone.findProcessedEvent(receipt, { portal, senderTag });
215
+ if (!event)
216
+ throw new MismatchError('Payment verification failed: Zone withdrawal not settled.', {
217
+ senderTag,
218
+ });
219
+ if (!event.callbackSuccess)
220
+ throw new MismatchError('Payment verification failed: Zone withdrawal bounced.', {
221
+ senderTag,
222
+ });
223
+ // The event has no memo, so the calldata's withdrawal shows what was paid and for which challenge.
224
+ const transaction = await getTransaction(client, { hash });
225
+ const calls = transaction.calls ??
226
+ (transaction.to ? [{ to: transaction.to, data: transaction.input }] : []);
227
+ const withdrawal = Zone.findWithdrawal(calls, { portal, senderTag });
228
+ if (!withdrawal ||
229
+ withdrawal.gasLimit !== 0n ||
230
+ !TempoAddress.isEqual(withdrawal.to, recipient) ||
231
+ !TempoAddress.isEqual(withdrawal.token, currency) ||
232
+ withdrawal.amount.toString() !== amount)
233
+ throw new MismatchError('Payment verification failed: Zone withdrawal not found.', {
234
+ senderTag,
235
+ });
236
+ if (!isChallengeBound([withdrawal.memo], { challengeId: challenge.id, realm: challenge.realm }))
237
+ throw new CredentialReplayedError({ reason: 'memo is not bound to this challenge' });
238
+ return { hash, portal, receipt, senderTag };
239
+ }
190
240
  async function validateProofCredential(credential, payload, context) {
191
241
  const { chainId, challenge, client, isZeroAmount } = context;
192
242
  if (!isZeroAmount)
@@ -282,6 +332,18 @@ export function charge(parameters = {}) {
282
332
  type: 'proof',
283
333
  };
284
334
  }
335
+ case 'zone': {
336
+ const { hash, portal, receipt, senderTag } = await validateZoneCredential(context.payload, context);
337
+ return {
338
+ details: { mode: 'push' },
339
+ hash,
340
+ payer: undefined,
341
+ portal,
342
+ receipt,
343
+ senderTag,
344
+ type: 'zone',
345
+ };
346
+ }
285
347
  case 'transaction': {
286
348
  const { fundingCurrency, isFeePayerTx, serializedTransaction, settlementSenders, transaction, transfers, } = await validateTransactionCredential(credential, context.payload, request, context);
287
349
  return {
@@ -316,6 +378,7 @@ export function charge(parameters = {}) {
316
378
  recipient,
317
379
  splits,
318
380
  supportedModes,
381
+ zones,
319
382
  },
320
383
  stableBinding: chargeBinding,
321
384
  html: html
@@ -450,6 +513,15 @@ export function charge(parameters = {}) {
450
513
  }
451
514
  return toReceipt(receipt.transactionHash, fundingCurrency);
452
515
  }
516
+ case 'zone': {
517
+ const { portal, receipt, senderTag } = validated;
518
+ if (!(await tryClaimZoneWithdrawal(store, portal, senderTag, replayExpires))) {
519
+ throw new CredentialReplayedError({
520
+ reason: 'Zone withdrawal has already been used',
521
+ });
522
+ }
523
+ return toReceipt(receipt.transactionHash);
524
+ }
453
525
  case 'proof': {
454
526
  if (proofStore && !(await tryClaimProof(proofStore, challenge.id, replayExpires))) {
455
527
  throw new CredentialReplayedError({
@@ -639,7 +711,11 @@ export function charge(parameters = {}) {
639
711
  if (!recovered && validUntil < deadline)
640
712
  recovered = await withDeadline(getTransactionReceipt(client, { hash: finalHash }), Math.max(deadline, Date.now() + client.pollingInterval), broadcastError).catch(() => undefined);
641
713
  if (!recovered)
642
- throw broadcastError;
714
+ throw new BroadcastOutcomeUnknownError({
715
+ cause: broadcastError,
716
+ transactionHash: finalHash,
717
+ validBefore: transaction.validBefore,
718
+ });
643
719
  receipt = recovered;
644
720
  }
645
721
  if (reservation)
@@ -663,8 +739,18 @@ export function charge(parameters = {}) {
663
739
  // Optimistic path: broadcast without waiting for confirmation
664
740
  // (simulation above already ran). The returned receipt assumes
665
741
  // success — callers opt in via waitForConfirmation: false.
742
+ const transactionHash = finalHash;
666
743
  const reference = await sendRawTransaction(client, {
667
744
  serializedTransaction: serializedTransaction_final,
745
+ }).catch((broadcastError) => {
746
+ // Without a receipt wait, an ambiguous failure leaves the outcome to the caller.
747
+ if (!isAmbiguousBroadcastError(broadcastError))
748
+ throw broadcastError;
749
+ throw new BroadcastOutcomeUnknownError({
750
+ cause: broadcastError,
751
+ transactionHash,
752
+ validBefore: transaction.validBefore,
753
+ });
668
754
  });
669
755
  if (reference.toLowerCase() !== finalHash.toLowerCase())
670
756
  throw new VerificationFailedError({
@@ -711,7 +797,7 @@ function chargeBinding(request) {
711
797
  // Exhaustively destructure so new charge request fields require an explicit binding decision.
712
798
  const { amount, currency, description, externalId, methodDetails, recipient, ...requestRest } = request;
713
799
  requestRest;
714
- const { chainId, feePayer, machineTokenEnabled, splits, supportedModes, ...methodDetailsRest } = methodDetails ?? {};
800
+ const { chainId, feePayer, machineTokenEnabled, splits, supportedModes, zones, ...methodDetailsRest } = methodDetails ?? {};
715
801
  methodDetailsRest;
716
802
  void feePayer;
717
803
  return {
@@ -724,6 +810,7 @@ function chargeBinding(request) {
724
810
  recipient,
725
811
  splits,
726
812
  supportedModes,
813
+ zones,
727
814
  };
728
815
  }
729
816
  function getExpectedTransfers(parameters) {
@@ -953,6 +1040,13 @@ function getHashStoreKey(hash) {
953
1040
  function getProofStoreKey(challengeId) {
954
1041
  return `mppx:charge:proof:${challengeId}`;
955
1042
  }
1043
+ /** @internal */
1044
+ function getZoneWithdrawalStoreKey(portal, senderTag) {
1045
+ return `mppx:charge:zone:${portal.toLowerCase()}:${senderTag.toLowerCase()}`;
1046
+ }
1047
+ async function tryClaimZoneWithdrawal(store, portal, senderTag, expires) {
1048
+ return Store.tryClaim(store, getZoneWithdrawalStoreKey(portal, senderTag), expires);
1049
+ }
956
1050
  async function tryClaimHash(store, hash, expires) {
957
1051
  return Store.tryClaim(store, getHashStoreKey(hash), expires);
958
1052
  }
@@ -51,6 +51,11 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
51
51
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
52
52
  signature: import("zod/mini").ZodMiniString<string>;
53
53
  type: import("zod/mini").ZodMiniLiteral<"proof">;
54
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
55
+ hash: import("zod/mini").ZodMiniString<string>;
56
+ senderTag: import("zod/mini").ZodMiniString<string>;
57
+ type: import("zod/mini").ZodMiniLiteral<"zone">;
58
+ zoneId: import("zod/mini").ZodMiniNumber<number>;
54
59
  }, import("zod/v4/core").$strip>], "type">;
55
60
  };
56
61
  request: import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniObject<{
@@ -73,6 +78,7 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
73
78
  pull: "pull";
74
79
  push: "push";
75
80
  }>>>;
81
+ zones: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniLiteral<true>, import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniNumber<number>>]>>;
76
82
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniTransform<{
77
83
  currency: string;
78
84
  description?: string | undefined;
@@ -89,6 +95,7 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
89
95
  amount: string;
90
96
  }[] | undefined;
91
97
  supportedModes?: ("pull" | "push")[] | undefined;
98
+ zones?: true | number[] | undefined;
92
99
  } | undefined;
93
100
  }, {
94
101
  machineTokenEnabled?: boolean | undefined;
@@ -107,6 +114,7 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
107
114
  recipient: `0x${string}`;
108
115
  }[] | undefined;
109
116
  supportedModes?: ("pull" | "push")[] | undefined;
117
+ zones?: true | number[] | undefined;
110
118
  }>>;
111
119
  };
112
120
  }, charge_.DeriveDefaults<NoExtraKeys<parameters, tempo.Parameters>>, undefined, {}, string | undefined>, import("../../Method.js").Server<{
@@ -213,6 +221,11 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
213
221
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
214
222
  signature: import("zod/mini").ZodMiniString<string>;
215
223
  type: import("zod/mini").ZodMiniLiteral<"proof">;
224
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
225
+ hash: import("zod/mini").ZodMiniString<string>;
226
+ senderTag: import("zod/mini").ZodMiniString<string>;
227
+ type: import("zod/mini").ZodMiniLiteral<"zone">;
228
+ zoneId: import("zod/mini").ZodMiniNumber<number>;
216
229
  }, import("zod/v4/core").$strip>], "type">;
217
230
  };
218
231
  request: import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniObject<{
@@ -235,6 +248,7 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
235
248
  pull: "pull";
236
249
  push: "push";
237
250
  }>>>;
251
+ zones: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniLiteral<true>, import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniNumber<number>>]>>;
238
252
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniTransform<{
239
253
  currency: string;
240
254
  description?: string | undefined;
@@ -251,6 +265,7 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
251
265
  amount: string;
252
266
  }[] | undefined;
253
267
  supportedModes?: ("pull" | "push")[] | undefined;
268
+ zones?: true | number[] | undefined;
254
269
  } | undefined;
255
270
  }, {
256
271
  machineTokenEnabled?: boolean | undefined;
@@ -269,6 +284,7 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
269
284
  recipient: `0x${string}`;
270
285
  }[] | undefined;
271
286
  supportedModes?: ("pull" | "push")[] | undefined;
287
+ zones?: true | number[] | undefined;
272
288
  }>>;
273
289
  };
274
290
  }, charge_.DeriveDefaults<Omit<parameters, "chainId" | "currencies" | "currency" | "decimals"> & {
@@ -2323,6 +2339,11 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
2323
2339
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
2324
2340
  signature: import("zod/mini").ZodMiniString<string>;
2325
2341
  type: import("zod/mini").ZodMiniLiteral<"proof">;
2342
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
2343
+ hash: import("zod/mini").ZodMiniString<string>;
2344
+ senderTag: import("zod/mini").ZodMiniString<string>;
2345
+ type: import("zod/mini").ZodMiniLiteral<"zone">;
2346
+ zoneId: import("zod/mini").ZodMiniNumber<number>;
2326
2347
  }, import("zod/v4/core").$strip>], "type">;
2327
2348
  };
2328
2349
  request: import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniObject<{
@@ -2345,6 +2366,7 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
2345
2366
  pull: "pull";
2346
2367
  push: "push";
2347
2368
  }>>>;
2369
+ zones: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniLiteral<true>, import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniNumber<number>>]>>;
2348
2370
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniTransform<{
2349
2371
  currency: string;
2350
2372
  description?: string | undefined;
@@ -2361,6 +2383,7 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
2361
2383
  amount: string;
2362
2384
  }[] | undefined;
2363
2385
  supportedModes?: ("pull" | "push")[] | undefined;
2386
+ zones?: true | number[] | undefined;
2364
2387
  } | undefined;
2365
2388
  }, {
2366
2389
  machineTokenEnabled?: boolean | undefined;
@@ -2379,6 +2402,7 @@ export declare function tempo<const parameters extends tempo.Parameters>(paramet
2379
2402
  recipient: `0x${string}`;
2380
2403
  }[] | undefined;
2381
2404
  supportedModes?: ("pull" | "push")[] | undefined;
2405
+ zones?: true | number[] | undefined;
2382
2406
  }>>;
2383
2407
  };
2384
2408
  }, charge_.DeriveDefaults<Omit<parameters, "chainId" | "currencies" | "currency" | "decimals"> & {
@@ -2467,6 +2491,11 @@ declare function chargeOffers<const parameters extends CurrencyParameters<charge
2467
2491
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
2468
2492
  signature: import("zod/mini").ZodMiniString<string>;
2469
2493
  type: import("zod/mini").ZodMiniLiteral<"proof">;
2494
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
2495
+ hash: import("zod/mini").ZodMiniString<string>;
2496
+ senderTag: import("zod/mini").ZodMiniString<string>;
2497
+ type: import("zod/mini").ZodMiniLiteral<"zone">;
2498
+ zoneId: import("zod/mini").ZodMiniNumber<number>;
2470
2499
  }, import("zod/v4/core").$strip>], "type">;
2471
2500
  };
2472
2501
  request: import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniObject<{
@@ -2489,6 +2518,7 @@ declare function chargeOffers<const parameters extends CurrencyParameters<charge
2489
2518
  pull: "pull";
2490
2519
  push: "push";
2491
2520
  }>>>;
2521
+ zones: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniLiteral<true>, import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniNumber<number>>]>>;
2492
2522
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniTransform<{
2493
2523
  currency: string;
2494
2524
  description?: string | undefined;
@@ -2505,6 +2535,7 @@ declare function chargeOffers<const parameters extends CurrencyParameters<charge
2505
2535
  amount: string;
2506
2536
  }[] | undefined;
2507
2537
  supportedModes?: ("pull" | "push")[] | undefined;
2538
+ zones?: true | number[] | undefined;
2508
2539
  } | undefined;
2509
2540
  }, {
2510
2541
  machineTokenEnabled?: boolean | undefined;
@@ -2523,6 +2554,7 @@ declare function chargeOffers<const parameters extends CurrencyParameters<charge
2523
2554
  recipient: `0x${string}`;
2524
2555
  }[] | undefined;
2525
2556
  supportedModes?: ("pull" | "push")[] | undefined;
2557
+ zones?: true | number[] | undefined;
2526
2558
  }>>;
2527
2559
  };
2528
2560
  }, charge_.DeriveDefaults<Omit<parameters, "chainId" | "currencies" | "currency" | "decimals"> & {
@@ -2543,6 +2575,11 @@ declare function chargeOffers<const parameters extends CurrencyParameters<charge
2543
2575
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
2544
2576
  signature: import("zod/mini").ZodMiniString<string>;
2545
2577
  type: import("zod/mini").ZodMiniLiteral<"proof">;
2578
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
2579
+ hash: import("zod/mini").ZodMiniString<string>;
2580
+ senderTag: import("zod/mini").ZodMiniString<string>;
2581
+ type: import("zod/mini").ZodMiniLiteral<"zone">;
2582
+ zoneId: import("zod/mini").ZodMiniNumber<number>;
2546
2583
  }, import("zod/v4/core").$strip>], "type">;
2547
2584
  };
2548
2585
  request: import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniObject<{
@@ -2565,6 +2602,7 @@ declare function chargeOffers<const parameters extends CurrencyParameters<charge
2565
2602
  pull: "pull";
2566
2603
  push: "push";
2567
2604
  }>>>;
2605
+ zones: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniLiteral<true>, import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniNumber<number>>]>>;
2568
2606
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniTransform<{
2569
2607
  currency: string;
2570
2608
  description?: string | undefined;
@@ -2581,6 +2619,7 @@ declare function chargeOffers<const parameters extends CurrencyParameters<charge
2581
2619
  amount: string;
2582
2620
  }[] | undefined;
2583
2621
  supportedModes?: ("pull" | "push")[] | undefined;
2622
+ zones?: true | number[] | undefined;
2584
2623
  } | undefined;
2585
2624
  }, {
2586
2625
  machineTokenEnabled?: boolean | undefined;
@@ -2599,6 +2638,7 @@ declare function chargeOffers<const parameters extends CurrencyParameters<charge
2599
2638
  recipient: `0x${string}`;
2600
2639
  }[] | undefined;
2601
2640
  supportedModes?: ("pull" | "push")[] | undefined;
2641
+ zones?: true | number[] | undefined;
2602
2642
  }>>;
2603
2643
  };
2604
2644
  }, charge_.DeriveDefaults<Omit<parameters, "chainId" | "currencies" | "currency" | "decimals"> & {