mppx 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,8 +17,6 @@ export function x402() {
17
17
  if (!header)
18
18
  return [];
19
19
  const paymentRequired = x402_Header.decodePaymentRequiredEnvelope(header);
20
- if (response.url && paymentRequired.resource.url !== response.url)
21
- throw new Error('x402 payment-required resource does not match response URL.');
22
20
  return paymentRequired.accepts.flatMap((rawAccepted, index) => {
23
21
  const parsed = x402_Types.PaymentRequirementsSchema.safeParse(rawAccepted);
24
22
  if (!parsed.success)
@@ -1,5 +1,5 @@
1
1
  /** Current mppx package version. */
2
- export declare const version = "0.10.1";
2
+ export declare const version = "0.11.0";
3
3
  /** Canonical SDK identifier for this mppx release. */
4
- export declare const sdkIdentifier = "mppx/0.10.1";
4
+ export declare const sdkIdentifier = "mppx/0.11.0";
5
5
  //# sourceMappingURL=version.d.ts.map
@@ -1,6 +1,6 @@
1
1
  // Generated by scripts/sync-version.ts.
2
2
  /** Current mppx package version. */
3
- export const version = '0.10.1';
3
+ export const version = '0.11.0';
4
4
  /** Canonical SDK identifier for this mppx release. */
5
5
  export const sdkIdentifier = `mppx/${version}`;
6
6
  //# sourceMappingURL=version.js.map
@@ -121,13 +121,21 @@ export function stripe(parameters) {
121
121
  }));
122
122
  }
123
123
  function makeTempoSession(params) {
124
- const { recipient, ...rest } = params;
124
+ const { recipient, onSessionSettlement, ...rest } = params;
125
125
  return tempoSession({
126
126
  currency: tempoCurrency,
127
127
  recipient,
128
128
  ...(!livemode && { testnet: true }),
129
129
  ...(hostedTempoFeePayer && { feePayer: hostedTempoFeePayer }),
130
130
  ...rest,
131
+ async onSessionSettlement(context) {
132
+ await tempoPaymentHandler({
133
+ intent: 'session',
134
+ receipt: { reference: context.txHash },
135
+ request: { amount: context.delta.toString() },
136
+ });
137
+ await onSessionSettlement?.(context);
138
+ },
131
139
  });
132
140
  }
