@dexterai/x402 2.1.0 → 3.0.1
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/dist/adapters/index.cjs +80 -12
- package/dist/adapters/index.d.cts +2 -2
- package/dist/adapters/index.d.ts +2 -2
- package/dist/adapters/index.js +80 -12
- package/dist/client/index.cjs +99 -65
- package/dist/client/index.d.cts +5 -105
- package/dist/client/index.d.ts +5 -105
- package/dist/client/index.js +98 -64
- package/dist/react/index.cjs +86 -12
- package/dist/react/index.d.cts +3 -3
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js +86 -12
- package/dist/{sponsored-access-Lxa11w_X.d.ts → sponsored-access-BVoucsEW.d.ts} +1 -1
- package/dist/{sponsored-access-DAVzu4x6.d.cts → sponsored-access-CE7WpV5b.d.cts} +1 -1
- package/dist/{types-D1u7iu8n.d.cts → types-C_aQh02s.d.cts} +24 -0
- package/dist/{types-YQlJI5E3.d.ts → types-DBS0XOsH.d.ts} +24 -0
- package/package.json +3 -2
package/dist/client/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export { P as PaymentReceipt, a as X402Client, X as X402ClientConfig, c as createX402Client, f as fireImpressionBeacon, g as getPaymentReceipt, d as getSponsoredAccessInfo, b as getSponsoredRecommendations } from '../sponsored-access-
|
|
1
|
+
export { P as PaymentReceipt, a as X402Client, X as X402ClientConfig, c as createX402Client, f as fireImpressionBeacon, g as getPaymentReceipt, d as getSponsoredAccessInfo, b as getSponsoredRecommendations } from '../sponsored-access-BVoucsEW.js';
|
|
2
2
|
import { A as AccessPassClientConfig, P as PaymentAccept } from '../types-_iT11DL0.js';
|
|
3
3
|
export { b as AccessPassInfo, a as AccessPassTier, D as DEXTER_FACILITATOR_URL, U as USDC_MINT, X as X402Error } from '../types-_iT11DL0.js';
|
|
4
4
|
import { Keypair } from '@solana/web3.js';
|
|
5
|
-
import { S as SolanaWallet, E as EvmWallet } from '../types-
|
|
6
|
-
export { B as BASE_MAINNET, C as ChainAdapter, b as SOLANA_MAINNET, W as WalletSet, a as createEvmAdapter, c as createSolanaAdapter } from '../types-
|
|
5
|
+
import { S as SolanaWallet, E as EvmWallet } from '../types-DBS0XOsH.js';
|
|
6
|
+
export { B as BASE_MAINNET, C as ChainAdapter, b as SOLANA_MAINNET, W as WalletSet, a as createEvmAdapter, c as createSolanaAdapter } from '../types-DBS0XOsH.js';
|
|
7
|
+
export { FormattedResource as CapabilityAPI, CapabilitySearchOptions, CapabilitySearchResult, NoMatchReason, capabilitySearch } from '@dexterai/x402-core';
|
|
7
8
|
export { SponsoredAccessSettlementInfo, SponsoredRecommendation } from '@dexterai/x402-ads-types';
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -237,107 +238,6 @@ declare function createEvmKeypairWallet(privateKey: string): Promise<EvmWallet>;
|
|
|
237
238
|
*/
|
|
238
239
|
declare function isEvmKeypairWallet(wallet: unknown): wallet is EvmWallet;
|
|
239
240
|
|
|
240
|
-
/**
|
|
241
|
-
* API Discovery — Find x402 Paid APIs
|
|
242
|
-
*
|
|
243
|
-
* Search the Dexter marketplace for x402-enabled APIs. Discover endpoints
|
|
244
|
-
* by category, price range, network, and quality score — then pay for them
|
|
245
|
-
* with the same SDK.
|
|
246
|
-
*
|
|
247
|
-
* @example
|
|
248
|
-
* ```typescript
|
|
249
|
-
* import { searchAPIs } from '@dexterai/x402/client';
|
|
250
|
-
*
|
|
251
|
-
* const results = await searchAPIs({ query: 'sentiment analysis', maxPrice: 0.10 });
|
|
252
|
-
* for (const api of results) {
|
|
253
|
-
* console.log(`${api.name}: ${api.price} — ${api.description}`);
|
|
254
|
-
* }
|
|
255
|
-
*
|
|
256
|
-
* // Then call one with wrapFetch:
|
|
257
|
-
* const response = await x402Fetch(results[0].url);
|
|
258
|
-
* ```
|
|
259
|
-
*/
|
|
260
|
-
/**
|
|
261
|
-
* Search options for discovering x402 APIs
|
|
262
|
-
*/
|
|
263
|
-
interface SearchAPIsOptions {
|
|
264
|
-
/** Search query (e.g., 'sentiment analysis', 'token price', 'image generation') */
|
|
265
|
-
query?: string;
|
|
266
|
-
/** Filter by category (e.g., 'defi', 'ai', 'data', 'social') */
|
|
267
|
-
category?: string;
|
|
268
|
-
/** Filter by payment network (e.g., 'solana', 'base', 'polygon') */
|
|
269
|
-
network?: string;
|
|
270
|
-
/** Maximum price per call in USDC */
|
|
271
|
-
maxPrice?: number;
|
|
272
|
-
/** Only return verified endpoints (quality score 75+) */
|
|
273
|
-
verifiedOnly?: boolean;
|
|
274
|
-
/** Sort order */
|
|
275
|
-
sort?: 'marketplace' | 'relevance' | 'quality_score' | 'settlements' | 'volume' | 'recent';
|
|
276
|
-
/** Maximum results to return (default 20, max 50) */
|
|
277
|
-
limit?: number;
|
|
278
|
-
/** Marketplace API URL (default: Dexter marketplace) */
|
|
279
|
-
marketplaceUrl?: string;
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* A discovered x402 API endpoint
|
|
283
|
-
*/
|
|
284
|
-
interface DiscoveredAPI {
|
|
285
|
-
/** API name */
|
|
286
|
-
name: string;
|
|
287
|
-
/** Full resource URL — pass directly to wrapFetch or createX402Client.fetch */
|
|
288
|
-
url: string;
|
|
289
|
-
/** HTTP method */
|
|
290
|
-
method: string;
|
|
291
|
-
/** Price per call (formatted, e.g., '$0.05') */
|
|
292
|
-
price: string;
|
|
293
|
-
/** Price per call in USDC (raw number, null if free) */
|
|
294
|
-
priceUsdc: number | null;
|
|
295
|
-
/** Payment network */
|
|
296
|
-
network: string | null;
|
|
297
|
-
/** Human-readable description */
|
|
298
|
-
description: string;
|
|
299
|
-
/** Category (e.g., 'defi', 'ai', 'data') */
|
|
300
|
-
category: string;
|
|
301
|
-
/** Quality score (0-100, null if unscored) */
|
|
302
|
-
qualityScore: number | null;
|
|
303
|
-
/** Whether the endpoint has been verified */
|
|
304
|
-
verified: boolean;
|
|
305
|
-
/** Total number of settlements (calls) */
|
|
306
|
-
totalCalls: number;
|
|
307
|
-
/** Total volume in USDC (formatted, e.g., '$1,234.56') */
|
|
308
|
-
totalVolume: string | null;
|
|
309
|
-
/** Seller name */
|
|
310
|
-
seller: string | null;
|
|
311
|
-
/** Seller reputation score */
|
|
312
|
-
sellerReputation: number | null;
|
|
313
|
-
/** Whether authentication is required beyond payment */
|
|
314
|
-
authRequired: boolean;
|
|
315
|
-
/** Last time someone called this API */
|
|
316
|
-
lastActive: string | null;
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Search the Dexter marketplace for x402 paid APIs.
|
|
320
|
-
*
|
|
321
|
-
* Returns a list of discovered endpoints that can be called directly
|
|
322
|
-
* with `wrapFetch` or `createX402Client.fetch`.
|
|
323
|
-
*
|
|
324
|
-
* @example Find AI APIs under $0.10
|
|
325
|
-
* ```typescript
|
|
326
|
-
* const apis = await searchAPIs({ query: 'ai', maxPrice: 0.10 });
|
|
327
|
-
* ```
|
|
328
|
-
*
|
|
329
|
-
* @example Browse all verified DeFi tools
|
|
330
|
-
* ```typescript
|
|
331
|
-
* const apis = await searchAPIs({ category: 'defi', verifiedOnly: true });
|
|
332
|
-
* ```
|
|
333
|
-
*
|
|
334
|
-
* @example Find cheapest APIs on Solana
|
|
335
|
-
* ```typescript
|
|
336
|
-
* const apis = await searchAPIs({ network: 'solana', sort: 'quality_score' });
|
|
337
|
-
* ```
|
|
338
|
-
*/
|
|
339
|
-
declare function searchAPIs(options?: SearchAPIsOptions): Promise<DiscoveredAPI[]>;
|
|
340
|
-
|
|
341
241
|
/**
|
|
342
242
|
* Budget Account — Autonomous Agent Spending Controls
|
|
343
243
|
*
|
|
@@ -423,4 +323,4 @@ interface BudgetAccount {
|
|
|
423
323
|
*/
|
|
424
324
|
declare function createBudgetAccount(config: BudgetAccountConfig): BudgetAccount;
|
|
425
325
|
|
|
426
|
-
export { AccessPassClientConfig, type BudgetAccount, type BudgetAccountConfig, type BudgetConfig,
|
|
326
|
+
export { AccessPassClientConfig, type BudgetAccount, type BudgetAccountConfig, type BudgetConfig, KEYPAIR_SYMBOL, type KeypairWallet, type PaymentRecord, type WrapFetchOptions, createBudgetAccount, createEvmKeypairWallet, createKeypairWallet, isEvmKeypairWallet, isKeypairWallet, wrapFetch };
|
package/dist/client/index.js
CHANGED
|
@@ -785,21 +785,51 @@ var EvmAdapter = class {
|
|
|
785
785
|
});
|
|
786
786
|
const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
|
|
787
787
|
const currentAllowance = await this.readAllowance(url, asset, wallet.address, PERMIT2_ADDRESS);
|
|
788
|
+
let approvalExtension;
|
|
788
789
|
if (currentAllowance < BigInt(amount)) {
|
|
789
|
-
|
|
790
|
+
const approveData = this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256);
|
|
791
|
+
if (wallet.signTransaction) {
|
|
792
|
+
this.log(`Signing Permit2 approval for relay (current allowance: ${currentAllowance})`);
|
|
793
|
+
const chainId2 = this.getChainId(accept.network);
|
|
794
|
+
const gasPrice = await this.readGasPrice(url);
|
|
795
|
+
const nonce2 = await this.readNonce(url, wallet.address);
|
|
796
|
+
const signedTx = await wallet.signTransaction({
|
|
797
|
+
to: asset,
|
|
798
|
+
data: approveData,
|
|
799
|
+
chainId: chainId2,
|
|
800
|
+
gas: 50000n,
|
|
801
|
+
// standard ERC-20 approve
|
|
802
|
+
gasPrice,
|
|
803
|
+
nonce: nonce2
|
|
804
|
+
});
|
|
805
|
+
approvalExtension = {
|
|
806
|
+
erc20ApprovalGasSponsoring: {
|
|
807
|
+
info: {
|
|
808
|
+
from: wallet.address,
|
|
809
|
+
asset,
|
|
810
|
+
spender: PERMIT2_ADDRESS,
|
|
811
|
+
amount: MAX_UINT256.toString(),
|
|
812
|
+
signedTransaction: signedTx,
|
|
813
|
+
version: "1"
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
this.log("Permit2 approval signed for facilitator relay");
|
|
818
|
+
} else if (wallet.sendTransaction) {
|
|
819
|
+
this.log(`Approving Permit2 directly (current allowance: ${currentAllowance})`);
|
|
820
|
+
const approveTxHash = await wallet.sendTransaction({
|
|
821
|
+
to: asset,
|
|
822
|
+
data: approveData,
|
|
823
|
+
value: 0n
|
|
824
|
+
});
|
|
825
|
+
this.log(`Permit2 approval tx sent: ${approveTxHash}`);
|
|
826
|
+
await this.waitForReceipt(url, approveTxHash);
|
|
827
|
+
this.log("Permit2 approval confirmed");
|
|
828
|
+
} else {
|
|
790
829
|
throw new Error(
|
|
791
|
-
"Permit2 payments require a wallet that supports sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
|
|
830
|
+
"Permit2 payments require a wallet that supports signTransaction or sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
|
|
792
831
|
);
|
|
793
832
|
}
|
|
794
|
-
this.log(`Approving Permit2 for ${asset} (current allowance: ${currentAllowance})`);
|
|
795
|
-
const approveTxHash = await wallet.sendTransaction({
|
|
796
|
-
to: asset,
|
|
797
|
-
data: this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256),
|
|
798
|
-
value: 0n
|
|
799
|
-
});
|
|
800
|
-
this.log(`Permit2 approval tx sent: ${approveTxHash}`);
|
|
801
|
-
await this.waitForReceipt(url, approveTxHash);
|
|
802
|
-
this.log("Permit2 approval confirmed");
|
|
803
833
|
} else {
|
|
804
834
|
this.log("Sufficient Permit2 allowance, skipping approval");
|
|
805
835
|
}
|
|
@@ -854,7 +884,8 @@ var EvmAdapter = class {
|
|
|
854
884
|
};
|
|
855
885
|
return {
|
|
856
886
|
serialized: JSON.stringify(payload),
|
|
857
|
-
signature
|
|
887
|
+
signature,
|
|
888
|
+
extensions: approvalExtension
|
|
858
889
|
};
|
|
859
890
|
}
|
|
860
891
|
/**
|
|
@@ -923,6 +954,43 @@ var EvmAdapter = class {
|
|
|
923
954
|
}
|
|
924
955
|
throw new Error(`Approval transaction receipt timeout after ${timeoutMs}ms: ${txHash}`);
|
|
925
956
|
}
|
|
957
|
+
/**
|
|
958
|
+
* Read gas price via eth_gasPrice RPC call.
|
|
959
|
+
*/
|
|
960
|
+
async readGasPrice(rpcUrl) {
|
|
961
|
+
try {
|
|
962
|
+
const response = await fetch(rpcUrl, {
|
|
963
|
+
method: "POST",
|
|
964
|
+
headers: { "Content-Type": "application/json" },
|
|
965
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
|
|
966
|
+
});
|
|
967
|
+
const result = await response.json();
|
|
968
|
+
return result.result ? BigInt(result.result) : 50000000n;
|
|
969
|
+
} catch {
|
|
970
|
+
return 50000000n;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Read transaction count (nonce) via eth_getTransactionCount RPC call.
|
|
975
|
+
*/
|
|
976
|
+
async readNonce(rpcUrl, address) {
|
|
977
|
+
try {
|
|
978
|
+
const response = await fetch(rpcUrl, {
|
|
979
|
+
method: "POST",
|
|
980
|
+
headers: { "Content-Type": "application/json" },
|
|
981
|
+
body: JSON.stringify({
|
|
982
|
+
jsonrpc: "2.0",
|
|
983
|
+
id: 1,
|
|
984
|
+
method: "eth_getTransactionCount",
|
|
985
|
+
params: [address, "latest"]
|
|
986
|
+
})
|
|
987
|
+
});
|
|
988
|
+
const result = await response.json();
|
|
989
|
+
return result.result ? parseInt(result.result, 16) : 0;
|
|
990
|
+
} catch {
|
|
991
|
+
return 0;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
926
994
|
/**
|
|
927
995
|
* Calculate how much to approve based on the facilitator's approval strategy.
|
|
928
996
|
* Buffered approvals reduce the number of on-chain approval txs for micropayments.
|
|
@@ -1184,6 +1252,9 @@ function createX402Client(config) {
|
|
|
1184
1252
|
accepted: accept,
|
|
1185
1253
|
payload
|
|
1186
1254
|
};
|
|
1255
|
+
if (signedTx.extensions) {
|
|
1256
|
+
paymentSignature.extensions = signedTx.extensions;
|
|
1257
|
+
}
|
|
1187
1258
|
const paymentSignatureHeader = btoa(JSON.stringify(paymentSignature));
|
|
1188
1259
|
const passResponse = await customFetch(passUrl, {
|
|
1189
1260
|
...init,
|
|
@@ -1362,6 +1433,9 @@ function createX402Client(config) {
|
|
|
1362
1433
|
accepted: accept,
|
|
1363
1434
|
payload
|
|
1364
1435
|
};
|
|
1436
|
+
if (signedTx.extensions) {
|
|
1437
|
+
paymentSignature.extensions = signedTx.extensions;
|
|
1438
|
+
}
|
|
1365
1439
|
const paymentSignatureHeader = btoa(JSON.stringify(paymentSignature));
|
|
1366
1440
|
log("Retrying request with payment...");
|
|
1367
1441
|
const retryResponse = await fetchWithRetry(input, {
|
|
@@ -1490,7 +1564,16 @@ async function createEvmKeypairWallet(privateKey) {
|
|
|
1490
1564
|
const account = privateKeyToAccount(normalizedKey);
|
|
1491
1565
|
return {
|
|
1492
1566
|
address: account.address,
|
|
1493
|
-
signTypedData: (params) => account.signTypedData(params)
|
|
1567
|
+
signTypedData: (params) => account.signTypedData(params),
|
|
1568
|
+
signTransaction: (params) => account.signTransaction({
|
|
1569
|
+
to: params.to,
|
|
1570
|
+
data: params.data,
|
|
1571
|
+
chainId: params.chainId,
|
|
1572
|
+
gas: params.gas,
|
|
1573
|
+
gasPrice: params.gasPrice,
|
|
1574
|
+
nonce: params.nonce,
|
|
1575
|
+
type: "legacy"
|
|
1576
|
+
})
|
|
1494
1577
|
};
|
|
1495
1578
|
}
|
|
1496
1579
|
function isEvmKeypairWallet(wallet) {
|
|
@@ -1557,56 +1640,7 @@ function wrapFetch(fetchImpl, options) {
|
|
|
1557
1640
|
}
|
|
1558
1641
|
|
|
1559
1642
|
// src/client/discovery.ts
|
|
1560
|
-
|
|
1561
|
-
async function searchAPIs(options = {}) {
|
|
1562
|
-
const {
|
|
1563
|
-
query,
|
|
1564
|
-
category,
|
|
1565
|
-
network,
|
|
1566
|
-
maxPrice,
|
|
1567
|
-
verifiedOnly,
|
|
1568
|
-
sort = "marketplace",
|
|
1569
|
-
limit = 20,
|
|
1570
|
-
marketplaceUrl = DEFAULT_MARKETPLACE
|
|
1571
|
-
} = options;
|
|
1572
|
-
const params = new URLSearchParams();
|
|
1573
|
-
if (query) params.set("search", query);
|
|
1574
|
-
if (category) params.set("category", category);
|
|
1575
|
-
if (network) params.set("network", network);
|
|
1576
|
-
if (maxPrice !== void 0) params.set("maxPrice", String(maxPrice));
|
|
1577
|
-
if (verifiedOnly) params.set("verified", "true");
|
|
1578
|
-
params.set("sort", sort);
|
|
1579
|
-
params.set("order", "desc");
|
|
1580
|
-
params.set("limit", String(Math.min(limit, 50)));
|
|
1581
|
-
const url = `${marketplaceUrl}?${params.toString()}`;
|
|
1582
|
-
const response = await fetch(url, {
|
|
1583
|
-
headers: { "Accept": "application/json" },
|
|
1584
|
-
signal: AbortSignal.timeout(15e3)
|
|
1585
|
-
});
|
|
1586
|
-
if (!response.ok) {
|
|
1587
|
-
throw new Error(`Marketplace search failed: ${response.status}`);
|
|
1588
|
-
}
|
|
1589
|
-
const data = await response.json();
|
|
1590
|
-
if (!data.resources) return [];
|
|
1591
|
-
return data.resources.map((r) => ({
|
|
1592
|
-
name: r.displayName || r.resourceUrl,
|
|
1593
|
-
url: r.resourceUrl,
|
|
1594
|
-
method: r.method || "GET",
|
|
1595
|
-
price: r.priceLabel || (r.priceUsdc ? `$${r.priceUsdc.toFixed(4)}` : "free"),
|
|
1596
|
-
priceUsdc: r.priceUsdc ?? null,
|
|
1597
|
-
network: r.priceNetwork ?? null,
|
|
1598
|
-
description: r.description || "",
|
|
1599
|
-
category: r.category || "uncategorized",
|
|
1600
|
-
qualityScore: r.qualityScore ?? null,
|
|
1601
|
-
verified: r.verificationStatus === "pass",
|
|
1602
|
-
totalCalls: r.totalSettlements || 0,
|
|
1603
|
-
totalVolume: r.totalVolumeUsdc ? `$${r.totalVolumeUsdc.toLocaleString("en-US", { minimumFractionDigits: 2 })}` : null,
|
|
1604
|
-
seller: r.seller?.displayName ?? null,
|
|
1605
|
-
sellerReputation: r.reputationScore ?? null,
|
|
1606
|
-
authRequired: r.authRequired || false,
|
|
1607
|
-
lastActive: r.lastSettlementAt ?? null
|
|
1608
|
-
}));
|
|
1609
|
-
}
|
|
1643
|
+
import { capabilitySearch } from "@dexterai/x402-core";
|
|
1610
1644
|
|
|
1611
1645
|
// src/client/budget-account.ts
|
|
1612
1646
|
function createBudgetAccount(config) {
|
|
@@ -1742,6 +1776,7 @@ export {
|
|
|
1742
1776
|
SOLANA_MAINNET,
|
|
1743
1777
|
USDC_MINT,
|
|
1744
1778
|
X402Error,
|
|
1779
|
+
capabilitySearch,
|
|
1745
1780
|
createBudgetAccount,
|
|
1746
1781
|
createEvmAdapter,
|
|
1747
1782
|
createEvmKeypairWallet,
|
|
@@ -1754,6 +1789,5 @@ export {
|
|
|
1754
1789
|
getSponsoredRecommendations,
|
|
1755
1790
|
isEvmKeypairWallet,
|
|
1756
1791
|
isKeypairWallet,
|
|
1757
|
-
searchAPIs,
|
|
1758
1792
|
wrapFetch
|
|
1759
1793
|
};
|
package/dist/react/index.cjs
CHANGED
|
@@ -655,21 +655,51 @@ var EvmAdapter = class {
|
|
|
655
655
|
});
|
|
656
656
|
const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
|
|
657
657
|
const currentAllowance = await this.readAllowance(url, asset, wallet.address, PERMIT2_ADDRESS);
|
|
658
|
+
let approvalExtension;
|
|
658
659
|
if (currentAllowance < BigInt(amount)) {
|
|
659
|
-
|
|
660
|
+
const approveData = this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256);
|
|
661
|
+
if (wallet.signTransaction) {
|
|
662
|
+
this.log(`Signing Permit2 approval for relay (current allowance: ${currentAllowance})`);
|
|
663
|
+
const chainId2 = this.getChainId(accept.network);
|
|
664
|
+
const gasPrice = await this.readGasPrice(url);
|
|
665
|
+
const nonce2 = await this.readNonce(url, wallet.address);
|
|
666
|
+
const signedTx = await wallet.signTransaction({
|
|
667
|
+
to: asset,
|
|
668
|
+
data: approveData,
|
|
669
|
+
chainId: chainId2,
|
|
670
|
+
gas: 50000n,
|
|
671
|
+
// standard ERC-20 approve
|
|
672
|
+
gasPrice,
|
|
673
|
+
nonce: nonce2
|
|
674
|
+
});
|
|
675
|
+
approvalExtension = {
|
|
676
|
+
erc20ApprovalGasSponsoring: {
|
|
677
|
+
info: {
|
|
678
|
+
from: wallet.address,
|
|
679
|
+
asset,
|
|
680
|
+
spender: PERMIT2_ADDRESS,
|
|
681
|
+
amount: MAX_UINT256.toString(),
|
|
682
|
+
signedTransaction: signedTx,
|
|
683
|
+
version: "1"
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
this.log("Permit2 approval signed for facilitator relay");
|
|
688
|
+
} else if (wallet.sendTransaction) {
|
|
689
|
+
this.log(`Approving Permit2 directly (current allowance: ${currentAllowance})`);
|
|
690
|
+
const approveTxHash = await wallet.sendTransaction({
|
|
691
|
+
to: asset,
|
|
692
|
+
data: approveData,
|
|
693
|
+
value: 0n
|
|
694
|
+
});
|
|
695
|
+
this.log(`Permit2 approval tx sent: ${approveTxHash}`);
|
|
696
|
+
await this.waitForReceipt(url, approveTxHash);
|
|
697
|
+
this.log("Permit2 approval confirmed");
|
|
698
|
+
} else {
|
|
660
699
|
throw new Error(
|
|
661
|
-
"Permit2 payments require a wallet that supports sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
|
|
700
|
+
"Permit2 payments require a wallet that supports signTransaction or sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
|
|
662
701
|
);
|
|
663
702
|
}
|
|
664
|
-
this.log(`Approving Permit2 for ${asset} (current allowance: ${currentAllowance})`);
|
|
665
|
-
const approveTxHash = await wallet.sendTransaction({
|
|
666
|
-
to: asset,
|
|
667
|
-
data: this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256),
|
|
668
|
-
value: 0n
|
|
669
|
-
});
|
|
670
|
-
this.log(`Permit2 approval tx sent: ${approveTxHash}`);
|
|
671
|
-
await this.waitForReceipt(url, approveTxHash);
|
|
672
|
-
this.log("Permit2 approval confirmed");
|
|
673
703
|
} else {
|
|
674
704
|
this.log("Sufficient Permit2 allowance, skipping approval");
|
|
675
705
|
}
|
|
@@ -724,7 +754,8 @@ var EvmAdapter = class {
|
|
|
724
754
|
};
|
|
725
755
|
return {
|
|
726
756
|
serialized: JSON.stringify(payload),
|
|
727
|
-
signature
|
|
757
|
+
signature,
|
|
758
|
+
extensions: approvalExtension
|
|
728
759
|
};
|
|
729
760
|
}
|
|
730
761
|
/**
|
|
@@ -793,6 +824,43 @@ var EvmAdapter = class {
|
|
|
793
824
|
}
|
|
794
825
|
throw new Error(`Approval transaction receipt timeout after ${timeoutMs}ms: ${txHash}`);
|
|
795
826
|
}
|
|
827
|
+
/**
|
|
828
|
+
* Read gas price via eth_gasPrice RPC call.
|
|
829
|
+
*/
|
|
830
|
+
async readGasPrice(rpcUrl) {
|
|
831
|
+
try {
|
|
832
|
+
const response = await fetch(rpcUrl, {
|
|
833
|
+
method: "POST",
|
|
834
|
+
headers: { "Content-Type": "application/json" },
|
|
835
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
|
|
836
|
+
});
|
|
837
|
+
const result = await response.json();
|
|
838
|
+
return result.result ? BigInt(result.result) : 50000000n;
|
|
839
|
+
} catch {
|
|
840
|
+
return 50000000n;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Read transaction count (nonce) via eth_getTransactionCount RPC call.
|
|
845
|
+
*/
|
|
846
|
+
async readNonce(rpcUrl, address) {
|
|
847
|
+
try {
|
|
848
|
+
const response = await fetch(rpcUrl, {
|
|
849
|
+
method: "POST",
|
|
850
|
+
headers: { "Content-Type": "application/json" },
|
|
851
|
+
body: JSON.stringify({
|
|
852
|
+
jsonrpc: "2.0",
|
|
853
|
+
id: 1,
|
|
854
|
+
method: "eth_getTransactionCount",
|
|
855
|
+
params: [address, "latest"]
|
|
856
|
+
})
|
|
857
|
+
});
|
|
858
|
+
const result = await response.json();
|
|
859
|
+
return result.result ? parseInt(result.result, 16) : 0;
|
|
860
|
+
} catch {
|
|
861
|
+
return 0;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
796
864
|
/**
|
|
797
865
|
* Calculate how much to approve based on the facilitator's approval strategy.
|
|
798
866
|
* Buffered approvals reduce the number of on-chain approval txs for micropayments.
|
|
@@ -1054,6 +1122,9 @@ function createX402Client(config) {
|
|
|
1054
1122
|
accepted: accept,
|
|
1055
1123
|
payload
|
|
1056
1124
|
};
|
|
1125
|
+
if (signedTx.extensions) {
|
|
1126
|
+
paymentSignature.extensions = signedTx.extensions;
|
|
1127
|
+
}
|
|
1057
1128
|
const paymentSignatureHeader = btoa(JSON.stringify(paymentSignature));
|
|
1058
1129
|
const passResponse = await customFetch(passUrl, {
|
|
1059
1130
|
...init,
|
|
@@ -1232,6 +1303,9 @@ function createX402Client(config) {
|
|
|
1232
1303
|
accepted: accept,
|
|
1233
1304
|
payload
|
|
1234
1305
|
};
|
|
1306
|
+
if (signedTx.extensions) {
|
|
1307
|
+
paymentSignature.extensions = signedTx.extensions;
|
|
1308
|
+
}
|
|
1235
1309
|
const paymentSignatureHeader = btoa(JSON.stringify(paymentSignature));
|
|
1236
1310
|
log("Retrying request with payment...");
|
|
1237
1311
|
const retryResponse = await fetchWithRetry(input, {
|
package/dist/react/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as X402Client } from '../sponsored-access-
|
|
2
|
-
export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-
|
|
3
|
-
import { W as WalletSet, d as BalanceInfo } from '../types-
|
|
1
|
+
import { a as X402Client } from '../sponsored-access-CE7WpV5b.cjs';
|
|
2
|
+
export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-CE7WpV5b.cjs';
|
|
3
|
+
import { W as WalletSet, d as BalanceInfo } from '../types-C_aQh02s.cjs';
|
|
4
4
|
import { SponsoredRecommendation } from '@dexterai/x402-ads-types';
|
|
5
5
|
export { SponsoredRecommendation } from '@dexterai/x402-ads-types';
|
|
6
6
|
import { a as AccessPassTier } from '../types-_iT11DL0.cjs';
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as X402Client } from '../sponsored-access-
|
|
2
|
-
export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-
|
|
3
|
-
import { W as WalletSet, d as BalanceInfo } from '../types-
|
|
1
|
+
import { a as X402Client } from '../sponsored-access-BVoucsEW.js';
|
|
2
|
+
export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-BVoucsEW.js';
|
|
3
|
+
import { W as WalletSet, d as BalanceInfo } from '../types-DBS0XOsH.js';
|
|
4
4
|
import { SponsoredRecommendation } from '@dexterai/x402-ads-types';
|
|
5
5
|
export { SponsoredRecommendation } from '@dexterai/x402-ads-types';
|
|
6
6
|
import { a as AccessPassTier } from '../types-_iT11DL0.js';
|
package/dist/react/index.js
CHANGED
|
@@ -628,21 +628,51 @@ var EvmAdapter = class {
|
|
|
628
628
|
});
|
|
629
629
|
const url = rpcUrl || this.getDefaultRpcUrl(accept.network);
|
|
630
630
|
const currentAllowance = await this.readAllowance(url, asset, wallet.address, PERMIT2_ADDRESS);
|
|
631
|
+
let approvalExtension;
|
|
631
632
|
if (currentAllowance < BigInt(amount)) {
|
|
632
|
-
|
|
633
|
+
const approveData = this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256);
|
|
634
|
+
if (wallet.signTransaction) {
|
|
635
|
+
this.log(`Signing Permit2 approval for relay (current allowance: ${currentAllowance})`);
|
|
636
|
+
const chainId2 = this.getChainId(accept.network);
|
|
637
|
+
const gasPrice = await this.readGasPrice(url);
|
|
638
|
+
const nonce2 = await this.readNonce(url, wallet.address);
|
|
639
|
+
const signedTx = await wallet.signTransaction({
|
|
640
|
+
to: asset,
|
|
641
|
+
data: approveData,
|
|
642
|
+
chainId: chainId2,
|
|
643
|
+
gas: 50000n,
|
|
644
|
+
// standard ERC-20 approve
|
|
645
|
+
gasPrice,
|
|
646
|
+
nonce: nonce2
|
|
647
|
+
});
|
|
648
|
+
approvalExtension = {
|
|
649
|
+
erc20ApprovalGasSponsoring: {
|
|
650
|
+
info: {
|
|
651
|
+
from: wallet.address,
|
|
652
|
+
asset,
|
|
653
|
+
spender: PERMIT2_ADDRESS,
|
|
654
|
+
amount: MAX_UINT256.toString(),
|
|
655
|
+
signedTransaction: signedTx,
|
|
656
|
+
version: "1"
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
this.log("Permit2 approval signed for facilitator relay");
|
|
661
|
+
} else if (wallet.sendTransaction) {
|
|
662
|
+
this.log(`Approving Permit2 directly (current allowance: ${currentAllowance})`);
|
|
663
|
+
const approveTxHash = await wallet.sendTransaction({
|
|
664
|
+
to: asset,
|
|
665
|
+
data: approveData,
|
|
666
|
+
value: 0n
|
|
667
|
+
});
|
|
668
|
+
this.log(`Permit2 approval tx sent: ${approveTxHash}`);
|
|
669
|
+
await this.waitForReceipt(url, approveTxHash);
|
|
670
|
+
this.log("Permit2 approval confirmed");
|
|
671
|
+
} else {
|
|
633
672
|
throw new Error(
|
|
634
|
-
"Permit2 payments require a wallet that supports sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
|
|
673
|
+
"Permit2 payments require a wallet that supports signTransaction or sendTransaction for the one-time Permit2 approval. Use createEvmKeypairWallet() or a browser wallet with transaction support."
|
|
635
674
|
);
|
|
636
675
|
}
|
|
637
|
-
this.log(`Approving Permit2 for ${asset} (current allowance: ${currentAllowance})`);
|
|
638
|
-
const approveTxHash = await wallet.sendTransaction({
|
|
639
|
-
to: asset,
|
|
640
|
-
data: this.encodeApprove(PERMIT2_ADDRESS, MAX_UINT256),
|
|
641
|
-
value: 0n
|
|
642
|
-
});
|
|
643
|
-
this.log(`Permit2 approval tx sent: ${approveTxHash}`);
|
|
644
|
-
await this.waitForReceipt(url, approveTxHash);
|
|
645
|
-
this.log("Permit2 approval confirmed");
|
|
646
676
|
} else {
|
|
647
677
|
this.log("Sufficient Permit2 allowance, skipping approval");
|
|
648
678
|
}
|
|
@@ -697,7 +727,8 @@ var EvmAdapter = class {
|
|
|
697
727
|
};
|
|
698
728
|
return {
|
|
699
729
|
serialized: JSON.stringify(payload),
|
|
700
|
-
signature
|
|
730
|
+
signature,
|
|
731
|
+
extensions: approvalExtension
|
|
701
732
|
};
|
|
702
733
|
}
|
|
703
734
|
/**
|
|
@@ -766,6 +797,43 @@ var EvmAdapter = class {
|
|
|
766
797
|
}
|
|
767
798
|
throw new Error(`Approval transaction receipt timeout after ${timeoutMs}ms: ${txHash}`);
|
|
768
799
|
}
|
|
800
|
+
/**
|
|
801
|
+
* Read gas price via eth_gasPrice RPC call.
|
|
802
|
+
*/
|
|
803
|
+
async readGasPrice(rpcUrl) {
|
|
804
|
+
try {
|
|
805
|
+
const response = await fetch(rpcUrl, {
|
|
806
|
+
method: "POST",
|
|
807
|
+
headers: { "Content-Type": "application/json" },
|
|
808
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
|
|
809
|
+
});
|
|
810
|
+
const result = await response.json();
|
|
811
|
+
return result.result ? BigInt(result.result) : 50000000n;
|
|
812
|
+
} catch {
|
|
813
|
+
return 50000000n;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Read transaction count (nonce) via eth_getTransactionCount RPC call.
|
|
818
|
+
*/
|
|
819
|
+
async readNonce(rpcUrl, address) {
|
|
820
|
+
try {
|
|
821
|
+
const response = await fetch(rpcUrl, {
|
|
822
|
+
method: "POST",
|
|
823
|
+
headers: { "Content-Type": "application/json" },
|
|
824
|
+
body: JSON.stringify({
|
|
825
|
+
jsonrpc: "2.0",
|
|
826
|
+
id: 1,
|
|
827
|
+
method: "eth_getTransactionCount",
|
|
828
|
+
params: [address, "latest"]
|
|
829
|
+
})
|
|
830
|
+
});
|
|
831
|
+
const result = await response.json();
|
|
832
|
+
return result.result ? parseInt(result.result, 16) : 0;
|
|
833
|
+
} catch {
|
|
834
|
+
return 0;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
769
837
|
/**
|
|
770
838
|
* Calculate how much to approve based on the facilitator's approval strategy.
|
|
771
839
|
* Buffered approvals reduce the number of on-chain approval txs for micropayments.
|
|
@@ -1027,6 +1095,9 @@ function createX402Client(config) {
|
|
|
1027
1095
|
accepted: accept,
|
|
1028
1096
|
payload
|
|
1029
1097
|
};
|
|
1098
|
+
if (signedTx.extensions) {
|
|
1099
|
+
paymentSignature.extensions = signedTx.extensions;
|
|
1100
|
+
}
|
|
1030
1101
|
const paymentSignatureHeader = btoa(JSON.stringify(paymentSignature));
|
|
1031
1102
|
const passResponse = await customFetch(passUrl, {
|
|
1032
1103
|
...init,
|
|
@@ -1205,6 +1276,9 @@ function createX402Client(config) {
|
|
|
1205
1276
|
accepted: accept,
|
|
1206
1277
|
payload
|
|
1207
1278
|
};
|
|
1279
|
+
if (signedTx.extensions) {
|
|
1280
|
+
paymentSignature.extensions = signedTx.extensions;
|
|
1281
|
+
}
|
|
1208
1282
|
const paymentSignatureHeader = btoa(JSON.stringify(paymentSignature));
|
|
1209
1283
|
log("Retrying request with payment...");
|
|
1210
1284
|
const retryResponse = await fetchWithRetry(input, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as ChainAdapter, W as WalletSet } from './types-
|
|
1
|
+
import { C as ChainAdapter, W as WalletSet } from './types-DBS0XOsH.js';
|
|
2
2
|
import { A as AccessPassClientConfig, P as PaymentAccept } from './types-_iT11DL0.js';
|
|
3
3
|
import { SponsoredRecommendation, SponsoredAccessSettlementInfo } from '@dexterai/x402-ads-types';
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as ChainAdapter, W as WalletSet } from './types-
|
|
1
|
+
import { C as ChainAdapter, W as WalletSet } from './types-C_aQh02s.cjs';
|
|
2
2
|
import { A as AccessPassClientConfig, P as PaymentAccept } from './types-_iT11DL0.cjs';
|
|
3
3
|
import { SponsoredRecommendation, SponsoredAccessSettlementInfo } from '@dexterai/x402-ads-types';
|
|
4
4
|
|