uvd-x402-sdk 2.3.0 → 2.5.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.
Files changed (56) hide show
  1. package/dist/adapters/index.d.mts +7 -1
  2. package/dist/adapters/index.d.ts +7 -1
  3. package/dist/adapters/index.js +87 -3
  4. package/dist/adapters/index.js.map +1 -1
  5. package/dist/adapters/index.mjs +87 -3
  6. package/dist/adapters/index.mjs.map +1 -1
  7. package/dist/index.d.mts +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js +244 -146
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +243 -147
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/providers/evm/index.d.mts +7 -2
  14. package/dist/providers/evm/index.d.ts +7 -2
  15. package/dist/providers/evm/index.js +101 -13
  16. package/dist/providers/evm/index.js.map +1 -1
  17. package/dist/providers/evm/index.mjs +101 -13
  18. package/dist/providers/evm/index.mjs.map +1 -1
  19. package/dist/providers/near/index.d.mts +6 -2
  20. package/dist/providers/near/index.d.ts +6 -2
  21. package/dist/providers/near/index.js +562 -5
  22. package/dist/providers/near/index.js.map +1 -1
  23. package/dist/providers/near/index.mjs +562 -5
  24. package/dist/providers/near/index.mjs.map +1 -1
  25. package/dist/providers/solana/index.d.mts +6 -4
  26. package/dist/providers/solana/index.d.ts +6 -4
  27. package/dist/providers/solana/index.js +33 -7
  28. package/dist/providers/solana/index.js.map +1 -1
  29. package/dist/providers/solana/index.mjs +33 -7
  30. package/dist/providers/solana/index.mjs.map +1 -1
  31. package/dist/providers/stellar/index.d.mts +6 -2
  32. package/dist/providers/stellar/index.d.ts +6 -2
  33. package/dist/providers/stellar/index.js +568 -11
  34. package/dist/providers/stellar/index.js.map +1 -1
  35. package/dist/providers/stellar/index.mjs +568 -11
  36. package/dist/providers/stellar/index.mjs.map +1 -1
  37. package/dist/react/index.js +96 -12
  38. package/dist/react/index.js.map +1 -1
  39. package/dist/react/index.mjs +96 -12
  40. package/dist/react/index.mjs.map +1 -1
  41. package/dist/utils/index.d.mts +30 -1
  42. package/dist/utils/index.d.ts +30 -1
  43. package/dist/utils/index.js +101 -0
  44. package/dist/utils/index.js.map +1 -1
  45. package/dist/utils/index.mjs +100 -1
  46. package/dist/utils/index.mjs.map +1 -1
  47. package/package.json +1 -1
  48. package/src/adapters/wagmi.ts +20 -5
  49. package/src/client/X402Client.ts +32 -15
  50. package/src/index.ts +3 -0
  51. package/src/providers/evm/index.ts +40 -15
  52. package/src/providers/near/index.ts +25 -8
  53. package/src/providers/solana/index.ts +29 -10
  54. package/src/providers/stellar/index.ts +31 -14
  55. package/src/utils/index.ts +5 -0
  56. package/src/utils/validation.ts +151 -0
package/dist/index.js CHANGED
@@ -684,6 +684,226 @@ function getChainsByToken(tokenType) {
684
684
  });
685
685
  }
686
686
 