133
141
  function makeBaseCharge(params) {
@@ -283,7 +291,7 @@ function customRails(additional) {
283
291
  }
284
292
  function createPaymentSuccessHandler(client, network, connect, metadata) {
285
293
  return (params) => {
286
- const { challenge, receipt, request, requestInput } = params;
294
+ const { challenge, intent, receipt, request, requestInput } = params;
287
295
  if (receipt?.reference && request?.amount) {
288
296
  const paymentIntentOptionsInput = requestInput?.paymentIntentOptions;
289
297
  const paymentIntentOptions = typeof paymentIntentOptionsInput === 'function' ? undefined : paymentIntentOptionsInput;
@@ -300,7 +308,7 @@ function createPaymentSuccessHandler(client, network, connect, metadata) {
300
308
  reference: receipt.reference,
301
309
  amount: String(request.amount),
302
310
  ...(connect && { connect }),
303
- analyticsMetadata: buildAnalytics({ challenge }),
311
+ analyticsMetadata: buildAnalytics({ challenge, intent }),
304
312
  ...(Object.keys(resolvedPaymentIntentOptions).length > 0 && {
305
313
  paymentIntentOptions: resolvedPaymentIntentOptions,
306
314
  }),
@@ -2,5 +2,6 @@ import type * as Challenge from '../../../Challenge.js';
2
2
  /** Builds Stripe metadata used to identify and analyze MPP payments. */
3
3
  export declare function buildAnalytics(parameters: {
4
4
  challenge?: Pick<Challenge.Challenge, 'id' | 'intent'> | undefined;
5
+ intent?: string | undefined;
5
6
  }): Record<string, string>;
6
7
  //# sourceMappingURL=analytics.d.ts.map
@@ -2,13 +2,13 @@ import { sdkIdentifier } from '../../../internal/version.js';
2
2
  import { machinePaymentMetadata } from '../../internal/constants.js';
3
3
  /** Builds Stripe metadata used to identify and analyze MPP payments. */
4
4
  export function buildAnalytics(parameters) {
5
- const { challenge } = parameters;
5
+ const { challenge, intent = challenge?.intent } = parameters;
6
6
  const metadata = {
7
7
  ...machinePaymentMetadata,
8
8
  mpp_sdk: sdkIdentifier,
9
+ ...(intent && { mpp_intent: intent }),
9
10
  ...(challenge && {
10
11
  mpp_challenge_id: challenge.id,
11
- mpp_intent: challenge.intent,
12
12
  }),
13
13
  };
14
14
  return Object.fromEntries(Object.entries(metadata).map(([key, value]) => [key, [...value].slice(0, 500).join('')]));
@@ -13,9 +13,9 @@ export function recordCryptoPayment(client, parameters) {
13
13
  const { network, reference, amount, connect, analyticsMetadata, paymentIntentOptions } = parameters;
14
14
  const { customer, hooks, metadata, receipt_email } = paymentIntentOptions ?? {};
15
15
  const { stripeNetworkName, tokenDecimals } = NETWORK_CONFIG[network];
16
- const amountCents = Math.round(Number(amount) / 10 ** (tokenDecimals - 2));
16
+ const amountCents = Number(BigInt(amount) / 10n ** BigInt(tokenDecimals - 2));
17
17
  if (amountCents < 1) {
18
- console.warn(`[stripe] skipping PI recording: ${amount} raw units on ${network} rounds to ${amountCents} cents (below Stripe minimum)`);
18
+ console.warn(`[stripe] skipping PI recording: ${amount} raw units on ${network} floors to ${amountCents} cents (below Stripe minimum)`);
19
19
  return Promise.resolve();
20
20
  }
21
21
  const requiredParams = {
@@ -35,6 +35,7 @@ export declare const charge: {
35
35
  }, z.core.$strip>], "type">;
36
36
  };
37
37
  request: z.ZodMiniPipe<z.ZodMiniObject<{
38
+ machineTokenEnabled: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
38
39
  amount: z.ZodMiniString<string>;
39
40
  chainId: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
40
41
  currency: z.ZodMiniString<string>;
@@ -42,7 +43,7 @@ export declare const charge: {
42
43
  description: z.ZodMiniOptional<z.ZodMiniString<string>>;
43
44
  externalId: z.ZodMiniOptional<z.ZodMiniString<string>>;
44
45
  feePayer: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniCustom<Account, Account>]>, z.ZodMiniTransform<boolean, boolean | Account>>>;
45
- memo: z.ZodMiniOptional<z.ZodMiniString<string>>;
46
+ memo: z.ZodMiniOptional<z.ZodMiniNever>;
46
47
  recipient: z.ZodMiniOptional<z.ZodMiniString<string>>;
47
48
  splits: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniObject<{
48
49
  amount: z.ZodMiniString<string>;
@@ -60,9 +61,9 @@ export declare const charge: {
60
61
  recipient?: string | undefined;
61
62
  amount: string;
62
63
  methodDetails?: {
64
+ machineTokenEnabled?: boolean | undefined;
63
65
  chainId?: number | undefined;
64
66
  feePayer?: boolean | undefined;
65
- memo?: string | undefined;
66
67
  splits?: {
67
68
  memo?: string | undefined;
68
69
  recipient: `0x${string}`;
@@ -71,6 +72,7 @@ export declare const charge: {
71
72
  supportedModes?: ("pull" | "push")[] | undefined;
72
73
  } | undefined;
73
74
  }, {
75
+ machineTokenEnabled?: boolean | undefined;
74
76
  amount: string;
75
77
  chainId?: number | undefined;
76
78
  currency: string;
@@ -78,7 +80,7 @@ export declare const charge: {
78
80
  description?: string | undefined;
79
81
  externalId?: string | undefined;
80
82
  feePayer?: boolean | undefined;
81
- memo?: string | undefined;
83
+ memo?: undefined;
82
84
  recipient?: string | undefined;
83
85
  splits?: {
84
86
  amount: string;
@@ -82,6 +82,7 @@ export const charge = Method.from({
82
82
  },
83
83
  request: z.pipe(z
84
84
  .object({
85
+ machineTokenEnabled: z.optional(z.boolean()),
85
86
  amount: z.amount(),
86
87
  chainId: z.optional(z.number()),
87
88
  currency: z.string(),
@@ -89,7 +90,7 @@ export const charge = Method.from({
89
90
  description: z.optional(z.string()),
90
91
  externalId: z.optional(z.string()),
91
92
  feePayer: z.optional(z.pipe(z.union([z.boolean(), z.custom()]), z.transform((v) => (typeof v === 'object' ? true : v)))),
92
- memo: z.optional(z.hash()),
93
+ memo: z.optional(z.never()),
93
94
  recipient: z.optional(z.string()),
94
95
  splits: z.optional(z.array(split).check(z.minLength(1), z.maxLength(10))),
95
96
  supportedModes: z.optional(z.array(z.enum(chargeModes)).check(z.minLength(1))),
@@ -101,19 +102,19 @@ export const charge = Method.from({
101
102
  const splitTotal = splits.reduce((sum, split) => sum + parseUnits(split.amount, decimals), 0n);
102
103
  return (splits.every((split) => parseUnits(split.amount, decimals) > 0n) &&
103
104
  splitTotal < totalAmount);
104
- }, 'Invalid splits')), z.transform(({ amount, chainId, decimals, feePayer, memo, splits, supportedModes, ...rest }) => ({
105
+ }, 'Invalid splits')), z.transform(({ machineTokenEnabled, amount, chainId, decimals, feePayer, memo: _memo, splits, supportedModes, ...rest }) => ({
105
106
  ...rest,
106
107
  amount: parseUnits(amount, decimals).toString(),
107
- ...(chainId !== undefined ||
108
+ ...(machineTokenEnabled !== undefined ||
109
+ chainId !== undefined ||
108
110
  feePayer !== undefined ||
109
- memo !== undefined ||
110
111
  splits !== undefined ||
111
112
  supportedModes !== undefined
112
113
  ? {
113
114
  methodDetails: {
115
+ ...(machineTokenEnabled !== undefined && { machineTokenEnabled }),
114
116
  ...(chainId !== undefined && { chainId }),
115
117
  ...(feePayer !== undefined && { feePayer }),
116
- ...(memo !== undefined && { memo }),
117
118
  ...(splits !== undefined && {
118
119
  splits: splits.map((split) => ({
119
120
  ...split,
@@ -1,4 +1,4 @@
1
- import { type Address } from 'viem';
1
+ import type { Address } from 'viem';
2
2
  import * as Method from '../../Method.js';
3
3
  import * as Account from '../../viem/Account.js';
4
4
  import * as Client from '../../viem/Client.js';
@@ -42,6 +42,7 @@ export declare function charge(parameters?: charge.Parameters): Method.Client<{
42
42
  }, z.core.$strip>], "type">;
43
43
  };
44
44
  request: z.ZodMiniPipe<z.ZodMiniObject<{
45
+ machineTokenEnabled: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
45
46
  amount: z.ZodMiniString<string>;
46
47
  chainId: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
47
48
  currency: z.ZodMiniString<string>;
@@ -49,7 +50,7 @@ export declare function charge(parameters?: charge.Parameters): Method.Client<{
49
50
  description: z.ZodMiniOptional<z.ZodMiniString<string>>;
50
51
  externalId: z.ZodMiniOptional<z.ZodMiniString<string>>;
51
52
  feePayer: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniCustom<import("viem").Account, import("viem").Account>]>, z.ZodMiniTransform<boolean, boolean | import("viem").Account>>>;
52
- memo: z.ZodMiniOptional<z.ZodMiniString<string>>;
53
+ memo: z.ZodMiniOptional<z.ZodMiniNever>;
53
54
  recipient: z.ZodMiniOptional<z.ZodMiniString<string>>;
54
55
  splits: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniObject<{
55
56
  amount: z.ZodMiniString<string>;
@@ -67,9 +68,9 @@ export declare function charge(parameters?: charge.Parameters): Method.Client<{
67
68
  recipient?: string | undefined;
68
69
  amount: string;
69
70
  methodDetails?: {
71
+ machineTokenEnabled?: boolean | undefined;
70
72
  chainId?: number | undefined;
71
73
  feePayer?: boolean | undefined;
72
- memo?: string | undefined;
73
74
  splits?: {
74
75
  memo?: string | undefined;
75
76
  recipient: `0x${string}`;
@@ -78,6 +79,7 @@ export declare function charge(parameters?: charge.Parameters): Method.Client<{
78
79
  supportedModes?: ("pull" | "push")[] | undefined;
79
80
  } | undefined;
80
81
  }, {
82
+ machineTokenEnabled?: boolean | undefined;
81
83
  amount: string;
82
84
  chainId?: number | undefined;
83
85
  currency: string;
@@ -85,7 +87,7 @@ export declare function charge(parameters?: charge.Parameters): Method.Client<{
85
87
  description?: string | undefined;
86
88
  externalId?: string | undefined;
87
89
  feePayer?: boolean | undefined;
88
- memo?: string | undefined;
90
+ memo?: undefined;
89
91
  recipient?: string | undefined;
90
92
  splits?: {
91
93
  amount: string;
@@ -1,4 +1,3 @@
1
- import { isAddressEqual } from 'viem';
2
1
  import { prepareTransactionRequest, sendCallsSync, sendTransactionSync, signTypedData, signTransaction, } from 'viem/actions';
3
2
  import { Actions } from 'viem/tempo';
4
3
  import { tempo as tempo_chain } from 'viem/tempo/chains';
@@ -12,9 +11,9 @@ import * as AutoSwap from '../internal/auto-swap.js';
12
11
  import * as Charge_internal from '../internal/charge.js';
13
12
  import * as defaults from '../internal/defaults.js';
14
13
  import { defaultFeeTokens, resolveFeeToken } from '../internal/fee-token.js';
14
+ import * as MachineTokenCharge from '../internal/machine-token-charge.js';
15
15
  import * as Proof from '../internal/proof.js';
16
16
  import * as Methods from '../Methods.js';
17
- import { mach } from '../Tokens.js';
18
17
  const chargeContextSchema = z.object({
19
18
  account: z.optional(z.custom()),
20
19
  autoSwap: z.optional(z.custom()),
@@ -98,9 +97,12 @@ export function charge(parameters = {}) {
98
97
  });
99
98
  }
100
99
  const currency = request.currency;
101
- const memo = methodDetails?.memo
102
- ? methodDetails.memo
103
- : Attribution.encode({ challengeId: challenge.id, clientId, serverId: challenge.realm });
100
+ const isMachineTokenCurrency = MachineTokenCharge.isMachineToken({ chainId, currency });
101
+ const memo = Attribution.encode({
102
+ challengeId: challenge.id,
103
+ clientId,
104
+ serverId: challenge.realm,
105
+ });
104
106
  const transfers = Charge_internal.getTransfers({
105
107
  amount,
106
108
  methodDetails: {
@@ -116,14 +118,66 @@ export function charge(parameters = {}) {
116
118
  token: currency,
117
119
  }));
118
120
  const autoSwap = AutoSwap.resolve(context?.autoSwap ?? parameters.autoSwap, AutoSwap.defaultCurrencies);
119
- const account = (await parameters.resolveAccount?.({
121
+ const machineTokenEnabled = methodDetails?.machineTokenEnabled === true;
122
+ const resolveAccount = async (calls) => (await parameters.resolveAccount?.({
120
123
  account: defaultAccount,
121
124
  chainId,
122
125
  operation: {
123
126
  kind: 'executeCalls',
124
- ...(autoSwap ? {} : { calls: transferCalls }),
127
+ ...(calls ? { calls } : {}),
125
128
  },
126
129
  })) ?? defaultAccount;
130
+ const machineTokenCandidate = machineTokenEnabled
131
+ ? MachineTokenCharge.getRoute({ chainId, currency, transfers })
132
+ : undefined;
133
+ let account = defaultAccount;
134
+ let machineTokenRoute;
135
+ if (machineTokenCandidate) {
136
+ const machineTokenAccount = await (async () => {
137
+ try {
138
+ return await resolveAccount(machineTokenCandidate.calls);
139
+ }
140
+ catch {
141
+ // A machine-token route is optional. A scoped account that cannot
142
+ // execute it may still be able to satisfy the direct payment.
143
+ return undefined;
144
+ }
145
+ })();
146
+ if (machineTokenAccount) {
147
+ machineTokenRoute = await MachineTokenCharge.findRoute(client, {
148
+ account: machineTokenAccount.address,
149
+ chainId,
150
+ currency,
151
+ transfers,
152
+ });
153
+ if (machineTokenRoute)
154
+ account = machineTokenAccount;
155
+ }
156
+ }
157
+ let swapCalls;
158
+ if (!machineTokenRoute) {
159
+ account = await resolveAccount(autoSwap ? undefined : transferCalls);
160
+ swapCalls = autoSwap
161
+ ? await AutoSwap.findCalls(client, {
162
+ account: account.address,
163
+ amountOut: BigInt(amount),
164
+ tokenOut: currency,
165
+ tokenIn: autoSwap.tokenIn,
166
+ slippage: autoSwap.slippage,
167
+ })
168
+ : undefined;
169
+ }
170
+ const calls = machineTokenRoute?.calls ?? [...(swapCalls ?? []), ...transferCalls];
171
+ const allowedFeeTokens = defaultFeeTokens(chainId);
172
+ const feeToken = machineTokenRoute || isMachineTokenCurrency
173
+ ? await resolveFeeToken({
174
+ account: account.address,
175
+ allowedTokens: allowedFeeTokens,
176
+ candidateTokens: allowedFeeTokens,
177
+ client,
178
+ prioritizeCandidates: true,
179
+ })
180
+ : undefined;
127
181
  const mode = (() => {
128
182
  const explicitMode = context?.mode ?? parameters.mode;
129
183
  if (explicitMode) {
@@ -136,27 +190,6 @@ export function charge(parameters = {}) {
136
190
  return preferredMode;
137
191
  return supportedModes[0];
138
192
  })();
139
- const swapCalls = autoSwap
140
- ? await AutoSwap.findCalls(client, {
141
- account: account.address,
142
- amountOut: BigInt(amount),
143
- tokenOut: currency,
144
- tokenIn: autoSwap.tokenIn,
145
- slippage: autoSwap.slippage,
146
- })
147
- : undefined;
148
- const calls = [...(swapCalls ?? []), ...transferCalls];
149
- const machAddress = mach.addresses[chainId];
150
- const allowedFeeTokens = defaultFeeTokens(chainId);
151
- const feeToken = machAddress && isAddressEqual(currency, machAddress)
152
- ? await resolveFeeToken({
153
- account: account.address,
154
- allowedTokens: allowedFeeTokens,
155
- candidateTokens: allowedFeeTokens,
156
- client,
157
- prioritizeCandidates: true,
158
- })
159
- : undefined;
160
193
  const validBefore = (() => {
161
194
  const defaultExpiry = Math.floor(Date.now() / 1000) + 25;
162
195
  if (!challenge.expires)
@@ -37,6 +37,7 @@ export declare function tempo(parameters?: tempo.Parameters): readonly [import("
37
37
  }, import("zod/v4/core").$strip>], "type">;
38
38
  };
39
39
  request: import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniObject<{
40
+ machineTokenEnabled: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniBoolean<boolean>>;
40
41
  amount: import("zod/mini").ZodMiniString<string>;
41
42
  chainId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNumber<number>>;
42
43
  currency: import("zod/mini").ZodMiniString<string>;
@@ -44,7 +45,7 @@ export declare function tempo(parameters?: tempo.Parameters): readonly [import("
44
45
  description: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
45
46
  externalId: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
46
47
  feePayer: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniBoolean<boolean>, import("zod/mini").ZodMiniCustom<import("viem").Account, import("viem").Account>]>, import("zod/mini").ZodMiniTransform<boolean, boolean | import("viem").Account>>>;
47
- memo: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
48
+ memo: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniNever>;
48
49
  recipient: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
49
50
  splits: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
50
51
  amount: import("zod/mini").ZodMiniString<string>;
@@ -62,9 +63,9 @@ export declare function tempo(parameters?: tempo.Parameters): readonly [import("
62
63
  recipient?: string | undefined;
63
64
  amount: string;
64
65
  methodDetails?: {
66
+ machineTokenEnabled?: boolean | undefined;
65
67
  chainId?: number | undefined;
66
68
  feePayer?: boolean | undefined;
67
- memo?: string | undefined;
68
69
  splits?: {
69
70
  memo?: string | undefined;
70
71
  recipient: `0x${string}`;
@@ -73,6 +74,7 @@ export declare function tempo(parameters?: tempo.Parameters): readonly [import("
73
74
  supportedModes?: ("pull" | "push")[] | undefined;
74
75
  } | undefined;
75
76
  }, {
77
+ machineTokenEnabled?: boolean | undefined;
76
78
  amount: string;
77
79
  chainId?: number | undefined;
78
80
  currency: string;
@@ -80,7 +82,7 @@ export declare function tempo(parameters?: tempo.Parameters): readonly [import("
80
82
  description?: string | undefined;
81
83
  externalId?: string | undefined;
82
84
  feePayer?: boolean | undefined;
83
- memo?: string | undefined;
85
+ memo?: undefined;
84
86
  recipient?: string | undefined;
85
87
  splits?: {
86
88
  amount: string;
@@ -3,5 +3,6 @@ export * as Methods from './Methods.js';
3
3
  export * as Session from './session/index.js';
4
4
  export * as SessionLegacy from './legacy/index.js';
5
5
  export * as Subscription from './subscription/index.js';
6
- export { mach } from './Tokens.js';
6
+ /** Canonical first-party machine-token deployments by Tempo chain ID. */
7
+ export { machineToken as machineTokenDeployments } from './internal/defaults.js';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -3,5 +3,6 @@ export * as Methods from './Methods.js';
3
3
  export * as Session from './session/index.js';
4
4
  export * as SessionLegacy from './legacy/index.js';
5
5
  export * as Subscription from './subscription/index.js';
6
- export { mach } from './Tokens.js';
6
+ /** Canonical first-party machine-token deployments by Tempo chain ID. */
7
+ export { machineToken as machineTokenDeployments } from './internal/defaults.js';
7
8
  //# sourceMappingURL=index.js.map
@@ -16,6 +16,17 @@ export declare const currency: {
16
16
  readonly 4217: "0x20C000000000000000000000b9537d11c60E8b50";
17
17
  readonly 42431: "0x20c0000000000000000000000000000000000000";
18
18
  };
19
+ /** Immutable canonical first-party machine-token deployments used by charge routes. */
20
+ export declare const machineToken: Readonly<{
21
+ readonly 4217: Readonly<{
22
+ swap: "0xF72E5107c32C655ffA7539a3C8e97B7C3cE16A3F";
23
+ token: "0x20c000000000000000000000f37de3740ADec032";
24
+ }>;
25
+ readonly 42431: Readonly<{
26
+ swap: "0xd05f8EdFBB54Da0d765C9fE9b2B3f7d2E3a8C466";
27
+ token: "0x20c000000000000000000000f37de3740ADec032";
28
+ }>;
29
+ }>;
19
30
  /**
20
31
  * Default token decimals for TIP-20 stablecoins (e.g. pathUSD, USDC).
21
32
  *
@@ -14,6 +14,17 @@ export const currency = {
14
14
  [chainId.mainnet]: tokens.usdc,
15
15
  [chainId.testnet]: tokens.pathUsd,
16
16
  };
17
+ /** Immutable canonical first-party machine-token deployments used by charge routes. */
18
+ export const machineToken = Object.freeze({
19
+ [chainId.mainnet]: Object.freeze({
20
+ swap: '0xF72E5107c32C655ffA7539a3C8e97B7C3cE16A3F',
21
+ token: '0x20c000000000000000000000f37de3740ADec032',
22
+ }),
23
+ [chainId.testnet]: Object.freeze({
24
+ swap: '0xd05f8EdFBB54Da0d765C9fE9b2B3f7d2E3a8C466',
25
+ token: '0x20c000000000000000000000f37de3740ADec032',
26
+ }),
27
+ });
17
28
  /**
18
29
  * Default token decimals for TIP-20 stablecoins (e.g. pathUSD, USDC).
19
30
  *
@@ -0,0 +1,56 @@
1
+ import type * as Hex from 'ox/Hex';
2
+ import { type Address, type Client } from 'viem';
3
+ type Call = {
4
+ data?: Hex.Hex | undefined;
5
+ to?: Address | undefined;
6
+ value?: bigint | undefined;
7
+ };
8
+ type RouteCall = {
9
+ data: Hex.Hex;
10
+ to: Address;
11
+ };
12
+ type Route = {
13
+ calls: readonly [RouteCall, RouteCall];
14
+ settlementSender: Address;
15
+ transfers: readonly [{
16
+ amount: bigint;
17
+ memo: Hex.Hex;
18
+ recipient: Address;
19
+ }];
20
+ };
21
+ type Transfer = {
22
+ amount: bigint | string;
23
+ memo?: string | undefined;
24
+ recipient: Address;
25
+ };
26
+ /** Returns whether a first-party machine-token charge route is deployed on a chain. */
27
+ export declare function isSupported(chainId: number | undefined): boolean;
28
+ /** Returns whether a currency is the machine token for a supported chain. */
29
+ export declare function isMachineToken(parameters: {
30
+ chainId: number | undefined;
31
+ currency: Address;
32
+ }): boolean;
33
+ /** Resolves the canonical first-party settlement route for a compatible charge. */
34
+ export declare function getRoute(parameters: {
35
+ chainId: number | undefined;
36
+ currency: Address;
37
+ transfers: readonly Transfer[];
38
+ }): Route | undefined;
39
+ /** Builds and simulates the first-party settlement route. */
40
+ export declare function findRoute(client: Client, parameters: {
41
+ account: Address;
42
+ chainId: number;
43
+ currency: Address;
44
+ transfers: readonly Transfer[];
45
+ }): Promise<Route | undefined>;
46
+ /** Matches an exact first-party settlement route. */
47
+ export declare function matchRoute(parameters: {
48
+ calls: readonly Call[];
49
+ chainId: number | undefined;
50
+ currency: Address;
51
+ transfers: readonly Transfer[];
52
+ }): Route | undefined;
53
+ /** Returns the trusted sender that settles the configured charge route on a chain. */
54
+ export declare function getSettlementSender(chainId: number | undefined): Address | undefined;
55
+ export {};
56
+ //# sourceMappingURL=machine-token-charge.d.ts.map
@@ -0,0 +1,108 @@
1
+ import { decodeFunctionData, encodeFunctionData, isAddress, isAddressEqual, parseAbi, } from 'viem';
2
+ import { call, readContract } from 'viem/actions';
3
+ import { Abis, Actions } from 'viem/tempo';
4
+ import * as defaults from './defaults.js';
5
+ const machineTokenSwapperAbi = parseAbi([
6
+ 'function swapTo(address inputToken,uint256 amount,address targetToken,address recipient,bytes32 memo)',
7
+ ]);
8
+ function getDeployment(chainId) {
9
+ if (chainId === undefined)
10
+ return undefined;
11
+ return defaults.machineToken[chainId];
12
+ }
13
+ /** Returns whether a first-party machine-token charge route is deployed on a chain. */
14
+ export function isSupported(chainId) {
15
+ return !!getDeployment(chainId);
16
+ }
17
+ /** Returns whether a currency is the machine token for a supported chain. */
18
+ export function isMachineToken(parameters) {
19
+ const deployment = getDeployment(parameters.chainId);
20
+ return (!!deployment &&
21
+ isAddress(parameters.currency, { strict: false }) &&
22
+ isAddressEqual(parameters.currency, deployment.token));
23
+ }
24
+ /** Resolves the canonical first-party settlement route for a compatible charge. */
25
+ export function getRoute(parameters) {
26
+ const deployment = getDeployment(parameters.chainId);
27
+ const transfer = parameters.transfers.length === 1 ? parameters.transfers[0] : undefined;
28
+ if (!deployment || !transfer?.memo)
29
+ return undefined;
30
+ const amount = BigInt(transfer.amount);
31
+ const memo = transfer.memo;
32
+ return {
33
+ calls: [
34
+ {
35
+ data: encodeFunctionData({
36
+ abi: Abis.tip20,
37
+ functionName: 'approve',
38
+ args: [deployment.swap, amount],
39
+ }),
40
+ to: deployment.token,
41
+ },
42
+ {
43
+ data: encodeFunctionData({
44
+ abi: machineTokenSwapperAbi,
45
+ functionName: 'swapTo',
46
+ args: [deployment.token, amount, parameters.currency, transfer.recipient, memo],
47
+ }),
48
+ to: deployment.swap,
49
+ },
50
+ ],
51
+ settlementSender: deployment.swap,
52
+ transfers: [{ amount, memo, recipient: transfer.recipient }],
53
+ };
54
+ }
55
+ /** Builds and simulates the first-party settlement route. */
56
+ export async function findRoute(client, parameters) {
57
+ const route = getRoute(parameters);
58
+ if (!route)
59
+ return undefined;
60
+ try {
61
+ const balance = await readContract(client, Actions.token.getBalance.call(client, {
62
+ account: parameters.account,
63
+ token: route.calls[0].to,
64
+ }));
65
+ if (balance < route.transfers[0].amount)
66
+ return undefined;
67
+ await call(client, { account: parameters.account, calls: route.calls });
68
+ return route;
69
+ }
70
+ catch {
71
+ return undefined;
72
+ }
73
+ }
74
+ /** Matches an exact first-party settlement route. */
75
+ export function matchRoute(parameters) {
76
+ const transfer = parameters.transfers.length === 1 ? parameters.transfers[0] : undefined;
77
+ const swap = parameters.calls[1];
78
+ if (!transfer || parameters.calls.length !== 2 || !swap?.data)
79
+ return undefined;
80
+ try {
81
+ const decoded = decodeFunctionData({ abi: machineTokenSwapperAbi, data: swap.data });
82
+ const route = getRoute({
83
+ ...parameters,
84
+ transfers: [{ ...transfer, memo: transfer.memo ?? decoded.args[4] }],
85
+ });
86
+ if (!route)
87
+ return undefined;
88
+ if (parameters.calls.some((call, index) => {
89
+ const expected = route.calls[index];
90
+ return (!call.data ||
91
+ !call.to ||
92
+ !expected ||
93
+ (call.value ?? 0n) !== 0n ||
94
+ !isAddressEqual(call.to, expected.to) ||
95
+ call.data.toLowerCase() !== expected.data.toLowerCase());
96
+ }))
97
+ return undefined;
98
+ return route;
99
+ }
100
+ catch {
101
+ return undefined;
102
+ }
103
+ }
104
+ /** Returns the trusted sender that settles the configured charge route on a chain. */
105
+ export function getSettlementSender(chainId) {
106
+ return getDeployment(chainId)?.swap;
107
+ }
108
+ //# sourceMappingURL=machine-token-charge.js.map
@@ -45,6 +45,8 @@ export declare namespace charge {
45
45
  } | undefined;
46
46
  };
47
47
  type Parameters = {
48
+ /** Enables first-party machine-token funding through the canonical swapper. */
49
+ machineTokenEnabled?: boolean | undefined;
48
50
  /** Render payment page when Accept header is text/html (e.g. in browsers) */
49
51
  html?: boolean | Html.Config | undefined;
50
52
  /**
@@ -99,6 +101,7 @@ export declare namespace charge {
99
101
  * relay broadcasts pull credentials, while it recognizes a push
100
102
  * credential as already broadcast and returns its receipt without sending
101
103
  * it again.
104
+ *
102
105
  */
103
106
  relay?: RelayOptions | undefined;
104
107
  /**