@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.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { defineChain, encodeAbiParameters, keccak256, encodePacked } from 'viem';
1
+ import { defineChain, encodeAbiParameters, keccak256, encodePacked, getAddress } from 'viem';
2
2
  import * as allChains from 'viem/chains';
3
+ import { decodePaymentSignatureHeader } from '@x402/core/http';
3
4
 
4
5
  // src/types.ts
5
6
  var SettlementExtraError = class extends Error {
@@ -175,7 +176,8 @@ function isValidHex(hex) {
175
176
  }
176
177
 
177
178
  // src/network-utils.ts
178
- var NETWORK_IDS = {
179
+ var NETWORK_ALIASES_V1_TO_V2 = {
180
+ // V1 human-readable names -> V2 CAIP-2 canonical keys
179
181
  "base-sepolia": "eip155:84532",
180
182
  "x-layer-testnet": "eip155:1952",
181
183
  "skale-base-sepolia": "eip155:324705682",
@@ -184,15 +186,12 @@ var NETWORK_IDS = {
184
186
  "bsc-testnet": "eip155:97",
185
187
  "bsc": "eip155:56"
186
188
  };
187
- var NETWORK_NAMES = {
188
- "eip155:84532": "base-sepolia",
189
- "eip155:1952": "x-layer-testnet",
190
- "eip155:324705682": "skale-base-sepolia",
191
- "eip155:8453": "base",
192
- "eip155:196": "x-layer",
193
- "eip155:97": "bsc-testnet",
194
- "eip155:56": "bsc"
195
- };
189
+ var NETWORK_ALIASES = Object.entries(
190
+ NETWORK_ALIASES_V1_TO_V2
191
+ ).reduce((acc, [name, caip2]) => {
192
+ acc[caip2] = name;
193
+ return acc;
194
+ }, {});
196
195
  var DEFAULT_ASSETS = {
197
196
  "eip155:84532": {
198
197
  address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
@@ -251,23 +250,14 @@ var DEFAULT_ASSETS = {
251
250
  }
252
251
  }
253
252
  };
254
- function getNetworkId(networkName) {
255
- const networkId = NETWORK_IDS[networkName];
256
- if (!networkId) {
257
- throw new Error(
258
- `Unsupported network: ${networkName}. Supported networks: ${Object.keys(NETWORK_IDS).join(", ")}`
259
- );
260
- }
261
- return networkId;
262
- }
263
- function getNetworkName(network) {
264
- const networkName = NETWORK_NAMES[network];
265
- if (!networkName) {
253
+ function getNetworkAlias(network) {
254
+ const networkAlias = NETWORK_ALIASES[network];
255
+ if (!networkAlias) {
266
256
  throw new Error(
267
- `Unsupported network ID: ${network}. Supported network IDs: ${Object.keys(NETWORK_NAMES).join(", ")}`
257
+ `Unsupported network ID: ${network}. Supported network IDs: ${Object.keys(NETWORK_ALIASES).join(", ")}`
268
258
  );
269
259
  }
270
- return networkName;
260
+ return networkAlias;
271
261
  }
272
262
  function getDefaultAsset(network) {
273
263
  const assetInfo = DEFAULT_ASSETS[network];
@@ -302,21 +292,8 @@ function processPriceToAtomicAmount(price, network) {
302
292
  };
303
293
  }
304
294
  }
305
- var NETWORK_ALIASES_V1_TO_V2 = {
306
- // V1 human-readable names -> V2 CAIP-2 canonical keys
307
- "base-sepolia": "eip155:84532",
308
- "x-layer-testnet": "eip155:1952",
309
- "skale-base-sepolia": "eip155:324705682",
310
- "base": "eip155:8453",
311
- "x-layer": "eip155:196",
312
- "bsc-testnet": "eip155:97",
313
- "bsc": "eip155:56"
314
- };
315
295
  function getSupportedNetworkIds() {
316
- return Object.keys(NETWORK_NAMES);
317
- }
318
- function getSupportedNetworksV2() {
319
- return getSupportedNetworkIds();
296
+ return Object.keys(NETWORK_ALIASES);
320
297
  }
321
298
  function getNetworkAliasesV1ToV2() {
322
299
  return { ...NETWORK_ALIASES_V1_TO_V2 };
@@ -324,11 +301,11 @@ function getNetworkAliasesV1ToV2() {
324
301
  function toCanonicalNetworkKey(network) {
325
302
  if (network.startsWith("eip155:")) {
326
303
  const canonicalNetwork2 = network;
327
- if (canonicalNetwork2 in NETWORK_NAMES) {
304
+ if (canonicalNetwork2 in NETWORK_ALIASES) {
328
305
  return canonicalNetwork2;
329
306
  }
330
307
  throw new Error(
331
- `Unsupported CAIP-2 network: ${network}. Supported networks: ${Object.keys(NETWORK_NAMES).join(", ")}`
308
+ `Unsupported CAIP-2 network: ${network}. Supported networks: ${Object.keys(NETWORK_ALIASES).join(", ")}`
332
309
  );
333
310
  }
334
311
  const canonicalNetwork = NETWORK_ALIASES_V1_TO_V2[network];
@@ -352,15 +329,33 @@ function getDefaultAssetConfig(network) {
352
329
  }
353
330
  };
354
331
  }
332
+ function normalizeToCAIP2(network) {
333
+ if (network.startsWith("eip155:")) {
334
+ const caip22 = network;
335
+ if (!(caip22 in networks)) {
336
+ throw new Error(
337
+ `Unsupported CAIP-2 network: ${network}. Supported networks: ${Object.keys(networks).join(", ")}`
338
+ );
339
+ }
340
+ return caip22;
341
+ }
342
+ const caip2 = NETWORK_ALIASES_V1_TO_V2[network];
343
+ if (!caip2) {
344
+ throw new Error(
345
+ `Unknown network: ${network}. Supported networks: ${Object.keys(NETWORK_ALIASES_V1_TO_V2).join(", ")}`
346
+ );
347
+ }
348
+ return caip2;
349
+ }
355
350
  var networks = {
356
- "base-sepolia": {
357
- chainId: parseInt(getNetworkId("base-sepolia").split(":")[1]),
351
+ "eip155:84532": {
352
+ chainId: 84532,
358
353
  name: "Base Sepolia",
359
354
  type: "testnet",
360
355
  addressExplorerBaseUrl: "https://sepolia.basescan.org/address/",
361
356
  txExplorerBaseUrl: "https://sepolia.basescan.org/tx/",
362
357
  settlementRouter: "0x817e4f0ee2fbdaac426f1178e149f7dc98873ecb",
363
- defaultAsset: getDefaultAssetConfig(getNetworkId("base-sepolia")),
358
+ defaultAsset: getDefaultAssetConfig("eip155:84532"),
364
359
  hooks: {
365
360
  transfer: "0x4DE234059C6CcC94B8fE1eb1BD24804794083569"
366
361
  },
@@ -375,14 +370,14 @@ var networks = {
375
370
  nativeToken: "ETH"
376
371
  }
377
372
  },
378
- "x-layer-testnet": {
379
- chainId: parseInt(getNetworkId("x-layer-testnet").split(":")[1]),
373
+ "eip155:1952": {
374
+ chainId: 1952,
380
375
  name: "X Layer Testnet",
381
376
  type: "testnet",
382
377
  addressExplorerBaseUrl: "https://www.oklink.com/xlayer-test/address/",
383
378
  txExplorerBaseUrl: "https://www.oklink.com/xlayer-test/tx/",
384
379
  settlementRouter: "0xba9980fb08771e2fd10c17450f52d39bcb9ed576",
385
- defaultAsset: getDefaultAssetConfig(getNetworkId("x-layer-testnet")),
380
+ defaultAsset: getDefaultAssetConfig("eip155:1952"),
386
381
  hooks: {
387
382
  transfer: "0xD4b98dd614c1Ea472fC4547a5d2B93f3D3637BEE"
388
383
  },
@@ -397,14 +392,14 @@ var networks = {
397
392
  nativeToken: "OKB"
398
393
  }
399
394
  },
400
- "skale-base-sepolia": {
401
- chainId: parseInt(getNetworkId("skale-base-sepolia").split(":")[1]),
395
+ "eip155:324705682": {
396
+ chainId: 324705682,
402
397
  name: "SKALE Base Sepolia",
403
398
  type: "testnet",
404
399
  addressExplorerBaseUrl: "https://base-sepolia-testnet-explorer.skalenodes.com/address/",
405
400
  txExplorerBaseUrl: "https://base-sepolia-testnet-explorer.skalenodes.com/tx/",
406
401
  settlementRouter: "0x1Ae0E196dC18355aF3a19985faf67354213F833D",
407
- defaultAsset: getDefaultAssetConfig(getNetworkId("skale-base-sepolia")),
402
+ defaultAsset: getDefaultAssetConfig("eip155:324705682"),
408
403
  hooks: {
409
404
  transfer: "0x2f05fe5674aE756E25C26855258B4877E9e021Fd"
410
405
  },
@@ -419,14 +414,14 @@ var networks = {
419
414
  nativeToken: "Credits"
420
415
  }
421
416
  },
422
- "bsc-testnet": {
423
- chainId: parseInt(getNetworkId("bsc-testnet").split(":")[1]),
417
+ "eip155:97": {
418
+ chainId: 97,
424
419
  name: "BSC Testnet",
425
420
  type: "testnet",
426
421
  addressExplorerBaseUrl: "https://testnet.bscscan.com/address/",
427
422
  txExplorerBaseUrl: "https://testnet.bscscan.com/tx/",
428
423
  settlementRouter: "0x1Ae0E196dC18355aF3a19985faf67354213F833D",
429
- defaultAsset: getDefaultAssetConfig(getNetworkId("bsc-testnet")),
424
+ defaultAsset: getDefaultAssetConfig("eip155:97"),
430
425
  hooks: {
431
426
  transfer: "0x2f05fe5674aE756E25C26855258B4877E9e021Fd"
432
427
  },
@@ -442,14 +437,14 @@ var networks = {
442
437
  }
443
438
  },
444
439
  // Mainnet configurations
445
- base: {
446
- chainId: parseInt(getNetworkId("base").split(":")[1]),
440
+ "eip155:8453": {
441
+ chainId: 8453,
447
442
  name: "Base Mainnet",
448
443
  type: "mainnet",
449
444
  addressExplorerBaseUrl: "https://basescan.org/address/",
450
445
  txExplorerBaseUrl: "https://basescan.org/tx/",
451
446
  settlementRouter: "0x73fc659Cd5494E69852bE8D9D23FE05Aab14b29B",
452
- defaultAsset: getDefaultAssetConfig(getNetworkId("base")),
447
+ defaultAsset: getDefaultAssetConfig("eip155:8453"),
453
448
  hooks: {
454
449
  transfer: "0x081258287F692D61575387ee2a4075f34dd7Aef7"
455
450
  },
@@ -464,14 +459,14 @@ var networks = {
464
459
  nativeToken: "ETH"
465
460
  }
466
461
  },
467
- "x-layer": {
468
- chainId: parseInt(getNetworkId("x-layer").split(":")[1]),
462
+ "eip155:196": {
463
+ chainId: 196,
469
464
  name: "X Layer Mainnet",
470
465
  type: "mainnet",
471
466
  addressExplorerBaseUrl: "https://www.oklink.com/xlayer/address/",
472
467
  txExplorerBaseUrl: "https://www.oklink.com/xlayer/tx/",
473
468
  settlementRouter: "0x73fc659Cd5494E69852bE8D9D23FE05Aab14b29B",
474
- defaultAsset: getDefaultAssetConfig(getNetworkId("x-layer")),
469
+ defaultAsset: getDefaultAssetConfig("eip155:196"),
475
470
  hooks: {
476
471
  transfer: "0x081258287F692D61575387ee2a4075f34dd7Aef7"
477
472
  },
@@ -486,14 +481,14 @@ var networks = {
486
481
  nativeToken: "OKB"
487
482
  }
488
483
  },
489
- bsc: {
490
- chainId: parseInt(getNetworkId("bsc").split(":")[1]),
484
+ "eip155:56": {
485
+ chainId: 56,
491
486
  name: "BSC Mainnet",
492
487
  type: "mainnet",
493
488
  addressExplorerBaseUrl: "https://bscscan.com/address/",
494
489
  txExplorerBaseUrl: "https://bscscan.com/tx/",
495
490
  settlementRouter: "0x1Ae0E196dC18355aF3a19985faf67354213F833D",
496
- defaultAsset: getDefaultAssetConfig(getNetworkId("bsc")),
491
+ defaultAsset: getDefaultAssetConfig("eip155:56"),
497
492
  hooks: {
498
493
  transfer: "0x2f05fe5674aE756E25C26855258B4877E9e021Fd"
499
494
  },
@@ -510,7 +505,8 @@ var networks = {
510
505
  }
511
506
  };
512
507
  function getNetworkConfig(network) {
513
- const config = networks[network];
508
+ const caip2Network = normalizeToCAIP2(network);
509
+ const config = networks[caip2Network];
514
510
  if (!config) {
515
511
  throw new Error(
516
512
  `Unsupported network: ${network}. Supported networks: ${Object.keys(networks).join(", ")}`
@@ -519,13 +515,18 @@ function getNetworkConfig(network) {
519
515
  return config;
520
516
  }
521
517
  function isNetworkSupported(network) {
522
- return network in networks;
518
+ try {
519
+ const caip2Network = normalizeToCAIP2(network);
520
+ return caip2Network in networks;
521
+ } catch {
522
+ return false;
523
+ }
523
524
  }
524
- function getSupportedNetworkNames() {
525
- return Object.keys(networks);
525
+ function getSupportedNetworkAliases() {
526
+ return Object.keys(networks).map((caip2) => getNetworkAlias(caip2));
526
527
  }
527
528
  function getSupportedNetworks() {
528
- return getSupportedNetworkNames();
529
+ return Object.keys(networks);
529
530
  }
530
531
  var customChains = {
531
532
  // X Layer Testnet
@@ -574,15 +575,31 @@ var customChains = {
574
575
  })
575
576
  };
576
577
  function getChain(network) {
577
- const networkId = getNetworkId(network);
578
- const chainId = parseInt(networkId.split(":")[1]);
578
+ let chainId;
579
+ if (network.startsWith("eip155:")) {
580
+ const caip2 = network;
581
+ if (!(caip2 in NETWORK_ALIASES)) {
582
+ throw new Error(
583
+ `Unsupported CAIP-2 network: ${network}. Supported networks: ${Object.keys(NETWORK_ALIASES).join(", ")}`
584
+ );
585
+ }
586
+ chainId = parseInt(network.split(":")[1]);
587
+ } else {
588
+ const caip2 = NETWORK_ALIASES_V1_TO_V2[network];
589
+ if (!caip2) {
590
+ throw new Error(
591
+ `Unknown network: ${network}. Supported networks: ${Object.keys(NETWORK_ALIASES_V1_TO_V2).join(", ")}`
592
+ );
593
+ }
594
+ chainId = parseInt(caip2.split(":")[1]);
595
+ }
579
596
  if (customChains[chainId]) {
580
597
  return customChains[chainId];
581
598
  }
582
599
  const chain = Object.values(allChains).find((c) => c.id === chainId);
583
600
  if (!chain) {
584
601
  throw new Error(
585
- `Unsupported network: ${network} (chain ID: ${chainId}). Please add custom chain definition in chains.ts`
602
+ `Unsupported chain ID: ${chainId}. Please add custom chain definition in chains.ts`
586
603
  );
587
604
  }
588
605
  return chain;
@@ -642,15 +659,15 @@ var TransferHook;
642
659
  );
643
660
  }
644
661
  TransferHook2.encode = encode;
645
- function getAddress(network) {
662
+ function getAddress2(network) {
646
663
  const config = getNetworkConfig(network);
647
664
  return config.hooks.transfer;
648
665
  }
649
- TransferHook2.getAddress = getAddress;
666
+ TransferHook2.getAddress = getAddress2;
650
667
  })(TransferHook || (TransferHook = {}));
651
668
  var NFTMintHook;
652
669
  ((NFTMintHook2) => {
653
- function getAddress(network) {
670
+ function getAddress2(network) {
654
671
  const config = getNetworkConfig(network);
655
672
  if (!config.demoHooks?.nftMint) {
656
673
  throw new Error(
@@ -659,7 +676,7 @@ var NFTMintHook;
659
676
  }
660
677
  return config.demoHooks.nftMint;
661
678
  }
662
- NFTMintHook2.getAddress = getAddress;
679
+ NFTMintHook2.getAddress = getAddress2;
663
680
  function getNFTContractAddress(network) {
664
681
  const config = getNetworkConfig(network);
665
682
  if (!config.demoHooks?.randomNFT) {
@@ -689,7 +706,7 @@ var NFTMintHook;
689
706
  })(NFTMintHook || (NFTMintHook = {}));
690
707
  var RewardHook;
691
708
  ((RewardHook2) => {
692
- function getAddress(network) {
709
+ function getAddress2(network) {
693
710
  const config = getNetworkConfig(network);
694
711
  if (!config.demoHooks?.reward) {
695
712
  throw new Error(
@@ -698,7 +715,7 @@ var RewardHook;
698
715
  }
699
716
  return config.demoHooks.reward;
700
717
  }
701
- RewardHook2.getAddress = getAddress;
718
+ RewardHook2.getAddress = getAddress2;
702
719
  function getTokenAddress(network) {
703
720
  const config = getNetworkConfig(network);
704
721
  if (!config.demoHooks?.rewardToken) {
@@ -800,8 +817,8 @@ function assertValidSettlementExtra(extra) {
800
817
 
801
818
  // src/utils.ts
802
819
  function addSettlementExtra(requirements, params) {
803
- const networkName = getNetworkName(requirements.network);
804
- const config = getNetworkConfig(networkName);
820
+ const networkAlias = getNetworkAlias(requirements.network);
821
+ const config = getNetworkConfig(networkAlias);
805
822
  const existingExtra = requirements.extra || {};
806
823
  const name = existingExtra.name || config.defaultAsset.eip712.name;
807
824
  const version = existingExtra.version || config.defaultAsset.eip712.version;
@@ -837,6 +854,9 @@ function createRouterSettlementExtension(params) {
837
854
  if (params?.description !== void 0) {
838
855
  info.description = params.description;
839
856
  }
857
+ if (params?.salt) {
858
+ info.salt = params.salt;
859
+ }
840
860
  if (params?.settlementRouter) info.settlementRouter = params.settlementRouter;
841
861
  if (params?.hook) info.hook = params.hook;
842
862
  if (params?.hookData) info.hookData = params.hookData;
@@ -856,8 +876,9 @@ function createRouterSettlementExtension(params) {
856
876
  finalPayTo: { type: "string", pattern: "^0x[a-fA-F0-9]{40}$" },
857
877
  facilitatorFee: { type: "string" }
858
878
  },
859
- // Salt is required in the final enriched version but not in the initial declaration
860
- required: ["schemaVersion", "settlementRouter", "hook", "hookData", "finalPayTo"]
879
+ // Salt is required in the final enriched version
880
+ // facilitatorFee is optional (facilitator will calculate if missing)
881
+ required: ["schemaVersion", "salt", "settlementRouter", "hook", "hookData", "finalPayTo"]
861
882
  };
862
883
  }
863
884
  return {
@@ -898,202 +919,6 @@ function createExtensionDeclaration(params) {
898
919
  };
899
920
  }
900
921
 
901
- // src/settlement-routes.ts
902
- function createSettlementRouteConfig(baseConfig, settlementOptions) {
903
- const acceptsArray = Array.isArray(baseConfig.accepts) ? baseConfig.accepts : [baseConfig.accepts];
904
- const firstOption = acceptsArray[0];
905
- const firstNetwork = firstOption.network;
906
- const networkConfig = getNetworkConfig(firstNetwork);
907
- if (!networkConfig) {
908
- throw new Error(`Network configuration not found for: ${firstNetwork}`);
909
- }
910
- const hook = settlementOptions.hook || TransferHook.getAddress(firstNetwork);
911
- const hookData = settlementOptions.hookData || TransferHook.encode();
912
- const enhancedAccepts = acceptsArray.map((option) => {
913
- const network = typeof option.network === "string" ? option.network : option.network;
914
- const optionNetworkConfig = getNetworkConfig(network);
915
- if (!optionNetworkConfig) {
916
- throw new Error(`Network configuration not found for: ${network}`);
917
- }
918
- const enhancedOption = {
919
- ...option,
920
- // Override payTo to use settlementRouter as the immediate recipient
921
- payTo: optionNetworkConfig.settlementRouter,
922
- // Only include EIP-712 domain info in extra
923
- extra: {
924
- ...option.extra || {},
925
- name: optionNetworkConfig.defaultAsset.eip712.name,
926
- version: optionNetworkConfig.defaultAsset.eip712.version
927
- }
928
- };
929
- return enhancedOption;
930
- });
931
- const extensions = {
932
- ...baseConfig.extensions || {},
933
- ...createExtensionDeclaration({
934
- description: settlementOptions.description || "Router settlement with atomic fee distribution",
935
- // Pass settlement parameters to be included in extension info
936
- settlementRouter: networkConfig.settlementRouter,
937
- hook,
938
- hookData,
939
- finalPayTo: settlementOptions.finalPayTo,
940
- facilitatorFee: settlementOptions.facilitatorFee || "0"
941
- })
942
- };
943
- return {
944
- ...baseConfig,
945
- accepts: enhancedAccepts.length === 1 ? enhancedAccepts[0] : enhancedAccepts,
946
- extensions
947
- };
948
- }
949
- function registerSettlementHooks(server, config = {}) {
950
- const {
951
- enableSaltExtraction = true,
952
- validateSettlementParams = true
953
- } = config;
954
- if (enableSaltExtraction) {
955
- server.onBeforeVerify(async (context) => {
956
- const { paymentPayload, requirements } = context;
957
- if (paymentPayload.extensions && "x402x-router-settlement" in paymentPayload.extensions) {
958
- const extension = paymentPayload.extensions["x402x-router-settlement"];
959
- if (extension?.info) {
960
- if (!requirements.extra) {
961
- requirements.extra = {};
962
- }
963
- const info = extension.info;
964
- if (info.salt) requirements.extra.salt = info.salt;
965
- if (info.settlementRouter) requirements.extra.settlementRouter = info.settlementRouter;
966
- if (info.hook) requirements.extra.hook = info.hook;
967
- if (info.hookData) requirements.extra.hookData = info.hookData;
968
- if (info.finalPayTo) requirements.extra.payTo = info.finalPayTo;
969
- if (info.facilitatorFee !== void 0) requirements.extra.facilitatorFee = info.facilitatorFee;
970
- }
971
- }
972
- return void 0;
973
- });
974
- }
975
- if (validateSettlementParams) {
976
- server.onBeforeSettle(async (context) => {
977
- const { paymentPayload, requirements } = context;
978
- let settlementParams = {};
979
- if (paymentPayload.extensions && "x402x-router-settlement" in paymentPayload.extensions) {
980
- const extension = paymentPayload.extensions["x402x-router-settlement"];
981
- if (extension?.info) {
982
- settlementParams = extension.info;
983
- }
984
- }
985
- if (!settlementParams.settlementRouter && requirements.extra) {
986
- settlementParams = requirements.extra;
987
- }
988
- const requiredFields = ["settlementRouter", "hook", "hookData"];
989
- const payToField = "finalPayTo" in settlementParams ? "finalPayTo" : "payTo";
990
- const missingFields = requiredFields.filter((field) => !settlementParams[field]);
991
- if (!settlementParams[payToField]) {
992
- missingFields.push(payToField);
993
- }
994
- if (missingFields.length > 0) {
995
- return {
996
- abort: true,
997
- reason: `Missing settlement parameters: ${missingFields.join(", ")}`
998
- };
999
- }
1000
- return void 0;
1001
- });
1002
- }
1003
- }
1004
-
1005
- // src/helpers.ts
1006
- function registerRouterSettlement2(server) {
1007
- return registerRouterSettlement(server);
1008
- }
1009
- async function createX402xFacilitator(config) {
1010
- try {
1011
- const importFn = new Function("specifier", "return import(specifier)");
1012
- const facilitatorModule = await importFn("@x402x/facilitator-sdk");
1013
- return facilitatorModule.createRouterSettlementFacilitator(config);
1014
- } catch (error) {
1015
- throw new Error(
1016
- "createX402xFacilitator requires @x402x/facilitator-sdk to be installed. Please install it using your package manager."
1017
- );
1018
- }
1019
- }
1020
- function withRouterSettlement(requirements, options) {
1021
- if (!requirements.network) {
1022
- throw new Error("Network is required in payment requirements");
1023
- }
1024
- if (!requirements.asset) {
1025
- throw new Error("Asset is required in payment requirements");
1026
- }
1027
- const networkConfig = getNetworkConfig(requirements.network);
1028
- if (!networkConfig) {
1029
- throw new Error(`Network configuration not found for network: ${requirements.network}`);
1030
- }
1031
- const salt = options.salt || generateSalt();
1032
- const settlementExtra = {
1033
- settlementRouter: networkConfig.settlementRouter,
1034
- salt,
1035
- payTo: options.payTo,
1036
- facilitatorFee: options.facilitatorFee,
1037
- hook: options.hook,
1038
- hookData: options.hookData,
1039
- name: options.name || networkConfig.defaultAsset.eip712.name,
1040
- version: options.version || networkConfig.defaultAsset.eip712.version
1041
- };
1042
- const extensionKey = getRouterSettlementExtensionKey();
1043
- const extensionDeclaration = createRouterSettlementExtension({
1044
- description: "Router settlement with atomic fee distribution"
1045
- });
1046
- const reqWithExtensions = requirements;
1047
- return {
1048
- ...requirements,
1049
- extra: {
1050
- ...reqWithExtensions.extra || {},
1051
- ...settlementExtra
1052
- },
1053
- extensions: {
1054
- ...reqWithExtensions.extensions || {},
1055
- [extensionKey]: extensionDeclaration
1056
- }
1057
- };
1058
- }
1059
- function isRouterSettlement(requirements) {
1060
- return !!(requirements.extra && "settlementRouter" in requirements.extra);
1061
- }
1062
-
1063
- // src/amount.ts
1064
- var AmountError = class extends Error {
1065
- constructor(message) {
1066
- super(message);
1067
- this.name = "AmountError";
1068
- }
1069
- };
1070
- function parseDefaultAssetAmount(amount, network) {
1071
- if (amount === null || amount === void 0 || amount === "") {
1072
- throw new AmountError("Amount is required");
1073
- }
1074
- const result = processPriceToAtomicAmount(amount, network);
1075
- if ("error" in result) {
1076
- throw new AmountError(`Invalid amount format: ${result.error}`);
1077
- }
1078
- return result.amount;
1079
- }
1080
- function formatDefaultAssetAmount(amount, network) {
1081
- const atomicAmount = BigInt(amount);
1082
- if (atomicAmount < 0n) {
1083
- throw new AmountError("Amount cannot be negative");
1084
- }
1085
- const asset = getDefaultAsset(network);
1086
- const decimals = asset.decimals;
1087
- const amountStr = atomicAmount.toString().padStart(decimals + 1, "0");
1088
- const integerPart = amountStr.slice(0, -decimals) || "0";
1089
- const decimalPart = amountStr.slice(-decimals);
1090
- const trimmedDecimal = decimalPart.replace(/0+$/, "");
1091
- if (trimmedDecimal) {
1092
- return `${integerPart}.${trimmedDecimal}`;
1093
- }
1094
- return integerPart;
1095
- }
1096
-
1097
922
  // src/facilitator.ts
1098
923
  function isSettlementMode(paymentRequirements) {
1099
924
  return !!paymentRequirements.extra?.settlementRouter;
@@ -1300,6 +1125,274 @@ async function settle(facilitatorUrl, paymentPayload, paymentRequirements, timeo
1300
1125
  }
1301
1126
  }
1302
1127
 
1128
+ // src/settlement-routes.ts
1129
+ var DEFAULT_FACILITATOR_URL = "https://facilitator.x402x.dev";
1130
+ function createSettlementRouteConfig(baseConfig, settlementOptions) {
1131
+ const acceptsArray = Array.isArray(baseConfig.accepts) ? baseConfig.accepts : [baseConfig.accepts];
1132
+ const enhancedAccepts = acceptsArray.map((option) => {
1133
+ const network = typeof option.network === "string" ? option.network : option.network;
1134
+ const optionNetworkConfig = getNetworkConfig(network);
1135
+ if (!optionNetworkConfig) {
1136
+ throw new Error(`Network configuration not found for: ${network}`);
1137
+ }
1138
+ const originalPayTo = typeof option.payTo === "string" ? option.payTo : void 0;
1139
+ const finalPayTo = settlementOptions?.finalPayTo || originalPayTo;
1140
+ if (!finalPayTo) {
1141
+ throw new Error(`Cannot determine finalPayTo: neither settlementOptions.finalPayTo nor option.payTo (string) is provided for network ${network}`);
1142
+ }
1143
+ const hook = settlementOptions?.hook || TransferHook.getAddress(network);
1144
+ const hookData = settlementOptions?.hookData || TransferHook.encode();
1145
+ const facilitatorUrl = settlementOptions?.facilitatorUrl || DEFAULT_FACILITATOR_URL;
1146
+ const hasFixedFee = settlementOptions?.facilitatorFee !== void 0;
1147
+ const dynamicPrice = async (context) => {
1148
+ const httpContext = context;
1149
+ const isRetry = !!httpContext.paymentHeader;
1150
+ if (isRetry) {
1151
+ console.log("[x402x-settlement] Retry request detected, replaying accepted");
1152
+ try {
1153
+ const paymentPayload = decodePaymentSignatureHeader(httpContext.paymentHeader);
1154
+ const accepted = paymentPayload.accepted;
1155
+ if (accepted.network === network && accepted.scheme === option.scheme) {
1156
+ console.log("[x402x-settlement] Replaying accepted for network:", network);
1157
+ return {
1158
+ asset: accepted.asset,
1159
+ amount: accepted.amount,
1160
+ extra: accepted.extra
1161
+ };
1162
+ } else {
1163
+ console.warn("[x402x-settlement] Network/scheme mismatch in retry, falling back to probe");
1164
+ }
1165
+ } catch (error) {
1166
+ console.error("[x402x-settlement] Failed to decode payment header, falling back to probe:", error);
1167
+ }
1168
+ }
1169
+ console.log("[x402x-settlement] Probe request, generating new salt and querying fee");
1170
+ const basePrice = typeof option.price === "function" ? await option.price(context) : option.price;
1171
+ let moneyPrice;
1172
+ if (typeof basePrice === "object" && basePrice !== null && "asset" in basePrice) {
1173
+ return basePrice;
1174
+ } else {
1175
+ moneyPrice = basePrice;
1176
+ }
1177
+ const amountStr = typeof moneyPrice === "number" ? moneyPrice.toString() : moneyPrice.toString().replace(/[^0-9.]/g, "");
1178
+ const amountFloat = parseFloat(amountStr);
1179
+ if (isNaN(amountFloat)) {
1180
+ throw new Error(`Invalid price format: ${moneyPrice}`);
1181
+ }
1182
+ const { address, decimals, eip712 } = optionNetworkConfig.defaultAsset;
1183
+ const atomicAmount = BigInt(Math.floor(amountFloat * 10 ** decimals)).toString();
1184
+ const salt = generateSalt();
1185
+ let facilitatorFee;
1186
+ if (hasFixedFee) {
1187
+ facilitatorFee = settlementOptions.facilitatorFee;
1188
+ console.log("[x402x-settlement] Using fixed facilitatorFee:", facilitatorFee);
1189
+ } else {
1190
+ console.log("[x402x-settlement] Querying facilitator for fee:", { network, hook, hookData });
1191
+ try {
1192
+ const feeResult = await calculateFacilitatorFee(facilitatorUrl, network, hook, hookData);
1193
+ if (!feeResult.hookAllowed) {
1194
+ throw new Error(`Hook not allowed by facilitator: ${hook} on network ${network}`);
1195
+ }
1196
+ facilitatorFee = feeResult.facilitatorFee;
1197
+ console.log("[x402x-settlement] Got facilitatorFee from facilitator:", facilitatorFee);
1198
+ } catch (error) {
1199
+ console.error("[x402x-settlement] Failed to query facilitator fee:", error);
1200
+ throw new Error(
1201
+ `Failed to calculate facilitator fee for network ${network}: ${error instanceof Error ? error.message : String(error)}`
1202
+ );
1203
+ }
1204
+ }
1205
+ const settlementExtension = createExtensionDeclaration({
1206
+ description: settlementOptions?.description || "Router settlement with atomic fee distribution",
1207
+ settlementRouter: optionNetworkConfig.settlementRouter,
1208
+ hook,
1209
+ hookData,
1210
+ finalPayTo,
1211
+ facilitatorFee,
1212
+ salt
1213
+ });
1214
+ return {
1215
+ asset: address,
1216
+ amount: atomicAmount,
1217
+ extra: {
1218
+ // EIP-712 domain parameters (scheme-specific for signing)
1219
+ name: eip712.name,
1220
+ version: eip712.version,
1221
+ // Network-specific settlement extension parameters (per-option x402x declaration with salt + fee)
1222
+ [ROUTER_SETTLEMENT_KEY]: settlementExtension[ROUTER_SETTLEMENT_KEY]
1223
+ }
1224
+ };
1225
+ };
1226
+ const enhancedOption = {
1227
+ ...option,
1228
+ // Override payTo to use settlementRouter as the immediate recipient
1229
+ payTo: optionNetworkConfig.settlementRouter,
1230
+ // Use DynamicPrice that queries fee on probe and replays on retry
1231
+ price: dynamicPrice,
1232
+ // Keep option.extra for any user-provided context (primary data is now in price.extra via dynamic function)
1233
+ extra: option.extra
1234
+ };
1235
+ return enhancedOption;
1236
+ });
1237
+ const extensions = {
1238
+ ...baseConfig.extensions || {}
1239
+ // Only include non-network-specific metadata at root level
1240
+ // Per-option x402x info is already in accepts[i].price.extra[ROUTER_SETTLEMENT_KEY]
1241
+ };
1242
+ return {
1243
+ ...baseConfig,
1244
+ accepts: enhancedAccepts.length === 1 ? enhancedAccepts[0] : enhancedAccepts,
1245
+ extensions
1246
+ };
1247
+ }
1248
+ function registerSettlementHooks(server, config = {}) {
1249
+ const {
1250
+ enableSaltExtraction = true,
1251
+ validateSettlementParams = true
1252
+ } = config;
1253
+ if (enableSaltExtraction) {
1254
+ server.onBeforeVerify(async (context) => {
1255
+ const { paymentPayload, requirements } = context;
1256
+ if (paymentPayload.extensions && "x402x-router-settlement" in paymentPayload.extensions) {
1257
+ const extension = paymentPayload.extensions["x402x-router-settlement"];
1258
+ if (extension?.info) {
1259
+ if (!requirements.extra) {
1260
+ requirements.extra = {};
1261
+ }
1262
+ const info = extension.info;
1263
+ if (info.salt) requirements.extra.salt = info.salt;
1264
+ if (info.settlementRouter) requirements.extra.settlementRouter = info.settlementRouter;
1265
+ if (info.hook) requirements.extra.hook = info.hook;
1266
+ if (info.hookData) requirements.extra.hookData = info.hookData;
1267
+ if (info.finalPayTo) requirements.extra.payTo = info.finalPayTo;
1268
+ if (info.facilitatorFee !== void 0) requirements.extra.facilitatorFee = info.facilitatorFee;
1269
+ }
1270
+ }
1271
+ return void 0;
1272
+ });
1273
+ }
1274
+ if (validateSettlementParams) {
1275
+ server.onBeforeSettle(async (context) => {
1276
+ const { paymentPayload, requirements } = context;
1277
+ let settlementParams = {};
1278
+ if (paymentPayload.extensions && "x402x-router-settlement" in paymentPayload.extensions) {
1279
+ const extension = paymentPayload.extensions["x402x-router-settlement"];
1280
+ if (extension?.info) {
1281
+ settlementParams = extension.info;
1282
+ }
1283
+ }
1284
+ if (!settlementParams.settlementRouter && requirements.extra) {
1285
+ settlementParams = requirements.extra;
1286
+ }
1287
+ const requiredFields = ["settlementRouter", "hook", "hookData"];
1288
+ const payToField = "finalPayTo" in settlementParams ? "finalPayTo" : "payTo";
1289
+ const missingFields = requiredFields.filter((field) => !settlementParams[field]);
1290
+ if (!settlementParams[payToField]) {
1291
+ missingFields.push(payToField);
1292
+ }
1293
+ if (missingFields.length > 0) {
1294
+ return {
1295
+ abort: true,
1296
+ reason: `Missing settlement parameters: ${missingFields.join(", ")}`
1297
+ };
1298
+ }
1299
+ return void 0;
1300
+ });
1301
+ }
1302
+ }
1303
+
1304
+ // src/helpers.ts
1305
+ function registerRouterSettlement2(server) {
1306
+ return registerRouterSettlement(server);
1307
+ }
1308
+ async function createX402xFacilitator(config) {
1309
+ try {
1310
+ const importFn = new Function("specifier", "return import(specifier)");
1311
+ const facilitatorModule = await importFn("@x402x/facilitator-sdk");
1312
+ return facilitatorModule.createRouterSettlementFacilitator(config);
1313
+ } catch (error) {
1314
+ throw new Error(
1315
+ "createX402xFacilitator requires @x402x/facilitator-sdk to be installed. Please install it using your package manager."
1316
+ );
1317
+ }
1318
+ }
1319
+ function withRouterSettlement(requirements, options) {
1320
+ if (!requirements.network) {
1321
+ throw new Error("Network is required in payment requirements");
1322
+ }
1323
+ if (!requirements.asset) {
1324
+ throw new Error("Asset is required in payment requirements");
1325
+ }
1326
+ const networkConfig = getNetworkConfig(requirements.network);
1327
+ if (!networkConfig) {
1328
+ throw new Error(`Network configuration not found for network: ${requirements.network}`);
1329
+ }
1330
+ const salt = options.salt || generateSalt();
1331
+ const settlementExtra = {
1332
+ settlementRouter: networkConfig.settlementRouter,
1333
+ salt,
1334
+ payTo: options.payTo,
1335
+ facilitatorFee: options.facilitatorFee,
1336
+ hook: options.hook,
1337
+ hookData: options.hookData,
1338
+ name: options.name || networkConfig.defaultAsset.eip712.name,
1339
+ version: options.version || networkConfig.defaultAsset.eip712.version
1340
+ };
1341
+ const extensionKey = getRouterSettlementExtensionKey();
1342
+ const extensionDeclaration = createRouterSettlementExtension({
1343
+ description: "Router settlement with atomic fee distribution"
1344
+ });
1345
+ const reqWithExtensions = requirements;
1346
+ return {
1347
+ ...requirements,
1348
+ extra: {
1349
+ ...reqWithExtensions.extra || {},
1350
+ ...settlementExtra
1351
+ },
1352
+ extensions: {
1353
+ ...reqWithExtensions.extensions || {},
1354
+ [extensionKey]: extensionDeclaration
1355
+ }
1356
+ };
1357
+ }
1358
+ function isRouterSettlement(requirements) {
1359
+ return !!(requirements.extra && "settlementRouter" in requirements.extra);
1360
+ }
1361
+
1362
+ // src/amount.ts
1363
+ var AmountError = class extends Error {
1364
+ constructor(message) {
1365
+ super(message);
1366
+ this.name = "AmountError";
1367
+ }
1368
+ };
1369
+ function parseDefaultAssetAmount(amount, network) {
1370
+ if (amount === null || amount === void 0 || amount === "") {
1371
+ throw new AmountError("Amount is required");
1372
+ }
1373
+ const result = processPriceToAtomicAmount(amount, network);
1374
+ if ("error" in result) {
1375
+ throw new AmountError(`Invalid amount format: ${result.error}`);
1376
+ }
1377
+ return result.amount;
1378
+ }
1379
+ function formatDefaultAssetAmount(amount, network) {
1380
+ const atomicAmount = BigInt(amount);
1381
+ if (atomicAmount < 0n) {
1382
+ throw new AmountError("Amount cannot be negative");
1383
+ }
1384
+ const asset = getDefaultAsset(network);
1385
+ const decimals = asset.decimals;
1386
+ const amountStr = atomicAmount.toString().padStart(decimals + 1, "0");
1387
+ const integerPart = amountStr.slice(0, -decimals) || "0";
1388
+ const decimalPart = amountStr.slice(-decimals);
1389
+ const trimmedDecimal = decimalPart.replace(/0+$/, "");
1390
+ if (trimmedDecimal) {
1391
+ return `${integerPart}.${trimmedDecimal}`;
1392
+ }
1393
+ return integerPart;
1394
+ }
1395
+
1303
1396
  // src/abi.ts
1304
1397
  var SETTLEMENT_ROUTER_ABI = [
1305
1398
  {
@@ -1391,68 +1484,188 @@ var SettlementRouterError = class extends Error {
1391
1484
  this.name = "SettlementRouterError";
1392
1485
  }
1393
1486
  };
1394
-
1395
- // src/legacy-compat.ts
1396
- var SupportedEVMNetworks = [
1397
- "eip155:84532",
1398
- // Base Sepolia
1399
- "eip155:1444673419",
1400
- // SKALE Base Sepolia
1401
- "eip155:8453"
1402
- // Base Mainnet
1403
- ];
1404
- var moneySchema = {
1405
- parse: (value) => {
1406
- if (typeof value === "string" || typeof value === "number") {
1407
- return value;
1487
+ var authorizationTypes = {
1488
+ TransferWithAuthorization: [
1489
+ { name: "from", type: "address" },
1490
+ { name: "to", type: "address" },
1491
+ { name: "value", type: "uint256" },
1492
+ { name: "validAfter", type: "uint256" },
1493
+ { name: "validBefore", type: "uint256" },
1494
+ { name: "nonce", type: "bytes32" }
1495
+ ]
1496
+ };
1497
+ var ExactEvmSchemeWithRouterSettlement = class {
1498
+ /**
1499
+ * Creates a new ExactEvmSchemeWithRouterSettlement instance.
1500
+ *
1501
+ * @param signer - The EVM signer for client operations (viem WalletClient or LocalAccount)
1502
+ */
1503
+ constructor(signer) {
1504
+ this.signer = signer;
1505
+ this.scheme = "exact";
1506
+ }
1507
+ /**
1508
+ * Set router-settlement extension data for the next payment payload creation.
1509
+ *
1510
+ * Intended to be called from an `x402Client.onBeforePaymentCreation` hook, which has access
1511
+ * to `paymentRequired.extensions`.
1512
+ */
1513
+ setRouterSettlementExtensionFromPaymentRequired(ext) {
1514
+ if (!ext) {
1515
+ this.routerSettlementFromPaymentRequired = void 0;
1516
+ return;
1408
1517
  }
1409
- throw new Error("Invalid money value");
1518
+ this.routerSettlementFromPaymentRequired = ext;
1519
+ }
1520
+ /**
1521
+ * Creates a payment payload for the Exact scheme with router settlement.
1522
+ *
1523
+ * This method:
1524
+ * 1. Extracts settlement parameters from PaymentRequired.extensions
1525
+ * 2. Calculates a commitment hash binding all parameters
1526
+ * 3. Uses the commitment as the EIP-3009 nonce
1527
+ * 4. Signs with settlementRouter as the 'to' address
1528
+ *
1529
+ * @param x402Version - The x402 protocol version (must be 2)
1530
+ * @param paymentRequirements - The payment requirements from the server
1531
+ * @returns Promise resolving to a payment payload
1532
+ *
1533
+ * @throws Error if x402Version is not 2
1534
+ * @throws Error if x402x-router-settlement extension is missing
1535
+ * @throws Error if required settlement parameters are missing
1536
+ */
1537
+ async createPaymentPayload(x402Version, paymentRequirements) {
1538
+ if (x402Version !== 2) {
1539
+ throw new Error(
1540
+ `ExactEvmSchemeWithRouterSettlement only supports x402 version 2, got: ${x402Version}`
1541
+ );
1542
+ }
1543
+ const routerSettlement = paymentRequirements.extra?.[ROUTER_SETTLEMENT_KEY] ?? this.routerSettlementFromPaymentRequired;
1544
+ if (!routerSettlement?.info) {
1545
+ throw new Error(
1546
+ "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)."
1547
+ );
1548
+ }
1549
+ const { salt, settlementRouter, hook, hookData, finalPayTo, facilitatorFee } = routerSettlement.info;
1550
+ this.routerSettlementFromPaymentRequired = void 0;
1551
+ if (!salt) throw new Error("Missing required parameter: salt");
1552
+ if (!settlementRouter) throw new Error("Missing required parameter: settlementRouter");
1553
+ if (!hook) throw new Error("Missing required parameter: hook");
1554
+ if (hookData === void 0) throw new Error("Missing required parameter: hookData");
1555
+ if (!finalPayTo) throw new Error("Missing required parameter: finalPayTo");
1556
+ const resolvedFacilitatorFee = facilitatorFee ?? "0";
1557
+ const chainId = parseInt(paymentRequirements.network.split(":")[1]);
1558
+ if (isNaN(chainId)) {
1559
+ throw new Error(`Invalid network format: ${paymentRequirements.network}`);
1560
+ }
1561
+ const now = Math.floor(Date.now() / 1e3);
1562
+ const validAfter = (now - 600).toString();
1563
+ const validBefore = (now + paymentRequirements.maxTimeoutSeconds).toString();
1564
+ const commitmentParams = {
1565
+ chainId,
1566
+ hub: settlementRouter,
1567
+ asset: paymentRequirements.asset,
1568
+ from: this.signer.address,
1569
+ value: paymentRequirements.amount,
1570
+ validAfter,
1571
+ validBefore,
1572
+ salt,
1573
+ payTo: finalPayTo,
1574
+ facilitatorFee: resolvedFacilitatorFee,
1575
+ hook,
1576
+ hookData
1577
+ };
1578
+ const nonce = calculateCommitment(commitmentParams);
1579
+ const authorization = {
1580
+ from: this.signer.address,
1581
+ to: getAddress(settlementRouter),
1582
+ value: paymentRequirements.amount,
1583
+ validAfter,
1584
+ validBefore,
1585
+ nonce
1586
+ };
1587
+ const signature = await this.signAuthorization(authorization, paymentRequirements, chainId);
1588
+ const payload = {
1589
+ authorization,
1590
+ signature
1591
+ };
1592
+ return {
1593
+ x402Version,
1594
+ payload
1595
+ };
1410
1596
  }
1411
- };
1412
- var settleResponseHeader = "X-Payment-Response";
1413
- var evm = {
1414
1597
  /**
1415
- * Check if a value is a valid EVM address
1598
+ * Sign the EIP-3009 authorization using EIP-712
1599
+ *
1600
+ * @param authorization - The authorization to sign
1601
+ * @param requirements - The payment requirements
1602
+ * @param chainId - The chain ID
1603
+ * @returns Promise resolving to the signature
1416
1604
  */
1417
- isAddress: (value) => {
1418
- if (typeof value !== "string") return false;
1419
- return /^0x[a-fA-F0-9]{40}$/.test(value);
1605
+ async signAuthorization(authorization, requirements, chainId) {
1606
+ if (!requirements.extra?.name || !requirements.extra?.version) {
1607
+ throw new Error(
1608
+ `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
1609
+ );
1610
+ }
1611
+ const { name, version } = requirements.extra;
1612
+ const domain = {
1613
+ name,
1614
+ version,
1615
+ chainId,
1616
+ verifyingContract: getAddress(requirements.asset)
1617
+ };
1618
+ const message = {
1619
+ from: getAddress(authorization.from),
1620
+ to: getAddress(authorization.to),
1621
+ value: BigInt(authorization.value),
1622
+ validAfter: BigInt(authorization.validAfter),
1623
+ validBefore: BigInt(authorization.validBefore),
1624
+ nonce: authorization.nonce
1625
+ };
1626
+ return await this.signer.signTypedData({
1627
+ domain,
1628
+ types: authorizationTypes,
1629
+ primaryType: "TransferWithAuthorization",
1630
+ message
1631
+ });
1420
1632
  }
1421
1633
  };
1422
- var exact = {
1423
- name: "exact"
1424
- // Additional scheme properties would go here
1425
- };
1426
- var ChainIdToNetwork = {
1427
- 84532: "eip155:84532",
1428
- // Base Sepolia
1429
- 1444673419: "eip155:1444673419",
1430
- // SKALE Base Sepolia
1431
- 8453: "eip155:8453"
1432
- // Base Mainnet
1433
- };
1434
- function isMultiNetworkSigner(signer) {
1435
- return !!(signer && typeof signer === "object" && "signTransaction" in signer);
1436
- }
1437
- function isSvmSignerWallet(signer) {
1438
- return !!(signer && typeof signer === "object" && "publicKey" in signer);
1439
- }
1440
- function createPaymentHeader(_requirements, _signer) {
1441
- throw new Error("createPaymentHeader is not implemented in v2 - use x402Client instead");
1442
- }
1443
- function selectPaymentRequirements(_requirements, _selector) {
1444
- throw new Error("selectPaymentRequirements is not implemented in v2 - use x402Client instead");
1445
- }
1446
- function decodeXPaymentResponse(_header) {
1447
- throw new Error("decodeXPaymentResponse is not implemented in v2 - use x402HTTPClient instead");
1448
- }
1449
- function useFacilitator(_config) {
1450
- throw new Error("useFacilitator is not implemented in v2 - use FacilitatorClient instead");
1634
+
1635
+ // src/client/extension-handler.ts
1636
+ function injectX402xExtensionHandler(client, onRouterSettlementExtension) {
1637
+ return client.onBeforePaymentCreation(async (context) => {
1638
+ const { paymentRequired, selectedRequirements } = context;
1639
+ console.log("[x402x-handler] onBeforePaymentCreation called");
1640
+ console.log("[x402x-handler] selectedRequirements.network:", selectedRequirements.network);
1641
+ console.log("[x402x-handler] selectedRequirements.extra keys:", Object.keys(selectedRequirements.extra || {}));
1642
+ const perOptionExtension = selectedRequirements.extra?.[ROUTER_SETTLEMENT_KEY];
1643
+ if (perOptionExtension) {
1644
+ if (!paymentRequired.extensions) {
1645
+ paymentRequired.extensions = {};
1646
+ }
1647
+ paymentRequired.extensions[ROUTER_SETTLEMENT_KEY] = perOptionExtension;
1648
+ console.log("[x402x-handler] \u2705 Copied per-option x402x info into PaymentRequired.extensions");
1649
+ console.log("[x402x-handler] Extension info:", JSON.stringify(perOptionExtension, null, 2));
1650
+ } else {
1651
+ console.warn("[x402x-handler] \u26A0\uFE0F No per-option x402x info found in selectedRequirements.extra");
1652
+ console.warn("[x402x-handler] This may cause facilitator errors. Check server-side createSettlementRouteConfig.");
1653
+ }
1654
+ if (onRouterSettlementExtension) {
1655
+ const extensionToUse = perOptionExtension || paymentRequired.extensions?.[ROUTER_SETTLEMENT_KEY];
1656
+ onRouterSettlementExtension(extensionToUse);
1657
+ }
1658
+ });
1451
1659
  }
1452
- function createSigner(_config) {
1453
- throw new Error("createSigner is not implemented in v2 - use appropriate v2 signer patterns");
1660
+ function registerX402xScheme(client, network, signer) {
1661
+ const scheme = new ExactEvmSchemeWithRouterSettlement(signer);
1662
+ injectX402xExtensionHandler(client, (ext) => {
1663
+ scheme.setRouterSettlementExtensionFromPaymentRequired(ext);
1664
+ });
1665
+ client.register(network, scheme);
1666
+ return client;
1454
1667
  }
1455
1668
 
1456
- export { AmountError, ChainIdToNetwork, FacilitatorValidationError, NETWORK_ALIASES_V1_TO_V2, NFTMintHook, ROUTER_SETTLEMENT_KEY, RewardHook, SETTLEMENT_ROUTER_ABI, SettlementExtraError, SettlementRouterError, SupportedEVMNetworks, TransferHook, addSettlementExtra, assertValidSettlementExtra, calculateCommitment, calculateFacilitatorFee, clearFeeCache, computeRoutePatterns, createExtensionDeclaration, createPaymentHeader, createRouterSettlementExtension, createSettlementRouteConfig, createSigner, createX402xFacilitator, decodeXPaymentResponse, evm, exact, findMatchingPaymentRequirements, findMatchingRoute, formatDefaultAssetAmount, generateSalt, getChain, getChainById, getCustomChains, getDefaultAsset, getNetworkAliasesV1ToV2, getNetworkConfig, getNetworkId, getNetworkName, getRouterSettlementExtensionKey, getSupportedNetworkIds, getSupportedNetworkNames, getSupportedNetworks, getSupportedNetworksV2, isCustomChain, isMultiNetworkSigner, isNetworkSupported, isRouterSettlement, isSettlementMode, isSvmSignerWallet, isValid32ByteHex, isValidAddress2 as isValidAddress, isValidHex2 as isValidHex, isValidNumericString, moneySchema, networks, parseDefaultAssetAmount, parseSettlementExtra, processPriceToAtomicAmount, registerRouterSettlement2 as registerRouterSettlement, registerSettlementHooks, routerSettlementServerExtension, selectPaymentRequirements, settle, settleResponseHeader, toCanonicalNetworkKey, toJsonSafe, useFacilitator, validateCommitmentParams, validateSettlementExtra, verify, withRouterSettlement };
1669
+ export { AmountError, ExactEvmSchemeWithRouterSettlement, FacilitatorValidationError, NETWORK_ALIASES, NETWORK_ALIASES_V1_TO_V2, NFTMintHook, ROUTER_SETTLEMENT_KEY, RewardHook, SETTLEMENT_ROUTER_ABI, SettlementExtraError, SettlementRouterError, TransferHook, addSettlementExtra, assertValidSettlementExtra, calculateCommitment, calculateFacilitatorFee, clearFeeCache, computeRoutePatterns, createExtensionDeclaration, createRouterSettlementExtension, createSettlementRouteConfig, createX402xFacilitator, findMatchingPaymentRequirements, findMatchingRoute, formatDefaultAssetAmount, generateSalt, getChain, getChainById, getCustomChains, getDefaultAsset, getNetworkAlias, getNetworkAliasesV1ToV2, getNetworkConfig, getRouterSettlementExtensionKey, getSupportedNetworkAliases, getSupportedNetworkIds, getSupportedNetworks, injectX402xExtensionHandler, isCustomChain, isNetworkSupported, isRouterSettlement, isSettlementMode, isValid32ByteHex, isValidAddress2 as isValidAddress, isValidHex2 as isValidHex, isValidNumericString, networks, parseDefaultAssetAmount, parseSettlementExtra, processPriceToAtomicAmount, registerRouterSettlement2 as registerRouterSettlement, registerSettlementHooks, registerX402xScheme, routerSettlementServerExtension, settle, toCanonicalNetworkKey, toJsonSafe, validateCommitmentParams, validateSettlementExtra, verify, withRouterSettlement };
1457
1670
  //# sourceMappingURL=index.mjs.map
1458
1671
  //# sourceMappingURL=index.mjs.map