@swapkit/wallet-hardware 4.9.5 → 4.9.7

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.
@@ -1,3 +1,4 @@
1
+ import { HDKey } from "@scure/bip32";
1
2
  import {
2
3
  Chain,
3
4
  type DerivationPathArray,
@@ -13,6 +14,7 @@ import {
13
14
  import {
14
15
  assertDerivationIndex,
15
16
  createHDWalletHelpers,
17
+ deriveAddressesFromXpub,
16
18
  getNetworkForChain,
17
19
  getUTXOAccountIndexFromPath,
18
20
  getUTXOAccountPath,
@@ -24,6 +26,62 @@ import type { BTCNetwork, PCZT, Transaction, ZcashTransaction } from "@swapkit/u
24
26
  import { NETWORKS, ZcashConsensusBranchId, ZcashVersionGroupId } from "@swapkit/utxo-signer";
25
27
  import { createWallet, getWalletSupportedChains } from "@swapkit/wallet-core";
26
28
 
29
+ type TrezorBip32Derivation = [Uint8Array, { fingerprint: number; path: number[] }];
30
+ type TrezorCoreMode = "auto" | "iframe" | "popup" | "suite-desktop" | "suite-web";
31
+ type TrezorTransport = "BridgeTransport" | "WebUsbTransport" | "NodeUsbTransport";
32
+ type TrezorExtendedPublicKeyInfo = {
33
+ accountIndex: number;
34
+ chainCode?: string;
35
+ depth?: number;
36
+ fingerprint?: number;
37
+ path: string;
38
+ publicKey?: string;
39
+ xpub: string;
40
+ xpubSegwit?: string;
41
+ };
42
+
43
+ const TREZOR_CORE_MODES = new Set<TrezorCoreMode>(["auto", "iframe", "popup", "suite-desktop", "suite-web"]);
44
+ const TREZOR_TRANSPORTS = new Set<TrezorTransport>(["BridgeTransport", "WebUsbTransport", "NodeUsbTransport"]);
45
+ const trezorXpubCache = new Map<string, TrezorExtendedPublicKeyInfo>();
46
+ let trezorSessionDispose: Promise<void> | undefined;
47
+
48
+ async function disconnectTrezorSession() {
49
+ trezorXpubCache.clear();
50
+
51
+ const dispose = (async () => {
52
+ try {
53
+ const TrezorConnect = (await import("@trezor/connect-web")).default;
54
+ await TrezorConnect.dispose();
55
+ } catch {
56
+ // Ignore stale or already-disposed sessions.
57
+ }
58
+ })();
59
+
60
+ trezorSessionDispose = dispose;
61
+ await dispose;
62
+
63
+ if (trezorSessionDispose === dispose) {
64
+ trezorSessionDispose = undefined;
65
+ }
66
+ }
67
+
68
+ function normalizeTrezorCoreMode(coreMode: unknown): TrezorCoreMode | undefined {
69
+ return typeof coreMode === "string" && TREZOR_CORE_MODES.has(coreMode as TrezorCoreMode)
70
+ ? (coreMode as TrezorCoreMode)
71
+ : undefined;
72
+ }
73
+
74
+ function normalizeTrezorTransports(transports: unknown): TrezorTransport[] | undefined {
75
+ if (!Array.isArray(transports)) return undefined;
76
+
77
+ const normalized = transports.filter(
78
+ (transport): transport is TrezorTransport =>
79
+ typeof transport === "string" && TREZOR_TRANSPORTS.has(transport as TrezorTransport),
80
+ );
81
+
82
+ return normalized.length > 0 ? normalized : undefined;
83
+ }
84
+
27
85
  function decodeOpReturnData(script: Uint8Array): string | null {
28
86
  if (script.length < 2 || script[0] !== 0x6a) return null;
29
87
  const dataLen = script[1];
@@ -50,6 +108,48 @@ function hardenDerivationPath(derivationPath: DerivationPathArray): number[] {
50
108
  );
51
109
  }
52
110
 
111
+ function isTrezorBip32Derivation(value: unknown): value is TrezorBip32Derivation {
112
+ return (
113
+ Array.isArray(value) &&
114
+ value[0] instanceof Uint8Array &&
115
+ typeof value[1] === "object" &&
116
+ value[1] !== null &&
117
+ typeof (value[1] as { fingerprint?: unknown }).fingerprint === "number" &&
118
+ Array.isArray((value[1] as { path?: unknown }).path)
119
+ );
120
+ }
121
+
122
+ function getFirstBip32Derivation(input: { bip32Derivation?: unknown }): TrezorBip32Derivation | undefined {
123
+ if (!Array.isArray(input.bip32Derivation)) return undefined;
124
+ const [firstDerivation] = input.bip32Derivation;
125
+
126
+ return isTrezorBip32Derivation(firstDerivation) ? firstDerivation : undefined;
127
+ }
128
+
129
+ function getPrevoutAmount(input: {
130
+ index?: number;
131
+ nonWitnessUtxo?: { outputs?: Array<{ amount?: bigint | number }> };
132
+ witnessUtxo?: { amount?: bigint | number };
133
+ }) {
134
+ if (input.witnessUtxo?.amount !== undefined) return input.witnessUtxo.amount.toString();
135
+
136
+ const prevout = input.index !== undefined ? input.nonWitnessUtxo?.outputs?.[input.index] : undefined;
137
+ if (prevout?.amount !== undefined) return prevout.amount.toString();
138
+
139
+ return undefined;
140
+ }
141
+
142
+ function normalizeTrezorSignature(signatureHex: string) {
143
+ const signature = Buffer.from(signatureHex, "hex");
144
+ const derLength = signature[1] !== undefined ? signature[1] + 2 : undefined;
145
+
146
+ if (derLength !== undefined && signature.length === derLength) {
147
+ return new Uint8Array([...signature, 0x01]);
148
+ }
149
+
150
+ return new Uint8Array(signature);
151
+ }
152
+
53
153
  function buildPCZTInputsForTrezor(
54
154
  pczt: PCZT,
55
155
  address_n: number[],
@@ -206,8 +306,27 @@ function buildUtxoOutputsForTrezor(
206
306
  const outputAddress = tx.getOutputAddress(i, network);
207
307
 
208
308
  if (!outputAddress) {
209
- outputs.push({ amount: "0", op_return_data: Buffer.from(memo).toString("hex"), script_type: "PAYTOOPRETURN" });
210
- continue;
309
+ const opReturnData = output.script ? decodeOpReturnData(output.script) : null;
310
+ if (opReturnData !== null || memo) {
311
+ outputs.push({
312
+ amount: "0",
313
+ op_return_data: opReturnData ?? Buffer.from(memo).toString("hex"),
314
+ script_type: "PAYTOOPRETURN",
315
+ });
316
+ continue;
317
+ }
318
+
319
+ throw new SwapKitError({
320
+ errorKey: "wallet_trezor_failed_to_sign_transaction",
321
+ info: { chain, error: "Unable to decode output address from scriptPubkey" },
322
+ });
323
+ }
324
+
325
+ if (output.amount === undefined) {
326
+ throw new SwapKitError({
327
+ errorKey: "wallet_trezor_failed_to_sign_transaction",
328
+ info: { chain, error: "Output amount is missing" },
329
+ });
211
330
  }
212
331
 
213
332
  const isBch = chain === Chain.BitcoinCash;
@@ -218,8 +337,8 @@ function buildUtxoOutputsForTrezor(
218
337
 
219
338
  outputs.push(
220
339
  isChangeAddress
221
- ? { address_n, amount: Number(output.amount), script_type: scriptType.output }
222
- : { address: cashAddrWithPrefix, amount: Number(output.amount), script_type: "PAYTOADDRESS" },
340
+ ? { address_n, amount: output.amount.toString(), script_type: scriptType.output }
341
+ : { address: cashAddrWithPrefix, amount: output.amount.toString(), script_type: "PAYTOADDRESS" },
223
342
  );
224
343
  }
225
344
  return outputs;
@@ -434,7 +553,7 @@ async function getTrezorWallet<T extends Chain>({
434
553
  case Chain.Dash:
435
554
  case Chain.Dogecoin:
436
555
  case Chain.Litecoin: {
437
- const { toCashAddress, getUtxoToolbox } = await import("@swapkit/toolboxes/utxo");
556
+ const { toCashAddress, getUtxoToolbox, stripPrefix } = await import("@swapkit/toolboxes/utxo");
438
557
  const utxoChain = chain as UTXOChain;
439
558
  const scriptType = getScriptType(derivationPath);
440
559
 
@@ -446,7 +565,11 @@ async function getTrezorWallet<T extends Chain>({
446
565
 
447
566
  const getAddress = async (path: DerivationPathArray = derivationPath) => {
448
567
  const TrezorConnect = (await import("@trezor/connect-web")).default;
449
- const { success, payload } = await TrezorConnect.getAddress({ coin, path: derivationPathToString(path) });
568
+ const { success, payload } = await TrezorConnect.getAddress({
569
+ coin,
570
+ path: derivationPathToString(path),
571
+ showOnTrezor: false,
572
+ });
450
573
 
451
574
  if (!success) {
452
575
  throw new SwapKitError({
@@ -456,19 +579,57 @@ async function getTrezorWallet<T extends Chain>({
456
579
  }
457
580
 
458
581
  if (chain === Chain.BitcoinCash) {
459
- const toolbox = await getUtxoToolbox(chain as typeof Chain.BitcoinCash);
460
- return toolbox.stripPrefix(payload.address);
582
+ return stripPrefix(payload.address);
461
583
  }
462
584
 
463
585
  return payload.address;
464
586
  };
465
587
 
466
- const address = await getAddress();
588
+ async function getAddressFromExtendedPublicKey() {
589
+ const accountInfo = await getExtendedPublicKeyInfo();
590
+ const addressIndex = Number(derivationPath[4] ?? 0);
591
+ const change = Boolean(derivationPath[3] ?? 0);
592
+
593
+ try {
594
+ // deriveAddressesFromXpub returns both external and change branches for each index.
595
+ const derivedAddress = deriveAddressesFromXpub({
596
+ accountIndex: accountInfo.accountIndex,
597
+ chain: utxoChain,
598
+ count: 1,
599
+ startIndex: addressIndex,
600
+ xpub: accountInfo.xpub,
601
+ }).find((derived) => derived.change === change && derived.index === addressIndex);
602
+
603
+ if (!derivedAddress) {
604
+ throw new SwapKitError({
605
+ errorKey: "wallet_trezor_failed_to_get_address",
606
+ info: { chain, error: "Unable to derive address from Trezor account public key" },
607
+ });
608
+ }
609
+
610
+ return derivedAddress.address;
611
+ } catch (error) {
612
+ if (error instanceof SwapKitError) throw error;
613
+
614
+ throw new SwapKitError({
615
+ errorKey: "wallet_trezor_failed_to_get_address",
616
+ info: {
617
+ chain,
618
+ error: error instanceof Error ? error.message : "Unable to derive address from Trezor xpub",
619
+ },
620
+ });
621
+ }
622
+ }
623
+
624
+ const address =
625
+ chain === Chain.Bitcoin || chain === Chain.Litecoin
626
+ ? await getAddressFromExtendedPublicKey()
627
+ : await getAddress();
628
+ const baseToolbox = getUtxoToolbox(chain);
467
629
 
468
630
  const signTransaction = async (tx: Transaction, inputs: UTXOType[], memo = "") => {
469
631
  const TrezorConnect = (await import("@trezor/connect-web")).default;
470
632
  const address_n = hardenDerivationPath(derivationPath);
471
- const toolbox = getUtxoToolbox(chain as typeof Chain.BitcoinCash);
472
633
  const network = getNetworkForChain(chain as UTXOChain);
473
634
 
474
635
  const outputs = buildUtxoOutputsForTrezor(
@@ -480,7 +641,7 @@ async function getTrezorWallet<T extends Chain>({
480
641
  chain,
481
642
  scriptType,
482
643
  toCashAddress,
483
- toolbox.stripPrefix,
644
+ stripPrefix,
484
645
  );
485
646
 
486
647
  const trezorInputs = inputs.map(({ hash, index, value }) => ({
@@ -504,13 +665,108 @@ async function getTrezorWallet<T extends Chain>({
504
665
  });
505
666
  };
506
667
 
668
+ const signPsbtTransaction = async (tx: Transaction): Promise<Transaction> => {
669
+ const TrezorConnect = (await import("@trezor/connect-web")).default;
670
+ const { hex: hexEncode } = await import("@scure/base");
671
+ const address_n = hardenDerivationPath(derivationPath);
672
+ const network = getNetworkForChain(chain as UTXOChain);
673
+ let fallbackPublicKey: Uint8Array | undefined;
674
+
675
+ async function getFallbackDerivation(): Promise<TrezorBip32Derivation> {
676
+ if (!fallbackPublicKey) {
677
+ const accountInfo = await getExtendedPublicKeyInfo();
678
+ const accountKey = HDKey.fromExtendedKey(accountInfo.xpub);
679
+ const leaf = accountKey.derive(`m/${Number(derivationPath[3] ?? 0)}/${Number(derivationPath[4] ?? 0)}`);
680
+
681
+ if (!leaf.publicKey) {
682
+ throw new SwapKitError({
683
+ errorKey: "wallet_trezor_failed_to_get_public_key",
684
+ info: { chain, error: "Unable to derive Trezor leaf public key from account xpub" },
685
+ });
686
+ }
687
+
688
+ fallbackPublicKey = leaf.publicKey;
689
+ }
690
+
691
+ return [fallbackPublicKey, { fingerprint: 0, path: address_n }];
692
+ }
693
+
694
+ const signerPubkeys: Uint8Array[] = [];
695
+ const trezorInputs = [];
696
+
697
+ for (let inputIndex = 0; inputIndex < tx.inputsLength; inputIndex++) {
698
+ const input = tx.getInput(inputIndex);
699
+ const existingDerivation = getFirstBip32Derivation(input);
700
+ const derivation = existingDerivation ?? (await getFallbackDerivation());
701
+ const amount = getPrevoutAmount(input);
702
+
703
+ if (!input.txid || input.index === undefined || !amount) {
704
+ throw new SwapKitError({
705
+ errorKey: "wallet_trezor_failed_to_sign_transaction",
706
+ info: { chain, error: `Input ${inputIndex} is missing prevout data required by Trezor` },
707
+ });
708
+ }
709
+
710
+ signerPubkeys[inputIndex] = derivation[0];
711
+
712
+ if (!existingDerivation) {
713
+ tx.updateInput(inputIndex, { bip32Derivation: [derivation] });
714
+ }
715
+
716
+ trezorInputs.push({
717
+ address_n: derivation[1].path,
718
+ amount,
719
+ prev_hash: hexEncode.encode(input.txid),
720
+ prev_index: input.index,
721
+ script_type: scriptType.input,
722
+ ...(input.sequence !== undefined ? { sequence: input.sequence } : {}),
723
+ });
724
+ }
725
+
726
+ const outputs = buildUtxoOutputsForTrezor(
727
+ tx,
728
+ network,
729
+ address_n,
730
+ address,
731
+ "",
732
+ chain,
733
+ scriptType,
734
+ toCashAddress,
735
+ stripPrefix,
736
+ );
737
+
738
+ const result = await TrezorConnect.signTransaction({
739
+ coin,
740
+ inputs: trezorInputs,
741
+ locktime: tx.lockTime,
742
+ outputs,
743
+ version: tx.version,
744
+ });
745
+
746
+ if (!result.success) {
747
+ const payload = result.payload as { error?: string; code?: string };
748
+ throw new SwapKitError({
749
+ errorKey: "wallet_trezor_failed_to_sign_transaction",
750
+ info: { chain, code: payload?.code ?? "unknown", error: payload?.error ?? "unknown", payload },
751
+ });
752
+ }
753
+
754
+ result.payload.signatures.forEach((signatureHex, inputIndex) => {
755
+ const pubkey = signerPubkeys[inputIndex];
756
+ if (!(signatureHex && pubkey)) return;
757
+
758
+ tx.updateInput(inputIndex, { partialSig: [[pubkey, normalizeTrezorSignature(signatureHex)]] });
759
+ });
760
+
761
+ return tx;
762
+ };
763
+
507
764
  const signTransactionWithMultipleInputs = async (
508
765
  tx: Transaction,
509
766
  inputs: Array<{ hash: string; index: number; value: number; derivationIndex: number; isChange: boolean }>,
510
767
  memo = "",
511
768
  ) => {
512
769
  const TrezorConnect = (await import("@trezor/connect-web")).default;
513
- const toolbox = await getUtxoToolbox(chain as typeof Chain.BitcoinCash);
514
770
  const network = getNetworkForChain(chain as UTXOChain);
515
771
  const baseAddressN = hardenDerivationPath(derivationPath.slice(0, 3) as DerivationPathArray);
516
772
 
@@ -523,7 +779,7 @@ async function getTrezorWallet<T extends Chain>({
523
779
  chain,
524
780
  scriptType,
525
781
  toCashAddress,
526
- toolbox.stripPrefix,
782
+ stripPrefix,
527
783
  );
528
784
 
529
785
  const trezorInputs = inputs.map(({ hash, index: inputIndex, value, derivationIndex, isChange }) => {
@@ -629,12 +885,21 @@ async function getTrezorWallet<T extends Chain>({
629
885
  return txHash;
630
886
  };
631
887
 
632
- const toolbox = await getUtxoToolbox(chain);
888
+ const toolbox =
889
+ chain === Chain.Bitcoin || chain === Chain.Litecoin
890
+ ? await getUtxoToolbox(utxoChain, {
891
+ signer: { getAddress: async () => address, signTransaction: signPsbtTransaction },
892
+ })
893
+ : baseToolbox;
633
894
 
634
895
  async function getExtendedPublicKeyInfo({ accountIndex }: { accountIndex?: number } = {}) {
635
896
  const TrezorConnect = (await import("@trezor/connect-web")).default;
636
897
  const resolvedAccountPath = getUTXOAccountPath({ accountIndex, chain: utxoChain, derivationPath });
637
898
  const path = derivationPathToString(resolvedAccountPath);
899
+ const cacheKey = `${chain}:${path}`;
900
+ const cached = trezorXpubCache.get(cacheKey);
901
+ if (cached) return cached;
902
+
638
903
  const { success, payload } = await TrezorConnect.getPublicKey({ coin, path });
639
904
 
640
905
  if (!success) {
@@ -644,7 +909,7 @@ async function getTrezorWallet<T extends Chain>({
644
909
  });
645
910
  }
646
911
 
647
- return {
912
+ const info = {
648
913
  accountIndex: getUTXOAccountIndexFromPath(resolvedAccountPath),
649
914
  chainCode: payload.chainCode,
650
915
  depth: payload.depth,
@@ -654,10 +919,13 @@ async function getTrezorWallet<T extends Chain>({
654
919
  xpub: payload.xpub,
655
920
  xpubSegwit: payload.xpubSegwit,
656
921
  };
922
+
923
+ trezorXpubCache.set(cacheKey, info);
924
+ return info;
657
925
  }
658
926
 
659
- function getExtendedPublicKey() {
660
- return getExtendedPublicKeyInfo();
927
+ function getExtendedPublicKey(params: { accountIndex?: number } = {}) {
928
+ return getExtendedPublicKeyInfo(params);
661
929
  }
662
930
 
663
931
  async function deriveAddressAtIndex({
@@ -791,19 +1059,55 @@ export const trezorWallet = createWallet({
791
1059
  }
792
1060
 
793
1061
  const TrezorConnect = (await import("@trezor/connect-web")).default;
794
- const { success } = await TrezorConnect.getDeviceState();
795
-
796
- if (!success) {
797
- const trezorConfig = SKConfig.get("integrations").trezor;
798
- const manifest = trezorConfig
799
- ? { ...trezorConfig, appName: (trezorConfig as any).appName || "SwapKit" }
800
- : { appName: "SwapKit", appUrl: "", email: "" };
801
- TrezorConnect.init({ lazyLoad: true, manifest });
1062
+
1063
+ const trezorConfig = SKConfig.get("integrations").trezor as Record<string, unknown> | undefined;
1064
+ const {
1065
+ connectSrc,
1066
+ coreMode,
1067
+ debug,
1068
+ interactionTimeout,
1069
+ lazyLoad,
1070
+ pendingTransportEvent,
1071
+ popup,
1072
+ transportReconnect,
1073
+ transports,
1074
+ ...manifestConfig
1075
+ } = trezorConfig ?? {};
1076
+ const manifest = {
1077
+ ...manifestConfig,
1078
+ appName: String(trezorConfig?.appName || "SwapKit"),
1079
+ appUrl: String(trezorConfig?.appUrl || ""),
1080
+ email: String(trezorConfig?.email || ""),
1081
+ };
1082
+ const isLocalhost =
1083
+ typeof globalThis.location !== "undefined" && ["localhost", "127.0.0.1"].includes(globalThis.location.hostname);
1084
+ const resolvedCoreMode = isLocalhost ? "popup" : normalizeTrezorCoreMode(coreMode);
1085
+ const resolvedTransports = isLocalhost ? ["WebUsbTransport" as const] : normalizeTrezorTransports(transports);
1086
+
1087
+ if (trezorSessionDispose) {
1088
+ await trezorSessionDispose;
802
1089
  }
803
1090
 
1091
+ if (isLocalhost) {
1092
+ await TrezorConnect.dispose();
1093
+ }
1094
+
1095
+ await TrezorConnect.init({
1096
+ connectSrc: connectSrc as string | undefined,
1097
+ coreMode: resolvedCoreMode,
1098
+ debug: debug as boolean | undefined,
1099
+ interactionTimeout: interactionTimeout as number | undefined,
1100
+ lazyLoad: isLocalhost ? false : ((lazyLoad as boolean | undefined) ?? true),
1101
+ manifest,
1102
+ pendingTransportEvent: pendingTransportEvent as boolean | undefined,
1103
+ popup: isLocalhost ? true : (popup as boolean | undefined),
1104
+ transportReconnect: transportReconnect as boolean | undefined,
1105
+ transports: resolvedTransports,
1106
+ });
1107
+
804
1108
  const wallet = await getTrezorWallet({ chain, derivationPath });
805
1109
 
806
- addChain({ ...wallet, chain, walletType });
1110
+ addChain({ ...wallet, chain, disconnect: disconnectTrezorSession, walletType });
807
1111
 
808
1112
  return true;
809
1113
  },
@@ -814,13 +1118,15 @@ export const trezorWallet = createWallet({
814
1118
  [Chain.Base]: true,
815
1119
  [Chain.Berachain]: true,
816
1120
  [Chain.BinanceSmartChain]: true,
1121
+ [Chain.Bitcoin]: true,
817
1122
  [Chain.Ethereum]: true,
818
1123
  [Chain.Gnosis]: true,
1124
+ [Chain.Litecoin]: true,
819
1125
  [Chain.Monad]: true,
820
1126
  [Chain.Optimism]: true,
821
1127
  [Chain.Polygon]: true,
822
1128
  [Chain.XLayer]: true,
823
- // BTC/BCH/DASH/DOGE/LTC/ZEC: pending PSBT→TrezorConnect converter (V3 plan PR)
1129
+ // BCH/DASH/DOGE/ZEC: pending PSBT→TrezorConnect converter (V3 plan PR)
824
1130
  },
825
1131
  name: "connectTrezor",
826
1132
  supportedChains: [
@@ -1,4 +0,0 @@
1
- import{c as w}from"./chunk-3yr76n9s.js";import{d as E}from"./chunk-n05bv2n5.js";import{base64 as x}from"@scure/base";import{HDKey as f}from"@scure/bip32";import{derivationPathToString as m,getWalletFormatFor as y,SwapKitError as K}from"@swapkit/helpers";function b(z){switch(z){case"bech32":return"wpkh(@0/**)";case"p2sh":return"sh(wpkh(@0/**))";case"legacy":return"pkh(@0/**)";default:return"wpkh(@0/**)"}}function P(z){return typeof z==="string"?z:m(z)}function g(z){return z.replace(/^m\//,"").split("/").filter(Boolean).map((M)=>{let Y=M.endsWith("'"),Q=Number.parseInt(Y?M.slice(0,-1):M,10);return Y?(Q|2147483648)>>>0:Q})}var B=({chain:z})=>{return(M,Y)=>{let Q,$;async function Z(){if(!Q){let q=Y??await w(),{AppClient:G}=await import("ledger-bitcoin");Q=new G(q)}return Q}async function X(){if(!$)$=await(await Z()).getMasterFingerprint();return $}let R=M?P(M):"84'/0'/0'/0/0",H=R.split("/").slice(0,3).join("/"),N=R.split("/").slice(3),O=Number(N[0]??0),U=Number(N[1]??0),k=y(R),S=b(k),_,j;async function D(){let q=await Z(),G=await X();if(!_)_=await q.getExtendedPubkey(`m/${H}`);let{DefaultWalletPolicy:J}=await import("ledger-bitcoin"),I=new J(S,`[${G}/${H}]${_}`);return{app:q,fpr:G,policy:I,xpub:_}}async function C(){if(!j){let{xpub:q}=await D(),J=f.fromExtendedKey(q).derive(`m/${O}/${U}`);if(!J.publicKey)throw new K("wallet_ledger_get_address_error",{message:`Cannot derive leaf pubkey for ${z}`});j=J.publicKey}return j}return{connect:async()=>{await Z()},getAddress:async()=>{let{app:q,policy:G}=await D(),J=await q.getWalletAddress(G,null,O,U,!1);if(!J)throw new K("wallet_ledger_get_address_error",{message:`Cannot get ${z} address from ledger derivation path: ${R}`});return J},getExtendedPublicKey:async(q=`m/${H}`)=>{return(await Z()).getExtendedPubkey(q)},signTransaction:async(q)=>{let{app:G,policy:J,fpr:I}=await D(),F=Number.parseInt(I,16)>>>0,L=g(R),T=await C();for(let V=0;V<q.inputsLength;V++)q.updateInput(V,{bip32Derivation:[[T,{fingerprint:F,path:L}]]});let v=x.encode(q.toPSBT(0)),A=await G.signPsbt(v,J,null);for(let[V,W]of A)q.updateInput(V,{partialSig:[[new Uint8Array(W.pubkey),new Uint8Array(W.signature)]]});return q.finalize(),q}}}},o=B({chain:"bitcoin"}),d=B({chain:"litecoin"});export{d as LitecoinPsbtLedger,o as BitcoinPsbtLedger};
2
-
3
- //# debugId=AE9B8E2F206F534564756E2164756E21
4
- //# sourceMappingURL=chunk-9jd3dhjv.js.map
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/ledger/clients/utxo-psbt.ts"],
4
- "sourcesContent": [
5
- "import type Transport from \"@ledgerhq/hw-transport\";\nimport { base64 } from \"@scure/base\";\nimport { HDKey } from \"@scure/bip32\";\nimport { type DerivationPathArray, derivationPathToString, getWalletFormatFor, SwapKitError } from \"@swapkit/helpers\";\nimport type { Transaction } from \"@swapkit/utxo-signer\";\n\nimport { getLedgerTransport } from \"../helpers/getLedgerTransport\";\n\ntype SupportedCoin = \"bitcoin\" | \"litecoin\";\n\ntype DefaultDescriptorTemplate = \"wpkh(@0/**)\" | \"tr(@0/**)\" | \"sh(wpkh(@0/**))\" | \"pkh(@0/**)\";\n\nfunction templateForFormat(format: ReturnType<typeof getWalletFormatFor>): DefaultDescriptorTemplate {\n switch (format) {\n case \"bech32\":\n return \"wpkh(@0/**)\";\n case \"p2sh\":\n return \"sh(wpkh(@0/**))\";\n case \"legacy\":\n return \"pkh(@0/**)\";\n default:\n return \"wpkh(@0/**)\";\n }\n}\n\nfunction pathToString(path: DerivationPathArray | string): string {\n return typeof path === \"string\" ? path : derivationPathToString(path);\n}\n\nfunction pathToNumberArray(path: string): number[] {\n return path\n .replace(/^m\\//, \"\")\n .split(\"/\")\n .filter(Boolean)\n .map((p) => {\n const hardened = p.endsWith(\"'\");\n const num = Number.parseInt(hardened ? p.slice(0, -1) : p, 10);\n return hardened ? (num | 0x80000000) >>> 0 : num;\n });\n}\n\nconst BaseLedgerPsbtUTXO = ({ chain }: { chain: SupportedCoin }) => {\n return (derivationPathArray?: DerivationPathArray | string, injectedTransport?: Transport) => {\n // Per-call state — each BitcoinPsbtLedger/LitecoinPsbtLedger invocation has its own\n // AppClient and master fingerprint so different consumers (e.g. concurrent MCP\n // sessions on different devices) cannot inherit each other's ledger bindings or xpub.\n let appClient: import(\"ledger-bitcoin\").AppClient | undefined;\n let masterFingerprint: string | undefined;\n\n async function getAppClient() {\n if (!appClient) {\n const transport = injectedTransport ?? (await getLedgerTransport());\n const { AppClient } = await import(\"ledger-bitcoin\");\n appClient = new AppClient(transport);\n }\n return appClient;\n }\n\n async function getFingerprint() {\n if (!masterFingerprint) {\n const app = await getAppClient();\n masterFingerprint = await app.getMasterFingerprint();\n }\n return masterFingerprint;\n }\n\n // Single-address account: change == index == 0 by default.\n const derivationPath = derivationPathArray ? pathToString(derivationPathArray) : \"84'/0'/0'/0/0\";\n const accountPath = derivationPath.split(\"/\").slice(0, 3).join(\"/\");\n const leafSegments = derivationPath.split(\"/\").slice(3);\n const change = Number(leafSegments[0] ?? 0);\n const addressIndex = Number(leafSegments[1] ?? 0);\n const format = getWalletFormatFor(derivationPath);\n const template = templateForFormat(format);\n\n let cachedAccountXpub: string | undefined;\n let cachedLeafPubkey: Uint8Array | undefined;\n\n async function buildPolicy() {\n const app = await getAppClient();\n const fpr = await getFingerprint();\n if (!cachedAccountXpub) {\n cachedAccountXpub = await app.getExtendedPubkey(`m/${accountPath}`);\n }\n const { DefaultWalletPolicy } = await import(\"ledger-bitcoin\");\n const policy = new DefaultWalletPolicy(template, `[${fpr}/${accountPath}]${cachedAccountXpub}`);\n return { app, fpr, policy, xpub: cachedAccountXpub };\n }\n\n async function getLeafPubkey() {\n if (!cachedLeafPubkey) {\n const { xpub } = await buildPolicy();\n const accountKey = HDKey.fromExtendedKey(xpub);\n const leaf = accountKey.derive(`m/${change}/${addressIndex}`);\n if (!leaf.publicKey) {\n throw new SwapKitError(\"wallet_ledger_get_address_error\", {\n message: `Cannot derive leaf pubkey for ${chain}`,\n });\n }\n cachedLeafPubkey = leaf.publicKey;\n }\n return cachedLeafPubkey;\n }\n\n return {\n connect: async () => {\n await getAppClient();\n },\n getAddress: async () => {\n const { app, policy } = await buildPolicy();\n const address = await app.getWalletAddress(policy, null, change, addressIndex, false);\n if (!address) {\n throw new SwapKitError(\"wallet_ledger_get_address_error\", {\n message: `Cannot get ${chain} address from ledger derivation path: ${derivationPath}`,\n });\n }\n return address;\n },\n getExtendedPublicKey: async (path = `m/${accountPath}`) => {\n const app = await getAppClient();\n return app.getExtendedPubkey(path);\n },\n signTransaction: async (tx: Transaction): Promise<Transaction> => {\n const { app, policy, fpr } = await buildPolicy();\n const fingerprintBE = Number.parseInt(fpr, 16) >>> 0;\n const pathNumbers = pathToNumberArray(derivationPath);\n const leafPubkey = await getLeafPubkey();\n\n // Single-address account: every input is owned by the same key + path.\n for (let i = 0; i < tx.inputsLength; i++) {\n tx.updateInput(i, { bip32Derivation: [[leafPubkey, { fingerprint: fingerprintBE, path: pathNumbers }]] });\n }\n\n const psbtB64 = base64.encode(tx.toPSBT(0));\n const sigs = await app.signPsbt(psbtB64, policy, null);\n\n for (const [idx, partial] of sigs) {\n tx.updateInput(idx, { partialSig: [[new Uint8Array(partial.pubkey), new Uint8Array(partial.signature)]] });\n }\n\n tx.finalize();\n return tx;\n },\n };\n };\n};\n\nexport const BitcoinPsbtLedger = BaseLedgerPsbtUTXO({ chain: \"bitcoin\" });\nexport const LitecoinPsbtLedger = BaseLedgerPsbtUTXO({ chain: \"litecoin\" });\n"
6
- ],
7
- "mappings": "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",
8
- "debugId": "AE9B8E2F206F534564756E2164756E21",
9
- "names": []
10
- }
@@ -1,4 +0,0 @@
1
- var w=require("@scure/base"),B=require("@scure/bip32"),M=require("@swapkit/helpers");function f(z){switch(z){case"bech32":return"wpkh(@0/**)";case"p2sh":return"sh(wpkh(@0/**))";case"legacy":return"pkh(@0/**)";default:return"wpkh(@0/**)"}}function m(z){return typeof z==="string"?z:M.derivationPathToString(z)}function y(z){return z.replace(/^m\//,"").split("/").filter(Boolean).map((Q)=>{let Z=Q.endsWith("'"),R=Number.parseInt(Z?Q.slice(0,-1):Q,10);return Z?(R|2147483648)>>>0:R})}var X=({chain:z})=>{return(Q,Z)=>{let R,H;async function _(){if(!R){let q=Z??await K(),{AppClient:G}=await import("ledger-bitcoin");R=new G(q)}return R}async function k(){if(!H)H=await(await _()).getMasterFingerprint();return H}let V=Q?m(Q):"84'/0'/0'/0/0",j=V.split("/").slice(0,3).join("/"),O=V.split("/").slice(3),U=Number(O[0]??0),W=Number(O[1]??0),S=M.getWalletFormatFor(V),C=f(S),$,D;async function I(){let q=await _(),G=await k();if(!$)$=await q.getExtendedPubkey(`m/${j}`);let{DefaultWalletPolicy:J}=await import("ledger-bitcoin"),N=new J(C,`[${G}/${j}]${$}`);return{app:q,fpr:G,policy:N,xpub:$}}async function F(){if(!D){let{xpub:q}=await I(),J=B.HDKey.fromExtendedKey(q).derive(`m/${U}/${W}`);if(!J.publicKey)throw new M.SwapKitError("wallet_ledger_get_address_error",{message:`Cannot derive leaf pubkey for ${z}`});D=J.publicKey}return D}return{connect:async()=>{await _()},getAddress:async()=>{let{app:q,policy:G}=await I(),J=await q.getWalletAddress(G,null,U,W,!1);if(!J)throw new M.SwapKitError("wallet_ledger_get_address_error",{message:`Cannot get ${z} address from ledger derivation path: ${V}`});return J},getExtendedPublicKey:async(q=`m/${j}`)=>{return(await _()).getExtendedPubkey(q)},signTransaction:async(q)=>{let{app:G,policy:J,fpr:N}=await I(),L=Number.parseInt(N,16)>>>0,T=y(V),v=await F();for(let Y=0;Y<q.inputsLength;Y++)q.updateInput(Y,{bip32Derivation:[[v,{fingerprint:L,path:T}]]});let A=w.base64.encode(q.toPSBT(0)),x=await G.signPsbt(A,J,null);for(let[Y,E]of x)q.updateInput(Y,{partialSig:[[new Uint8Array(E.pubkey),new Uint8Array(E.signature)]]});return q.finalize(),q}}}},P=X({chain:"bitcoin"}),g=X({chain:"litecoin"});
2
-
3
- //# debugId=EEF70E29FB42902064756E2164756E21
4
- //# sourceMappingURL=chunk-m08x6an5.js.map
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/ledger/clients/utxo-psbt.ts"],
4
- "sourcesContent": [
5
- "import type Transport from \"@ledgerhq/hw-transport\";\nimport { base64 } from \"@scure/base\";\nimport { HDKey } from \"@scure/bip32\";\nimport { type DerivationPathArray, derivationPathToString, getWalletFormatFor, SwapKitError } from \"@swapkit/helpers\";\nimport type { Transaction } from \"@swapkit/utxo-signer\";\n\nimport { getLedgerTransport } from \"../helpers/getLedgerTransport\";\n\ntype SupportedCoin = \"bitcoin\" | \"litecoin\";\n\ntype DefaultDescriptorTemplate = \"wpkh(@0/**)\" | \"tr(@0/**)\" | \"sh(wpkh(@0/**))\" | \"pkh(@0/**)\";\n\nfunction templateForFormat(format: ReturnType<typeof getWalletFormatFor>): DefaultDescriptorTemplate {\n switch (format) {\n case \"bech32\":\n return \"wpkh(@0/**)\";\n case \"p2sh\":\n return \"sh(wpkh(@0/**))\";\n case \"legacy\":\n return \"pkh(@0/**)\";\n default:\n return \"wpkh(@0/**)\";\n }\n}\n\nfunction pathToString(path: DerivationPathArray | string): string {\n return typeof path === \"string\" ? path : derivationPathToString(path);\n}\n\nfunction pathToNumberArray(path: string): number[] {\n return path\n .replace(/^m\\//, \"\")\n .split(\"/\")\n .filter(Boolean)\n .map((p) => {\n const hardened = p.endsWith(\"'\");\n const num = Number.parseInt(hardened ? p.slice(0, -1) : p, 10);\n return hardened ? (num | 0x80000000) >>> 0 : num;\n });\n}\n\nconst BaseLedgerPsbtUTXO = ({ chain }: { chain: SupportedCoin }) => {\n return (derivationPathArray?: DerivationPathArray | string, injectedTransport?: Transport) => {\n // Per-call state — each BitcoinPsbtLedger/LitecoinPsbtLedger invocation has its own\n // AppClient and master fingerprint so different consumers (e.g. concurrent MCP\n // sessions on different devices) cannot inherit each other's ledger bindings or xpub.\n let appClient: import(\"ledger-bitcoin\").AppClient | undefined;\n let masterFingerprint: string | undefined;\n\n async function getAppClient() {\n if (!appClient) {\n const transport = injectedTransport ?? (await getLedgerTransport());\n const { AppClient } = await import(\"ledger-bitcoin\");\n appClient = new AppClient(transport);\n }\n return appClient;\n }\n\n async function getFingerprint() {\n if (!masterFingerprint) {\n const app = await getAppClient();\n masterFingerprint = await app.getMasterFingerprint();\n }\n return masterFingerprint;\n }\n\n // Single-address account: change == index == 0 by default.\n const derivationPath = derivationPathArray ? pathToString(derivationPathArray) : \"84'/0'/0'/0/0\";\n const accountPath = derivationPath.split(\"/\").slice(0, 3).join(\"/\");\n const leafSegments = derivationPath.split(\"/\").slice(3);\n const change = Number(leafSegments[0] ?? 0);\n const addressIndex = Number(leafSegments[1] ?? 0);\n const format = getWalletFormatFor(derivationPath);\n const template = templateForFormat(format);\n\n let cachedAccountXpub: string | undefined;\n let cachedLeafPubkey: Uint8Array | undefined;\n\n async function buildPolicy() {\n const app = await getAppClient();\n const fpr = await getFingerprint();\n if (!cachedAccountXpub) {\n cachedAccountXpub = await app.getExtendedPubkey(`m/${accountPath}`);\n }\n const { DefaultWalletPolicy } = await import(\"ledger-bitcoin\");\n const policy = new DefaultWalletPolicy(template, `[${fpr}/${accountPath}]${cachedAccountXpub}`);\n return { app, fpr, policy, xpub: cachedAccountXpub };\n }\n\n async function getLeafPubkey() {\n if (!cachedLeafPubkey) {\n const { xpub } = await buildPolicy();\n const accountKey = HDKey.fromExtendedKey(xpub);\n const leaf = accountKey.derive(`m/${change}/${addressIndex}`);\n if (!leaf.publicKey) {\n throw new SwapKitError(\"wallet_ledger_get_address_error\", {\n message: `Cannot derive leaf pubkey for ${chain}`,\n });\n }\n cachedLeafPubkey = leaf.publicKey;\n }\n return cachedLeafPubkey;\n }\n\n return {\n connect: async () => {\n await getAppClient();\n },\n getAddress: async () => {\n const { app, policy } = await buildPolicy();\n const address = await app.getWalletAddress(policy, null, change, addressIndex, false);\n if (!address) {\n throw new SwapKitError(\"wallet_ledger_get_address_error\", {\n message: `Cannot get ${chain} address from ledger derivation path: ${derivationPath}`,\n });\n }\n return address;\n },\n getExtendedPublicKey: async (path = `m/${accountPath}`) => {\n const app = await getAppClient();\n return app.getExtendedPubkey(path);\n },\n signTransaction: async (tx: Transaction): Promise<Transaction> => {\n const { app, policy, fpr } = await buildPolicy();\n const fingerprintBE = Number.parseInt(fpr, 16) >>> 0;\n const pathNumbers = pathToNumberArray(derivationPath);\n const leafPubkey = await getLeafPubkey();\n\n // Single-address account: every input is owned by the same key + path.\n for (let i = 0; i < tx.inputsLength; i++) {\n tx.updateInput(i, { bip32Derivation: [[leafPubkey, { fingerprint: fingerprintBE, path: pathNumbers }]] });\n }\n\n const psbtB64 = base64.encode(tx.toPSBT(0));\n const sigs = await app.signPsbt(psbtB64, policy, null);\n\n for (const [idx, partial] of sigs) {\n tx.updateInput(idx, { partialSig: [[new Uint8Array(partial.pubkey), new Uint8Array(partial.signature)]] });\n }\n\n tx.finalize();\n return tx;\n },\n };\n };\n};\n\nexport const BitcoinPsbtLedger = BaseLedgerPsbtUTXO({ chain: \"bitcoin\" });\nexport const LitecoinPsbtLedger = BaseLedgerPsbtUTXO({ chain: \"litecoin\" });\n"
6
- ],
7
- "mappings": "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",
8
- "debugId": "EEF70E29FB42902064756E2164756E21",
9
- "names": []
10
- }