687
+ // src/utils/x402.ts
688
+ function detectX402Version(data) {
689
+ if (typeof data !== "object" || data === null) {
690
+ return 1;
691
+ }
692
+ const obj = data;
693
+ if (obj.x402Version === 2) {
694
+ return 2;
695
+ }
696
+ if (obj.accepts && Array.isArray(obj.accepts)) {
697
+ return 2;
698
+ }
699
+ if (typeof obj.network === "string") {
700
+ if (obj.network.includes(":")) {
701
+ return 2;
702
+ }
703
+ }
704
+ return 1;
705
+ }
706
+ function chainToCAIP2(chainName) {
707
+ const caip2 = CAIP2_IDENTIFIERS[chainName.toLowerCase()];
708
+ if (caip2) {
709
+ return caip2;
710
+ }
711
+ const chain = getChainByName(chainName);
712
+ if (chain) {
713
+ if (chain.networkType === "evm") {
714
+ return `eip155:${chain.chainId}`;
715
+ }
716
+ return `${chain.networkType}:${chainName}`;
717
+ }
718
+ return chainName;
719
+ }
720
+ function caip2ToChain(caip2) {
721
+ if (CAIP2_TO_CHAIN[caip2]) {
722
+ return CAIP2_TO_CHAIN[caip2];
723
+ }
724
+ const match = caip2.match(/^eip155:(\d+)$/);
725
+ if (match) {
726
+ const chainId = parseInt(match[1], 10);
727
+ for (const [name, _config] of Object.entries(CAIP2_IDENTIFIERS)) {
728
+ const chain = getChainByName(name);
729
+ if (chain?.chainId === chainId) {
730
+ return name;
731
+ }
732
+ }
733
+ }
734
+ const parts = caip2.split(":");
735
+ if (parts.length === 2) {
736
+ const networkName = parts[1];
737
+ if (getChainByName(networkName)) {
738
+ return networkName;
739
+ }
740
+ }
741
+ return null;
742
+ }
743
+ function parseNetworkIdentifier(network) {
744
+ if (network.includes(":")) {
745
+ return caip2ToChain(network) || network;
746
+ }
747
+ return network.toLowerCase();
748
+ }
749
+ function encodeX402Header(header) {
750
+ return btoa(JSON.stringify(header));
751
+ }
752
+ function decodeX402Header(encoded) {
753
+ const json = atob(encoded);
754
+ return JSON.parse(json);
755
+ }
756
+ function createX402V1Header(network, payload) {
757
+ return {
758
+ x402Version: 1,
759
+ scheme: "exact",
760
+ network,
761
+ payload
762
+ };
763
+ }
764
+ function createX402V2Header(network, payload, accepts) {
765
+ const header = {
766
+ x402Version: 2,
767
+ scheme: "exact",
768
+ network: network.includes(":") ? network : chainToCAIP2(network),
769
+ payload
770
+ };
771
+ if (accepts && accepts.length > 0) {
772
+ header.accepts = accepts;
773
+ }
774
+ return header;
775
+ }
776
+ function createX402Header(chainConfig, payload, version = "auto") {
777
+ const effectiveVersion = version === "auto" ? 1 : version;
778
+ if (effectiveVersion === 2) {
779
+ return createX402V2Header(chainConfig.name, payload);
780
+ }
781
+ return createX402V1Header(chainConfig.name, payload);
782
+ }
783
+ function generatePaymentOptions(chainConfigs, amount, facilitator) {
784
+ return chainConfigs.filter((chain) => chain.x402.enabled).map((chain) => {
785
+ const atomicAmount = Math.floor(
786
+ parseFloat(amount) * Math.pow(10, chain.usdc.decimals)
787
+ ).toString();
788
+ return {
789
+ network: chainToCAIP2(chain.name),
790
+ asset: chain.usdc.address,
791
+ amount: atomicAmount,
792
+ facilitator: facilitator || chain.x402.facilitatorUrl
793
+ };
794
+ });
795
+ }
796
+ function isCAIP2Format(network) {
797
+ return network.includes(":");
798
+ }
799
+ function convertX402Header(header, targetVersion) {
800
+ if (header.x402Version === targetVersion) {
801
+ return header;
802
+ }
803
+ if (targetVersion === 2) {
804
+ return {
805
+ x402Version: 2,
806
+ scheme: "exact",
807
+ network: chainToCAIP2(header.network),
808
+ payload: header.payload
809
+ };
810
+ } else {
811
+ const chainName = isCAIP2Format(header.network) ? caip2ToChain(header.network) || header.network : header.network;
812
+ return {
813
+ x402Version: 1,
814
+ scheme: "exact",
815
+ network: chainName,
816
+ payload: header.payload
817
+ };
818
+ }
819
+ }
820
+
821
+ // src/utils/validation.ts
822
+ var ETH_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
823
+ var SOLANA_ADDRESS_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
824
+ var STELLAR_ADDRESS_REGEX = /^G[A-Z2-7]{55}$/;
825
+ var NEAR_ADDRESS_REGEX = /^[a-z0-9._-]+$/;
826
+ function validateRecipient(recipient, networkType) {
827
+ if (!recipient) {
828
+ throw new X402Error(
829
+ "Recipient address is required. The payTo/recipient field cannot be empty. Please provide a valid recipient address where payments should be sent.",
830
+ "INVALID_RECIPIENT"
831
+ );
832
+ }
833
+ const trimmed = recipient.trim();
834
+ if (trimmed === "") {
835
+ throw new X402Error(
836
+ "Recipient address cannot be empty or whitespace. Please provide a valid recipient address.",
837
+ "INVALID_RECIPIENT"
838
+ );
839
+ }
840
+ if (networkType) {
841
+ switch (networkType) {
842
+ case "evm":
843
+ if (!ETH_ADDRESS_REGEX.test(trimmed)) {
844
+ throw new X402Error(
845
+ `Invalid EVM recipient address: "${trimmed}". Expected a 40-character hexadecimal address starting with 0x.`,
846
+ "INVALID_RECIPIENT"
847
+ );
848
+ }
849
+ break;
850
+ case "svm":
851
+ case "solana":
852
+ if (!SOLANA_ADDRESS_REGEX.test(trimmed)) {
853
+ throw new X402Error(
854
+ `Invalid Solana recipient address: "${trimmed}". Expected a base58-encoded public key (32-44 characters).`,
855
+ "INVALID_RECIPIENT"
856
+ );
857
+ }
858
+ break;
859
+ case "stellar":
860
+ if (!STELLAR_ADDRESS_REGEX.test(trimmed)) {
861
+ throw new X402Error(
862
+ `Invalid Stellar recipient address: "${trimmed}". Expected a G-prefixed public key (56 characters).`,
863
+ "INVALID_RECIPIENT"
864
+ );
865
+ }
866
+ break;
867
+ case "near":
868
+ if (!NEAR_ADDRESS_REGEX.test(trimmed) || trimmed.length > 64) {
869
+ throw new X402Error(
870
+ `Invalid NEAR recipient address: "${trimmed}". Expected a valid NEAR account ID.`,
871
+ "INVALID_RECIPIENT"
872
+ );
873
+ }
874
+ break;
875
+ }
876
+ }
877
+ }
878
+ function validateAmount(amount) {
879
+ if (!amount) {
880
+ throw new X402Error(
881
+ "Payment amount is required.",
882
+ "INVALID_AMOUNT"
883
+ );
884
+ }
885
+ const trimmed = amount.trim();
886
+ if (trimmed === "") {
887
+ throw new X402Error(
888
+ "Payment amount cannot be empty.",
889
+ "INVALID_AMOUNT"
890
+ );
891
+ }
892
+ const num = parseFloat(trimmed);
893
+ if (isNaN(num)) {
894
+ throw new X402Error(
895
+ `Invalid payment amount: "${trimmed}". Expected a valid number.`,
896
+ "INVALID_AMOUNT"
897
+ );
898
+ }
899
+ if (num <= 0) {
900
+ throw new X402Error(
901
+ `Payment amount must be positive. Got: ${trimmed}`,
902
+ "INVALID_AMOUNT"
903
+ );
904
+ }
905
+ }
906
+
687
907
  // src/client/X402Client.ts
