@dexterai/x402 1.9.1 → 1.9.3
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/README.md +12 -0
- package/dist/server/index.cjs +134 -116
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +10 -7
- package/dist/server/index.d.ts +10 -7
- package/dist/server/index.js +133 -116
- package/dist/server/index.js.map +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -77,10 +77,22 @@ The simplest way to make x402 payments from scripts:
|
|
|
77
77
|
```typescript
|
|
78
78
|
import { wrapFetch } from '@dexterai/x402/client';
|
|
79
79
|
|
|
80
|
+
// Solana
|
|
80
81
|
const x402Fetch = wrapFetch(fetch, {
|
|
81
82
|
walletPrivateKey: process.env.SOLANA_PRIVATE_KEY,
|
|
82
83
|
});
|
|
83
84
|
|
|
85
|
+
// EVM (Base, Polygon, Arbitrum, Optimism, Avalanche, SKALE)
|
|
86
|
+
const x402Fetch = wrapFetch(fetch, {
|
|
87
|
+
evmPrivateKey: process.env.EVM_PRIVATE_KEY, // requires: npm install viem
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Both — SDK picks the chain with balance
|
|
91
|
+
const x402Fetch = wrapFetch(fetch, {
|
|
92
|
+
walletPrivateKey: process.env.SOLANA_PRIVATE_KEY,
|
|
93
|
+
evmPrivateKey: process.env.EVM_PRIVATE_KEY,
|
|
94
|
+
});
|
|
95
|
+
|
|
84
96
|
// That's it. 402 responses are handled automatically.
|
|
85
97
|
const response = await x402Fetch('https://api.example.com/protected');
|
|
86
98
|
```
|
package/dist/server/index.cjs
CHANGED
|
@@ -44,6 +44,7 @@ __export(server_exports, {
|
|
|
44
44
|
createDynamicPricing: () => createDynamicPricing,
|
|
45
45
|
createTokenPricing: () => createTokenPricing,
|
|
46
46
|
createX402Server: () => createX402Server,
|
|
47
|
+
escapeHtml: () => escapeHtml,
|
|
47
48
|
estimateCost: () => estimateCost,
|
|
48
49
|
findModel: () => findModel,
|
|
49
50
|
formatModelPricing: () => formatModelPricing,
|
|
@@ -431,9 +432,104 @@ function createX402Server(config) {
|
|
|
431
432
|
};
|
|
432
433
|
}
|
|
433
434
|
|
|
435
|
+
// src/server/stripe-payto.ts
|
|
436
|
+
var stripeProviderNetworks = /* @__PURE__ */ new WeakMap();
|
|
437
|
+
function getStripeProviderNetwork(provider) {
|
|
438
|
+
return stripeProviderNetworks.get(provider);
|
|
439
|
+
}
|
|
440
|
+
var STRIPE_NETWORK_KEYS = {
|
|
441
|
+
"base": "base",
|
|
442
|
+
"base-sepolia": "base_sepolia"
|
|
443
|
+
};
|
|
444
|
+
var CAIP2_NETWORKS = {
|
|
445
|
+
"base": "eip155:8453",
|
|
446
|
+
"base-sepolia": "eip155:84532"
|
|
447
|
+
};
|
|
448
|
+
var USDC_DECIMALS = 6;
|
|
449
|
+
function stripePayTo(secretKeyOrConfig) {
|
|
450
|
+
const config = typeof secretKeyOrConfig === "string" ? { secretKey: secretKeyOrConfig } : secretKeyOrConfig;
|
|
451
|
+
const networkName = config.network ?? "base";
|
|
452
|
+
const stripeNetworkKey = STRIPE_NETWORK_KEYS[networkName] ?? "base";
|
|
453
|
+
const caip2Network = CAIP2_NETWORKS[networkName] ?? "eip155:8453";
|
|
454
|
+
const apiVersion = config.apiVersion ?? "2026-01-28.clover";
|
|
455
|
+
let stripeClient = null;
|
|
456
|
+
async function getStripe() {
|
|
457
|
+
if (stripeClient) return stripeClient;
|
|
458
|
+
try {
|
|
459
|
+
const { default: Stripe } = await import("stripe");
|
|
460
|
+
stripeClient = new Stripe(config.secretKey, {
|
|
461
|
+
apiVersion,
|
|
462
|
+
appInfo: {
|
|
463
|
+
name: "@dexterai/x402",
|
|
464
|
+
url: "https://dexter.cash/sdk"
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
return stripeClient;
|
|
468
|
+
} catch {
|
|
469
|
+
throw new Error(
|
|
470
|
+
'The "stripe" package is required for stripePayTo(). Install it with: npm install stripe'
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
const provider = async (context) => {
|
|
475
|
+
if (context.paymentHeader) {
|
|
476
|
+
try {
|
|
477
|
+
const decoded = JSON.parse(
|
|
478
|
+
Buffer.from(context.paymentHeader, "base64").toString()
|
|
479
|
+
);
|
|
480
|
+
const toAddress = decoded.payload?.authorization?.to;
|
|
481
|
+
if (toAddress && typeof toAddress === "string") {
|
|
482
|
+
return toAddress;
|
|
483
|
+
}
|
|
484
|
+
const acceptedPayTo = decoded.accepted?.payTo;
|
|
485
|
+
if (acceptedPayTo && typeof acceptedPayTo === "string") {
|
|
486
|
+
return acceptedPayTo;
|
|
487
|
+
}
|
|
488
|
+
} catch {
|
|
489
|
+
}
|
|
490
|
+
throw new Error(
|
|
491
|
+
"Could not extract deposit address from payment header. Ensure the client is sending a valid x402 PAYMENT-SIGNATURE."
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
const stripe = await getStripe();
|
|
495
|
+
const amountAtomic = context.amountAtomic ? parseInt(context.amountAtomic, 10) : 1e4;
|
|
496
|
+
const amountInCents = Math.max(1, Math.round(amountAtomic / Math.pow(10, USDC_DECIMALS - 2)));
|
|
497
|
+
const paymentIntent = await stripe.paymentIntents.create({
|
|
498
|
+
amount: amountInCents,
|
|
499
|
+
currency: "usd",
|
|
500
|
+
payment_method_types: ["crypto"],
|
|
501
|
+
payment_method_data: { type: "crypto" },
|
|
502
|
+
payment_method_options: {
|
|
503
|
+
crypto: { mode: "custom" }
|
|
504
|
+
},
|
|
505
|
+
confirm: true
|
|
506
|
+
});
|
|
507
|
+
const nextAction = paymentIntent.next_action;
|
|
508
|
+
if (!nextAction?.crypto_collect_deposit_details) {
|
|
509
|
+
throw new Error(
|
|
510
|
+
"Stripe PaymentIntent did not return crypto deposit details. Ensure your Stripe account has crypto payins enabled: https://support.stripe.com/questions/get-started-with-pay-with-crypto"
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
const depositDetails = nextAction.crypto_collect_deposit_details;
|
|
514
|
+
const payToAddress = depositDetails.deposit_addresses?.[stripeNetworkKey]?.address;
|
|
515
|
+
if (!payToAddress) {
|
|
516
|
+
throw new Error(
|
|
517
|
+
`No deposit address found for network "${stripeNetworkKey}". Available networks: ${Object.keys(depositDetails.deposit_addresses || {}).join(", ")}`
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
return payToAddress;
|
|
521
|
+
};
|
|
522
|
+
provider._x402Defaults = {
|
|
523
|
+
network: caip2Network,
|
|
524
|
+
facilitatorUrl: "https://x402.dexter.cash"
|
|
525
|
+
};
|
|
526
|
+
stripeProviderNetworks.set(provider, caip2Network);
|
|
527
|
+
return provider;
|
|
528
|
+
}
|
|
529
|
+
|
|
434
530
|
// src/server/middleware.ts
|
|
435
531
|
var DEFAULT_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
|
436
|
-
var
|
|
532
|
+
var USDC_DECIMALS2 = 6;
|
|
437
533
|
function resolvePayToForNetwork(payTo, network) {
|
|
438
534
|
if (typeof payTo === "string" || typeof payTo === "function") return payTo;
|
|
439
535
|
if (network in payTo) return payTo[network];
|
|
@@ -471,9 +567,9 @@ function x402Middleware(config) {
|
|
|
471
567
|
const servers = /* @__PURE__ */ new Map();
|
|
472
568
|
for (const net of configuredNetworks) {
|
|
473
569
|
const netPayTo = resolvePayToForNetwork(payTo, net);
|
|
474
|
-
if (typeof netPayTo === "function"
|
|
475
|
-
const stripeNet = netPayTo
|
|
476
|
-
if (net !== stripeNet) {
|
|
570
|
+
if (typeof netPayTo === "function") {
|
|
571
|
+
const stripeNet = getStripeProviderNetwork(netPayTo);
|
|
572
|
+
if (stripeNet && net !== stripeNet) {
|
|
477
573
|
throw new Error(
|
|
478
574
|
`stripePayTo is configured for "${stripeNet}" but middleware includes network "${net}". Stripe only supports Base deposit addresses. Use a static payTo for other chains.`
|
|
479
575
|
);
|
|
@@ -496,7 +592,7 @@ function x402Middleware(config) {
|
|
|
496
592
|
const resourceUrl = getResourceUrl?.(req) ?? staticResourceUrl ?? `${req.protocol}://${req.get("host")}${req.originalUrl}`;
|
|
497
593
|
const requestAmount = getAmount?.(req) ?? amount;
|
|
498
594
|
const requestDescription = getDescription?.(req) ?? description;
|
|
499
|
-
const decimals = asset?.decimals ??
|
|
595
|
+
const decimals = asset?.decimals ?? USDC_DECIMALS2;
|
|
500
596
|
const amountAtomic = toAtomicUnits(parseFloat(requestAmount), decimals);
|
|
501
597
|
const requirementsOptions = {
|
|
502
598
|
amountAtomic,
|
|
@@ -615,7 +711,7 @@ function x402Middleware(config) {
|
|
|
615
711
|
}
|
|
616
712
|
|
|
617
713
|
// src/server/browser-support.ts
|
|
618
|
-
function
|
|
714
|
+
function escapeHtml(s) {
|
|
619
715
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
620
716
|
}
|
|
621
717
|
var USDC_ICON_SVG = `<svg width="18" height="18" viewBox="0 0 2000 2000" xmlns="http://www.w3.org/2000/svg"><path d="M1000 2000c554.17 0 1000-445.83 1000-1000S1554.17 0 1000 0 0 445.83 0 1000s445.83 1000 1000 1000z" fill="#2775ca"/><path d="M1275 1158.33c0-145.83-87.5-195.83-262.5-216.66-125-16.67-150-50-150-108.34s41.67-95.83 125-95.83c75 0 116.67 25 137.5 87.5 4.17 12.5 16.67 20.83 29.17 20.83h66.66c16.67 0 29.17-12.5 29.17-29.16v-4.17c-16.67-91.67-91.67-162.5-187.5-170.83v-100c0-16.67-12.5-29.17-33.33-33.34h-62.5c-16.67 0-29.17 12.5-33.34 33.34v95.83c-125 16.67-204.16 100-204.16 204.17 0 137.5 83.33 191.66 258.33 212.5 116.67 20.83 154.17 45.83 154.17 112.5s-58.34 112.5-137.5 112.5c-108.34 0-145.84-45.84-158.34-108.34-4.16-16.66-16.66-25-29.16-25h-70.84c-16.66 0-29.16 12.5-29.16 29.17v4.17c16.66 104.16 83.33 179.16 220.83 200v100c0 16.66 12.5 29.16 33.33 33.33h62.5c16.67 0 29.17-12.5 33.34-33.33v-100c125-20.84 208.33-108.34 208.33-220.84z" fill="#fff"/><path d="M787.5 1595.83c-325-116.66-491.67-479.16-370.83-800 62.5-175 200-308.33 370.83-370.83 16.67-8.33 25-20.83 25-41.67V325c0-16.67-8.33-29.17-25-33.33-4.17 0-12.5 0-16.67 4.16-395.83 125-612.5 545.84-487.5 941.67 75 233.33 254.17 412.5 487.5 487.5 16.67 8.33 33.34 0 37.5-16.67 4.17-4.16 4.17-8.33 4.17-16.66v-58.34c0-12.5-12.5-29.16-25-37.5zM1229.17 295.83c-16.67-8.33-33.34 0-37.5 16.67-4.17 4.17-4.17 8.33-4.17 16.67v58.33c0 16.67 12.5 33.33 25 41.67 325 116.66 491.67 479.16 370.83 800-62.5 175-200 308.33-370.83 370.83-16.67 8.33-25 20.83-25 41.67V1700c0 16.67 8.33 29.17 25 33.33 4.17 0 12.5 0 16.67-4.16 395.83-125 612.5-545.84 487.5-941.67-75-237.5-258.34-416.67-487.5-491.67z" fill="#fff"/></svg>`;
|
|
@@ -877,22 +973,22 @@ function generatePaywallHtml(paymentRequiredHeader, requestUrl, method, config,
|
|
|
877
973
|
} catch {
|
|
878
974
|
}
|
|
879
975
|
const chainName = network.includes("solana") ? "Solana" : network.includes("eip155") ? "Base" : "";
|
|
880
|
-
const endpointSection = config.showEndpoint ? `<div class="endpoint"><code>${
|
|
976
|
+
const endpointSection = config.showEndpoint ? `<div class="endpoint"><code>${escapeHtml(method)} ${escapeHtml(requestUrl)}</code></div>` : "";
|
|
881
977
|
return `<!DOCTYPE html>
|
|
882
978
|
<html lang="en">
|
|
883
979
|
<head>
|
|
884
980
|
<meta charset="utf-8">
|
|
885
981
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
886
|
-
<title>${
|
|
982
|
+
<title>${escapeHtml(config.title)} \u2014 ${escapeHtml(price)} USDC</title>
|
|
887
983
|
<style>${DEXTER_STYLES}${PAY_BUTTON_STYLES}</style>
|
|
888
984
|
</head>
|
|
889
985
|
<body>
|
|
890
986
|
<div class="card">
|
|
891
987
|
<div class="crest">${DEXTER_CREST_SVG}</div>
|
|
892
|
-
<h1>${
|
|
893
|
-
<p class="desc">${
|
|
894
|
-
<div class="price">${USDC_ICON_SVG}<span id="price-value">${
|
|
895
|
-
<div class="chain">${
|
|
988
|
+
<h1>${escapeHtml(config.title)}</h1>
|
|
989
|
+
<p class="desc">${escapeHtml(description)}</p>
|
|
990
|
+
<div class="price">${USDC_ICON_SVG}<span id="price-value">${escapeHtml(price)}</span></div>
|
|
991
|
+
<div class="chain">${escapeHtml(chainName)}${chainName ? " network" : ""}</div>
|
|
896
992
|
${endpointSection}
|
|
897
993
|
|
|
898
994
|
<div id="pay-section" class="pay-section" style="display:none">
|
|
@@ -1017,7 +1113,7 @@ function verifyJwt(token, secret) {
|
|
|
1017
1113
|
}
|
|
1018
1114
|
}
|
|
1019
1115
|
var DEFAULT_NETWORK2 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
|
1020
|
-
var
|
|
1116
|
+
var USDC_DECIMALS3 = 6;
|
|
1021
1117
|
function x402AccessPass(config) {
|
|
1022
1118
|
const {
|
|
1023
1119
|
payTo,
|
|
@@ -1040,7 +1136,7 @@ function x402AccessPass(config) {
|
|
|
1040
1136
|
}
|
|
1041
1137
|
const log = verbose ? console.log.bind(console, "[x402:access-pass]") : () => {
|
|
1042
1138
|
};
|
|
1043
|
-
const decimals = asset?.decimals ??
|
|
1139
|
+
const decimals = asset?.decimals ?? USDC_DECIMALS3;
|
|
1044
1140
|
const builtTiers = [];
|
|
1045
1141
|
if (tierPrices) {
|
|
1046
1142
|
for (const [id, price] of Object.entries(tierPrices)) {
|
|
@@ -1304,7 +1400,6 @@ function formatPricing(config) {
|
|
|
1304
1400
|
|
|
1305
1401
|
// src/server/token-pricing.ts
|
|
1306
1402
|
var import_crypto3 = require("crypto");
|
|
1307
|
-
var import_tiktoken = require("tiktoken");
|
|
1308
1403
|
|
|
1309
1404
|
// src/server/model-registry.ts
|
|
1310
1405
|
var STANDARD_PARAMS = {
|
|
@@ -1881,17 +1976,30 @@ var MODEL_PRICING_MAP = Object.fromEntries(
|
|
|
1881
1976
|
);
|
|
1882
1977
|
|
|
1883
1978
|
// src/server/token-pricing.ts
|
|
1979
|
+
var _tiktoken = null;
|
|
1980
|
+
async function loadTiktoken() {
|
|
1981
|
+
if (_tiktoken) return _tiktoken;
|
|
1982
|
+
try {
|
|
1983
|
+
_tiktoken = await import("tiktoken");
|
|
1984
|
+
return _tiktoken;
|
|
1985
|
+
} catch {
|
|
1986
|
+
throw new Error(
|
|
1987
|
+
'Token pricing requires the "tiktoken" package. Install with: npm install tiktoken'
|
|
1988
|
+
);
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1884
1991
|
var MODEL_PRICING = MODEL_PRICING_MAP;
|
|
1885
1992
|
var DEFAULT_MODEL = "gpt-4o-mini";
|
|
1886
|
-
function getEncodingForModel(model) {
|
|
1993
|
+
async function getEncodingForModel(model) {
|
|
1994
|
+
const tiktoken = await loadTiktoken();
|
|
1887
1995
|
try {
|
|
1888
|
-
return
|
|
1996
|
+
return tiktoken.encoding_for_model(model);
|
|
1889
1997
|
} catch {
|
|
1890
|
-
return
|
|
1998
|
+
return tiktoken.get_encoding("cl100k_base");
|
|
1891
1999
|
}
|
|
1892
2000
|
}
|
|
1893
|
-
function countTokens(text, model = DEFAULT_MODEL) {
|
|
1894
|
-
const encoding = getEncodingForModel(model);
|
|
2001
|
+
async function countTokens(text, model = DEFAULT_MODEL) {
|
|
2002
|
+
const encoding = await getEncodingForModel(model);
|
|
1895
2003
|
try {
|
|
1896
2004
|
const tokens = encoding.encode(text);
|
|
1897
2005
|
return tokens.length;
|
|
@@ -1925,17 +2033,17 @@ function createTokenPricing(config = {}) {
|
|
|
1925
2033
|
decimals: config.decimals ?? 6
|
|
1926
2034
|
};
|
|
1927
2035
|
const { minUsd, maxUsd, decimals } = fullConfig;
|
|
1928
|
-
function countTokensInternal(input) {
|
|
2036
|
+
async function countTokensInternal(input) {
|
|
1929
2037
|
if (customTokenizer) {
|
|
1930
2038
|
return customTokenizer(input);
|
|
1931
2039
|
}
|
|
1932
2040
|
return countTokens(input, model);
|
|
1933
2041
|
}
|
|
1934
|
-
function calculate(input, systemPrompt) {
|
|
2042
|
+
async function calculate(input, systemPrompt) {
|
|
1935
2043
|
const fullInput = systemPrompt ? `${systemPrompt}
|
|
1936
2044
|
|
|
1937
2045
|
${input}` : input;
|
|
1938
|
-
const inputTokens = countTokensInternal(fullInput);
|
|
2046
|
+
const inputTokens = await countTokensInternal(fullInput);
|
|
1939
2047
|
let usdAmount = inputTokens / 1e6 * modelInfo.input;
|
|
1940
2048
|
usdAmount = Math.max(usdAmount, minUsd);
|
|
1941
2049
|
usdAmount = Math.min(usdAmount, maxUsd);
|
|
@@ -1954,9 +2062,9 @@ ${input}` : input;
|
|
|
1954
2062
|
quoteHash
|
|
1955
2063
|
};
|
|
1956
2064
|
}
|
|
1957
|
-
function validateQuote(input, quoteHash) {
|
|
2065
|
+
async function validateQuote(input, quoteHash) {
|
|
1958
2066
|
if (!quoteHash) return false;
|
|
1959
|
-
const inputTokens = countTokensInternal(input);
|
|
2067
|
+
const inputTokens = await countTokensInternal(input);
|
|
1960
2068
|
const expectedHash = generateQuoteHash(input, model, modelInfo.input, inputTokens);
|
|
1961
2069
|
return expectedHash === quoteHash;
|
|
1962
2070
|
}
|
|
@@ -1991,97 +2099,6 @@ function formatTokenPricing(model = DEFAULT_MODEL) {
|
|
|
1991
2099
|
return `$${pricing.input.toFixed(2)} per 1M tokens (${actualModel})`;
|
|
1992
2100
|
}
|
|
1993
2101
|
|
|
1994
|
-
// src/server/stripe-payto.ts
|
|
1995
|
-
var STRIPE_NETWORK_KEYS = {
|
|
1996
|
-
"base": "base",
|
|
1997
|
-
"base-sepolia": "base_sepolia"
|
|
1998
|
-
};
|
|
1999
|
-
var CAIP2_NETWORKS = {
|
|
2000
|
-
"base": "eip155:8453",
|
|
2001
|
-
"base-sepolia": "eip155:84532"
|
|
2002
|
-
};
|
|
2003
|
-
var USDC_DECIMALS3 = 6;
|
|
2004
|
-
function stripePayTo(secretKeyOrConfig) {
|
|
2005
|
-
const config = typeof secretKeyOrConfig === "string" ? { secretKey: secretKeyOrConfig } : secretKeyOrConfig;
|
|
2006
|
-
const networkName = config.network ?? "base";
|
|
2007
|
-
const stripeNetworkKey = STRIPE_NETWORK_KEYS[networkName] ?? "base";
|
|
2008
|
-
const caip2Network = CAIP2_NETWORKS[networkName] ?? "eip155:8453";
|
|
2009
|
-
const apiVersion = config.apiVersion ?? "2026-01-28.clover";
|
|
2010
|
-
let stripeClient = null;
|
|
2011
|
-
async function getStripe() {
|
|
2012
|
-
if (stripeClient) return stripeClient;
|
|
2013
|
-
try {
|
|
2014
|
-
const { default: Stripe } = await import("stripe");
|
|
2015
|
-
stripeClient = new Stripe(config.secretKey, {
|
|
2016
|
-
apiVersion,
|
|
2017
|
-
appInfo: {
|
|
2018
|
-
name: "@dexterai/x402",
|
|
2019
|
-
url: "https://dexter.cash/sdk"
|
|
2020
|
-
}
|
|
2021
|
-
});
|
|
2022
|
-
return stripeClient;
|
|
2023
|
-
} catch {
|
|
2024
|
-
throw new Error(
|
|
2025
|
-
'The "stripe" package is required for stripePayTo(). Install it with: npm install stripe'
|
|
2026
|
-
);
|
|
2027
|
-
}
|
|
2028
|
-
}
|
|
2029
|
-
const provider = async (context) => {
|
|
2030
|
-
if (context.paymentHeader) {
|
|
2031
|
-
try {
|
|
2032
|
-
const decoded = JSON.parse(
|
|
2033
|
-
Buffer.from(context.paymentHeader, "base64").toString()
|
|
2034
|
-
);
|
|
2035
|
-
const toAddress = decoded.payload?.authorization?.to;
|
|
2036
|
-
if (toAddress && typeof toAddress === "string") {
|
|
2037
|
-
return toAddress;
|
|
2038
|
-
}
|
|
2039
|
-
const acceptedPayTo = decoded.accepted?.payTo;
|
|
2040
|
-
if (acceptedPayTo && typeof acceptedPayTo === "string") {
|
|
2041
|
-
return acceptedPayTo;
|
|
2042
|
-
}
|
|
2043
|
-
} catch {
|
|
2044
|
-
}
|
|
2045
|
-
throw new Error(
|
|
2046
|
-
"Could not extract deposit address from payment header. Ensure the client is sending a valid x402 PAYMENT-SIGNATURE."
|
|
2047
|
-
);
|
|
2048
|
-
}
|
|
2049
|
-
const stripe = await getStripe();
|
|
2050
|
-
const amountAtomic = context.amountAtomic ? parseInt(context.amountAtomic, 10) : 1e4;
|
|
2051
|
-
const amountInCents = Math.max(1, Math.round(amountAtomic / Math.pow(10, USDC_DECIMALS3 - 2)));
|
|
2052
|
-
const paymentIntent = await stripe.paymentIntents.create({
|
|
2053
|
-
amount: amountInCents,
|
|
2054
|
-
currency: "usd",
|
|
2055
|
-
payment_method_types: ["crypto"],
|
|
2056
|
-
payment_method_data: { type: "crypto" },
|
|
2057
|
-
payment_method_options: {
|
|
2058
|
-
crypto: { mode: "custom" }
|
|
2059
|
-
},
|
|
2060
|
-
confirm: true
|
|
2061
|
-
});
|
|
2062
|
-
const nextAction = paymentIntent.next_action;
|
|
2063
|
-
if (!nextAction?.crypto_collect_deposit_details) {
|
|
2064
|
-
throw new Error(
|
|
2065
|
-
"Stripe PaymentIntent did not return crypto deposit details. Ensure your Stripe account has crypto payins enabled: https://support.stripe.com/questions/get-started-with-pay-with-crypto"
|
|
2066
|
-
);
|
|
2067
|
-
}
|
|
2068
|
-
const depositDetails = nextAction.crypto_collect_deposit_details;
|
|
2069
|
-
const payToAddress = depositDetails.deposit_addresses?.[stripeNetworkKey]?.address;
|
|
2070
|
-
if (!payToAddress) {
|
|
2071
|
-
throw new Error(
|
|
2072
|
-
`No deposit address found for network "${stripeNetworkKey}". Available networks: ${Object.keys(depositDetails.deposit_addresses || {}).join(", ")}`
|
|
2073
|
-
);
|
|
2074
|
-
}
|
|
2075
|
-
return payToAddress;
|
|
2076
|
-
};
|
|
2077
|
-
provider._x402Defaults = {
|
|
2078
|
-
network: caip2Network,
|
|
2079
|
-
facilitatorUrl: "https://x402.dexter.cash"
|
|
2080
|
-
};
|
|
2081
|
-
provider._stripeNetwork = caip2Network;
|
|
2082
|
-
return provider;
|
|
2083
|
-
}
|
|
2084
|
-
|
|
2085
2102
|
// src/server/index.ts
|
|
2086
2103
|
var import_x402_ads_types = require("@dexterai/x402-ads-types");
|
|
2087
2104
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -2100,6 +2117,7 @@ var import_x402_ads_types = require("@dexterai/x402-ads-types");
|
|
|
2100
2117
|
createDynamicPricing,
|
|
2101
2118
|
createTokenPricing,
|
|
2102
2119
|
createX402Server,
|
|
2120
|
+
escapeHtml,
|
|
2103
2121
|
estimateCost,
|
|
2104
2122
|
findModel,
|
|
2105
2123
|
formatModelPricing,
|