@x402x/extensions 2.0.0 → 2.1.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/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var viem = require('viem');
4
4
  var allChains = require('viem/chains');
5
+ var http = require('@x402/core/http');
5
6
 
6
7
  function _interopNamespace(e) {
7
8
  if (e && e.__esModule) return e;
@@ -197,7 +198,8 @@ function isValidHex(hex) {
197
198
  }
198
199
 
199
200
  // src/network-utils.ts
200
- var NETWORK_IDS = {
201
+ var NETWORK_ALIASES_V1_TO_V2 = {
202
+ // V1 human-readable names -> V2 CAIP-2 canonical keys
201
203
  "base-sepolia": "eip155:84532",
202
204
  "x-layer-testnet": "eip155:1952",
203
205
  "skale-base-sepolia": "eip155:324705682",
@@ -206,15 +208,12 @@ var NETWORK_IDS = {
206
208
  "bsc-testnet": "eip155:97",
207
209
  "bsc": "eip155:56"
208
210
  };
209
- var NETWORK_NAMES = {
210
- "eip155:84532": "base-sepolia",
211
- "eip155:1952": "x-layer-testnet",
212
- "eip155:324705682": "skale-base-sepolia",
213
- "eip155:8453": "base",
214
- "eip155:196": "x-layer",
215
- "eip155:97": "bsc-testnet",
216
- "eip155:56": "bsc"
217
- };
211
+ var NETWORK_ALIASES = Object.entries(
212
+ NETWORK_ALIASES_V1_TO_V2
213
+ ).reduce((acc, [name, caip2]) => {
214
+ acc[caip2] = name;
215
+ return acc;
216
+ }, {});
218
217
  var DEFAULT_ASSETS = {
219
218
  "eip155:84532": {
220
219
  address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
@@ -273,23 +272,14 @@ var DEFAULT_ASSETS = {
273
272
  }
274
273
  }
275
274
  };
276
- function getNetworkId(networkName) {
277
- const networkId = NETWORK_IDS[networkName];
278
- if (!networkId) {
279
- throw new Error(
280
- `Unsupported network: ${networkName}. Supported networks: ${Object.keys(NETWORK_IDS).join(", ")}`
281
- );
282
- }
283
- return networkId;
284
- }
285
- function getNetworkName(network) {
286
- const networkName = NETWORK_NAMES[network];
287
- if (!networkName) {
275
+ function getNetworkAlias(network) {
276
+ const networkAlias = NETWORK_ALIASES[network];
277
+ if (!networkAlias) {
288
278
  throw new Error(
289
- `Unsupported network ID: ${network}. Supported network IDs: ${Object.keys(NETWORK_NAMES).join(", ")}`
279
+ `Unsupported network ID: ${network}. Supported network IDs: ${Object.keys(NETWORK_ALIASES).join(", ")}`
290
280
  );
291
281
  }
292
- return networkName;
282
+ return networkAlias;
293
283
  }
294
284
  function getDefaultAsset(network) {
295
285
  const assetInfo = DEFAULT_ASSETS[network];
@@ -324,21 +314,8 @@ function processPriceToAtomicAmount(price, network) {
324
314
  };
325
315
  }
326
316
  }
327
- var NETWORK_ALIASES_V1_TO_V2 = {
328
- // V1 human-readable names -> V2 CAIP-2 canonical keys
329
- "base-sepolia": "eip155:84532",
330
- "x-layer-testnet": "eip155:1952",
331
- "skale-base-sepolia": "eip155:324705682",
332
- "base": "eip155:8453",
333
- "x-layer": "eip155:196",
334
- "bsc-testnet": "eip155:97",
335
- "bsc": "eip155:56"
336
- };
337
317
  function getSupportedNetworkIds() {
338
- return Object.keys(NETWORK_NAMES);
339
- }
340
- function getSupportedNetworksV2() {
341
- return getSupportedNetworkIds();
318
+ return Object.keys(NETWORK_ALIASES);
342
319
  }
343
320
  function getNetworkAliasesV1ToV2() {
344
321
  return { ...NETWORK_ALIASES_V1_TO_V2 };
@@ -346,11 +323,11 @@ function getNetworkAliasesV1ToV2() {
346
323
  function toCanonicalNetworkKey(network) {
347
324
  if (network.startsWith("eip155:")) {
348
325
  const canonicalNetwork2 = network;
349
- if (canonicalNetwork2 in NETWORK_NAMES) {
326
+ if (canonicalNetwork2 in NETWORK_ALIASES) {
350
327
  return canonicalNetwork2;
351
328
  }
352
329
  throw new Error(
353
- `Unsupported CAIP-2 network: ${network}. Supported networks: ${Object.keys(NETWORK_NAMES).join(", ")}`
330
+ `Unsupported CAIP-2 network: ${network}. Supported networks: ${Object.keys(NETWORK_ALIASES).join(", ")}`
354
331
  );
355
332
  }
356
333
  const canonicalNetwork = NETWORK_ALIASES_V1_TO_V2[network];
@@ -374,15 +351,33 @@ function getDefaultAssetConfig(network) {
374
351
  }
375
352
  };
376
353
  }
354
+ function normalizeToCAIP2(network) {
355
+ if (network.startsWith("eip155:")) {
356
+ const caip22 = network;
357
+ if (!(caip22 in networks)) {
358
+ throw new Error(
359
+ `Unsupported CAIP-2 network: ${network}. Supported networks: ${Object.keys(networks).join(", ")}`
360
+ );
361
+ }
362
+ return caip22;
363
+ }
364
+ const caip2 = NETWORK_ALIASES_V1_TO_V2[network];
365
+ if (!caip2) {
366
+ throw new Error(
367
+ `Unknown network: ${network}. Supported networks: ${Object.keys(NETWORK_ALIASES_V1_TO_V2).join(", ")}`
368
+ );
369
+ }
370
+ return caip2;
371
+ }
377
372
  var networks = {
378
- "base-sepolia": {
379
- chainId: parseInt(getNetworkId("base-sepolia").split(":")[1]),
373
+ "eip155:84532": {
374
+ chainId: 84532,
380
375
  name: "Base Sepolia",
381
376
  type: "testnet",
382
377
  addressExplorerBaseUrl: "https://sepolia.basescan.org/address/",
383
378
  txExplorerBaseUrl: "https://sepolia.basescan.org/tx/",
384
379
  settlementRouter: "0x817e4f0ee2fbdaac426f1178e149f7dc98873ecb",
385
- defaultAsset: getDefaultAssetConfig(getNetworkId("base-sepolia")),
380
+ defaultAsset: getDefaultAssetConfig("eip155:84532"),
386
381
  hooks: {
387
382
  transfer: "0x4DE234059C6CcC94B8fE1eb1BD24804794083569"
388
383
  },
@@ -397,14 +392,14 @@ var networks = {
397
392
  nativeToken: "ETH"
398
393
  }
399
394
  },
400
- "x-layer-testnet": {
401
- chainId: parseInt(getNetworkId("x-layer-testnet").split(":")[1]),
395
+ "eip155:1952": {
396
+ chainId: 1952,
402
397
  name: "X Layer Testnet",
403
398
  type: "testnet",
404
399
  addressExplorerBaseUrl: "https://www.oklink.com/xlayer-test/address/",
405
400
  txExplorerBaseUrl: "https://www.oklink.com/xlayer-test/tx/",
406
401
  settlementRouter: "0xba9980fb08771e2fd10c17450f52d39bcb9ed576",
407
- defaultAsset: getDefaultAssetConfig(getNetworkId("x-layer-testnet")),
402
+ defaultAsset: getDefaultAssetConfig("eip155:1952"),
408
403
  hooks: {
409
404
  transfer: "0xD4b98dd614c1Ea472fC4547a5d2B93f3D3637BEE"
410
405
  },
@@ -419,14 +414,14 @@ var networks = {
419
414
  nativeToken: "OKB"
420
415
  }
421
416
  },
422
- "skale-base-sepolia": {
423
- chainId: parseInt(getNetworkId("skale-base-sepolia").split(":")[1]),
417
+ "eip155:324705682": {
418
+ chainId: 324705682,
424
419
  name: "SKALE Base Sepolia",
425
420
  type: "testnet",
426
421
  addressExplorerBaseUrl: "https://base-sepolia-testnet-explorer.skalenodes.com/address/",
427
422
  txExplorerBaseUrl: "https://base-sepolia-testnet-explorer.skalenodes.com/tx/",
428
423
  settlementRouter: "0x1Ae0E196dC18355aF3a19985faf67354213F833D",
429
- defaultAsset: getDefaultAssetConfig(getNetworkId("skale-base-sepolia")),
424
+ defaultAsset: getDefaultAssetConfig("eip155:324705682"),
430
425
  hooks: {
431
426
  transfer: "0x2f05fe5674aE756E25C26855258B4877E9e021Fd"
432
427
  },
@@ -441,14 +436,14 @@ var networks = {
441
436
  nativeToken: "Credits"
442
437
  }
443
438
  },
444
- "bsc-testnet": {
445
- chainId: parseInt(getNetworkId("bsc-testnet").split(":")[1]),
439
+ "eip155:97": {
440
+ chainId: 97,
446
441
  name: "BSC Testnet",
447
442
  type: "testnet",
448
443
  addressExplorerBaseUrl: "https://testnet.bscscan.com/address/",
449
444
  txExplorerBaseUrl: "https://testnet.bscscan.com/tx/",
450
445
  settlementRouter: "0x1Ae0E196dC18355aF3a19985faf67354213F833D",
451
- defaultAsset: getDefaultAssetConfig(getNetworkId("bsc-testnet")),
446
+ defaultAsset: getDefaultAssetConfig("eip155:97"),
452
447
  hooks: {
453
448
  transfer: "0x2f05fe5674aE756E25C26855258B4877E9e021Fd"
454
449
  },
@@ -464,14 +459,14 @@ var networks = {
464
459
  }
465
460
  },
466
461
  // Mainnet configurations
467
- base: {
468
- chainId: parseInt(getNetworkId("base").split(":")[1]),
462
+ "eip155:8453": {
463
+ chainId: 8453,
469
464
  name: "Base Mainnet",
470
465
  type: "mainnet",
471
466
  addressExplorerBaseUrl: "https://basescan.org/address/",
472
467
  txExplorerBaseUrl: "https://basescan.org/tx/",
473
468
  settlementRouter: "0x73fc659Cd5494E69852bE8D9D23FE05Aab14b29B",
474
- defaultAsset: getDefaultAssetConfig(getNetworkId("base")),
469
+ defaultAsset: getDefaultAssetConfig("eip155:8453"),
475
470
  hooks: {
476
471
  transfer: "0x081258287F692D61575387ee2a4075f34dd7Aef7"
477
472
  },
@@ -486,14 +481,14 @@ var networks = {
486
481
  nativeToken: "ETH"
487
482
  }
488
483
  },
489
- "x-layer": {
490
- chainId: parseInt(getNetworkId("x-layer").split(":")[1]),
484
+ "eip155:196": {
485
+ chainId: 196,
491
486
  name: "X Layer Mainnet",
492
487
  type: "mainnet",
493
488
  addressExplorerBaseUrl: "https://www.oklink.com/xlayer/address/",
494
489
  txExplorerBaseUrl: "https://www.oklink.com/xlayer/tx/",
495
490
  settlementRouter: "0x73fc659Cd5494E69852bE8D9D23FE05Aab14b29B",
496
- defaultAsset: getDefaultAssetConfig(getNetworkId("x-layer")),
491
+ defaultAsset: getDefaultAssetConfig("eip155:196"),
497
492
  hooks: {
498
493
  transfer: "0x081258287F692D61575387ee2a4075f34dd7Aef7"
499
494
  },
@@ -508,14 +503,14 @@ var networks = {
508
503
  nativeToken: "OKB"
509
504
  }
510
505
  },
511
- bsc: {
512
- chainId: parseInt(getNetworkId("bsc").split(":")[1]),
506
+ "eip155:56": {
507
+ chainId: 56,
513
508
  name: "BSC Mainnet",
514
509
  type: "mainnet",
515
510
  addressExplorerBaseUrl: "https://bscscan.com/address/",
516
511
  txExplorerBaseUrl: "https://bscscan.com/tx/",
517
512
  settlementRouter: "0x1Ae0E196dC18355aF3a19985faf67354213F833D",
518
- defaultAsset: getDefaultAssetConfig(getNetworkId("bsc")),
513
+ defaultAsset: getDefaultAssetConfig("eip155:56"),
519
514
  hooks: {
520
515
  transfer: "0x2f05fe5674aE756E25C26855258B4877E9e021Fd"
521
516
  },
@@ -532,7 +527,8 @@ var networks = {
532
527
  }
533
528
  };
534
529
  function getNetworkConfig(network) {
535
- const config = networks[network];
530
+ const caip2Network = normalizeToCAIP2(network);
531
+ const config = networks[caip2Network];
536
532
  if (!config) {
537
533
  throw new Error(
538
534
  `Unsupported network: ${network}. Supported networks: ${Object.keys(networks).join(", ")}`
@@ -541,13 +537,18 @@ function getNetworkConfig(network) {
541
537
  return config;
542
538
  }
543
539
  function isNetworkSupported(network) {
544
- return network in networks;
540
+ try {
541
+ const caip2Network = normalizeToCAIP2(network);
542
+ return caip2Network in networks;
543
+ } catch {
544
+ return false;
545
+ }
545
546
  }
546
- function getSupportedNetworkNames() {
547
- return Object.keys(networks);
547
+ function getSupportedNetworkAliases() {
548
+ return Object.keys(networks).map((caip2) => getNetworkAlias(caip2));
548
549
  }
549
550
  function getSupportedNetworks() {
550
- return getSupportedNetworkNames();
551
+ return Object.keys(networks);
551
552
  }
552
553
  var customChains = {
553
554
  // X Layer Testnet
@@ -596,15 +597,31 @@ var customChains = {
596
597
  })
597
598
  };
598
599
  function getChain(network) {
599
- const networkId = getNetworkId(network);
600
- const chainId = parseInt(networkId.split(":")[1]);
600
+ let chainId;
601
+ if (network.startsWith("eip155:")) {
602
+ const caip2 = network;
603
+ if (!(caip2 in NETWORK_ALIASES)) {
604
+ throw new Error(
605
+ `Unsupported CAIP-2 network: ${network}. Supported networks: ${Object.keys(NETWORK_ALIASES).join(", ")}`
606
+ );
607
+ }
608
+ chainId = parseInt(network.split(":")[1]);
609
+ } else {
610
+ const caip2 = NETWORK_ALIASES_V1_TO_V2[network];
611
+ if (!caip2) {
612
+ throw new Error(
613
+ `Unknown network: ${network}. Supported networks: ${Object.keys(NETWORK_ALIASES_V1_TO_V2).join(", ")}`
614
+ );
615
+ }
616
+ chainId = parseInt(caip2.split(":")[1]);
617
+ }
601
618
  if (customChains[chainId]) {
602
619
  return customChains[chainId];
603
620
  }
604
621
  const chain = Object.values(allChains__namespace).find((c) => c.id === chainId);
605
622
  if (!chain) {
606
623
  throw new Error(
607
- `Unsupported network: ${network} (chain ID: ${chainId}). Please add custom chain definition in chains.ts`
624
+ `Unsupported chain ID: ${chainId}. Please add custom chain definition in chains.ts`
608
625
  );
609
626
  }
610
627
  return chain;
@@ -664,15 +681,15 @@ exports.TransferHook = void 0;
664
681
  );
665
682
  }
666
683
  TransferHook2.encode = encode;
667
- function getAddress(network) {
684
+ function getAddress2(network) {
668
685
  const config = getNetworkConfig(network);
669
686
  return config.hooks.transfer;
670
687
  }
671
- TransferHook2.getAddress = getAddress;
688
+ TransferHook2.getAddress = getAddress2;
672
689
  })(exports.TransferHook || (exports.TransferHook = {}));
673
690
  exports.NFTMintHook = void 0;
674
691
  ((NFTMintHook2) => {
675
- function getAddress(network) {
692
+ function getAddress2(network) {
676
693
  const config = getNetworkConfig(network);
677
694
  if (!config.demoHooks?.nftMint) {
678
695
  throw new Error(
@@ -681,7 +698,7 @@ exports.NFTMintHook = void 0;
681
698
  }
682
699
  return config.demoHooks.nftMint;
683
700
  }
684
- NFTMintHook2.getAddress = getAddress;
701
+ NFTMintHook2.getAddress = getAddress2;
685
702
  function getNFTContractAddress(network) {
686
703
  const config = getNetworkConfig(network);
687
704
  if (!config.demoHooks?.randomNFT) {
@@ -711,7 +728,7 @@ exports.NFTMintHook = void 0;
711
728
  })(exports.NFTMintHook || (exports.NFTMintHook = {}));
712
729
  exports.RewardHook = void 0;
713
730
  ((RewardHook2) => {
714
- function getAddress(network) {
731
+ function getAddress2(network) {
715
732
  const config = getNetworkConfig(network);
716
733
  if (!config.demoHooks?.reward) {
717
734
  throw new Error(
@@ -720,7 +737,7 @@ exports.RewardHook = void 0;
720
737
  }
721
738
  return config.demoHooks.reward;
722
739
  }
723
- RewardHook2.getAddress = getAddress;
740
+ RewardHook2.getAddress = getAddress2;
724
741
  function getTokenAddress(network) {
725
742
  const config = getNetworkConfig(network);
726
743
  if (!config.demoHooks?.rewardToken) {
@@ -822,8 +839,8 @@ function assertValidSettlementExtra(extra) {
822
839
 
823
840
  // src/utils.ts
824
841
  function addSettlementExtra(requirements, params) {
825
- const networkName = getNetworkName(requirements.network);
826
- const config = getNetworkConfig(networkName);
842
+ const networkAlias = getNetworkAlias(requirements.network);
843
+ const config = getNetworkConfig(networkAlias);
827
844
  const existingExtra = requirements.extra || {};
828
845
  const name = existingExtra.name || config.defaultAsset.eip712.name;
829
846
  const version = existingExtra.version || config.defaultAsset.eip712.version;
@@ -859,6 +876,9 @@ function createRouterSettlementExtension(params) {
859
876
  if (params?.description !== void 0) {
860
877
  info.description = params.description;
861
878
  }
879
+ if (params?.salt) {
880
+ info.salt = params.salt;
881
+ }
862
882
  if (params?.settlementRouter) info.settlementRouter = params.settlementRouter;
863
883
  if (params?.hook) info.hook = params.hook;
864
884
  if (params?.hookData) info.hookData = params.hookData;
@@ -878,8 +898,9 @@ function createRouterSettlementExtension(params) {
878
898
  finalPayTo: { type: "string", pattern: "^0x[a-fA-F0-9]{40}$" },
879
899
  facilitatorFee: { type: "string" }
880
900
  },
881
- // Salt is required in the final enriched version but not in the initial declaration
882
- required: ["schemaVersion", "settlementRouter", "hook", "hookData", "finalPayTo"]
901
+ // Salt is required in the final enriched version
902
+ // facilitatorFee is optional (facilitator will calculate if missing)
903
+ required: ["schemaVersion", "salt", "settlementRouter", "hook", "hookData", "finalPayTo"]
883
904
  };
884
905
  }
885
906
  return {
@@ -920,202 +941,6 @@ function createExtensionDeclaration(params) {
920
941
  };
921
942
  }
922
943
 
923
- // src/settlement-routes.ts
924
- function createSettlementRouteConfig(baseConfig, settlementOptions) {
925
- const acceptsArray = Array.isArray(baseConfig.accepts) ? baseConfig.accepts : [baseConfig.accepts];
926
- const firstOption = acceptsArray[0];
927
- const firstNetwork = firstOption.network;
928
- const networkConfig = getNetworkConfig(firstNetwork);
929
- if (!networkConfig) {
930
- throw new Error(`Network configuration not found for: ${firstNetwork}`);
931
- }
932
- const hook = settlementOptions.hook || exports.TransferHook.getAddress(firstNetwork);
933
- const hookData = settlementOptions.hookData || exports.TransferHook.encode();
934
- const enhancedAccepts = acceptsArray.map((option) => {
935
- const network = typeof option.network === "string" ? option.network : option.network;
936
- const optionNetworkConfig = getNetworkConfig(network);
937
- if (!optionNetworkConfig) {
938
- throw new Error(`Network configuration not found for: ${network}`);
939
- }
940
- const enhancedOption = {
941
- ...option,
942
- // Override payTo to use settlementRouter as the immediate recipient
943
- payTo: optionNetworkConfig.settlementRouter,
944
- // Only include EIP-712 domain info in extra
945
- extra: {
946
- ...option.extra || {},
947
- name: optionNetworkConfig.defaultAsset.eip712.name,
948
- version: optionNetworkConfig.defaultAsset.eip712.version
949
- }
950
- };
951
- return enhancedOption;
952
- });
953
- const extensions = {
954
- ...baseConfig.extensions || {},
955
- ...createExtensionDeclaration({
956
- description: settlementOptions.description || "Router settlement with atomic fee distribution",
957
- // Pass settlement parameters to be included in extension info
958
- settlementRouter: networkConfig.settlementRouter,
959
- hook,
960
- hookData,
961
- finalPayTo: settlementOptions.finalPayTo,
962
- facilitatorFee: settlementOptions.facilitatorFee || "0"
963
- })
964
- };
965
- return {
966
- ...baseConfig,
967
- accepts: enhancedAccepts.length === 1 ? enhancedAccepts[0] : enhancedAccepts,
968
- extensions
969
- };
970
- }
971
- function registerSettlementHooks(server, config = {}) {
972
- const {
973
- enableSaltExtraction = true,
974
- validateSettlementParams = true
975
- } = config;
976
- if (enableSaltExtraction) {
977
- server.onBeforeVerify(async (context) => {
978
- const { paymentPayload, requirements } = context;
979
- if (paymentPayload.extensions && "x402x-router-settlement" in paymentPayload.extensions) {
980
- const extension = paymentPayload.extensions["x402x-router-settlement"];
981
- if (extension?.info) {
982
- if (!requirements.extra) {
983
- requirements.extra = {};
984
- }
985
- const info = extension.info;
986
- if (info.salt) requirements.extra.salt = info.salt;
987
- if (info.settlementRouter) requirements.extra.settlementRouter = info.settlementRouter;
988
- if (info.hook) requirements.extra.hook = info.hook;
989
- if (info.hookData) requirements.extra.hookData = info.hookData;
990
- if (info.finalPayTo) requirements.extra.payTo = info.finalPayTo;
991
- if (info.facilitatorFee !== void 0) requirements.extra.facilitatorFee = info.facilitatorFee;
992
- }
993
- }
994
- return void 0;
995
- });
996
- }
997
- if (validateSettlementParams) {
998
- server.onBeforeSettle(async (context) => {
999
- const { paymentPayload, requirements } = context;
1000
- let settlementParams = {};
1001
- if (paymentPayload.extensions && "x402x-router-settlement" in paymentPayload.extensions) {
1002
- const extension = paymentPayload.extensions["x402x-router-settlement"];
1003
- if (extension?.info) {
1004
- settlementParams = extension.info;
1005
- }
1006
- }
1007
- if (!settlementParams.settlementRouter && requirements.extra) {
1008
- settlementParams = requirements.extra;
1009
- }
1010
- const requiredFields = ["settlementRouter", "hook", "hookData"];
1011
- const payToField = "finalPayTo" in settlementParams ? "finalPayTo" : "payTo";
1012
- const missingFields = requiredFields.filter((field) => !settlementParams[field]);
1013
- if (!settlementParams[payToField]) {
1014
- missingFields.push(payToField);
1015
- }
1016
- if (missingFields.length > 0) {
1017
- return {
1018
- abort: true,
1019
- reason: `Missing settlement parameters: ${missingFields.join(", ")}`
1020
- };
1021
- }
1022
- return void 0;
1023
- });
1024
- }
1025
- }
1026
-
1027
- // src/helpers.ts
1028
- function registerRouterSettlement2(server) {
1029
- return registerRouterSettlement(server);
1030
- }
1031
- async function createX402xFacilitator(config) {
1032
- try {
1033
- const importFn = new Function("specifier", "return import(specifier)");
1034
- const facilitatorModule = await importFn("@x402x/facilitator-sdk");
1035
- return facilitatorModule.createRouterSettlementFacilitator(config);
1036
- } catch (error) {
1037
- throw new Error(
1038
- "createX402xFacilitator requires @x402x/facilitator-sdk to be installed. Please install it using your package manager."
1039
- );
1040
- }
1041
- }
1042
- function withRouterSettlement(requirements, options) {
1043
- if (!requirements.network) {
1044
- throw new Error("Network is required in payment requirements");
1045
- }
1046
- if (!requirements.asset) {
1047
- throw new Error("Asset is required in payment requirements");
1048
- }
1049
- const networkConfig = getNetworkConfig(requirements.network);
1050
- if (!networkConfig) {
1051
- throw new Error(`Network configuration not found for network: ${requirements.network}`);
1052
- }
1053
- const salt = options.salt || generateSalt();
1054
- const settlementExtra = {
1055
- settlementRouter: networkConfig.settlementRouter,
1056
- salt,
1057
- payTo: options.payTo,
1058
- facilitatorFee: options.facilitatorFee,
1059
- hook: options.hook,
1060
- hookData: options.hookData,
1061
- name: options.name || networkConfig.defaultAsset.eip712.name,
1062
- version: options.version || networkConfig.defaultAsset.eip712.version
1063
- };
1064
- const extensionKey = getRouterSettlementExtensionKey();
1065
- const extensionDeclaration = createRouterSettlementExtension({
1066
- description: "Router settlement with atomic fee distribution"
1067
- });
1068
- const reqWithExtensions = requirements;
1069
- return {
1070
- ...requirements,
1071
- extra: {
1072
- ...reqWithExtensions.extra || {},
1073
- ...settlementExtra
1074
- },
1075
- extensions: {
1076
- ...reqWithExtensions.extensions || {},
1077
- [extensionKey]: extensionDeclaration
1078
- }
1079
- };
1080
- }
1081
- function isRouterSettlement(requirements) {
1082
- return !!(requirements.extra && "settlementRouter" in requirements.extra);
1083
- }
1084
-
1085
- // src/amount.ts
1086
- var AmountError = class extends Error {
1087
- constructor(message) {
1088
- super(message);
1089
- this.name = "AmountError";
1090
- }
1091
- };
1092
- function parseDefaultAssetAmount(amount, network) {
1093
- if (amount === null || amount === void 0 || amount === "") {
1094
- throw new AmountError("Amount is required");
1095
- }
1096
- const result = processPriceToAtomicAmount(amount, network);
1097
- if ("error" in result) {
1098
- throw new AmountError(`Invalid amount format: ${result.error}`);
1099
- }
1100
- return result.amount;
1101
- }
1102
- function formatDefaultAssetAmount(amount, network) {
1103
- const atomicAmount = BigInt(amount);
1104
- if (atomicAmount < 0n) {
1105
- throw new AmountError("Amount cannot be negative");
1106
- }
1107
- const asset = getDefaultAsset(network);
1108
- const decimals = asset.decimals;
1109
- const amountStr = atomicAmount.toString().padStart(decimals + 1, "0");
1110
- const integerPart = amountStr.slice(0, -decimals) || "0";
1111
- const decimalPart = amountStr.slice(-decimals);
1112
- const trimmedDecimal = decimalPart.replace(/0+$/, "");
1113
- if (trimmedDecimal) {
1114
- return `${integerPart}.${trimmedDecimal}`;
1115
- }
1116
- return integerPart;
1117
- }
1118
-
1119
944
  // src/facilitator.ts
1120
945
  function isSettlementMode(paymentRequirements) {
1121
946
  return !!paymentRequirements.extra?.settlementRouter;
@@ -1322,6 +1147,274 @@ async function settle(facilitatorUrl, paymentPayload, paymentRequirements, timeo
1322
1147
  }
1323
1148
  }
1324
1149
 
1150
+ // src/settlement-routes.ts
1151
+ var DEFAULT_FACILITATOR_URL = "https://facilitator.x402x.dev";
1152
+ function createSettlementRouteConfig(baseConfig, settlementOptions) {
1153
+ const acceptsArray = Array.isArray(baseConfig.accepts) ? baseConfig.accepts : [baseConfig.accepts];
1154
+ const enhancedAccepts = acceptsArray.map((option) => {
1155
+ const network = typeof option.network === "string" ? option.network : option.network;
1156
+ const optionNetworkConfig = getNetworkConfig(network);
1157
+ if (!optionNetworkConfig) {
1158
+ throw new Error(`Network configuration not found for: ${network}`);
1159
+ }
1160
+ const originalPayTo = typeof option.payTo === "string" ? option.payTo : void 0;
1161
+ const finalPayTo = settlementOptions?.finalPayTo || originalPayTo;
1162
+ if (!finalPayTo) {
1163
+ throw new Error(`Cannot determine finalPayTo: neither settlementOptions.finalPayTo nor option.payTo (string) is provided for network ${network}`);
1164
+ }
1165
+ const hook = settlementOptions?.hook || exports.TransferHook.getAddress(network);
1166
+ const hookData = settlementOptions?.hookData || exports.TransferHook.encode();
1167
+ const facilitatorUrl = settlementOptions?.facilitatorUrl || DEFAULT_FACILITATOR_URL;
1168
+ const hasFixedFee = settlementOptions?.facilitatorFee !== void 0;
1169
+ const dynamicPrice = async (context) => {
1170
+ const httpContext = context;
1171
+ const isRetry = !!httpContext.paymentHeader;
1172
+ if (isRetry) {
1173
+ console.log("[x402x-settlement] Retry request detected, replaying accepted");
1174
+ try {
1175
+ const paymentPayload = http.decodePaymentSignatureHeader(httpContext.paymentHeader);
1176
+ const accepted = paymentPayload.accepted;
1177
+ if (accepted.network === network && accepted.scheme === option.scheme) {
1178
+ console.log("[x402x-settlement] Replaying accepted for network:", network);
1179
+ return {
1180
+ asset: accepted.asset,
1181
+ amount: accepted.amount,
1182
+ extra: accepted.extra
1183
+ };
1184
+ } else {
1185
+ console.warn("[x402x-settlement] Network/scheme mismatch in retry, falling back to probe");
1186
+ }
1187
+ } catch (error) {
1188
+ console.error("[x402x-settlement] Failed to decode payment header, falling back to probe:", error);
1189
+ }
1190
+ }
1191
+ console.log("[x402x-settlement] Probe request, generating new salt and querying fee");
1192
+ const basePrice = typeof option.price === "function" ? await option.price(context) : option.price;
1193
+ let moneyPrice;
1194
+ if (typeof basePrice === "object" && basePrice !== null && "asset" in basePrice) {
1195
+ return basePrice;
1196
+ } else {
1197
+ moneyPrice = basePrice;
1198
+ }
1199
+ const amountStr = typeof moneyPrice === "number" ? moneyPrice.toString() : moneyPrice.toString().replace(/[^0-9.]/g, "");
1200
+ const amountFloat = parseFloat(amountStr);
1201
+ if (isNaN(amountFloat)) {
1202
+ throw new Error(`Invalid price format: ${moneyPrice}`);
1203
+ }
1204
+ const { address, decimals, eip712 } = optionNetworkConfig.defaultAsset;
1205
+ const atomicAmount = BigInt(Math.floor(amountFloat * 10 ** decimals)).toString();
1206
+ const salt = generateSalt();
1207
+ let facilitatorFee;
1208
+ if (hasFixedFee) {
1209
+ facilitatorFee = settlementOptions.facilitatorFee;
1210
+ console.log("[x402x-settlement] Using fixed facilitatorFee:", facilitatorFee);
1211
+ } else {
1212
+ console.log("[x402x-settlement] Querying facilitator for fee:", { network, hook, hookData });
1213
+ try {
1214
+ const feeResult = await calculateFacilitatorFee(facilitatorUrl, network, hook, hookData);
1215
+ if (!feeResult.hookAllowed) {
1216
+ throw new Error(`Hook not allowed by facilitator: ${hook} on network ${network}`);
1217
+ }
1218
+ facilitatorFee = feeResult.facilitatorFee;
1219
+ console.log("[x402x-settlement] Got facilitatorFee from facilitator:", facilitatorFee);
1220
+ } catch (error) {
1221
+ console.error("[x402x-settlement] Failed to query facilitator fee:", error);
1222
+ throw new Error(
1223
+ `Failed to calculate facilitator fee for network ${network}: ${error instanceof Error ? error.message : String(error)}`
1224
+ );
1225
+ }
1226
+ }
1227
+ const settlementExtension = createExtensionDeclaration({
1228
+ description: settlementOptions?.description || "Router settlement with atomic fee distribution",
1229
+ settlementRouter: optionNetworkConfig.settlementRouter,
1230
+ hook,
1231
+ hookData,
1232
+ finalPayTo,
1233
+ facilitatorFee,
1234
+ salt
1235
+ });
1236
+ return {
1237
+ asset: address,
1238
+ amount: atomicAmount,
1239
+ extra: {
1240
+ // EIP-712 domain parameters (scheme-specific for signing)
1241
+ name: eip712.name,
1242
+ version: eip712.version,
1243
+ // Network-specific settlement extension parameters (per-option x402x declaration with salt + fee)
1244
+ [ROUTER_SETTLEMENT_KEY]: settlementExtension[ROUTER_SETTLEMENT_KEY]
1245
+ }
1246
+ };
1247
+ };
1248
+ const enhancedOption = {
1249
+ ...option,
1250
+ // Override payTo to use settlementRouter as the immediate recipient
1251
+ payTo: optionNetworkConfig.settlementRouter,
1252
+ // Use DynamicPrice that queries fee on probe and replays on retry
1253
+ price: dynamicPrice,
1254
+ // Keep option.extra for any user-provided context (primary data is now in price.extra via dynamic function)
1255
+ extra: option.extra
1256
+ };
1257
+ return enhancedOption;
1258
+ });
1259
+ const extensions = {
1260
+ ...baseConfig.extensions || {}
1261
+ // Only include non-network-specific metadata at root level
1262
+ // Per-option x402x info is already in accepts[i].price.extra[ROUTER_SETTLEMENT_KEY]
1263
+ };
1264
+ return {
1265
+ ...baseConfig,
1266
+ accepts: enhancedAccepts.length === 1 ? enhancedAccepts[0] : enhancedAccepts,
1267
+ extensions
1268
+ };
1269
+ }
1270
+ function registerSettlementHooks(server, config = {}) {
1271
+ const {
1272
+ enableSaltExtraction = true,
1273
+ validateSettlementParams = true
1274
+ } = config;
1275
+ if (enableSaltExtraction) {
1276
+ server.onBeforeVerify(async (context) => {
1277
+ const { paymentPayload, requirements } = context;
1278
+ if (paymentPayload.extensions && "x402x-router-settlement" in paymentPayload.extensions) {
1279
+ const extension = paymentPayload.extensions["x402x-router-settlement"];
1280
+ if (extension?.info) {
1281
+ if (!requirements.extra) {
1282
+ requirements.extra = {};
1283
+ }
1284
+ const info = extension.info;
1285
+ if (info.salt) requirements.extra.salt = info.salt;
1286
+ if (info.settlementRouter) requirements.extra.settlementRouter = info.settlementRouter;
1287
+ if (info.hook) requirements.extra.hook = info.hook;
1288
+ if (info.hookData) requirements.extra.hookData = info.hookData;
1289
+ if (info.finalPayTo) requirements.extra.payTo = info.finalPayTo;
1290
+ if (info.facilitatorFee !== void 0) requirements.extra.facilitatorFee = info.facilitatorFee;
1291
+ }
1292
+ }
1293
+ return void 0;
1294
+ });
1295
+ }
1296
+ if (validateSettlementParams) {
1297
+ server.onBeforeSettle(async (context) => {
1298
+ const { paymentPayload, requirements } = context;
1299
+ let settlementParams = {};
1300
+ if (paymentPayload.extensions && "x402x-router-settlement" in paymentPayload.extensions) {
1301
+ const extension = paymentPayload.extensions["x402x-router-settlement"];
1302
+ if (extension?.info) {
1303
+ settlementParams = extension.info;
1304
+ }
1305
+ }
1306
+ if (!settlementParams.settlementRouter && requirements.extra) {
1307
+ settlementParams = requirements.extra;
1308
+ }
1309
+ const requiredFields = ["settlementRouter", "hook", "hookData"];
1310
+ const payToField = "finalPayTo" in settlementParams ? "finalPayTo" : "payTo";
1311
+ const missingFields = requiredFields.filter((field) => !settlementParams[field]);
1312
+ if (!settlementParams[payToField]) {
1313
+ missingFields.push(payToField);
1314
+ }
1315
+ if (missingFields.length > 0) {
1316
+ return {
1317
+ abort: true,
1318
+ reason: `Missing settlement parameters: ${missingFields.join(", ")}`
1319
+ };
1320
+ }
1321
+ return void 0;
1322
+ });
1323
+ }
1324
+ }
1325
+
1326
+ // src/helpers.ts
1327
+ function registerRouterSettlement2(server) {
1328
+ return registerRouterSettlement(server);
1329
+ }
1330
+ async function createX402xFacilitator(config) {
1331
+ try {
1332
+ const importFn = new Function("specifier", "return import(specifier)");
1333
+ const facilitatorModule = await importFn("@x402x/facilitator-sdk");
1334
+ return facilitatorModule.createRouterSettlementFacilitator(config);
1335
+ } catch (error) {
1336
+ throw new Error(
1337
+ "createX402xFacilitator requires @x402x/facilitator-sdk to be installed. Please install it using your package manager."
1338
+ );
1339
+ }
1340
+ }
1341
+ function withRouterSettlement(requirements, options) {
1342
+ if (!requirements.network) {
1343
+ throw new Error("Network is required in payment requirements");
1344
+ }
1345
+ if (!requirements.asset) {
1346
+ throw new Error("Asset is required in payment requirements");
1347
+ }
1348
+ const networkConfig = getNetworkConfig(requirements.network);
1349
+ if (!networkConfig) {
1350
+ throw new Error(`Network configuration not found for network: ${requirements.network}`);
1351
+ }
1352
+ const salt = options.salt || generateSalt();
1353
+ const settlementExtra = {
1354
+ settlementRouter: networkConfig.settlementRouter,
1355
+ salt,
1356
+ payTo: options.payTo,
1357
+ facilitatorFee: options.facilitatorFee,
1358
+ hook: options.hook,
1359
+ hookData: options.hookData,
1360
+ name: options.name || networkConfig.defaultAsset.eip712.name,
1361
+ version: options.version || networkConfig.defaultAsset.eip712.version
1362
+ };
1363
+ const extensionKey = getRouterSettlementExtensionKey();
1364
+ const extensionDeclaration = createRouterSettlementExtension({
1365
+ description: "Router settlement with atomic fee distribution"
1366
+ });
1367
+ const reqWithExtensions = requirements;
1368
+ return {
1369
+ ...requirements,
1370
+ extra: {
1371
+ ...reqWithExtensions.extra || {},
1372
+ ...settlementExtra
1373
+ },
1374
+ extensions: {
1375
+ ...reqWithExtensions.extensions || {},
1376
+ [extensionKey]: extensionDeclaration
1377
+ }
1378
+ };
1379
+ }
1380
+ function isRouterSettlement(requirements) {
1381
+ return !!(requirements.extra && "settlementRouter" in requirements.extra);
1382
+ }
1383
+
1384
+ // src/amount.ts
1385
+ var AmountError = class extends Error {
1386
+ constructor(message) {
1387
+ super(message);
1388
+ this.name = "AmountError";
1389
+ }
1390
+ };
1391
+ function parseDefaultAssetAmount(amount, network) {
1392
+ if (amount === null || amount === void 0 || amount === "") {
1393
+ throw new AmountError("Amount is required");
1394
+ }
1395
+ const result = processPriceToAtomicAmount(amount, network);
1396
+ if ("error" in result) {
1397
+ throw new AmountError(`Invalid amount format: ${result.error}`);
1398
+ }
1399
+ return result.amount;
1400
+ }
1401
+ function formatDefaultAssetAmount(amount, network) {
1402
+ const atomicAmount = BigInt(amount);
1403
+ if (atomicAmount < 0n) {
1404
+ throw new AmountError("Amount cannot be negative");
1405
+ }
1406
+ const asset = getDefaultAsset(network);
1407
+ const decimals = asset.decimals;
1408
+ const amountStr = atomicAmount.toString().padStart(decimals + 1, "0");
1409
+ const integerPart = amountStr.slice(0, -decimals) || "0";
1410
+ const decimalPart = amountStr.slice(-decimals);
1411
+ const trimmedDecimal = decimalPart.replace(/0+$/, "");
1412
+ if (trimmedDecimal) {
1413
+ return `${integerPart}.${trimmedDecimal}`;
1414
+ }
1415
+ return integerPart;
1416
+ }
1417
+
1325
1418
  // src/abi.ts
1326
1419
  var SETTLEMENT_ROUTER_ABI = [
1327
1420
  {
@@ -1413,77 +1506,197 @@ var SettlementRouterError = class extends Error {
1413
1506
  this.name = "SettlementRouterError";
1414
1507
  }
1415
1508
  };
1416
-
1417
- // src/legacy-compat.ts
1418
- var SupportedEVMNetworks = [
1419
- "eip155:84532",
1420
- // Base Sepolia
1421
- "eip155:1444673419",
1422
- // SKALE Base Sepolia
1423
- "eip155:8453"
1424
- // Base Mainnet
1425
- ];
1426
- var moneySchema = {
1427
- parse: (value) => {
1428
- if (typeof value === "string" || typeof value === "number") {
1429
- return value;
1509
+ var authorizationTypes = {
1510
+ TransferWithAuthorization: [
1511
+ { name: "from", type: "address" },
1512
+ { name: "to", type: "address" },
1513
+ { name: "value", type: "uint256" },
1514
+ { name: "validAfter", type: "uint256" },
1515
+ { name: "validBefore", type: "uint256" },
1516
+ { name: "nonce", type: "bytes32" }
1517
+ ]
1518
+ };
1519
+ var ExactEvmSchemeWithRouterSettlement = class {
1520
+ /**
1521
+ * Creates a new ExactEvmSchemeWithRouterSettlement instance.
1522
+ *
1523
+ * @param signer - The EVM signer for client operations (viem WalletClient or LocalAccount)
1524
+ */
1525
+ constructor(signer) {
1526
+ this.signer = signer;
1527
+ this.scheme = "exact";
1528
+ }
1529
+ /**
1530
+ * Set router-settlement extension data for the next payment payload creation.
1531
+ *
1532
+ * Intended to be called from an `x402Client.onBeforePaymentCreation` hook, which has access
1533
+ * to `paymentRequired.extensions`.
1534
+ */
1535
+ setRouterSettlementExtensionFromPaymentRequired(ext) {
1536
+ if (!ext) {
1537
+ this.routerSettlementFromPaymentRequired = void 0;
1538
+ return;
1430
1539
  }
1431
- throw new Error("Invalid money value");
1540
+ this.routerSettlementFromPaymentRequired = ext;
1541
+ }
1542
+ /**
1543
+ * Creates a payment payload for the Exact scheme with router settlement.
1544
+ *
1545
+ * This method:
1546
+ * 1. Extracts settlement parameters from PaymentRequired.extensions
1547
+ * 2. Calculates a commitment hash binding all parameters
1548
+ * 3. Uses the commitment as the EIP-3009 nonce
1549
+ * 4. Signs with settlementRouter as the 'to' address
1550
+ *
1551
+ * @param x402Version - The x402 protocol version (must be 2)
1552
+ * @param paymentRequirements - The payment requirements from the server
1553
+ * @returns Promise resolving to a payment payload
1554
+ *
1555
+ * @throws Error if x402Version is not 2
1556
+ * @throws Error if x402x-router-settlement extension is missing
1557
+ * @throws Error if required settlement parameters are missing
1558
+ */
1559
+ async createPaymentPayload(x402Version, paymentRequirements) {
1560
+ if (x402Version !== 2) {
1561
+ throw new Error(
1562
+ `ExactEvmSchemeWithRouterSettlement only supports x402 version 2, got: ${x402Version}`
1563
+ );
1564
+ }
1565
+ const routerSettlement = paymentRequirements.extra?.[ROUTER_SETTLEMENT_KEY] ?? this.routerSettlementFromPaymentRequired;
1566
+ if (!routerSettlement?.info) {
1567
+ throw new Error(
1568
+ "x402x-router-settlement extension not available for scheme signing. Ensure the resource server includes the extension in PaymentRequired.extensions and the client registered x402x via registerX402xScheme() (or injected the handler)."
1569
+ );
1570
+ }
1571
+ const { salt, settlementRouter, hook, hookData, finalPayTo, facilitatorFee } = routerSettlement.info;
1572
+ this.routerSettlementFromPaymentRequired = void 0;
1573
+ if (!salt) throw new Error("Missing required parameter: salt");
1574
+ if (!settlementRouter) throw new Error("Missing required parameter: settlementRouter");
1575
+ if (!hook) throw new Error("Missing required parameter: hook");
1576
+ if (hookData === void 0) throw new Error("Missing required parameter: hookData");
1577
+ if (!finalPayTo) throw new Error("Missing required parameter: finalPayTo");
1578
+ const resolvedFacilitatorFee = facilitatorFee ?? "0";
1579
+ const chainId = parseInt(paymentRequirements.network.split(":")[1]);
1580
+ if (isNaN(chainId)) {
1581
+ throw new Error(`Invalid network format: ${paymentRequirements.network}`);
1582
+ }
1583
+ const now = Math.floor(Date.now() / 1e3);
1584
+ const validAfter = (now - 600).toString();
1585
+ const validBefore = (now + paymentRequirements.maxTimeoutSeconds).toString();
1586
+ const commitmentParams = {
1587
+ chainId,
1588
+ hub: settlementRouter,
1589
+ asset: paymentRequirements.asset,
1590
+ from: this.signer.address,
1591
+ value: paymentRequirements.amount,
1592
+ validAfter,
1593
+ validBefore,
1594
+ salt,
1595
+ payTo: finalPayTo,
1596
+ facilitatorFee: resolvedFacilitatorFee,
1597
+ hook,
1598
+ hookData
1599
+ };
1600
+ const nonce = calculateCommitment(commitmentParams);
1601
+ const authorization = {
1602
+ from: this.signer.address,
1603
+ to: viem.getAddress(settlementRouter),
1604
+ value: paymentRequirements.amount,
1605
+ validAfter,
1606
+ validBefore,
1607
+ nonce
1608
+ };
1609
+ const signature = await this.signAuthorization(authorization, paymentRequirements, chainId);
1610
+ const payload = {
1611
+ authorization,
1612
+ signature
1613
+ };
1614
+ return {
1615
+ x402Version,
1616
+ payload
1617
+ };
1432
1618
  }
1433
- };
1434
- var settleResponseHeader = "X-Payment-Response";
1435
- var evm = {
1436
1619
  /**
1437
- * Check if a value is a valid EVM address
1620
+ * Sign the EIP-3009 authorization using EIP-712
1621
+ *
1622
+ * @param authorization - The authorization to sign
1623
+ * @param requirements - The payment requirements
1624
+ * @param chainId - The chain ID
1625
+ * @returns Promise resolving to the signature
1438
1626
  */
1439
- isAddress: (value) => {
1440
- if (typeof value !== "string") return false;
1441
- return /^0x[a-fA-F0-9]{40}$/.test(value);
1627
+ async signAuthorization(authorization, requirements, chainId) {
1628
+ if (!requirements.extra?.name || !requirements.extra?.version) {
1629
+ throw new Error(
1630
+ `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
1631
+ );
1632
+ }
1633
+ const { name, version } = requirements.extra;
1634
+ const domain = {
1635
+ name,
1636
+ version,
1637
+ chainId,
1638
+ verifyingContract: viem.getAddress(requirements.asset)
1639
+ };
1640
+ const message = {
1641
+ from: viem.getAddress(authorization.from),
1642
+ to: viem.getAddress(authorization.to),
1643
+ value: BigInt(authorization.value),
1644
+ validAfter: BigInt(authorization.validAfter),
1645
+ validBefore: BigInt(authorization.validBefore),
1646
+ nonce: authorization.nonce
1647
+ };
1648
+ return await this.signer.signTypedData({
1649
+ domain,
1650
+ types: authorizationTypes,
1651
+ primaryType: "TransferWithAuthorization",
1652
+ message
1653
+ });
1442
1654
  }
1443
1655
  };
1444
- var exact = {
1445
- name: "exact"
1446
- // Additional scheme properties would go here
1447
- };
1448
- var ChainIdToNetwork = {
1449
- 84532: "eip155:84532",
1450
- // Base Sepolia
1451
- 1444673419: "eip155:1444673419",
1452
- // SKALE Base Sepolia
1453
- 8453: "eip155:8453"
1454
- // Base Mainnet
1455
- };
1456
- function isMultiNetworkSigner(signer) {
1457
- return !!(signer && typeof signer === "object" && "signTransaction" in signer);
1458
- }
1459
- function isSvmSignerWallet(signer) {
1460
- return !!(signer && typeof signer === "object" && "publicKey" in signer);
1461
- }
1462
- function createPaymentHeader(_requirements, _signer) {
1463
- throw new Error("createPaymentHeader is not implemented in v2 - use x402Client instead");
1464
- }
1465
- function selectPaymentRequirements(_requirements, _selector) {
1466
- throw new Error("selectPaymentRequirements is not implemented in v2 - use x402Client instead");
1467
- }
1468
- function decodeXPaymentResponse(_header) {
1469
- throw new Error("decodeXPaymentResponse is not implemented in v2 - use x402HTTPClient instead");
1470
- }
1471
- function useFacilitator(_config) {
1472
- throw new Error("useFacilitator is not implemented in v2 - use FacilitatorClient instead");
1656
+
1657
+ // src/client/extension-handler.ts
1658
+ function injectX402xExtensionHandler(client, onRouterSettlementExtension) {
1659
+ return client.onBeforePaymentCreation(async (context) => {
1660
+ const { paymentRequired, selectedRequirements } = context;
1661
+ console.log("[x402x-handler] onBeforePaymentCreation called");
1662
+ console.log("[x402x-handler] selectedRequirements.network:", selectedRequirements.network);
1663
+ console.log("[x402x-handler] selectedRequirements.extra keys:", Object.keys(selectedRequirements.extra || {}));
1664
+ const perOptionExtension = selectedRequirements.extra?.[ROUTER_SETTLEMENT_KEY];
1665
+ if (perOptionExtension) {
1666
+ if (!paymentRequired.extensions) {
1667
+ paymentRequired.extensions = {};
1668
+ }
1669
+ paymentRequired.extensions[ROUTER_SETTLEMENT_KEY] = perOptionExtension;
1670
+ console.log("[x402x-handler] \u2705 Copied per-option x402x info into PaymentRequired.extensions");
1671
+ console.log("[x402x-handler] Extension info:", JSON.stringify(perOptionExtension, null, 2));
1672
+ } else {
1673
+ console.warn("[x402x-handler] \u26A0\uFE0F No per-option x402x info found in selectedRequirements.extra");
1674
+ console.warn("[x402x-handler] This may cause facilitator errors. Check server-side createSettlementRouteConfig.");
1675
+ }
1676
+ if (onRouterSettlementExtension) {
1677
+ const extensionToUse = perOptionExtension || paymentRequired.extensions?.[ROUTER_SETTLEMENT_KEY];
1678
+ onRouterSettlementExtension(extensionToUse);
1679
+ }
1680
+ });
1473
1681
  }
1474
- function createSigner(_config) {
1475
- throw new Error("createSigner is not implemented in v2 - use appropriate v2 signer patterns");
1682
+ function registerX402xScheme(client, network, signer) {
1683
+ const scheme = new ExactEvmSchemeWithRouterSettlement(signer);
1684
+ injectX402xExtensionHandler(client, (ext) => {
1685
+ scheme.setRouterSettlementExtensionFromPaymentRequired(ext);
1686
+ });
1687
+ client.register(network, scheme);
1688
+ return client;
1476
1689
  }
1477
1690
 
1478
1691
  exports.AmountError = AmountError;
1479
- exports.ChainIdToNetwork = ChainIdToNetwork;
1692
+ exports.ExactEvmSchemeWithRouterSettlement = ExactEvmSchemeWithRouterSettlement;
1480
1693
  exports.FacilitatorValidationError = FacilitatorValidationError;
1694
+ exports.NETWORK_ALIASES = NETWORK_ALIASES;
1481
1695
  exports.NETWORK_ALIASES_V1_TO_V2 = NETWORK_ALIASES_V1_TO_V2;
1482
1696
  exports.ROUTER_SETTLEMENT_KEY = ROUTER_SETTLEMENT_KEY;
1483
1697
  exports.SETTLEMENT_ROUTER_ABI = SETTLEMENT_ROUTER_ABI;
1484
1698
  exports.SettlementExtraError = SettlementExtraError;
1485
1699
  exports.SettlementRouterError = SettlementRouterError;
1486
- exports.SupportedEVMNetworks = SupportedEVMNetworks;
1487
1700
  exports.addSettlementExtra = addSettlementExtra;
1488
1701
  exports.assertValidSettlementExtra = assertValidSettlementExtra;
1489
1702
  exports.calculateCommitment = calculateCommitment;
@@ -1491,14 +1704,9 @@ exports.calculateFacilitatorFee = calculateFacilitatorFee;
1491
1704
  exports.clearFeeCache = clearFeeCache;
1492
1705
  exports.computeRoutePatterns = computeRoutePatterns;
1493
1706
  exports.createExtensionDeclaration = createExtensionDeclaration;
1494
- exports.createPaymentHeader = createPaymentHeader;
1495
1707
  exports.createRouterSettlementExtension = createRouterSettlementExtension;
1496
1708
  exports.createSettlementRouteConfig = createSettlementRouteConfig;
1497
- exports.createSigner = createSigner;
1498
1709
  exports.createX402xFacilitator = createX402xFacilitator;
1499
- exports.decodeXPaymentResponse = decodeXPaymentResponse;
1500
- exports.evm = evm;
1501
- exports.exact = exact;
1502
1710
  exports.findMatchingPaymentRequirements = findMatchingPaymentRequirements;
1503
1711
  exports.findMatchingRoute = findMatchingRoute;
1504
1712
  exports.formatDefaultAssetAmount = formatDefaultAssetAmount;
@@ -1507,39 +1715,33 @@ exports.getChain = getChain;
1507
1715
  exports.getChainById = getChainById;
1508
1716
  exports.getCustomChains = getCustomChains;
1509
1717
  exports.getDefaultAsset = getDefaultAsset;
1718
+ exports.getNetworkAlias = getNetworkAlias;
1510
1719
  exports.getNetworkAliasesV1ToV2 = getNetworkAliasesV1ToV2;
1511
1720
  exports.getNetworkConfig = getNetworkConfig;
1512
- exports.getNetworkId = getNetworkId;
1513
- exports.getNetworkName = getNetworkName;
1514
1721
  exports.getRouterSettlementExtensionKey = getRouterSettlementExtensionKey;
1722
+ exports.getSupportedNetworkAliases = getSupportedNetworkAliases;
1515
1723
  exports.getSupportedNetworkIds = getSupportedNetworkIds;
1516
- exports.getSupportedNetworkNames = getSupportedNetworkNames;
1517
1724
  exports.getSupportedNetworks = getSupportedNetworks;
1518
- exports.getSupportedNetworksV2 = getSupportedNetworksV2;
1725
+ exports.injectX402xExtensionHandler = injectX402xExtensionHandler;
1519
1726
  exports.isCustomChain = isCustomChain;
1520
- exports.isMultiNetworkSigner = isMultiNetworkSigner;
1521
1727
  exports.isNetworkSupported = isNetworkSupported;
1522
1728
  exports.isRouterSettlement = isRouterSettlement;
1523
1729
  exports.isSettlementMode = isSettlementMode;
1524
- exports.isSvmSignerWallet = isSvmSignerWallet;
1525
1730
  exports.isValid32ByteHex = isValid32ByteHex;
1526
1731
  exports.isValidAddress = isValidAddress2;
1527
1732
  exports.isValidHex = isValidHex2;
1528
1733
  exports.isValidNumericString = isValidNumericString;
1529
- exports.moneySchema = moneySchema;
1530
1734
  exports.networks = networks;
1531
1735
  exports.parseDefaultAssetAmount = parseDefaultAssetAmount;
1532
1736
  exports.parseSettlementExtra = parseSettlementExtra;
1533
1737
  exports.processPriceToAtomicAmount = processPriceToAtomicAmount;
1534
1738
  exports.registerRouterSettlement = registerRouterSettlement2;
1535
1739
  exports.registerSettlementHooks = registerSettlementHooks;
1740
+ exports.registerX402xScheme = registerX402xScheme;
1536
1741
  exports.routerSettlementServerExtension = routerSettlementServerExtension;
1537
- exports.selectPaymentRequirements = selectPaymentRequirements;
1538
1742
  exports.settle = settle;
1539
- exports.settleResponseHeader = settleResponseHeader;
1540
1743
  exports.toCanonicalNetworkKey = toCanonicalNetworkKey;
1541
1744
  exports.toJsonSafe = toJsonSafe;
1542
- exports.useFacilitator = useFacilitator;
1543
1745
  exports.validateCommitmentParams = validateCommitmentParams;
1544
1746
  exports.validateSettlementExtra = validateSettlementExtra;
1545
1747
  exports.verify = verify;