688
908
  var X402Client = class {
689
909
  // Configuration
@@ -1034,6 +1254,7 @@ var X402Client = class {
1034
1254
  throw new X402Error("Wallet not connected", "WALLET_NOT_CONNECTED");
1035
1255
  }
1036
1256
  const recipient = this.getRecipientForNetwork(paymentInfo, "evm");
1257
+ validateRecipient(recipient, "evm");
1037
1258
  const nonceBytes = new Uint8Array(32);
1038
1259
  if (typeof window !== "undefined" && window.crypto) {
1039
1260
  window.crypto.getRandomValues(nonceBytes);
@@ -1115,21 +1336,30 @@ var X402Client = class {
1115
1336
  }
1116
1337
  encodeEVMPaymentHeader(payload, chain) {
1117
1338
  const fullSignature = payload.r + payload.s.slice(2) + payload.v.toString(16).padStart(2, "0");
1118
- const x402Payload = {
1339
+ const version = this.config.x402Version === 2 ? 2 : 1;
1340
+ const payloadData = {
1341
+ signature: fullSignature,
1342
+ authorization: {
1343
+ from: payload.from,
1344
+ to: payload.to,
1345
+ value: payload.value,
1346
+ validAfter: payload.validAfter.toString(),
1347
+ validBefore: payload.validBefore.toString(),
1348
+ nonce: payload.nonce
1349
+ }
1350
+ };
1351
+ const x402Payload = version === 2 ? {
1352
+ x402Version: 2,
1353
+ scheme: "exact",
1354
+ network: chainToCAIP2(chain.name),
1355
+ // CAIP-2 format for v2
1356
+ payload: payloadData
1357
+ } : {
1119
1358
  x402Version: 1,
1120
1359
  scheme: "exact",
1121
1360
  network: chain.name,
1122
- payload: {
1123
- signature: fullSignature,
1124
- authorization: {
1125
- from: payload.from,
1126
- to: payload.to,
1127
- value: payload.value,
1128
- validAfter: payload.validAfter.toString(),
1129
- validBefore: payload.validBefore.toString(),
1130
- nonce: payload.nonce
1131
- }
1132
- }
1361
+ // Plain chain name for v1
1362
+ payload: payloadData
1133
1363
  };
1134
1364
  const jsonString = JSON.stringify(x402Payload);
1135
1365
  return btoa(jsonString);
@@ -1176,140 +1406,6 @@ var X402Client = class {
1176
1406
  }
1177
1407
  };
1178
1408
 
1179
- // src/utils/x402.ts
1180
- function detectX402Version(data) {
1181
- if (typeof data !== "object" || data === null) {
1182
- return 1;
1183
- }
1184
- const obj = data;
1185
- if (obj.x402Version === 2) {
1186
- return 2;
1187
- }
1188
- if (obj.accepts && Array.isArray(obj.accepts)) {
1189
- return 2;
1190
- }
1191
- if (typeof obj.network === "string") {
1192
- if (obj.network.includes(":")) {
1193
- return 2;
1194
- }
1195
- }
1196
- return 1;
1197
- }
1198
- function chainToCAIP2(chainName) {
1199
- const caip2 = CAIP2_IDENTIFIERS[chainName.toLowerCase()];
1200
- if (caip2) {
1201
- return caip2;
1202
- }
1203
- const chain = getChainByName(chainName);
1204
- if (chain) {
1205
- if (chain.networkType === "evm") {
1206
- return `eip155:${chain.chainId}`;
1207
- }
1208
- return `${chain.networkType}:${chainName}`;
1209
- }
1210
- return chainName;
1211
- }
1212
- function caip2ToChain(caip2) {
1213
- if (CAIP2_TO_CHAIN[caip2]) {
1214
- return CAIP2_TO_CHAIN[caip2];
1215
- }
1216
- const match = caip2.match(/^eip155:(\d+)$/);
1217
- if (match) {
1218
- const chainId = parseInt(match[1], 10);
1219
- for (const [name, _config] of Object.entries(CAIP2_IDENTIFIERS)) {
1220
- const chain = getChainByName(name);
1221
- if (chain?.chainId === chainId) {
1222
- return name;
1223
- }
1224
- }
1225
- }
1226
- const parts = caip2.split(":");
1227
- if (parts.length === 2) {
1228
- const networkName = parts[1];
1229
- if (getChainByName(networkName)) {
1230
- return networkName;
1231
- }
1232
- }
1233
- return null;
1234
- }
1235
- function parseNetworkIdentifier(network) {
1236
- if (network.includes(":")) {
1237
- return caip2ToChain(network) || network;
1238
- }
1239
- return network.toLowerCase();
1240
- }
1241
- function encodeX402Header(header) {
1242
- return btoa(JSON.stringify(header));
1243
- }
1244
- function decodeX402Header(encoded) {
1245
- const json = atob(encoded);
1246
- return JSON.parse(json);
1247
- }
1248
- function createX402V1Header(network, payload) {
1249
- return {
1250
- x402Version: 1,
1251
- scheme: "exact",
1252
- network,
1253
- payload
1254
- };
1255
- }
1256
- function createX402V2Header(network, payload, accepts) {
1257
- const header = {
1258
- x402Version: 2,
1259
- scheme: "exact",
1260
- network: network.includes(":") ? network : chainToCAIP2(network),
1261
- payload
1262
- };
1263
- if (accepts && accepts.length > 0) {
1264
- header.accepts = accepts;
1265
- }
1266
- return header;
1267
- }
1268
- function createX402Header(chainConfig, payload, version = "auto") {
1269
- const effectiveVersion = version === "auto" ? 1 : version;
1270
- if (effectiveVersion === 2) {
1271
- return createX402V2Header(chainConfig.name, payload);
1272
- }
1273
- return createX402V1Header(chainConfig.name, payload);
1274
- }
1275
- function generatePaymentOptions(chainConfigs, amount, facilitator) {
1276
- return chainConfigs.filter((chain) => chain.x402.enabled).map((chain) => {
1277
- const atomicAmount = Math.floor(
1278
- parseFloat(amount) * Math.pow(10, chain.usdc.decimals)
1279
- ).toString();
1280
- return {
1281
- network: chainToCAIP2(chain.name),
1282
- asset: chain.usdc.address,
1283
- amount: atomicAmount,
1284
- facilitator: facilitator || chain.x402.facilitatorUrl
1285
- };
1286
- });
1287
- }
1288
- function isCAIP2Format(network) {
1289
- return network.includes(":");
1290
- }
1291
- function convertX402Header(header, targetVersion) {
1292
- if (header.x402Version === targetVersion) {
1293
- return header;
1294
- }
1295
- if (targetVersion === 2) {
1296
- return {
1297
- x402Version: 2,
1298
- scheme: "exact",
1299
- network: chainToCAIP2(header.network),
1300
- payload: header.payload
1301
- };
1302
- } else {
1303
- const chainName = isCAIP2Format(header.network) ? caip2ToChain(header.network) || header.network : header.network;
1304
- return {
1305
- x402Version: 1,
1306
- scheme: "exact",
1307
- network: chainName,
1308
- payload: header.payload
1309
- };
1310
- }
1311
- }
1312
-
1313
1409
  exports.CAIP2_IDENTIFIERS = CAIP2_IDENTIFIERS;
1314
1410
  exports.CAIP2_TO_CHAIN = CAIP2_TO_CHAIN;
1315
1411
  exports.DEFAULT_CHAIN = DEFAULT_CHAIN;
@@ -1345,5 +1441,7 @@ exports.isChainSupported = isChainSupported;
1345
1441
  exports.isSVMChain = isSVMChain;
1346
1442
  exports.isTokenSupported = isTokenSupported;
1347
1443
  exports.parseNetworkIdentifier = parseNetworkIdentifier;
1444
+ exports.validateAmount = validateAmount;
1445
+ exports.validateRecipient = validateRecipient;
1348
1446
  //# sourceMappingURL=index.js.map
1349
1447
  //# sourceMappingURL=index.js.map