mppx 0.8.6 → 0.8.8
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 +19 -0
- package/dist/cli/internal.js +2 -2
- package/dist/cli/internal.js.map +1 -1
- package/dist/cli/plugins/evm.d.ts +2 -0
- package/dist/cli/plugins/evm.d.ts.map +1 -0
- package/dist/cli/plugins/evm.js +51 -0
- package/dist/cli/plugins/evm.js.map +1 -0
- package/dist/cli/plugins/index.d.ts +1 -0
- package/dist/cli/plugins/index.d.ts.map +1 -1
- package/dist/cli/plugins/index.js +1 -0
- package/dist/cli/plugins/index.js.map +1 -1
- package/dist/cli/plugins/stripe.d.ts.map +1 -1
- package/dist/cli/plugins/stripe.js +3 -2
- package/dist/cli/plugins/stripe.js.map +1 -1
- package/dist/cli/validate/challenge.d.ts +2 -0
- package/dist/cli/validate/challenge.d.ts.map +1 -1
- package/dist/cli/validate/challenge.js +191 -84
- package/dist/cli/validate/challenge.js.map +1 -1
- package/dist/cli/validate/discovery.d.ts +1 -0
- package/dist/cli/validate/discovery.d.ts.map +1 -1
- package/dist/cli/validate/discovery.js +99 -35
- package/dist/cli/validate/discovery.js.map +1 -1
- package/dist/cli/validate/helpers.d.ts +14 -1
- package/dist/cli/validate/helpers.d.ts.map +1 -1
- package/dist/cli/validate/helpers.js +0 -13
- package/dist/cli/validate/helpers.js.map +1 -1
- package/dist/cli/validate/index.d.ts +1 -0
- package/dist/cli/validate/index.d.ts.map +1 -1
- package/dist/cli/validate/index.js +102 -153
- package/dist/cli/validate/index.js.map +1 -1
- package/dist/cli/validate/payment.d.ts +4 -1
- package/dist/cli/validate/payment.d.ts.map +1 -1
- package/dist/cli/validate/payment.js +312 -106
- package/dist/cli/validate/payment.js.map +1 -1
- package/dist/evm/Chains.d.ts +4 -0
- package/dist/evm/Chains.d.ts.map +1 -1
- package/dist/evm/Chains.js +4 -0
- package/dist/evm/Chains.js.map +1 -1
- package/dist/internal/AcceptPayment.d.ts.map +1 -1
- package/dist/internal/AcceptPayment.js +7 -1
- package/dist/internal/AcceptPayment.js.map +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/stripe/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/server/internal/request-body.d.ts.map +1 -1
- package/dist/tempo/server/internal/request-body.js +2 -0
- package/dist/tempo/server/internal/request-body.js.map +1 -1
- package/dist/tempo/session/server/ChannelStore.js +4 -4
- package/dist/tempo/session/server/ChannelStore.js.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.d.ts +8 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.js +21 -1
- package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
- package/dist/tempo/session/server/Session.d.ts.map +1 -1
- package/dist/tempo/session/server/Session.js +1 -0
- package/dist/tempo/session/server/Session.js.map +1 -1
- package/dist/validation/core.d.ts +75 -0
- package/dist/validation/core.d.ts.map +1 -0
- package/dist/validation/core.js +269 -0
- package/dist/validation/core.js.map +1 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +2 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/x402/Assets.d.ts +9 -0
- package/dist/x402/Assets.d.ts.map +1 -1
- package/dist/x402/Assets.js +38 -0
- package/dist/x402/Assets.js.map +1 -1
- package/package.json +9 -4
- package/src/cli/internal.ts +2 -2
- package/src/cli/plugins/evm.ts +55 -0
- package/src/cli/plugins/index.ts +1 -0
- package/src/cli/plugins/stripe.ts +3 -2
- package/src/cli/validate/challenge.ts +345 -127
- package/src/cli/validate/discovery.test.ts +307 -0
- package/src/cli/validate/discovery.ts +104 -38
- package/src/cli/validate/helpers.ts +15 -13
- package/src/cli/validate/index.ts +121 -242
- package/src/cli/validate/payment.ts +413 -144
- package/src/cli/validate.test.ts +237 -3
- package/src/client/internal/Fetch.test.ts +142 -2
- package/src/evm/Chains.ts +6 -0
- package/src/evm/PublicInterface.test-d.ts +7 -0
- package/src/internal/AcceptPayment.test.ts +45 -0
- package/src/internal/AcceptPayment.ts +11 -1
- package/src/stripe/server/internal/html/package.json +1 -1
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/server/internal/html/package.json +1 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/server/internal/request-body.test.ts +9 -0
- package/src/tempo/server/internal/request-body.ts +2 -0
- package/src/tempo/session/server/ChannelStore.test.ts +17 -0
- package/src/tempo/session/server/ChannelStore.ts +4 -4
- package/src/tempo/session/server/CredentialVerification.test.ts +118 -1
- package/src/tempo/session/server/CredentialVerification.ts +30 -0
- package/src/tempo/session/server/Session.integration.test.ts +5 -0
- package/src/tempo/session/server/Session.test.ts +119 -53
- package/src/tempo/session/server/Session.ts +1 -0
- package/src/validation/core.ts +374 -0
- package/src/validation/index.ts +11 -0
- package/src/x402/Assets.test.ts +42 -0
- package/src/x402/Assets.ts +40 -0
- package/src/x402/Exact.localnet.test.ts +475 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/validate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,QAAQ,IAAI,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/validate/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { CheckResult, EndpointSpec } from './helpers.js';
|
|
2
|
-
export declare function validatePaymentFlow(baseUrl: string, endpoint: EndpointSpec, verbose: boolean, options
|
|
2
|
+
export declare function validatePaymentFlow(baseUrl: string, endpoint: EndpointSpec, verbose: boolean, options: {
|
|
3
3
|
body?: string | undefined;
|
|
4
4
|
query?: string[] | undefined;
|
|
5
5
|
yes?: boolean | undefined;
|
|
6
|
+
silent?: boolean | undefined;
|
|
7
|
+
interactive?: boolean | undefined;
|
|
8
|
+
onResults?: (results: CheckResult[]) => void;
|
|
6
9
|
}): Promise<CheckResult[]>;
|
|
7
10
|
//# sourceMappingURL=payment.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payment.d.ts","sourceRoot":"","sources":["../../../src/cli/validate/payment.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"payment.d.ts","sourceRoot":"","sources":["../../../src/cli/validate/payment.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAuG7D,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IACP,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;IAC5B,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACzB,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC5B,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,CAAA;CAC7C,GACA,OAAO,CAAC,WAAW,EAAE,CAAC,CAiJxB"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as childProcess from 'node:child_process';
|
|
2
|
+
import { createClient, erc20Abi, http } from 'viem';
|
|
2
3
|
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
|
|
3
|
-
import { waitForTransactionReceipt } from 'viem/actions';
|
|
4
|
+
import { readContract, waitForTransactionReceipt } from 'viem/actions';
|
|
5
|
+
import * as viemChains from 'viem/chains';
|
|
4
6
|
import { Actions } from 'viem/tempo';
|
|
5
7
|
import { tempoModerato, tempo as tempoMainnetChain } from 'viem/tempo/chains';
|
|
6
8
|
import * as Challenge from '../../Challenge.js';
|
|
@@ -10,18 +12,21 @@ import * as Receipt from '../../Receipt.js';
|
|
|
10
12
|
import { tempo as tempoMethods } from '../../tempo/client/index.js';
|
|
11
13
|
import { chainId as tempoChainIds } from '../../tempo/internal/defaults.js';
|
|
12
14
|
import { resolveAccount, resolveAccountName } from '../account.js';
|
|
13
|
-
import { loadConfig,
|
|
15
|
+
import { loadConfig, resolvePlugin } from '../internal.js';
|
|
14
16
|
import { fetchTokenInfo, confirm, pc } from '../utils.js';
|
|
15
|
-
import { buildUrl
|
|
16
|
-
|
|
17
|
+
import { buildUrl } from './discovery.js';
|
|
18
|
+
import { check, fail, fetchWithTimeout, formatBytes, isValidIntegerAmount, skip, warn, } from './helpers.js';
|
|
19
|
+
async function provisionAndPayTestnet(challenge, verbose, silent) {
|
|
17
20
|
try {
|
|
18
|
-
|
|
21
|
+
if (!silent)
|
|
22
|
+
console.log(pc.dim(' Provisioning testnet wallet and funding via faucet...'));
|
|
19
23
|
const key = generatePrivateKey();
|
|
20
24
|
const account = privateKeyToAccount(key);
|
|
21
25
|
const client = createClient({ chain: tempoModerato, transport: http() });
|
|
22
26
|
const hashes = await Actions.faucet.fund(client, { account });
|
|
23
27
|
await Promise.all(hashes.map((hash) => waitForTransactionReceipt(client, { hash })));
|
|
24
|
-
|
|
28
|
+
if (!silent)
|
|
29
|
+
console.log(pc.dim(` Using wallet: ${account.address}`));
|
|
25
30
|
const methods = [...tempoMethods({ account })];
|
|
26
31
|
return { methods };
|
|
27
32
|
}
|
|
@@ -48,12 +53,57 @@ async function resolveWalletAddress() {
|
|
|
48
53
|
return undefined;
|
|
49
54
|
}
|
|
50
55
|
}
|
|
56
|
+
// Auto-detect Stripe test key from the Stripe CLI if installed and logged in.
|
|
57
|
+
function resolveStripeKey(verbose) {
|
|
58
|
+
try {
|
|
59
|
+
const { execSync } = childProcess;
|
|
60
|
+
const output = execSync('stripe config --list', { encoding: 'utf8', timeout: 5000 });
|
|
61
|
+
const match = output.match(/test_mode_api_key\s*=\s*'([^']+)'/);
|
|
62
|
+
if (match?.[1]) {
|
|
63
|
+
if (verbose)
|
|
64
|
+
console.log(pc.dim(' Using Stripe test key from stripe CLI'));
|
|
65
|
+
return match[1];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch { }
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
async function fetchEvmTokenInfo(chain, token, account) {
|
|
72
|
+
const client = createClient({ chain, transport: http() });
|
|
73
|
+
const [balance, symbol] = await Promise.all([
|
|
74
|
+
readContract(client, {
|
|
75
|
+
address: token,
|
|
76
|
+
abi: erc20Abi,
|
|
77
|
+
functionName: 'balanceOf',
|
|
78
|
+
args: [account],
|
|
79
|
+
}),
|
|
80
|
+
readContract(client, { address: token, abi: erc20Abi, functionName: 'symbol' }).catch(() => undefined),
|
|
81
|
+
]);
|
|
82
|
+
return { balance, symbol: symbol ?? undefined };
|
|
83
|
+
}
|
|
84
|
+
function resolveEvmChain(chainId) {
|
|
85
|
+
const all = Object.values(viemChains);
|
|
86
|
+
return all.find((c) => c.id === chainId);
|
|
87
|
+
}
|
|
88
|
+
function formatAmount(amount, decimals) {
|
|
89
|
+
return `$${(Number(amount) / 10 ** decimals).toFixed(2)}`;
|
|
90
|
+
}
|
|
91
|
+
function methodSetupHint(challenge) {
|
|
92
|
+
switch (challenge.method) {
|
|
93
|
+
case Constants.Methods.evm:
|
|
94
|
+
return 'no EVM payment plugin yet';
|
|
95
|
+
case 'solana':
|
|
96
|
+
return 'no Solana payment plugin yet';
|
|
97
|
+
default:
|
|
98
|
+
return `no plugin for ${challenge.method}/${challenge.intent}`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
51
101
|
export async function validatePaymentFlow(baseUrl, endpoint, verbose, options) {
|
|
52
102
|
const results = [];
|
|
53
|
-
const url = buildUrl(baseUrl, endpoint, options
|
|
103
|
+
const url = buildUrl(baseUrl, endpoint, options.query);
|
|
54
104
|
const fetchHeaders = {};
|
|
55
105
|
let fetchBody;
|
|
56
|
-
if (options
|
|
106
|
+
if (options.body) {
|
|
57
107
|
fetchBody = options.body;
|
|
58
108
|
fetchHeaders['content-type'] = 'application/json';
|
|
59
109
|
}
|
|
@@ -74,32 +124,41 @@ export async function validatePaymentFlow(baseUrl, endpoint, verbose, options) {
|
|
|
74
124
|
results.push(skip('Payment: skipped', `Endpoint returned ${challengeResponse.status}`));
|
|
75
125
|
return results;
|
|
76
126
|
}
|
|
77
|
-
// Parse
|
|
78
|
-
let
|
|
127
|
+
// Parse all challenges
|
|
128
|
+
let challenges;
|
|
79
129
|
try {
|
|
80
|
-
|
|
130
|
+
challenges = Challenge.fromResponseList(challengeResponse);
|
|
81
131
|
}
|
|
82
132
|
catch (error) {
|
|
83
133
|
results.push(fail('Payment: parse challenge', error.message));
|
|
84
134
|
return results;
|
|
85
135
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
136
|
+
if (challenges.length === 0) {
|
|
137
|
+
results.push(fail('Payment: parse challenge', 'No Payment challenges in response'));
|
|
138
|
+
return results;
|
|
139
|
+
}
|
|
90
140
|
// Testnet Tempo: always use ephemeral wallet (zero-setup, free money)
|
|
91
|
-
|
|
92
|
-
|
|
141
|
+
const tempoTestnetChallenge = challenges.find((ch) => {
|
|
142
|
+
if (ch.method !== Constants.Methods.tempo)
|
|
143
|
+
return false;
|
|
144
|
+
const req = ch.request;
|
|
145
|
+
const md = req.methodDetails;
|
|
146
|
+
return typeof md?.chainId === 'number' && md.chainId !== tempoChainIds.mainnet;
|
|
147
|
+
});
|
|
148
|
+
if (tempoTestnetChallenge) {
|
|
149
|
+
const provisioned = await provisionAndPayTestnet(tempoTestnetChallenge, verbose, options.silent);
|
|
93
150
|
if (provisioned) {
|
|
94
151
|
const fakeResp = new Response(null, {
|
|
95
152
|
status: 402,
|
|
96
|
-
headers: {
|
|
153
|
+
headers: {
|
|
154
|
+
[Constants.Headers.wwwAuthenticate]: Challenge.serialize(tempoTestnetChallenge),
|
|
155
|
+
},
|
|
97
156
|
});
|
|
98
157
|
try {
|
|
99
158
|
const mppx = Mppx.create({ methods: provisioned.methods, polyfill: false });
|
|
100
159
|
const cred = await mppx.createCredential(fakeResp);
|
|
101
|
-
results.push(check('Payment:
|
|
102
|
-
return await sendAndValidateResponse(results, url, endpoint, cred, fetchHeaders, fetchBody, verbose,
|
|
160
|
+
results.push(check('Payment: submitted', 'ephemeral testnet wallet'));
|
|
161
|
+
return await sendAndValidateResponse(results, url, endpoint, cred, fetchHeaders, fetchBody, verbose, tempoModerato);
|
|
103
162
|
}
|
|
104
163
|
catch (error) {
|
|
105
164
|
results.push(fail('Payment: create credential', error.message));
|
|
@@ -111,39 +170,117 @@ export async function validatePaymentFlow(baseUrl, endpoint, verbose, options) {
|
|
|
111
170
|
return results;
|
|
112
171
|
}
|
|
113
172
|
}
|
|
114
|
-
//
|
|
173
|
+
// Try each challenge method (skip testnet challenge already handled above)
|
|
115
174
|
const loaded = await loadConfig().catch(() => undefined);
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
175
|
+
const isInteractive = options.interactive;
|
|
176
|
+
const stripeKey = process.env.MPPX_STRIPE_SECRET_KEY ?? resolveStripeKey(verbose);
|
|
177
|
+
const isStripeTestKey = stripeKey?.startsWith('sk_test_') || stripeKey?.startsWith('rk_test_');
|
|
178
|
+
const supportedPaymentMethods = new Set([
|
|
179
|
+
Constants.Methods.tempo,
|
|
180
|
+
Constants.Methods.evm,
|
|
181
|
+
Constants.Methods.stripe,
|
|
182
|
+
]);
|
|
183
|
+
for (const challenge of challenges) {
|
|
184
|
+
if (challenge === tempoTestnetChallenge)
|
|
185
|
+
continue;
|
|
186
|
+
if (!supportedPaymentMethods.has(challenge.method))
|
|
187
|
+
continue;
|
|
188
|
+
if (!options.silent)
|
|
189
|
+
console.log('');
|
|
190
|
+
const flushStart = results.length;
|
|
191
|
+
const flush = () => {
|
|
192
|
+
if (options.onResults && results.length > flushStart)
|
|
193
|
+
options.onResults(results.slice(flushStart));
|
|
194
|
+
};
|
|
195
|
+
const tag = `Payment [${challenge.method}]`;
|
|
196
|
+
try {
|
|
197
|
+
switch (challenge.method) {
|
|
198
|
+
case Constants.Methods.tempo:
|
|
199
|
+
case Constants.Methods.evm:
|
|
200
|
+
await attemptCryptoPayment(challenge, tag, {
|
|
201
|
+
results,
|
|
202
|
+
url,
|
|
203
|
+
endpoint,
|
|
204
|
+
fetchHeaders,
|
|
205
|
+
fetchBody,
|
|
206
|
+
verbose,
|
|
207
|
+
loaded,
|
|
208
|
+
isInteractive,
|
|
209
|
+
options,
|
|
210
|
+
});
|
|
211
|
+
break;
|
|
212
|
+
case Constants.Methods.stripe:
|
|
213
|
+
await attemptStripePayment(challenge, tag, {
|
|
214
|
+
results,
|
|
215
|
+
url,
|
|
216
|
+
endpoint,
|
|
217
|
+
fetchHeaders,
|
|
218
|
+
fetchBody,
|
|
219
|
+
verbose,
|
|
220
|
+
loaded,
|
|
221
|
+
isInteractive,
|
|
222
|
+
isStripeTestKey: isStripeTestKey ?? false,
|
|
223
|
+
stripeKey,
|
|
224
|
+
options,
|
|
225
|
+
});
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
flush();
|
|
231
|
+
}
|
|
125
232
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
233
|
+
return results;
|
|
234
|
+
}
|
|
235
|
+
async function attemptCryptoPayment(challenge, tag, ctx) {
|
|
236
|
+
const { results, url, endpoint, fetchHeaders, fetchBody, verbose, loaded, options } = ctx;
|
|
237
|
+
const request = challenge.request;
|
|
238
|
+
const methodDetails = request.methodDetails;
|
|
239
|
+
const requiredAmount = isValidIntegerAmount(request.amount)
|
|
240
|
+
? BigInt(request.amount)
|
|
241
|
+
: undefined;
|
|
242
|
+
const decimals = methodDetails?.decimals ?? request.decimals ?? 6;
|
|
129
243
|
const currency = request.currency;
|
|
130
|
-
//
|
|
244
|
+
// Resolve wallet
|
|
131
245
|
let walletAddress;
|
|
132
|
-
|
|
246
|
+
try {
|
|
247
|
+
walletAddress = await resolveWalletAddress();
|
|
248
|
+
}
|
|
249
|
+
catch { }
|
|
250
|
+
if (!walletAddress) {
|
|
251
|
+
results.push(skip(tag, 'no wallet configured. Run "mppx account create" to create one.'));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
// Pre-flight balance check and chain resolution
|
|
255
|
+
let paymentChain;
|
|
256
|
+
if (challenge.method === Constants.Methods.tempo)
|
|
257
|
+
paymentChain = tempoMainnetChain;
|
|
258
|
+
else if (challenge.method === Constants.Methods.evm) {
|
|
259
|
+
const chainId = methodDetails?.chainId;
|
|
260
|
+
if (chainId)
|
|
261
|
+
paymentChain = resolveEvmChain(chainId);
|
|
262
|
+
}
|
|
263
|
+
let tokenSymbol;
|
|
264
|
+
if (requiredAmount && currency && paymentChain) {
|
|
133
265
|
try {
|
|
134
|
-
|
|
135
|
-
if (
|
|
266
|
+
let balance;
|
|
267
|
+
if (challenge.method === Constants.Methods.tempo) {
|
|
136
268
|
const client = createClient({ chain: tempoMainnetChain, transport: http() });
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
269
|
+
const info = await fetchTokenInfo(client, currency, walletAddress);
|
|
270
|
+
balance = info.balance;
|
|
271
|
+
tokenSymbol = info.symbol;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
const info = await fetchEvmTokenInfo(paymentChain, currency, walletAddress);
|
|
275
|
+
balance = info.balance;
|
|
276
|
+
tokenSymbol = info.symbol;
|
|
277
|
+
}
|
|
278
|
+
if (balance < requiredAmount) {
|
|
279
|
+
const requiredDisplay = formatAmount(requiredAmount, decimals);
|
|
280
|
+
const balanceDisplay = formatAmount(balance, decimals);
|
|
281
|
+
const symbol = tokenSymbol ?? 'tokens';
|
|
282
|
+
results.push(skip(tag, `insufficient balance (have ${balanceDisplay}, need ${requiredDisplay} ${symbol} on ${paymentChain.name})`, `Fund wallet ${walletAddress} with at least ${requiredDisplay} ${symbol} on ${paymentChain.name}.`));
|
|
283
|
+
return;
|
|
147
284
|
}
|
|
148
285
|
}
|
|
149
286
|
catch (e) {
|
|
@@ -151,29 +288,40 @@ export async function validatePaymentFlow(baseUrl, endpoint, verbose, options) {
|
|
|
151
288
|
console.log(pc.dim(` Balance check skipped: ${e.message}`));
|
|
152
289
|
}
|
|
153
290
|
}
|
|
154
|
-
// Prompt
|
|
155
|
-
const amountDisplay = requiredAmount
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
if (!options
|
|
166
|
-
|
|
167
|
-
|
|
291
|
+
// Prompt
|
|
292
|
+
const amountDisplay = requiredAmount ? formatAmount(requiredAmount, decimals) : 'unknown amount';
|
|
293
|
+
const tokenDisplay = tokenSymbol ?? (currency?.length === 3 ? currency.toUpperCase() : '');
|
|
294
|
+
const chainName = paymentChain?.name;
|
|
295
|
+
const paymentDesc = `${amountDisplay}${tokenDisplay ? ` ${tokenDisplay}` : ''}${chainName ? ` on ${chainName}` : ''}`;
|
|
296
|
+
if (!options.silent)
|
|
297
|
+
console.log(pc.dim(` Attempting payment with wallet ${walletAddress}`));
|
|
298
|
+
if (paymentChain?.testnet) {
|
|
299
|
+
if (!options.silent)
|
|
300
|
+
console.log(pc.dim(` Auto-approved: ${paymentDesc} (testnet)`));
|
|
301
|
+
}
|
|
302
|
+
else if (!options.yes && !ctx.isInteractive) {
|
|
303
|
+
results.push(skip(tag, 'non-interactive mode, use --yes to approve'));
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
else if (!options.yes) {
|
|
307
|
+
const ok = await confirm(` ${pc.yellow('Pay')} ${paymentDesc}. Continue?`, false);
|
|
168
308
|
if (!ok) {
|
|
169
|
-
results.push(skip(
|
|
170
|
-
return
|
|
309
|
+
results.push(skip(tag, 'declined'));
|
|
310
|
+
return;
|
|
171
311
|
}
|
|
172
312
|
}
|
|
173
313
|
else {
|
|
174
|
-
|
|
314
|
+
if (!options.silent)
|
|
315
|
+
console.log(pc.dim(` Auto-approved: ${paymentDesc}`));
|
|
316
|
+
}
|
|
317
|
+
// Resolve plugin and pay
|
|
318
|
+
const resolved = resolvePlugin(challenge, loaded?.config);
|
|
319
|
+
const plugin = resolved.plugin;
|
|
320
|
+
const directMethod = resolved.method;
|
|
321
|
+
if (!plugin && !directMethod) {
|
|
322
|
+
results.push(skip(tag, methodSetupHint(challenge)));
|
|
323
|
+
return;
|
|
175
324
|
}
|
|
176
|
-
// Setup plugin or use direct method
|
|
177
325
|
let methods;
|
|
178
326
|
let createCredentialFn;
|
|
179
327
|
if (plugin) {
|
|
@@ -187,26 +335,102 @@ export async function validatePaymentFlow(baseUrl, endpoint, verbose, options) {
|
|
|
187
335
|
createCredentialFn = pluginResult.createCredential;
|
|
188
336
|
}
|
|
189
337
|
catch (error) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
results.push(skip('Payment: no wallet configured', msg));
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
results.push(fail('Payment: wallet setup', msg));
|
|
196
|
-
}
|
|
197
|
-
return results;
|
|
338
|
+
results.push(skip(tag, error.message));
|
|
339
|
+
return;
|
|
198
340
|
}
|
|
199
341
|
}
|
|
200
342
|
else {
|
|
201
343
|
methods = [directMethod];
|
|
202
344
|
}
|
|
203
|
-
|
|
204
|
-
|
|
345
|
+
const credential = await createAndSend(challenge, methods, createCredentialFn, tag, results);
|
|
346
|
+
if (!credential)
|
|
347
|
+
return;
|
|
348
|
+
plugin?.prepareCredentialRequest?.({ challenge, credential, headers: fetchHeaders });
|
|
349
|
+
await sendAndValidateResponse(results, url, endpoint, credential, fetchHeaders, fetchBody, verbose, paymentChain);
|
|
350
|
+
}
|
|
351
|
+
async function attemptStripePayment(challenge, tag, ctx) {
|
|
352
|
+
const { results, url, endpoint, fetchHeaders, fetchBody, verbose, loaded, options, isStripeTestKey, stripeKey, } = ctx;
|
|
353
|
+
const request = challenge.request;
|
|
354
|
+
const requiredAmount = isValidIntegerAmount(request.amount)
|
|
355
|
+
? BigInt(request.amount)
|
|
356
|
+
: undefined;
|
|
357
|
+
const decimals = request.decimals ?? 2;
|
|
358
|
+
const currency = request.currency;
|
|
359
|
+
const amountDisplay = requiredAmount ? formatAmount(requiredAmount, decimals) : 'unknown amount';
|
|
360
|
+
const tokenDisplay = currency?.length === 3 ? currency.toUpperCase() : '';
|
|
361
|
+
const paymentDesc = `${amountDisplay}${tokenDisplay ? ` ${tokenDisplay}` : ''} via Stripe${isStripeTestKey ? ' (testmode)' : ''}`;
|
|
362
|
+
if (isStripeTestKey) {
|
|
363
|
+
if (!options.silent)
|
|
364
|
+
console.log(pc.dim(` Attempting: ${paymentDesc}`));
|
|
365
|
+
}
|
|
366
|
+
else if (!options.yes && !ctx.isInteractive) {
|
|
367
|
+
results.push(skip(tag, 'non-interactive mode, use --yes to approve'));
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
else if (!options.yes) {
|
|
371
|
+
const ok = await confirm(` ${pc.yellow('Pay')} ${paymentDesc}. Continue?`, false);
|
|
372
|
+
if (!ok) {
|
|
373
|
+
results.push(skip(tag, 'declined'));
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
if (!options.silent)
|
|
379
|
+
console.log(pc.dim(` Auto-approved: ${paymentDesc}`));
|
|
380
|
+
}
|
|
381
|
+
// Resolve plugin
|
|
382
|
+
const resolved = resolvePlugin(challenge, loaded?.config);
|
|
383
|
+
const plugin = resolved.plugin;
|
|
384
|
+
if (!plugin) {
|
|
385
|
+
results.push(skip(tag, 'no Stripe plugin available'));
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
let methods;
|
|
389
|
+
let createCredentialFn;
|
|
390
|
+
try {
|
|
391
|
+
const methodOpts = { paymentMethod: 'pm_card_visa' };
|
|
392
|
+
if (stripeKey)
|
|
393
|
+
methodOpts.secretKey = stripeKey;
|
|
394
|
+
const pluginResult = await plugin.setup({
|
|
395
|
+
challenge,
|
|
396
|
+
options: {},
|
|
397
|
+
methodOpts,
|
|
398
|
+
});
|
|
399
|
+
methods = pluginResult.methods;
|
|
400
|
+
createCredentialFn = pluginResult.createCredential;
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
results.push(skip(tag, error.message));
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
const credential = await createAndSend(challenge, methods, createCredentialFn, tag, results);
|
|
407
|
+
if (!credential)
|
|
408
|
+
return;
|
|
409
|
+
plugin.prepareCredentialRequest?.({ challenge, credential, headers: fetchHeaders });
|
|
410
|
+
// Stripe testmode: detect livemode rejection gracefully
|
|
411
|
+
if (isStripeTestKey) {
|
|
412
|
+
const resp = await fetchWithTimeout(url, {
|
|
413
|
+
method: endpoint.method,
|
|
414
|
+
headers: { ...fetchHeaders, [Constants.Headers.authorization]: credential },
|
|
415
|
+
body: fetchBody ?? null,
|
|
416
|
+
}, 30_000);
|
|
417
|
+
if (resp.status >= 200 && resp.status < 300) {
|
|
418
|
+
results.push(check(`${tag}: successful`, `HTTP ${resp.status}`));
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
results.push(skip(`${tag}: server is in livemode`, undefined, 'Run your server with a Stripe test key to automatically validate Stripe payments in testmode.'));
|
|
422
|
+
}
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
await sendAndValidateResponse(results, url, endpoint, credential, fetchHeaders, fetchBody, verbose, undefined);
|
|
426
|
+
}
|
|
427
|
+
async function createAndSend(challenge, methods, createCredentialFn, tag, results) {
|
|
205
428
|
const fakeResponse = new Response(null, {
|
|
206
429
|
status: 402,
|
|
207
430
|
headers: { [Constants.Headers.wwwAuthenticate]: Challenge.serialize(challenge) },
|
|
208
431
|
});
|
|
209
432
|
try {
|
|
433
|
+
let credential;
|
|
210
434
|
if (createCredentialFn) {
|
|
211
435
|
credential = await createCredentialFn(fakeResponse);
|
|
212
436
|
}
|
|
@@ -214,39 +438,21 @@ export async function validatePaymentFlow(baseUrl, endpoint, verbose, options) {
|
|
|
214
438
|
const mppx = Mppx.create({ methods, polyfill: false });
|
|
215
439
|
credential = await mppx.createCredential(fakeResponse);
|
|
216
440
|
}
|
|
441
|
+
results.push(check(`${tag}: submitted`));
|
|
442
|
+
return credential;
|
|
217
443
|
}
|
|
218
444
|
catch (error) {
|
|
219
445
|
const msg = error.message;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (isInsufficientBalance) {
|
|
223
|
-
const match = msg.match(/available:\s*(\d+),\s*required:\s*(\d+)/);
|
|
224
|
-
const available = match ? BigInt(match[1]) : undefined;
|
|
225
|
-
const required = match ? BigInt(match[2]) : requiredAmount;
|
|
226
|
-
const fromMatch = msg.match(/from:\s*(0x[0-9a-fA-F]{40})/);
|
|
227
|
-
const fromAddr = fromMatch?.[1];
|
|
228
|
-
const requiredDisplay = required
|
|
229
|
-
? `$${(Number(required) / 10 ** decimals).toFixed(2)}`
|
|
230
|
-
: 'unknown';
|
|
231
|
-
const availableDisplay = available !== undefined ? `$${(Number(available) / 10 ** decimals).toFixed(2)}` : undefined;
|
|
232
|
-
const detail = availableDisplay
|
|
233
|
-
? `Have ${availableDisplay}, need ${requiredDisplay}`
|
|
234
|
-
: `Endpoint requires ${requiredDisplay}`;
|
|
235
|
-
const hint = fromAddr
|
|
236
|
-
? `Wallet ${fromAddr} needs at least ${requiredDisplay}. This is a local wallet created by "mppx account create". Fund it to run payment tests, or point at a testnet server for free validation.`
|
|
237
|
-
: `Fund your mppx wallet with at least ${requiredDisplay} to run payment tests, or use a testnet server.`;
|
|
238
|
-
results.push(skip('Payment: insufficient balance', detail, hint));
|
|
239
|
-
return results;
|
|
446
|
+
if (msg.toLowerCase().includes('insufficient')) {
|
|
447
|
+
results.push(skip(tag, `insufficient balance: ${msg}`));
|
|
240
448
|
}
|
|
241
|
-
|
|
242
|
-
|
|
449
|
+
else {
|
|
450
|
+
results.push(fail(tag, msg));
|
|
451
|
+
}
|
|
452
|
+
return undefined;
|
|
243
453
|
}
|
|
244
|
-
results.push(check('Payment: credential created'));
|
|
245
|
-
// Prepare and send
|
|
246
|
-
plugin?.prepareCredentialRequest?.({ challenge, credential, headers: fetchHeaders });
|
|
247
|
-
return await sendAndValidateResponse(results, url, endpoint, credential, fetchHeaders, fetchBody, verbose, isTestnet);
|
|
248
454
|
}
|
|
249
|
-
async function sendAndValidateResponse(results, url, endpoint, credential, baseHeaders, fetchBody, verbose,
|
|
455
|
+
async function sendAndValidateResponse(results, url, endpoint, credential, baseHeaders, fetchBody, verbose, explorerChain) {
|
|
250
456
|
let paymentResponse;
|
|
251
457
|
try {
|
|
252
458
|
paymentResponse = await fetchWithTimeout(url, {
|
|
@@ -367,10 +573,10 @@ async function sendAndValidateResponse(results, url, endpoint, credential, baseH
|
|
|
367
573
|
try {
|
|
368
574
|
const receipt = Receipt.deserialize(receiptHeader);
|
|
369
575
|
if (receipt.reference && /^0x[0-9a-fA-F]{64}$/.test(receipt.reference)) {
|
|
370
|
-
const
|
|
371
|
-
const explorerUrl = chain.blockExplorers?.default?.url;
|
|
576
|
+
const explorerUrl = explorerChain?.blockExplorers?.default?.url;
|
|
372
577
|
if (explorerUrl) {
|
|
373
|
-
|
|
578
|
+
const path = explorerUrl.includes('tempo') ? 'receipt' : 'tx';
|
|
579
|
+
results.push(check('On-chain transaction', `${explorerUrl}/${path}/${receipt.reference}`));
|
|
374
580
|
}
|
|
375
581
|
}
|
|
376
582
|
}
|