mppx 0.10.1 → 0.12.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.
- package/CHANGELOG.md +41 -0
- package/README.md +22 -1
- package/dist/cli/agent.d.ts +3 -0
- package/dist/cli/agent.js +20 -0
- package/dist/cli/cli.d.ts +1 -1
- package/dist/cli/cli.js +135 -135
- package/dist/cli/plugins/index.js +12 -12
- package/dist/cli/validate/payment.js +29 -12
- package/dist/client/internal/protocols/X402.js +0 -2
- package/dist/evm/server/Methods.d.ts +164 -3
- package/dist/evm/server/Methods.js +50 -2
- package/dist/internal/version.d.ts +2 -2
- package/dist/internal/version.js +1 -1
- package/dist/server/Mppx.d.ts +5 -1
- package/dist/server/Mppx.js +120 -49
- package/dist/server/internal/html/compose.main.gen.d.ts +1 -1
- package/dist/server/internal/html/serviceWorker.gen.d.ts +1 -1
- package/dist/stripe/server/Methods.js +13 -7
- package/dist/stripe/server/internal/analytics.d.ts +1 -0
- package/dist/stripe/server/internal/analytics.js +2 -2
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/record-payment.js +2 -2
- package/dist/tempo/Methods.d.ts +5 -3
- package/dist/tempo/Methods.js +6 -5
- package/dist/tempo/client/Charge.d.ts +6 -4
- package/dist/tempo/client/Charge.js +61 -28
- package/dist/tempo/client/Methods.d.ts +5 -3
- package/dist/tempo/index.d.ts +2 -1
- package/dist/tempo/index.js +2 -1
- package/dist/tempo/internal/currencies.d.ts +19 -0
- package/dist/tempo/internal/currencies.js +41 -0
- package/dist/tempo/internal/defaults.d.ts +16 -3
- package/dist/tempo/internal/defaults.js +17 -2
- package/dist/tempo/internal/fee-payer.d.ts +5 -4
- package/dist/tempo/internal/fee-payer.js +7 -5
- package/dist/tempo/internal/machine-token-charge.d.ts +56 -0
- package/dist/tempo/internal/machine-token-charge.js +108 -0
- package/dist/tempo/server/Charge.d.ts +15 -1
- package/dist/tempo/server/Charge.js +101 -67
- package/dist/tempo/server/Methods.d.ts +5008 -40
- package/dist/tempo/server/Methods.js +105 -11
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/session/server/ChannelStore.d.ts +2 -0
- package/dist/tempo/session/server/ChannelStore.js +12 -3
- package/dist/tempo/session/server/CredentialVerification.d.ts +2 -0
- package/dist/tempo/session/server/CredentialVerification.js +22 -13
- package/dist/tempo/session/server/RequestState.d.ts +6 -0
- package/dist/tempo/session/server/RequestState.js +11 -4
- package/dist/tempo/session/server/Session.js +8 -1
- package/dist/tempo/session/server/Settlement.d.ts +2 -0
- package/dist/tempo/session/server/Settlement.js +13 -8
- package/dist/tempo/subscription/KeyAuthorization.d.ts +70 -8
- package/package.json +3 -3
- package/dist/tempo/Tokens.d.ts +0 -13
- package/dist/tempo/Tokens.js +0 -13
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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.
|
|
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?:
|
|
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
|
|
102
|
-
|
|
103
|
-
|
|
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
|
|
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
|
-
...(
|
|
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").
|
|
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?:
|
|
85
|
+
memo?: undefined;
|
|
84
86
|
recipient?: string | undefined;
|
|
85
87
|
splits?: {
|
|
86
88
|
amount: string;
|
package/dist/tempo/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
package/dist/tempo/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Token } from 'viem/tokens';
|
|
2
|
+
/** An explicit token address or a chain-indexed token definition. */
|
|
3
|
+
export type Currency = string | Token;
|
|
4
|
+
/** Resolves ordered USD offers without expanding acceptance from a live registry. */
|
|
5
|
+
export declare function resolve(parameters: {
|
|
6
|
+
chainId?: number | undefined;
|
|
7
|
+
testnet?: boolean | undefined;
|
|
8
|
+
currencies?: readonly Currency[] | undefined;
|
|
9
|
+
decimals?: number | undefined;
|
|
10
|
+
}): [({
|
|
11
|
+
currency: string;
|
|
12
|
+
decimals: number;
|
|
13
|
+
chainId: number;
|
|
14
|
+
}[])[number], ...{
|
|
15
|
+
currency: string;
|
|
16
|
+
decimals: number;
|
|
17
|
+
chainId: number;
|
|
18
|
+
}[]];
|
|
19
|
+
//# sourceMappingURL=currencies.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { isAddress } from 'viem';
|
|
2
|
+
import * as defaults from './defaults.js';
|
|
3
|
+
/** Resolves ordered USD offers without expanding acceptance from a live registry. */
|
|
4
|
+
export function resolve(parameters) {
|
|
5
|
+
const chainId = parameters.chainId ?? (parameters.testnet ? defaults.chainId.testnet : defaults.chainId.mainnet);
|
|
6
|
+
const currencies = parameters.currencies ??
|
|
7
|
+
(chainId === defaults.chainId.mainnet
|
|
8
|
+
? [defaults.tokens.ousd, defaults.tokens.usdc]
|
|
9
|
+
: chainId === defaults.chainId.testnet
|
|
10
|
+
? // TODO: Use viem's chain-specific OUSD definition once it includes Moderato (42431).
|
|
11
|
+
[defaults.tokens.ousd, defaults.tokens.pathUsd]
|
|
12
|
+
: [defaults.resolveCurrency({ chainId })]);
|
|
13
|
+
const seen = new Set();
|
|
14
|
+
const resolved = [];
|
|
15
|
+
for (const token of currencies) {
|
|
16
|
+
// A shared USD price cannot also price EUR, BTC, or unknown denominations.
|
|
17
|
+
if (typeof token !== 'string' && token.currency !== 'USD')
|
|
18
|
+
continue;
|
|
19
|
+
const currency = typeof token === 'string' ? token : token.addresses[chainId];
|
|
20
|
+
if (currency === undefined)
|
|
21
|
+
continue;
|
|
22
|
+
if (!isAddress(currency, { strict: false }))
|
|
23
|
+
throw new Error(`Invalid Tempo currency address: ${currency}.`);
|
|
24
|
+
const decimals = typeof token === 'string' ? (parameters.decimals ?? defaults.decimals) : token.decimals;
|
|
25
|
+
if (typeof token !== 'string' &&
|
|
26
|
+
parameters.decimals !== undefined &&
|
|
27
|
+
parameters.decimals !== decimals)
|
|
28
|
+
throw new Error('Configured `decimals` must match each token definition.');
|
|
29
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 255)
|
|
30
|
+
throw new Error('Token decimals must be an integer between 0 and 255.');
|
|
31
|
+
const key = currency.toLowerCase();
|
|
32
|
+
if (seen.has(key))
|
|
33
|
+
continue;
|
|
34
|
+
seen.add(key);
|
|
35
|
+
resolved.push({ currency, decimals, chainId });
|
|
36
|
+
}
|
|
37
|
+
if (resolved.length === 0)
|
|
38
|
+
throw new Error(`No accepted USD currencies for chain ${chainId}.`);
|
|
39
|
+
return resolved;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=currencies.js.map
|
|
@@ -6,16 +6,29 @@ export declare const chainId: {
|
|
|
6
6
|
export type ChainId = ValueOf<typeof chainId>;
|
|
7
7
|
/** Token addresses. */
|
|
8
8
|
export declare const tokens: {
|
|
9
|
+
/** OpenUSD (OUSD), deployed at the same address on Tempo mainnet and Moderato. */
|
|
10
|
+
readonly ousd: "0x20c0000000000000000000006a37DA5C996874BE";
|
|
9
11
|
/** USDC (USDC.e) token address. */
|
|
10
|
-
readonly usdc:
|
|
12
|
+
readonly usdc: `0x${string}`;
|
|
11
13
|
/** pathUSD token address. */
|
|
12
|
-
readonly pathUsd:
|
|
14
|
+
readonly pathUsd: "0x20c0000000000000000000000000000000000000";
|
|
13
15
|
};
|
|
14
16
|
/** Chain ID → default currency. */
|
|
15
17
|
export declare const currency: {
|
|
16
|
-
readonly 4217:
|
|
18
|
+
readonly 4217: `0x${string}`;
|
|
17
19
|
readonly 42431: "0x20c0000000000000000000000000000000000000";
|
|
18
20
|
};
|
|
21
|
+
/** Immutable canonical first-party machine-token deployments used by charge routes. */
|
|
22
|
+
export declare const machineToken: Readonly<{
|
|
23
|
+
readonly 4217: Readonly<{
|
|
24
|
+
swap: "0xF72E5107c32C655ffA7539a3C8e97B7C3cE16A3F";
|
|
25
|
+
token: "0x20c000000000000000000000f37de3740ADec032";
|
|
26
|
+
}>;
|
|
27
|
+
readonly 42431: Readonly<{
|
|
28
|
+
swap: "0xd05f8EdFBB54Da0d765C9fE9b2B3f7d2E3a8C466";
|
|
29
|
+
token: "0x20c000000000000000000000f37de3740ADec032";
|
|
30
|
+
}>;
|
|
31
|
+
}>;
|
|
19
32
|
/**
|
|
20
33
|
* Default token decimals for TIP-20 stablecoins (e.g. pathUSD, USDC).
|
|
21
34
|
*
|
|
@@ -1,19 +1,34 @@
|
|
|
1
|
+
import { getAddress } from 'viem';
|
|
2
|
+
import { ousd, pathusd, usdce } from 'viem/tokens';
|
|
1
3
|
export const chainId = {
|
|
2
4
|
mainnet: 4217,
|
|
3
5
|
testnet: 42431,
|
|
4
6
|
};
|
|
5
7
|
/** Token addresses. */
|
|
6
8
|
export const tokens = {
|
|
9
|
+
/** OpenUSD (OUSD), deployed at the same address on Tempo mainnet and Moderato. */
|
|
10
|
+
ousd: ousd(chainId.mainnet).address,
|
|
7
11
|
/** USDC (USDC.e) token address. */
|
|
8
|
-
usdc:
|
|
12
|
+
usdc: getAddress(usdce(chainId.mainnet).address),
|
|
9
13
|
/** pathUSD token address. */
|
|
10
|
-
pathUsd:
|
|
14
|
+
pathUsd: pathusd(chainId.mainnet).address,
|
|
11
15
|
};
|
|
12
16
|
/** Chain ID → default currency. */
|
|
13
17
|
export const currency = {
|
|
14
18
|
[chainId.mainnet]: tokens.usdc,
|
|
15
19
|
[chainId.testnet]: tokens.pathUsd,
|
|
16
20
|
};
|
|
21
|
+
/** Immutable canonical first-party machine-token deployments used by charge routes. */
|
|
22
|
+
export const machineToken = Object.freeze({
|
|
23
|
+
[chainId.mainnet]: Object.freeze({
|
|
24
|
+
swap: '0xF72E5107c32C655ffA7539a3C8e97B7C3cE16A3F',
|
|
25
|
+
token: '0x20c000000000000000000000f37de3740ADec032',
|
|
26
|
+
}),
|
|
27
|
+
[chainId.testnet]: Object.freeze({
|
|
28
|
+
swap: '0xd05f8EdFBB54Da0d765C9fE9b2B3f7d2E3a8C466',
|
|
29
|
+
token: '0x20c000000000000000000000f37de3740ADec032',
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
17
32
|
/**
|
|
18
33
|
* Default token decimals for TIP-20 stablecoins (e.g. pathUSD, USDC).
|
|
19
34
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { TempoAddress } from 'ox/tempo';
|
|
2
2
|
import type { Hex } from 'viem';
|
|
3
3
|
import type { Account } from 'viem';
|
|
4
4
|
import { Transaction } from 'viem/tempo';
|
|
@@ -27,10 +27,10 @@ type ExpectedTransfer = {
|
|
|
27
27
|
};
|
|
28
28
|
/** Returns fee tokens that mppx allows sponsored transactions to charge. */
|
|
29
29
|
export declare function defaultAllowedFeeTokens(chainId: number | undefined): `0x${string}`[];
|
|
30
|
-
/**
|
|
30
|
+
/** Validates the fee-token address and, when supplied, the server's allowlist. */
|
|
31
31
|
export declare function assertAllowedFeeToken(transaction: {
|
|
32
32
|
feeToken?: unknown;
|
|
33
|
-
}, allowedFeeTokens
|
|
33
|
+
}, allowedFeeTokens?: readonly TempoAddress.Address[] | undefined): void;
|
|
34
34
|
declare function hostedFeePayerRequest(transaction: SponsoredTransaction): {
|
|
35
35
|
accessList?: any;
|
|
36
36
|
calls: any;
|
|
@@ -56,7 +56,8 @@ declare function hostedFeePayerRequest(transaction: SponsoredTransaction): {
|
|
|
56
56
|
* simulate the exact transaction the sponsor broadcasts.
|
|
57
57
|
*/
|
|
58
58
|
export declare function fillHostedFeePayerTransaction(parameters: {
|
|
59
|
-
|
|
59
|
+
/** Optional merchant restriction on the hosted sponsor's token choice. */
|
|
60
|
+
allowedFeeTokens?: readonly TempoAddress.Address[] | undefined;
|
|
60
61
|
challengeExpires?: string | undefined;
|
|
61
62
|
chainId: number;
|
|
62
63
|
details: Record<string, string>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Secp256k1 } from 'ox';
|
|
2
|
-
import { TxEnvelopeTempo } from 'ox/tempo';
|
|
1
|
+
import { Address, Secp256k1 } from 'ox';
|
|
2
|
+
import { TempoAddress, TxEnvelopeTempo } from 'ox/tempo';
|
|
3
3
|
import { decodeFunctionData, encodeFunctionData, maxUint256, toHex } from 'viem';
|
|
4
4
|
import { Abis, Addresses, Transaction } from 'viem/tempo';
|
|
5
5
|
import * as TempoAddress_internal from './address.js';
|
|
@@ -63,15 +63,17 @@ const supportedTransactionKeys = new Set([
|
|
|
63
63
|
export function defaultAllowedFeeTokens(chainId) {
|
|
64
64
|
return defaultFeeTokens(chainId);
|
|
65
65
|
}
|
|
66
|
-
/**
|
|
66
|
+
/** Validates the fee-token address and, when supplied, the server's allowlist. */
|
|
67
67
|
export function assertAllowedFeeToken(transaction, allowedFeeTokens) {
|
|
68
68
|
const { feeToken } = transaction;
|
|
69
69
|
if (feeToken === undefined)
|
|
70
70
|
return;
|
|
71
|
-
if (typeof feeToken !== 'string'
|
|
71
|
+
if (typeof feeToken !== 'string' ||
|
|
72
|
+
!(Address.validate(feeToken, { strict: false }) || TempoAddress.validate(feeToken)))
|
|
72
73
|
throw new FeePayerValidationError('fee-sponsored transaction feeToken is invalid', {});
|
|
73
74
|
const normalized = feeToken;
|
|
74
|
-
if (
|
|
75
|
+
if (allowedFeeTokens &&
|
|
76
|
+
!allowedFeeTokens.some((allowed) => TempoAddress_internal.isEqual(allowed, normalized)))
|
|
75
77
|
throw new FeePayerValidationError('fee-sponsored transaction feeToken is not allowed', {
|
|
76
78
|
feeToken,
|
|
77
79
|
});
|
|
@@ -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,18 @@ export declare namespace charge {
|
|
|
45
45
|
} | undefined;
|
|
46
46
|
};
|
|
47
47
|
type Parameters = {
|
|
48
|
+
/**
|
|
49
|
+
* Tokens permitted for sponsored charge transaction fees, including tokens
|
|
50
|
+
* selected by a remote fee payer. Local sponsorship defaults to pathUSD and
|
|
51
|
+
* USDC.e on mainnet, and pathUSD on other chains. Hosted sponsorship has no
|
|
52
|
+
* token allowlist by default and trusts the configured provider's choice.
|
|
53
|
+
* A custom list replaces the local defaults and restricts hosted sponsorship.
|
|
54
|
+
* It must contain at least one token. Address validation and other sponsorship
|
|
55
|
+
* checks still apply. This does not change the payment currency or sessions.
|
|
56
|
+
*/
|
|
57
|
+
allowedFeeTokens?: readonly `0x${string}`[] | undefined;
|
|
58
|
+
/** Enables first-party machine-token funding through the canonical swapper. */
|
|
59
|
+
machineTokenEnabled?: boolean | undefined;
|
|
48
60
|
/** Render payment page when Accept header is text/html (e.g. in browsers) */
|
|
49
61
|
html?: boolean | Html.Config | undefined;
|
|
50
62
|
/**
|
|
@@ -56,7 +68,8 @@ export declare namespace charge {
|
|
|
56
68
|
feePayerPolicy?: FeePayerPolicy | undefined;
|
|
57
69
|
/**
|
|
58
70
|
* Token a local fee payer uses to pay gas. If omitted, mppx selects a
|
|
59
|
-
* funded allowed token
|
|
71
|
+
* funded allowed token in `allowedFeeTokens` order (pathUSD first by default).
|
|
72
|
+
* An explicit token must also be in the allowed list.
|
|
60
73
|
*
|
|
61
74
|
* This option is not supported with a remote fee-payer URL, which selects
|
|
62
75
|
* its own token.
|
|
@@ -99,6 +112,7 @@ export declare namespace charge {
|
|
|
99
112
|
* relay broadcasts pull credentials, while it recognizes a push
|
|
100
113
|
* credential as already broadcast and returns its receipt without sending
|
|
101
114
|
* it again.
|
|
115
|
+
*
|
|
102
116
|
*/
|
|
103
117
|
relay?: RelayOptions | undefined;
|
|
104
118
|
/**
|