@dexterai/x402 2.1.0 → 3.0.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.
@@ -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
- if (!wallet.sendTransaction) {
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,55 +1640,84 @@ function wrapFetch(fetchImpl, options) {
1557
1640
  }
1558
1641
 
1559
1642
  // src/client/discovery.ts
1560
- var DEFAULT_MARKETPLACE = "https://x402.dexter.cash/api/facilitator/marketplace/resources";
1561
- async function searchAPIs(options = {}) {
1643
+ var DEFAULT_CAPABILITY_ENDPOINT = "https://x402.dexter.cash/api/x402gle/capability";
1644
+ function formatPriceLabel(priceUsdc) {
1645
+ if (priceUsdc == null) return "price on request";
1646
+ if (priceUsdc === 0) return "free";
1647
+ if (priceUsdc < 0.01) return `$${priceUsdc.toFixed(4)}`;
1648
+ return `$${priceUsdc.toFixed(2)}`;
1649
+ }
1650
+ function mapResult(r) {
1651
+ return {
1652
+ resourceId: r.resourceId,
1653
+ name: r.displayName ?? r.resourceUrl,
1654
+ url: r.resourceUrl,
1655
+ method: r.method || "GET",
1656
+ price: formatPriceLabel(r.pricing.usdc),
1657
+ priceUsdc: r.pricing.usdc,
1658
+ network: r.pricing.network,
1659
+ description: r.description ?? "",
1660
+ category: r.category ?? "uncategorized",
1661
+ qualityScore: r.verification.qualityScore,
1662
+ verified: r.verification.status === "pass",
1663
+ verificationStatus: r.verification.status,
1664
+ totalCalls: r.usage.totalSettlements,
1665
+ totalVolumeUsdc: r.usage.totalVolumeUsdc,
1666
+ iconUrl: r.icon,
1667
+ host: r.host,
1668
+ gamingFlags: r.gaming.flags,
1669
+ gamingSuspicious: r.gaming.suspicious,
1670
+ tier: r.tier,
1671
+ similarity: Math.round(r.similarity * 1e3) / 1e3,
1672
+ why: r.why,
1673
+ score: r.score
1674
+ };
1675
+ }
1676
+ async function capabilitySearch(options) {
1677
+ if (!options?.query || !options.query.trim()) {
1678
+ throw new Error("capabilitySearch: query is required");
1679
+ }
1562
1680
  const {
1563
1681
  query,
1564
- category,
1565
- network,
1566
- maxPrice,
1567
- verifiedOnly,
1568
- sort = "marketplace",
1569
1682
  limit = 20,
1570
- marketplaceUrl = DEFAULT_MARKETPLACE
1683
+ unverified,
1684
+ testnets,
1685
+ rerank,
1686
+ endpoint = DEFAULT_CAPABILITY_ENDPOINT
1571
1687
  } = options;
1572
1688
  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()}`;
1689
+ params.set("q", query);
1690
+ params.set("limit", String(Math.min(Math.max(limit, 1), 50)));
1691
+ if (unverified) params.set("unverified", "true");
1692
+ if (testnets) params.set("testnets", "true");
1693
+ if (rerank === false) params.set("rerank", "false");
1694
+ const url = `${endpoint}?${params.toString()}`;
1582
1695
  const response = await fetch(url, {
1583
- headers: { "Accept": "application/json" },
1584
- signal: AbortSignal.timeout(15e3)
1696
+ headers: { Accept: "application/json" },
1697
+ signal: AbortSignal.timeout(2e4)
1585
1698
  });
1586
1699
  if (!response.ok) {
1587
- throw new Error(`Marketplace search failed: ${response.status}`);
1700
+ const body = await response.text().catch(() => "");
1701
+ throw new Error(`Capability search failed: ${response.status} ${body.slice(0, 400)}`);
1588
1702
  }
1589
1703
  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
- }));
1704
+ if (!data.ok) {
1705
+ throw new Error(
1706
+ `Capability search error${data.stage ? ` at stage ${data.stage}` : ""}: ${data.error ?? "unknown"}`
1707
+ );
1708
+ }
1709
+ return {
1710
+ query: data.query,
1711
+ strongResults: data.strongResults.map(mapResult),
1712
+ relatedResults: data.relatedResults.map(mapResult),
1713
+ strongCount: data.strongCount,
1714
+ relatedCount: data.relatedCount,
1715
+ topSimilarity: data.topSimilarity,
1716
+ noMatchReason: data.noMatchReason,
1717
+ rerank: data.rerank,
1718
+ intent: data.intent,
1719
+ durationMs: data.durationMs
1720
+ };
1609
1721
  }
1610
1722
 
1611
1723
  // src/client/budget-account.ts
@@ -1742,6 +1854,7 @@ export {
1742
1854
  SOLANA_MAINNET,
1743
1855
  USDC_MINT,
1744
1856
  X402Error,
1857
+ capabilitySearch,
1745
1858
  createBudgetAccount,
1746
1859
  createEvmAdapter,
1747
1860
  createEvmKeypairWallet,
@@ -1754,6 +1867,5 @@ export {
1754
1867
  getSponsoredRecommendations,
1755
1868
  isEvmKeypairWallet,
1756
1869
  isKeypairWallet,
1757
- searchAPIs,
1758
1870
  wrapFetch
1759
1871
  };
@@ -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
- if (!wallet.sendTransaction) {
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, {
@@ -1,6 +1,6 @@
1
- import { a as X402Client } from '../sponsored-access-DAVzu4x6.cjs';
2
- export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-DAVzu4x6.cjs';
3
- import { W as WalletSet, d as BalanceInfo } from '../types-D1u7iu8n.cjs';
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';
@@ -1,6 +1,6 @@
1
- import { a as X402Client } from '../sponsored-access-Lxa11w_X.js';
2
- export { f as fireImpressionBeacon, b as getSponsoredRecommendations } from '../sponsored-access-Lxa11w_X.js';
3
- import { W as WalletSet, d as BalanceInfo } from '../types-YQlJI5E3.js';
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';
@@ -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
- if (!wallet.sendTransaction) {
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-YQlJI5E3.js';
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-D1u7iu8n.cjs';
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
 
@@ -72,6 +72,20 @@ interface EvmWallet {
72
72
  data: string;
73
73
  value?: bigint;
74
74
  }): Promise<string>;
75
+ /**
76
+ * Sign a transaction without broadcasting.
77
+ * Returns the RLP-encoded signed transaction as a hex string.
78
+ * Used by the erc20ApprovalGasSponsoring extension to hand a signed
79
+ * approval tx to the facilitator for relay.
80
+ */
81
+ signTransaction?(params: {
82
+ to: string;
83
+ data: string;
84
+ chainId: number;
85
+ gas?: bigint;
86
+ gasPrice?: bigint;
87
+ nonce?: number;
88
+ }): Promise<string>;
75
89
  }
76
90
  /**
77
91
  * Check if an object is a valid EVM wallet
@@ -122,6 +136,14 @@ declare class EvmAdapter implements ChainAdapter {
122
136
  * Wait for a transaction receipt by polling eth_getTransactionReceipt.
123
137
  */
124
138
  private waitForReceipt;
139
+ /**
140
+ * Read gas price via eth_gasPrice RPC call.
141
+ */
142
+ private readGasPrice;
143
+ /**
144
+ * Read transaction count (nonce) via eth_getTransactionCount RPC call.
145
+ */
146
+ private readNonce;
125
147
  /**
126
148
  * Calculate how much to approve based on the facilitator's approval strategy.
127
149
  * Buffered approvals reduce the number of on-chain approval txs for micropayments.
@@ -210,6 +232,8 @@ interface SignedTransaction {
210
232
  serialized: string;
211
233
  /** Transaction signature/hash if available before broadcast */
212
234
  signature?: string;
235
+ /** Protocol extensions (e.g., erc20ApprovalGasSponsoring) to attach to the payment payload */
236
+ extensions?: Record<string, unknown>;
213
237
  }
214
238
  /**
215
239
  * Chain adapter interface - each chain implements this