@swapkit/wallet-hardware 4.9.6 → 4.9.8
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/keepkey/index.cjs +2 -2
- package/dist/keepkey/index.cjs.map +3 -3
- package/dist/keepkey/index.js +2 -2
- package/dist/keepkey/index.js.map +3 -3
- package/dist/ledger/index.cjs +3 -3
- package/dist/ledger/index.cjs.map +3 -3
- package/dist/ledger/index.js +3 -3
- package/dist/ledger/index.js.map +3 -3
- package/dist/trezor/index.cjs +2 -2
- package/dist/trezor/index.cjs.map +3 -3
- package/dist/trezor/index.js +2 -2
- package/dist/trezor/index.js.map +3 -3
- package/dist/types/trezor/index.d.ts.map +1 -1
- package/package.json +7 -5
- package/src/keepkey/chains/utxo.ts +2 -2
- package/src/ledger/index.ts +2 -2
- package/src/trezor/index.ts +345 -27
package/src/trezor/index.ts
CHANGED
|
@@ -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,74 @@ 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 DEFAULT_TREZOR_MANIFEST = { appName: "SwapKit", appUrl: "https://swapkit.dev", email: "support@swapkit.dev" };
|
|
46
|
+
const DEFAULT_TREZOR_TRANSPORTS = ["WebUsbTransport" as const];
|
|
47
|
+
const trezorXpubCache = new Map<string, TrezorExtendedPublicKeyInfo>();
|
|
48
|
+
let trezorSessionDispose: Promise<void> | undefined;
|
|
49
|
+
|
|
50
|
+
async function disconnectTrezorSession() {
|
|
51
|
+
trezorXpubCache.clear();
|
|
52
|
+
|
|
53
|
+
const dispose = (async () => {
|
|
54
|
+
try {
|
|
55
|
+
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
56
|
+
await TrezorConnect.dispose();
|
|
57
|
+
} catch {
|
|
58
|
+
// Ignore stale or already-disposed sessions.
|
|
59
|
+
}
|
|
60
|
+
})();
|
|
61
|
+
|
|
62
|
+
trezorSessionDispose = dispose;
|
|
63
|
+
await dispose;
|
|
64
|
+
|
|
65
|
+
if (trezorSessionDispose === dispose) {
|
|
66
|
+
trezorSessionDispose = undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function normalizeTrezorCoreMode(coreMode: unknown): TrezorCoreMode | undefined {
|
|
71
|
+
return typeof coreMode === "string" && TREZOR_CORE_MODES.has(coreMode as TrezorCoreMode)
|
|
72
|
+
? (coreMode as TrezorCoreMode)
|
|
73
|
+
: undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function normalizeTrezorTransports(transports: unknown): TrezorTransport[] | undefined {
|
|
77
|
+
if (!Array.isArray(transports)) return undefined;
|
|
78
|
+
|
|
79
|
+
const normalized = transports.filter(
|
|
80
|
+
(transport): transport is TrezorTransport =>
|
|
81
|
+
typeof transport === "string" && TREZOR_TRANSPORTS.has(transport as TrezorTransport),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getTrezorManifestValue(value: unknown, fallback: string) {
|
|
88
|
+
return typeof value === "string" && value.trim() ? value : fallback;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function getDefaultTrezorAppUrl() {
|
|
92
|
+
return typeof globalThis.location !== "undefined" && globalThis.location.origin
|
|
93
|
+
? globalThis.location.origin
|
|
94
|
+
: DEFAULT_TREZOR_MANIFEST.appUrl;
|
|
95
|
+
}
|
|
96
|
+
|
|
27
97
|
function decodeOpReturnData(script: Uint8Array): string | null {
|
|
28
98
|
if (script.length < 2 || script[0] !== 0x6a) return null;
|
|
29
99
|
const dataLen = script[1];
|
|
@@ -50,6 +120,48 @@ function hardenDerivationPath(derivationPath: DerivationPathArray): number[] {
|
|
|
50
120
|
);
|
|
51
121
|
}
|
|
52
122
|
|
|
123
|
+
function isTrezorBip32Derivation(value: unknown): value is TrezorBip32Derivation {
|
|
124
|
+
return (
|
|
125
|
+
Array.isArray(value) &&
|
|
126
|
+
value[0] instanceof Uint8Array &&
|
|
127
|
+
typeof value[1] === "object" &&
|
|
128
|
+
value[1] !== null &&
|
|
129
|
+
typeof (value[1] as { fingerprint?: unknown }).fingerprint === "number" &&
|
|
130
|
+
Array.isArray((value[1] as { path?: unknown }).path)
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function getFirstBip32Derivation(input: { bip32Derivation?: unknown }): TrezorBip32Derivation | undefined {
|
|
135
|
+
if (!Array.isArray(input.bip32Derivation)) return undefined;
|
|
136
|
+
const [firstDerivation] = input.bip32Derivation;
|
|
137
|
+
|
|
138
|
+
return isTrezorBip32Derivation(firstDerivation) ? firstDerivation : undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function getPrevoutAmount(input: {
|
|
142
|
+
index?: number;
|
|
143
|
+
nonWitnessUtxo?: { outputs?: Array<{ amount?: bigint | number }> };
|
|
144
|
+
witnessUtxo?: { amount?: bigint | number };
|
|
145
|
+
}) {
|
|
146
|
+
if (input.witnessUtxo?.amount !== undefined) return input.witnessUtxo.amount.toString();
|
|
147
|
+
|
|
148
|
+
const prevout = input.index !== undefined ? input.nonWitnessUtxo?.outputs?.[input.index] : undefined;
|
|
149
|
+
if (prevout?.amount !== undefined) return prevout.amount.toString();
|
|
150
|
+
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function normalizeTrezorSignature(signatureHex: string) {
|
|
155
|
+
const signature = Buffer.from(signatureHex, "hex");
|
|
156
|
+
const derLength = signature[1] !== undefined ? signature[1] + 2 : undefined;
|
|
157
|
+
|
|
158
|
+
if (derLength !== undefined && signature.length === derLength) {
|
|
159
|
+
return new Uint8Array([...signature, 0x01]);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return new Uint8Array(signature);
|
|
163
|
+
}
|
|
164
|
+
|
|
53
165
|
function buildPCZTInputsForTrezor(
|
|
54
166
|
pczt: PCZT,
|
|
55
167
|
address_n: number[],
|
|
@@ -206,8 +318,27 @@ function buildUtxoOutputsForTrezor(
|
|
|
206
318
|
const outputAddress = tx.getOutputAddress(i, network);
|
|
207
319
|
|
|
208
320
|
if (!outputAddress) {
|
|
209
|
-
|
|
210
|
-
|
|
321
|
+
const opReturnData = output.script ? decodeOpReturnData(output.script) : null;
|
|
322
|
+
if (opReturnData !== null || memo) {
|
|
323
|
+
outputs.push({
|
|
324
|
+
amount: "0",
|
|
325
|
+
op_return_data: opReturnData ?? Buffer.from(memo).toString("hex"),
|
|
326
|
+
script_type: "PAYTOOPRETURN",
|
|
327
|
+
});
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
throw new SwapKitError({
|
|
332
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
333
|
+
info: { chain, error: "Unable to decode output address from scriptPubkey" },
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (output.amount === undefined) {
|
|
338
|
+
throw new SwapKitError({
|
|
339
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
340
|
+
info: { chain, error: "Output amount is missing" },
|
|
341
|
+
});
|
|
211
342
|
}
|
|
212
343
|
|
|
213
344
|
const isBch = chain === Chain.BitcoinCash;
|
|
@@ -218,8 +349,8 @@ function buildUtxoOutputsForTrezor(
|
|
|
218
349
|
|
|
219
350
|
outputs.push(
|
|
220
351
|
isChangeAddress
|
|
221
|
-
? { address_n, amount:
|
|
222
|
-
: { address: cashAddrWithPrefix, amount:
|
|
352
|
+
? { address_n, amount: output.amount.toString(), script_type: scriptType.output }
|
|
353
|
+
: { address: cashAddrWithPrefix, amount: output.amount.toString(), script_type: "PAYTOADDRESS" },
|
|
223
354
|
);
|
|
224
355
|
}
|
|
225
356
|
return outputs;
|
|
@@ -434,7 +565,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
434
565
|
case Chain.Dash:
|
|
435
566
|
case Chain.Dogecoin:
|
|
436
567
|
case Chain.Litecoin: {
|
|
437
|
-
const { toCashAddress, getUtxoToolbox } = await import("@swapkit/toolboxes/utxo");
|
|
568
|
+
const { toCashAddress, getUtxoToolbox, stripPrefix } = await import("@swapkit/toolboxes/utxo");
|
|
438
569
|
const utxoChain = chain as UTXOChain;
|
|
439
570
|
const scriptType = getScriptType(derivationPath);
|
|
440
571
|
|
|
@@ -446,7 +577,11 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
446
577
|
|
|
447
578
|
const getAddress = async (path: DerivationPathArray = derivationPath) => {
|
|
448
579
|
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
449
|
-
const { success, payload } = await TrezorConnect.getAddress({
|
|
580
|
+
const { success, payload } = await TrezorConnect.getAddress({
|
|
581
|
+
coin,
|
|
582
|
+
path: derivationPathToString(path),
|
|
583
|
+
showOnTrezor: false,
|
|
584
|
+
});
|
|
450
585
|
|
|
451
586
|
if (!success) {
|
|
452
587
|
throw new SwapKitError({
|
|
@@ -456,19 +591,57 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
456
591
|
}
|
|
457
592
|
|
|
458
593
|
if (chain === Chain.BitcoinCash) {
|
|
459
|
-
|
|
460
|
-
return toolbox.stripPrefix(payload.address);
|
|
594
|
+
return stripPrefix(payload.address);
|
|
461
595
|
}
|
|
462
596
|
|
|
463
597
|
return payload.address;
|
|
464
598
|
};
|
|
465
599
|
|
|
466
|
-
|
|
600
|
+
async function getAddressFromExtendedPublicKey() {
|
|
601
|
+
const accountInfo = await getExtendedPublicKeyInfo();
|
|
602
|
+
const addressIndex = Number(derivationPath[4] ?? 0);
|
|
603
|
+
const change = Boolean(derivationPath[3] ?? 0);
|
|
604
|
+
|
|
605
|
+
try {
|
|
606
|
+
// deriveAddressesFromXpub returns both external and change branches for each index.
|
|
607
|
+
const derivedAddress = deriveAddressesFromXpub({
|
|
608
|
+
accountIndex: accountInfo.accountIndex,
|
|
609
|
+
chain: utxoChain,
|
|
610
|
+
count: 1,
|
|
611
|
+
startIndex: addressIndex,
|
|
612
|
+
xpub: accountInfo.xpub,
|
|
613
|
+
}).find((derived) => derived.change === change && derived.index === addressIndex);
|
|
614
|
+
|
|
615
|
+
if (!derivedAddress) {
|
|
616
|
+
throw new SwapKitError({
|
|
617
|
+
errorKey: "wallet_trezor_failed_to_get_address",
|
|
618
|
+
info: { chain, error: "Unable to derive address from Trezor account public key" },
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
return derivedAddress.address;
|
|
623
|
+
} catch (error) {
|
|
624
|
+
if (error instanceof SwapKitError) throw error;
|
|
625
|
+
|
|
626
|
+
throw new SwapKitError({
|
|
627
|
+
errorKey: "wallet_trezor_failed_to_get_address",
|
|
628
|
+
info: {
|
|
629
|
+
chain,
|
|
630
|
+
error: error instanceof Error ? error.message : "Unable to derive address from Trezor xpub",
|
|
631
|
+
},
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
const address =
|
|
637
|
+
chain === Chain.Bitcoin || chain === Chain.Litecoin
|
|
638
|
+
? await getAddressFromExtendedPublicKey()
|
|
639
|
+
: await getAddress();
|
|
640
|
+
const baseToolbox = getUtxoToolbox(chain);
|
|
467
641
|
|
|
468
642
|
const signTransaction = async (tx: Transaction, inputs: UTXOType[], memo = "") => {
|
|
469
643
|
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
470
644
|
const address_n = hardenDerivationPath(derivationPath);
|
|
471
|
-
const toolbox = getUtxoToolbox(chain as typeof Chain.BitcoinCash);
|
|
472
645
|
const network = getNetworkForChain(chain as UTXOChain);
|
|
473
646
|
|
|
474
647
|
const outputs = buildUtxoOutputsForTrezor(
|
|
@@ -480,7 +653,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
480
653
|
chain,
|
|
481
654
|
scriptType,
|
|
482
655
|
toCashAddress,
|
|
483
|
-
|
|
656
|
+
stripPrefix,
|
|
484
657
|
);
|
|
485
658
|
|
|
486
659
|
const trezorInputs = inputs.map(({ hash, index, value }) => ({
|
|
@@ -504,13 +677,108 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
504
677
|
});
|
|
505
678
|
};
|
|
506
679
|
|
|
680
|
+
const signPsbtTransaction = async (tx: Transaction): Promise<Transaction> => {
|
|
681
|
+
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
682
|
+
const { hex: hexEncode } = await import("@scure/base");
|
|
683
|
+
const address_n = hardenDerivationPath(derivationPath);
|
|
684
|
+
const network = getNetworkForChain(chain as UTXOChain);
|
|
685
|
+
let fallbackPublicKey: Uint8Array | undefined;
|
|
686
|
+
|
|
687
|
+
async function getFallbackDerivation(): Promise<TrezorBip32Derivation> {
|
|
688
|
+
if (!fallbackPublicKey) {
|
|
689
|
+
const accountInfo = await getExtendedPublicKeyInfo();
|
|
690
|
+
const accountKey = HDKey.fromExtendedKey(accountInfo.xpub);
|
|
691
|
+
const leaf = accountKey.derive(`m/${Number(derivationPath[3] ?? 0)}/${Number(derivationPath[4] ?? 0)}`);
|
|
692
|
+
|
|
693
|
+
if (!leaf.publicKey) {
|
|
694
|
+
throw new SwapKitError({
|
|
695
|
+
errorKey: "wallet_trezor_failed_to_get_public_key",
|
|
696
|
+
info: { chain, error: "Unable to derive Trezor leaf public key from account xpub" },
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
fallbackPublicKey = leaf.publicKey;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
return [fallbackPublicKey, { fingerprint: 0, path: address_n }];
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
const signerPubkeys: Uint8Array[] = [];
|
|
707
|
+
const trezorInputs = [];
|
|
708
|
+
|
|
709
|
+
for (let inputIndex = 0; inputIndex < tx.inputsLength; inputIndex++) {
|
|
710
|
+
const input = tx.getInput(inputIndex);
|
|
711
|
+
const existingDerivation = getFirstBip32Derivation(input);
|
|
712
|
+
const derivation = existingDerivation ?? (await getFallbackDerivation());
|
|
713
|
+
const amount = getPrevoutAmount(input);
|
|
714
|
+
|
|
715
|
+
if (!input.txid || input.index === undefined || !amount) {
|
|
716
|
+
throw new SwapKitError({
|
|
717
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
718
|
+
info: { chain, error: `Input ${inputIndex} is missing prevout data required by Trezor` },
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
signerPubkeys[inputIndex] = derivation[0];
|
|
723
|
+
|
|
724
|
+
if (!existingDerivation) {
|
|
725
|
+
tx.updateInput(inputIndex, { bip32Derivation: [derivation] });
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
trezorInputs.push({
|
|
729
|
+
address_n: derivation[1].path,
|
|
730
|
+
amount,
|
|
731
|
+
prev_hash: hexEncode.encode(input.txid),
|
|
732
|
+
prev_index: input.index,
|
|
733
|
+
script_type: scriptType.input,
|
|
734
|
+
...(input.sequence !== undefined ? { sequence: input.sequence } : {}),
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const outputs = buildUtxoOutputsForTrezor(
|
|
739
|
+
tx,
|
|
740
|
+
network,
|
|
741
|
+
address_n,
|
|
742
|
+
address,
|
|
743
|
+
"",
|
|
744
|
+
chain,
|
|
745
|
+
scriptType,
|
|
746
|
+
toCashAddress,
|
|
747
|
+
stripPrefix,
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
const result = await TrezorConnect.signTransaction({
|
|
751
|
+
coin,
|
|
752
|
+
inputs: trezorInputs,
|
|
753
|
+
locktime: tx.lockTime,
|
|
754
|
+
outputs,
|
|
755
|
+
version: tx.version,
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
if (!result.success) {
|
|
759
|
+
const payload = result.payload as { error?: string; code?: string };
|
|
760
|
+
throw new SwapKitError({
|
|
761
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
762
|
+
info: { chain, code: payload?.code ?? "unknown", error: payload?.error ?? "unknown", payload },
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
result.payload.signatures.forEach((signatureHex, inputIndex) => {
|
|
767
|
+
const pubkey = signerPubkeys[inputIndex];
|
|
768
|
+
if (!(signatureHex && pubkey)) return;
|
|
769
|
+
|
|
770
|
+
tx.updateInput(inputIndex, { partialSig: [[pubkey, normalizeTrezorSignature(signatureHex)]] });
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
return tx;
|
|
774
|
+
};
|
|
775
|
+
|
|
507
776
|
const signTransactionWithMultipleInputs = async (
|
|
508
777
|
tx: Transaction,
|
|
509
778
|
inputs: Array<{ hash: string; index: number; value: number; derivationIndex: number; isChange: boolean }>,
|
|
510
779
|
memo = "",
|
|
511
780
|
) => {
|
|
512
781
|
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
513
|
-
const toolbox = await getUtxoToolbox(chain as typeof Chain.BitcoinCash);
|
|
514
782
|
const network = getNetworkForChain(chain as UTXOChain);
|
|
515
783
|
const baseAddressN = hardenDerivationPath(derivationPath.slice(0, 3) as DerivationPathArray);
|
|
516
784
|
|
|
@@ -523,7 +791,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
523
791
|
chain,
|
|
524
792
|
scriptType,
|
|
525
793
|
toCashAddress,
|
|
526
|
-
|
|
794
|
+
stripPrefix,
|
|
527
795
|
);
|
|
528
796
|
|
|
529
797
|
const trezorInputs = inputs.map(({ hash, index: inputIndex, value, derivationIndex, isChange }) => {
|
|
@@ -629,12 +897,21 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
629
897
|
return txHash;
|
|
630
898
|
};
|
|
631
899
|
|
|
632
|
-
const toolbox =
|
|
900
|
+
const toolbox =
|
|
901
|
+
chain === Chain.Bitcoin || chain === Chain.Litecoin
|
|
902
|
+
? await getUtxoToolbox(utxoChain, {
|
|
903
|
+
signer: { getAddress: async () => address, signTransaction: signPsbtTransaction },
|
|
904
|
+
})
|
|
905
|
+
: baseToolbox;
|
|
633
906
|
|
|
634
907
|
async function getExtendedPublicKeyInfo({ accountIndex }: { accountIndex?: number } = {}) {
|
|
635
908
|
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
636
909
|
const resolvedAccountPath = getUTXOAccountPath({ accountIndex, chain: utxoChain, derivationPath });
|
|
637
910
|
const path = derivationPathToString(resolvedAccountPath);
|
|
911
|
+
const cacheKey = `${chain}:${path}`;
|
|
912
|
+
const cached = trezorXpubCache.get(cacheKey);
|
|
913
|
+
if (cached) return cached;
|
|
914
|
+
|
|
638
915
|
const { success, payload } = await TrezorConnect.getPublicKey({ coin, path });
|
|
639
916
|
|
|
640
917
|
if (!success) {
|
|
@@ -644,7 +921,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
644
921
|
});
|
|
645
922
|
}
|
|
646
923
|
|
|
647
|
-
|
|
924
|
+
const info = {
|
|
648
925
|
accountIndex: getUTXOAccountIndexFromPath(resolvedAccountPath),
|
|
649
926
|
chainCode: payload.chainCode,
|
|
650
927
|
depth: payload.depth,
|
|
@@ -654,10 +931,13 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
654
931
|
xpub: payload.xpub,
|
|
655
932
|
xpubSegwit: payload.xpubSegwit,
|
|
656
933
|
};
|
|
934
|
+
|
|
935
|
+
trezorXpubCache.set(cacheKey, info);
|
|
936
|
+
return info;
|
|
657
937
|
}
|
|
658
938
|
|
|
659
|
-
function getExtendedPublicKey() {
|
|
660
|
-
return getExtendedPublicKeyInfo();
|
|
939
|
+
function getExtendedPublicKey(params: { accountIndex?: number } = {}) {
|
|
940
|
+
return getExtendedPublicKeyInfo(params);
|
|
661
941
|
}
|
|
662
942
|
|
|
663
943
|
async function deriveAddressAtIndex({
|
|
@@ -791,19 +1071,55 @@ export const trezorWallet = createWallet({
|
|
|
791
1071
|
}
|
|
792
1072
|
|
|
793
1073
|
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
1074
|
+
|
|
1075
|
+
const trezorConfig = SKConfig.get("integrations").trezor as Record<string, unknown> | undefined;
|
|
1076
|
+
const {
|
|
1077
|
+
connectSrc,
|
|
1078
|
+
coreMode,
|
|
1079
|
+
debug,
|
|
1080
|
+
interactionTimeout,
|
|
1081
|
+
lazyLoad,
|
|
1082
|
+
pendingTransportEvent,
|
|
1083
|
+
popup,
|
|
1084
|
+
transportReconnect,
|
|
1085
|
+
transports,
|
|
1086
|
+
...manifestConfig
|
|
1087
|
+
} = trezorConfig ?? {};
|
|
1088
|
+
const manifest = {
|
|
1089
|
+
...manifestConfig,
|
|
1090
|
+
appName: getTrezorManifestValue(trezorConfig?.appName, DEFAULT_TREZOR_MANIFEST.appName),
|
|
1091
|
+
appUrl: getTrezorManifestValue(trezorConfig?.appUrl, getDefaultTrezorAppUrl()),
|
|
1092
|
+
email: getTrezorManifestValue(trezorConfig?.email, DEFAULT_TREZOR_MANIFEST.email),
|
|
1093
|
+
};
|
|
1094
|
+
const isLocalhost =
|
|
1095
|
+
typeof globalThis.location !== "undefined" && ["localhost", "127.0.0.1"].includes(globalThis.location.hostname);
|
|
1096
|
+
const resolvedCoreMode = normalizeTrezorCoreMode(coreMode) ?? "popup";
|
|
1097
|
+
const resolvedTransports = normalizeTrezorTransports(transports) ?? DEFAULT_TREZOR_TRANSPORTS;
|
|
1098
|
+
|
|
1099
|
+
if (trezorSessionDispose) {
|
|
1100
|
+
await trezorSessionDispose;
|
|
802
1101
|
}
|
|
803
1102
|
|
|
1103
|
+
if (isLocalhost) {
|
|
1104
|
+
await TrezorConnect.dispose();
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
await TrezorConnect.init({
|
|
1108
|
+
connectSrc: connectSrc as string | undefined,
|
|
1109
|
+
coreMode: resolvedCoreMode,
|
|
1110
|
+
debug: debug as boolean | undefined,
|
|
1111
|
+
interactionTimeout: interactionTimeout as number | undefined,
|
|
1112
|
+
lazyLoad: (lazyLoad as boolean | undefined) ?? false,
|
|
1113
|
+
manifest,
|
|
1114
|
+
pendingTransportEvent: pendingTransportEvent as boolean | undefined,
|
|
1115
|
+
popup: (popup as boolean | undefined) ?? true,
|
|
1116
|
+
transportReconnect: transportReconnect as boolean | undefined,
|
|
1117
|
+
transports: resolvedTransports,
|
|
1118
|
+
});
|
|
1119
|
+
|
|
804
1120
|
const wallet = await getTrezorWallet({ chain, derivationPath });
|
|
805
1121
|
|
|
806
|
-
addChain({ ...wallet, chain, walletType });
|
|
1122
|
+
addChain({ ...wallet, chain, disconnect: disconnectTrezorSession, walletType });
|
|
807
1123
|
|
|
808
1124
|
return true;
|
|
809
1125
|
},
|
|
@@ -814,13 +1130,15 @@ export const trezorWallet = createWallet({
|
|
|
814
1130
|
[Chain.Base]: true,
|
|
815
1131
|
[Chain.Berachain]: true,
|
|
816
1132
|
[Chain.BinanceSmartChain]: true,
|
|
1133
|
+
[Chain.Bitcoin]: true,
|
|
817
1134
|
[Chain.Ethereum]: true,
|
|
818
1135
|
[Chain.Gnosis]: true,
|
|
1136
|
+
[Chain.Litecoin]: true,
|
|
819
1137
|
[Chain.Monad]: true,
|
|
820
1138
|
[Chain.Optimism]: true,
|
|
821
1139
|
[Chain.Polygon]: true,
|
|
822
1140
|
[Chain.XLayer]: true,
|
|
823
|
-
//
|
|
1141
|
+
// BCH/DASH/DOGE/ZEC: pending PSBT→TrezorConnect converter (V3 plan PR)
|
|
824
1142
|
},
|
|
825
1143
|
name: "connectTrezor",
|
|
826
1144
|
supportedChains: [
|