@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.
- 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 +166 -54
- package/dist/client/index.d.cts +182 -61
- package/dist/client/index.d.ts +182 -61
- package/dist/client/index.js +165 -53
- 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 +1 -1
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,55 +1640,84 @@ function wrapFetch(fetchImpl, options) {
|
|
|
1557
1640
|
}
|
|
1558
1641
|
|
|
1559
1642
|
// src/client/discovery.ts
|
|
1560
|
-
var
|
|
1561
|
-
|
|
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
|
-
|
|
1683
|
+
unverified,
|
|
1684
|
+
testnets,
|
|
1685
|
+
rerank,
|
|
1686
|
+
endpoint = DEFAULT_CAPABILITY_ENDPOINT
|
|
1571
1687
|
} = options;
|
|
1572
1688
|
const params = new URLSearchParams();
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
if (
|
|
1576
|
-
if (
|
|
1577
|
-
if (
|
|
1578
|
-
params.
|
|
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: {
|
|
1584
|
-
signal: AbortSignal.timeout(
|
|
1696
|
+
headers: { Accept: "application/json" },
|
|
1697
|
+
signal: AbortSignal.timeout(2e4)
|
|
1585
1698
|
});
|
|
1586
1699
|
if (!response.ok) {
|
|
1587
|
-
|
|
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.
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
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
|
};
|
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
|
|
|
@@ -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
|