@swapkit/wallet-hardware 4.9.9 → 4.9.11
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/chunk-bwf31zxr.js +4 -0
- package/dist/chunk-bwf31zxr.js.map +10 -0
- package/dist/chunk-hegt01q0.js +4 -0
- package/dist/chunk-hegt01q0.js.map +10 -0
- package/dist/ledger/index.cjs +3 -3
- package/dist/ledger/index.cjs.map +4 -4
- package/dist/ledger/index.js +3 -3
- package/dist/ledger/index.js.map +4 -4
- 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/keepkey/index.d.ts +1 -0
- package/dist/types/keepkey/index.d.ts.map +1 -1
- package/dist/types/ledger/clients/thorchain/index.d.ts +1 -0
- package/dist/types/ledger/clients/thorchain/index.d.ts.map +1 -1
- package/dist/types/ledger/clients/utxo-legacy-adapter.d.ts +17 -9
- package/dist/types/ledger/clients/utxo-legacy-adapter.d.ts.map +1 -1
- package/dist/types/ledger/index.d.ts +7 -1
- package/dist/types/ledger/index.d.ts.map +1 -1
- package/dist/types/trezor/index.d.ts +13 -2
- package/dist/types/trezor/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/ledger/clients/thorchain/index.ts +41 -1
- package/src/ledger/clients/utxo-legacy-adapter.ts +40 -19
- package/src/ledger/index.ts +55 -18
- package/src/trezor/index.ts +279 -70
- package/dist/chunk-mrsfcest.js +0 -4
- package/dist/chunk-mrsfcest.js.map +0 -10
- package/dist/chunk-px09mwnt.js +0 -4
- package/dist/chunk-px09mwnt.js.map +0 -10
package/src/trezor/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HDKey } from "@scure/bip32";
|
|
1
|
+
import { HDKey, type Versions } from "@scure/bip32";
|
|
2
2
|
import {
|
|
3
3
|
Chain,
|
|
4
4
|
type DerivationPathArray,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
FeeOption,
|
|
7
7
|
filterSupportedChains,
|
|
8
8
|
type GenericTransferParams,
|
|
9
|
+
NetworkDerivationPath,
|
|
9
10
|
SKConfig,
|
|
10
11
|
SwapKitError,
|
|
11
12
|
type UTXOChain,
|
|
@@ -14,7 +15,6 @@ import {
|
|
|
14
15
|
import {
|
|
15
16
|
assertDerivationIndex,
|
|
16
17
|
createHDWalletHelpers,
|
|
17
|
-
deriveAddressesFromXpub,
|
|
18
18
|
getNetworkForChain,
|
|
19
19
|
getUTXOAccountIndexFromPath,
|
|
20
20
|
getUTXOAccountPath,
|
|
@@ -23,12 +23,13 @@ import {
|
|
|
23
23
|
type UTXOType,
|
|
24
24
|
} from "@swapkit/toolboxes/utxo";
|
|
25
25
|
import type { BTCNetwork, PCZT, Transaction, ZcashTransaction } from "@swapkit/utxo-signer";
|
|
26
|
-
import { NETWORKS, ZcashConsensusBranchId, ZcashVersionGroupId } from "@swapkit/utxo-signer";
|
|
27
|
-
import { createWallet, getWalletSupportedChains } from "@swapkit/wallet-core";
|
|
26
|
+
import { BCHSigHash, NETWORKS, ZcashConsensusBranchId, ZcashVersionGroupId } from "@swapkit/utxo-signer";
|
|
27
|
+
import { createWallet, getWalletSupportedChains, type HardwareExtendedPublicKeyInfo } from "@swapkit/wallet-core";
|
|
28
28
|
|
|
29
29
|
type TrezorBip32Derivation = [Uint8Array, { fingerprint: number; path: number[] }];
|
|
30
30
|
type TrezorCoreMode = "auto" | "iframe" | "popup" | "suite-desktop" | "suite-web";
|
|
31
31
|
type TrezorTransport = "BridgeTransport" | "WebUsbTransport" | "NodeUsbTransport";
|
|
32
|
+
type ConnectTrezorOptions = { address?: string };
|
|
32
33
|
type TrezorExtendedPublicKeyInfo = {
|
|
33
34
|
accountIndex: number;
|
|
34
35
|
chainCode?: string;
|
|
@@ -44,8 +45,16 @@ const TREZOR_CORE_MODES = new Set<TrezorCoreMode>(["auto", "iframe", "popup", "s
|
|
|
44
45
|
const TREZOR_TRANSPORTS = new Set<TrezorTransport>(["BridgeTransport", "WebUsbTransport", "NodeUsbTransport"]);
|
|
45
46
|
const DEFAULT_TREZOR_MANIFEST = { appName: "SwapKit", appUrl: "https://swapkit.dev", email: "support@swapkit.dev" };
|
|
46
47
|
const DEFAULT_TREZOR_TRANSPORTS = ["WebUsbTransport" as const];
|
|
48
|
+
const TREZOR_KEEP_SESSION_PARAMS = { keepSession: true } as const;
|
|
47
49
|
const trezorXpubCache = new Map<string, TrezorExtendedPublicKeyInfo>();
|
|
48
50
|
let trezorSessionDispose: Promise<void> | undefined;
|
|
51
|
+
const EXTENDED_KEY_VERSION_CANDIDATES = [
|
|
52
|
+
NETWORKS.bitcoin.bip32,
|
|
53
|
+
NETWORKS.bitcoinCash.bip32,
|
|
54
|
+
NETWORKS.dash.bip32,
|
|
55
|
+
NETWORKS.dogecoin.bip32,
|
|
56
|
+
NETWORKS.litecoin.bip32,
|
|
57
|
+
];
|
|
49
58
|
|
|
50
59
|
async function disconnectTrezorSession() {
|
|
51
60
|
trezorXpubCache.clear();
|
|
@@ -94,6 +103,98 @@ function getDefaultTrezorAppUrl() {
|
|
|
94
103
|
: DEFAULT_TREZOR_MANIFEST.appUrl;
|
|
95
104
|
}
|
|
96
105
|
|
|
106
|
+
async function initTrezorConnect() {
|
|
107
|
+
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
108
|
+
|
|
109
|
+
const trezorConfig = SKConfig.get("integrations").trezor as Record<string, unknown> | undefined;
|
|
110
|
+
const {
|
|
111
|
+
connectSrc,
|
|
112
|
+
coreMode,
|
|
113
|
+
debug,
|
|
114
|
+
interactionTimeout,
|
|
115
|
+
lazyLoad,
|
|
116
|
+
pendingTransportEvent,
|
|
117
|
+
popup,
|
|
118
|
+
transportReconnect,
|
|
119
|
+
transports,
|
|
120
|
+
...manifestConfig
|
|
121
|
+
} = trezorConfig ?? {};
|
|
122
|
+
const manifest = {
|
|
123
|
+
...manifestConfig,
|
|
124
|
+
appName: getTrezorManifestValue(trezorConfig?.appName, DEFAULT_TREZOR_MANIFEST.appName),
|
|
125
|
+
appUrl: getTrezorManifestValue(trezorConfig?.appUrl, getDefaultTrezorAppUrl()),
|
|
126
|
+
email: getTrezorManifestValue(trezorConfig?.email, DEFAULT_TREZOR_MANIFEST.email),
|
|
127
|
+
};
|
|
128
|
+
const isLocalhost =
|
|
129
|
+
typeof globalThis.location !== "undefined" && ["localhost", "127.0.0.1"].includes(globalThis.location.hostname);
|
|
130
|
+
const resolvedCoreMode = normalizeTrezorCoreMode(coreMode) ?? "popup";
|
|
131
|
+
const resolvedTransports = normalizeTrezorTransports(transports) ?? DEFAULT_TREZOR_TRANSPORTS;
|
|
132
|
+
|
|
133
|
+
if (trezorSessionDispose) {
|
|
134
|
+
await trezorSessionDispose;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (isLocalhost) {
|
|
138
|
+
await TrezorConnect.dispose();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await TrezorConnect.init({
|
|
142
|
+
connectSrc: connectSrc as string | undefined,
|
|
143
|
+
coreMode: resolvedCoreMode,
|
|
144
|
+
debug: debug as boolean | undefined,
|
|
145
|
+
interactionTimeout: interactionTimeout as number | undefined,
|
|
146
|
+
lazyLoad: (lazyLoad as boolean | undefined) ?? false,
|
|
147
|
+
manifest,
|
|
148
|
+
pendingTransportEvent: pendingTransportEvent as boolean | undefined,
|
|
149
|
+
popup: (popup as boolean | undefined) ?? true,
|
|
150
|
+
transportReconnect: transportReconnect as boolean | undefined,
|
|
151
|
+
transports: resolvedTransports,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return { coreMode: resolvedCoreMode, isLocalhost, popup: (popup as boolean | undefined) ?? true, TrezorConnect };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function normalizeTrezorExtendedPublicKey(xpub: string, chain: UTXOChain) {
|
|
158
|
+
const targetVersions = getNetworkForChain(chain).bip32;
|
|
159
|
+
const candidates = [
|
|
160
|
+
targetVersions,
|
|
161
|
+
...EXTENDED_KEY_VERSION_CANDIDATES.filter(
|
|
162
|
+
(versions) => versions.public !== targetVersions.public || versions.private !== targetVersions.private,
|
|
163
|
+
),
|
|
164
|
+
];
|
|
165
|
+
let lastError: unknown;
|
|
166
|
+
|
|
167
|
+
for (const versions of candidates) {
|
|
168
|
+
try {
|
|
169
|
+
const key = HDKey.fromExtendedKey(xpub, versions as Versions);
|
|
170
|
+
if (!(key.publicKey && key.chainCode)) throw new Error("Extended key is missing public key data");
|
|
171
|
+
|
|
172
|
+
return new HDKey({
|
|
173
|
+
chainCode: key.chainCode,
|
|
174
|
+
depth: key.depth,
|
|
175
|
+
index: key.index,
|
|
176
|
+
parentFingerprint: key.parentFingerprint,
|
|
177
|
+
publicKey: key.publicKey,
|
|
178
|
+
versions: targetVersions,
|
|
179
|
+
}).publicExtendedKey;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
lastError = error;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
throw lastError instanceof Error ? lastError : new Error("Unable to parse Trezor extended public key");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function tryNormalizeTrezorExtendedPublicKey(xpub: string | undefined, chain: UTXOChain) {
|
|
189
|
+
if (!xpub) return undefined;
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
return normalizeTrezorExtendedPublicKey(xpub, chain);
|
|
193
|
+
} catch {
|
|
194
|
+
return xpub;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
97
198
|
function decodeOpReturnData(script: Uint8Array): string | null {
|
|
98
199
|
if (script.length < 2 || script[0] !== 0x6a) return null;
|
|
99
200
|
const dataLen = script[1];
|
|
@@ -151,12 +252,12 @@ function getPrevoutAmount(input: {
|
|
|
151
252
|
return undefined;
|
|
152
253
|
}
|
|
153
254
|
|
|
154
|
-
function normalizeTrezorSignature(signatureHex: string) {
|
|
255
|
+
export function normalizeTrezorSignature(signatureHex: string, chain: Chain) {
|
|
155
256
|
const signature = Buffer.from(signatureHex, "hex");
|
|
156
257
|
const derLength = signature[1] !== undefined ? signature[1] + 2 : undefined;
|
|
157
258
|
|
|
158
259
|
if (derLength !== undefined && signature.length === derLength) {
|
|
159
|
-
return new Uint8Array([...signature, 0x01]);
|
|
260
|
+
return new Uint8Array([...signature, chain === Chain.BitcoinCash ? BCHSigHash.ALL : 0x01]);
|
|
160
261
|
}
|
|
161
262
|
|
|
162
263
|
return new Uint8Array(signature);
|
|
@@ -356,10 +457,20 @@ function buildUtxoOutputsForTrezor(
|
|
|
356
457
|
return outputs;
|
|
357
458
|
}
|
|
358
459
|
|
|
460
|
+
function shouldUseTrezorPsbtSigner(chain: Chain) {
|
|
461
|
+
return chain === Chain.Bitcoin || chain === Chain.Litecoin;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function shouldUseTrezorSerializedSigner(chain: Chain) {
|
|
465
|
+
return chain === Chain.BitcoinCash || chain === Chain.Dash || chain === Chain.Dogecoin;
|
|
466
|
+
}
|
|
467
|
+
|
|
359
468
|
async function getTrezorWallet<T extends Chain>({
|
|
469
|
+
address: providedAddress,
|
|
360
470
|
chain,
|
|
361
471
|
derivationPath,
|
|
362
472
|
}: {
|
|
473
|
+
address?: string;
|
|
363
474
|
chain: T;
|
|
364
475
|
derivationPath: DerivationPathArray;
|
|
365
476
|
}) {
|
|
@@ -573,13 +684,16 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
573
684
|
throw new SwapKitError({ errorKey: "wallet_trezor_derivation_path_not_supported", info: { derivationPath } });
|
|
574
685
|
}
|
|
575
686
|
|
|
687
|
+
const resolvedScriptType = scriptType;
|
|
576
688
|
const coin = chain.toLowerCase();
|
|
577
689
|
|
|
578
690
|
const getAddress = async (path: DerivationPathArray = derivationPath) => {
|
|
579
691
|
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
692
|
+
const pathString = derivationPathToString(path);
|
|
580
693
|
const { success, payload } = await TrezorConnect.getAddress({
|
|
581
694
|
coin,
|
|
582
|
-
|
|
695
|
+
...TREZOR_KEEP_SESSION_PARAMS,
|
|
696
|
+
path: pathString,
|
|
583
697
|
showOnTrezor: false,
|
|
584
698
|
});
|
|
585
699
|
|
|
@@ -597,46 +711,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
597
711
|
return payload.address;
|
|
598
712
|
};
|
|
599
713
|
|
|
600
|
-
|
|
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();
|
|
714
|
+
const address = providedAddress ?? (await getAddress());
|
|
640
715
|
const baseToolbox = getUtxoToolbox(chain);
|
|
641
716
|
|
|
642
717
|
const signTransaction = async (tx: Transaction, inputs: UTXOType[], memo = "") => {
|
|
@@ -651,7 +726,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
651
726
|
address,
|
|
652
727
|
memo,
|
|
653
728
|
chain,
|
|
654
|
-
|
|
729
|
+
resolvedScriptType,
|
|
655
730
|
toCashAddress,
|
|
656
731
|
stripPrefix,
|
|
657
732
|
);
|
|
@@ -661,7 +736,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
661
736
|
amount: value,
|
|
662
737
|
prev_hash: hash,
|
|
663
738
|
prev_index: index,
|
|
664
|
-
script_type:
|
|
739
|
+
script_type: resolvedScriptType.input,
|
|
665
740
|
}));
|
|
666
741
|
|
|
667
742
|
const result = await TrezorConnect.signTransaction({ coin, inputs: trezorInputs, outputs });
|
|
@@ -687,7 +762,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
687
762
|
async function getFallbackDerivation(): Promise<TrezorBip32Derivation> {
|
|
688
763
|
if (!fallbackPublicKey) {
|
|
689
764
|
const accountInfo = await getExtendedPublicKeyInfo();
|
|
690
|
-
const accountKey = HDKey.fromExtendedKey(accountInfo.xpub);
|
|
765
|
+
const accountKey = HDKey.fromExtendedKey(accountInfo.xpub, network.bip32);
|
|
691
766
|
const leaf = accountKey.derive(`m/${Number(derivationPath[3] ?? 0)}/${Number(derivationPath[4] ?? 0)}`);
|
|
692
767
|
|
|
693
768
|
if (!leaf.publicKey) {
|
|
@@ -730,7 +805,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
730
805
|
amount,
|
|
731
806
|
prev_hash: hexEncode.encode(input.txid),
|
|
732
807
|
prev_index: input.index,
|
|
733
|
-
script_type:
|
|
808
|
+
script_type: resolvedScriptType.input,
|
|
734
809
|
...(input.sequence !== undefined ? { sequence: input.sequence } : {}),
|
|
735
810
|
});
|
|
736
811
|
}
|
|
@@ -742,13 +817,14 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
742
817
|
address,
|
|
743
818
|
"",
|
|
744
819
|
chain,
|
|
745
|
-
|
|
820
|
+
resolvedScriptType,
|
|
746
821
|
toCashAddress,
|
|
747
822
|
stripPrefix,
|
|
748
823
|
);
|
|
749
824
|
|
|
750
825
|
const result = await TrezorConnect.signTransaction({
|
|
751
826
|
coin,
|
|
827
|
+
...TREZOR_KEEP_SESSION_PARAMS,
|
|
752
828
|
inputs: trezorInputs,
|
|
753
829
|
locktime: tx.lockTime,
|
|
754
830
|
outputs,
|
|
@@ -767,12 +843,71 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
767
843
|
const pubkey = signerPubkeys[inputIndex];
|
|
768
844
|
if (!(signatureHex && pubkey)) return;
|
|
769
845
|
|
|
770
|
-
tx.updateInput(inputIndex, { partialSig: [[pubkey, normalizeTrezorSignature(signatureHex)]] });
|
|
846
|
+
tx.updateInput(inputIndex, { partialSig: [[pubkey, normalizeTrezorSignature(signatureHex, chain)]] });
|
|
771
847
|
});
|
|
772
848
|
|
|
773
849
|
return tx;
|
|
774
850
|
};
|
|
775
851
|
|
|
852
|
+
const signSerializedTransaction = async (tx: Transaction) => {
|
|
853
|
+
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
854
|
+
const { hex: hexEncode } = await import("@scure/base");
|
|
855
|
+
const address_n = hardenDerivationPath(derivationPath);
|
|
856
|
+
const network = getNetworkForChain(chain as UTXOChain);
|
|
857
|
+
|
|
858
|
+
const trezorInputs = [];
|
|
859
|
+
for (let inputIndex = 0; inputIndex < tx.inputsLength; inputIndex++) {
|
|
860
|
+
const input = tx.getInput(inputIndex);
|
|
861
|
+
const amount = getPrevoutAmount(input);
|
|
862
|
+
|
|
863
|
+
if (!input.txid || input.index === undefined || !amount) {
|
|
864
|
+
throw new SwapKitError({
|
|
865
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
866
|
+
info: { chain, error: `Input ${inputIndex} is missing prevout data required by Trezor` },
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
trezorInputs.push({
|
|
871
|
+
address_n,
|
|
872
|
+
amount,
|
|
873
|
+
prev_hash: hexEncode.encode(input.txid),
|
|
874
|
+
prev_index: input.index,
|
|
875
|
+
script_type: resolvedScriptType.input,
|
|
876
|
+
...(input.sequence !== undefined ? { sequence: input.sequence } : {}),
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
const outputs = buildUtxoOutputsForTrezor(
|
|
881
|
+
tx,
|
|
882
|
+
network,
|
|
883
|
+
address_n,
|
|
884
|
+
address,
|
|
885
|
+
"",
|
|
886
|
+
chain,
|
|
887
|
+
resolvedScriptType,
|
|
888
|
+
toCashAddress,
|
|
889
|
+
stripPrefix,
|
|
890
|
+
);
|
|
891
|
+
|
|
892
|
+
const result = await TrezorConnect.signTransaction({
|
|
893
|
+
coin,
|
|
894
|
+
inputs: trezorInputs,
|
|
895
|
+
locktime: tx.lockTime,
|
|
896
|
+
outputs,
|
|
897
|
+
version: tx.version,
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
if (result.success) {
|
|
901
|
+
return result.payload.serializedTx;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
const payload = result.payload as { error?: string; code?: string };
|
|
905
|
+
throw new SwapKitError({
|
|
906
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
907
|
+
info: { chain, code: payload?.code ?? "unknown", error: payload?.error ?? "unknown", payload },
|
|
908
|
+
});
|
|
909
|
+
};
|
|
910
|
+
|
|
776
911
|
const signTransactionWithMultipleInputs = async (
|
|
777
912
|
tx: Transaction,
|
|
778
913
|
inputs: Array<{ hash: string; index: number; value: number; derivationIndex: number; isChange: boolean }>,
|
|
@@ -789,7 +924,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
789
924
|
address,
|
|
790
925
|
memo,
|
|
791
926
|
chain,
|
|
792
|
-
|
|
927
|
+
resolvedScriptType,
|
|
793
928
|
toCashAddress,
|
|
794
929
|
stripPrefix,
|
|
795
930
|
);
|
|
@@ -802,7 +937,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
802
937
|
amount: value,
|
|
803
938
|
prev_hash: hash,
|
|
804
939
|
prev_index: inputIndex,
|
|
805
|
-
script_type:
|
|
940
|
+
script_type: resolvedScriptType.input,
|
|
806
941
|
};
|
|
807
942
|
});
|
|
808
943
|
|
|
@@ -897,12 +1032,15 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
897
1032
|
return txHash;
|
|
898
1033
|
};
|
|
899
1034
|
|
|
900
|
-
const toolbox =
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1035
|
+
const toolbox = shouldUseTrezorPsbtSigner(chain)
|
|
1036
|
+
? await getUtxoToolbox(utxoChain, {
|
|
1037
|
+
signer: { getAddress: async () => address, signTransaction: signPsbtTransaction },
|
|
1038
|
+
})
|
|
1039
|
+
: baseToolbox;
|
|
1040
|
+
|
|
1041
|
+
const signAndBroadcastTransaction = shouldUseTrezorSerializedSigner(chain)
|
|
1042
|
+
? async (tx: Transaction) => baseToolbox.broadcastTx(await signSerializedTransaction(tx))
|
|
1043
|
+
: toolbox.signAndBroadcastTransaction;
|
|
906
1044
|
|
|
907
1045
|
async function getExtendedPublicKeyInfo({ accountIndex }: { accountIndex?: number } = {}) {
|
|
908
1046
|
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
@@ -912,7 +1050,8 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
912
1050
|
const cached = trezorXpubCache.get(cacheKey);
|
|
913
1051
|
if (cached) return cached;
|
|
914
1052
|
|
|
915
|
-
const
|
|
1053
|
+
const result = await TrezorConnect.getPublicKey({ coin, path });
|
|
1054
|
+
const { success, payload } = result;
|
|
916
1055
|
|
|
917
1056
|
if (!success) {
|
|
918
1057
|
throw new SwapKitError({
|
|
@@ -921,6 +1060,8 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
921
1060
|
});
|
|
922
1061
|
}
|
|
923
1062
|
|
|
1063
|
+
const xpub = normalizeTrezorExtendedPublicKey(payload.xpub, utxoChain);
|
|
1064
|
+
const xpubSegwit = tryNormalizeTrezorExtendedPublicKey(payload.xpubSegwit, utxoChain);
|
|
924
1065
|
const info = {
|
|
925
1066
|
accountIndex: getUTXOAccountIndexFromPath(resolvedAccountPath),
|
|
926
1067
|
chainCode: payload.chainCode,
|
|
@@ -928,8 +1069,8 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
928
1069
|
fingerprint: payload.fingerprint,
|
|
929
1070
|
path: payload.serializedPath,
|
|
930
1071
|
publicKey: payload.publicKey,
|
|
931
|
-
xpub
|
|
932
|
-
xpubSegwit
|
|
1072
|
+
xpub,
|
|
1073
|
+
xpubSegwit,
|
|
933
1074
|
};
|
|
934
1075
|
|
|
935
1076
|
trezorXpubCache.set(cacheKey, info);
|
|
@@ -955,7 +1096,12 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
955
1096
|
const resolvedAccountPath = getUTXOAccountPath({ accountIndex, chain: utxoChain, derivationPath });
|
|
956
1097
|
const fullPath = `${derivationPathToString(resolvedAccountPath)}/${Number(change)}/${index}`;
|
|
957
1098
|
|
|
958
|
-
const { success, payload } = await TrezorConnect.getAddress({
|
|
1099
|
+
const { success, payload } = await TrezorConnect.getAddress({
|
|
1100
|
+
coin,
|
|
1101
|
+
...TREZOR_KEEP_SESSION_PARAMS,
|
|
1102
|
+
path: fullPath,
|
|
1103
|
+
showOnTrezor: false,
|
|
1104
|
+
});
|
|
959
1105
|
|
|
960
1106
|
if (!success) {
|
|
961
1107
|
return undefined;
|
|
@@ -967,7 +1113,13 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
967
1113
|
finalAddress = bchToolbox.stripPrefix(payload.address);
|
|
968
1114
|
}
|
|
969
1115
|
|
|
970
|
-
const pubKeyResult = await TrezorConnect.getPublicKey({
|
|
1116
|
+
const pubKeyResult = await TrezorConnect.getPublicKey({
|
|
1117
|
+
coin,
|
|
1118
|
+
...TREZOR_KEEP_SESSION_PARAMS,
|
|
1119
|
+
path: fullPath,
|
|
1120
|
+
scriptType: resolvedScriptType.input,
|
|
1121
|
+
showOnTrezor: false,
|
|
1122
|
+
});
|
|
971
1123
|
const pubkey = pubKeyResult.success ? pubKeyResult.payload.publicKey : "";
|
|
972
1124
|
|
|
973
1125
|
return {
|
|
@@ -1004,7 +1156,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
1004
1156
|
showOnTrezor: false,
|
|
1005
1157
|
}));
|
|
1006
1158
|
|
|
1007
|
-
const { success, payload } = await TrezorConnect.getAddress({ bundle: paths });
|
|
1159
|
+
const { success, payload } = await TrezorConnect.getAddress({ ...TREZOR_KEEP_SESSION_PARAMS, bundle: paths });
|
|
1008
1160
|
|
|
1009
1161
|
if (!success || !Array.isArray(payload)) {
|
|
1010
1162
|
return [];
|
|
@@ -1047,6 +1199,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
1047
1199
|
deriveAddresses: deriveAddressesBatch,
|
|
1048
1200
|
getExtendedPublicKey,
|
|
1049
1201
|
getExtendedPublicKeyInfo,
|
|
1202
|
+
signAndBroadcastTransaction,
|
|
1050
1203
|
signTransaction,
|
|
1051
1204
|
signTransactionWithMultipleInputs,
|
|
1052
1205
|
transfer,
|
|
@@ -1059,9 +1212,61 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
1059
1212
|
}
|
|
1060
1213
|
}
|
|
1061
1214
|
|
|
1215
|
+
export async function getTrezorExtendedPublicKey(
|
|
1216
|
+
chain: Chain,
|
|
1217
|
+
derivationPath?: DerivationPathArray,
|
|
1218
|
+
{ accountIndex }: { accountIndex?: number } = {},
|
|
1219
|
+
): Promise<HardwareExtendedPublicKeyInfo | undefined> {
|
|
1220
|
+
if (![Chain.BitcoinCash, Chain.Bitcoin, Chain.Dash, Chain.Dogecoin, Chain.Litecoin].includes(chain)) {
|
|
1221
|
+
throw new SwapKitError({ errorKey: "wallet_chain_not_supported", info: { chain, wallet: WalletOption.TREZOR } });
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
const { TrezorConnect } = await initTrezorConnect();
|
|
1225
|
+
const utxoChain = chain as UTXOChain;
|
|
1226
|
+
const resolvedDerivationPath = derivationPath ?? (NetworkDerivationPath[chain] as DerivationPathArray);
|
|
1227
|
+
const coin = chain.toLowerCase();
|
|
1228
|
+
|
|
1229
|
+
const resolvedAccountPath = getUTXOAccountPath({
|
|
1230
|
+
accountIndex,
|
|
1231
|
+
chain: utxoChain,
|
|
1232
|
+
derivationPath: resolvedDerivationPath,
|
|
1233
|
+
});
|
|
1234
|
+
const path = derivationPathToString(resolvedAccountPath);
|
|
1235
|
+
const cacheKey = `${chain}:${path}`;
|
|
1236
|
+
const cached = trezorXpubCache.get(cacheKey);
|
|
1237
|
+
if (cached) return cached;
|
|
1238
|
+
|
|
1239
|
+
const { success, payload } = await TrezorConnect.getPublicKey({ coin, path, showOnTrezor: true });
|
|
1240
|
+
|
|
1241
|
+
if (!success) {
|
|
1242
|
+
throw new SwapKitError({
|
|
1243
|
+
errorKey: "wallet_trezor_failed_to_get_public_key",
|
|
1244
|
+
info: { chain, error: (payload as { error: string; code?: string }).error || "Unknown error" },
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
const info = {
|
|
1249
|
+
accountIndex: getUTXOAccountIndexFromPath(resolvedAccountPath),
|
|
1250
|
+
chainCode: payload.chainCode,
|
|
1251
|
+
depth: payload.depth,
|
|
1252
|
+
fingerprint: payload.fingerprint,
|
|
1253
|
+
path: payload.serializedPath,
|
|
1254
|
+
publicKey: payload.publicKey,
|
|
1255
|
+
xpub: normalizeTrezorExtendedPublicKey(payload.xpub, utxoChain),
|
|
1256
|
+
xpubSegwit: tryNormalizeTrezorExtendedPublicKey(payload.xpubSegwit, utxoChain),
|
|
1257
|
+
};
|
|
1258
|
+
|
|
1259
|
+
trezorXpubCache.set(cacheKey, info);
|
|
1260
|
+
return info;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1062
1263
|
export const trezorWallet = createWallet({
|
|
1063
1264
|
connect: ({ addChain, supportedChains, walletType }) =>
|
|
1064
|
-
async function connectTrezor(
|
|
1265
|
+
async function connectTrezor(
|
|
1266
|
+
chains: Chain[],
|
|
1267
|
+
derivationPath: DerivationPathArray,
|
|
1268
|
+
{ address }: ConnectTrezorOptions = {},
|
|
1269
|
+
) {
|
|
1065
1270
|
const [chain] = filterSupportedChains({ chains, supportedChains, walletType });
|
|
1066
1271
|
if (!chain) {
|
|
1067
1272
|
throw new SwapKitError({
|
|
@@ -1117,7 +1322,7 @@ export const trezorWallet = createWallet({
|
|
|
1117
1322
|
transports: resolvedTransports,
|
|
1118
1323
|
});
|
|
1119
1324
|
|
|
1120
|
-
const wallet = await getTrezorWallet({ chain, derivationPath });
|
|
1325
|
+
const wallet = await getTrezorWallet({ address, chain, derivationPath });
|
|
1121
1326
|
|
|
1122
1327
|
addChain({ ...wallet, chain, disconnect: disconnectTrezorSession, walletType });
|
|
1123
1328
|
|
|
@@ -1131,15 +1336,19 @@ export const trezorWallet = createWallet({
|
|
|
1131
1336
|
[Chain.Berachain]: true,
|
|
1132
1337
|
[Chain.BinanceSmartChain]: true,
|
|
1133
1338
|
[Chain.Bitcoin]: true,
|
|
1339
|
+
[Chain.BitcoinCash]: true,
|
|
1340
|
+
[Chain.Dash]: true,
|
|
1134
1341
|
[Chain.Ethereum]: true,
|
|
1135
1342
|
[Chain.Gnosis]: true,
|
|
1343
|
+
[Chain.Dogecoin]: true,
|
|
1136
1344
|
[Chain.Litecoin]: true,
|
|
1137
1345
|
[Chain.Monad]: true,
|
|
1138
1346
|
[Chain.Optimism]: true,
|
|
1139
1347
|
[Chain.Polygon]: true,
|
|
1140
1348
|
[Chain.XLayer]: true,
|
|
1141
|
-
//
|
|
1349
|
+
// ZEC: pending PCZT/TrezorConnect validation
|
|
1142
1350
|
},
|
|
1351
|
+
getExtendedPublicKey: getTrezorExtendedPublicKey,
|
|
1143
1352
|
name: "connectTrezor",
|
|
1144
1353
|
supportedChains: [
|
|
1145
1354
|
Chain.Arbitrum,
|
package/dist/chunk-mrsfcest.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
var A=require("@scure/base");async function E(q){let{RawTx:D}=await import("@swapkit/utxo-signer"),v=[];for(let j=0;j<q.inputsLength;j++){let f=q.getInput(j);if(!f.txid||f.index===void 0)throw Error(`PSBT input ${j} is missing txid/index`);let B=f.nonWitnessUtxo?A.hex.encode(D.encode(f.nonWitnessUtxo)):"",z=f.witnessUtxo?{script:f.witnessUtxo.script,value:Number(f.witnessUtxo.amount)}:void 0;v.push({hash:A.hex.encode(f.txid),index:f.index,txHex:B,value:z?.value??0,witnessUtxo:z})}return v}function G({legacyClient:q,chain:D,address:v}){return{getAddress:async()=>v,signTransaction:async(j)=>{let f=await E(j),B=await q.signTransaction(j,f),{Transaction:z}=await import("@swapkit/utxo-signer");return z.fromRaw(A.hex.decode(B))}}}
|
|
2
|
-
|
|
3
|
-
//# debugId=E761B05D18A24EBF64756E2164756E21
|
|
4
|
-
//# sourceMappingURL=chunk-mrsfcest.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/ledger/clients/utxo-legacy-adapter.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import { hex } from \"@scure/base\";\nimport type { UTXOChain } from \"@swapkit/helpers\";\nimport type { UTXOType } from \"@swapkit/toolboxes/utxo\";\nimport type { Transaction } from \"@swapkit/utxo-signer\";\n\n/**\n * Extract per-input metadata from a V3 PSBT in the shape the legacy\n * `@ledgerhq/hw-app-btc.createPaymentTransaction` adapter expects.\n *\n * For segwit inputs the SwapKit V3 API populates `witnessUtxo`; for legacy\n * (BCH/DOGE/DASH) it populates `nonWitnessUtxo` with the full prior-tx bytes.\n * We re-encode the parsed `nonWitnessUtxo` back to hex via `RawTx.encode` so\n * `btcApp.splitTransaction(hex)` can consume it.\n *\n * Single-address account assumption: all inputs share our derivation path.\n */\nexport async function extractInputsFromPsbt(tx: Transaction): Promise<UTXOType[]> {\n const { RawTx } = await import(\"@swapkit/utxo-signer\");\n const inputs: UTXOType[] = [];\n\n for (let i = 0; i < tx.inputsLength; i++) {\n const input = tx.getInput(i);\n\n if (!input.txid || input.index === undefined) {\n throw new Error(`PSBT input ${i} is missing txid/index`);\n }\n\n const txHex = input.nonWitnessUtxo ? hex.encode(RawTx.encode(input.nonWitnessUtxo)) : \"\";\n const witnessUtxo = input.witnessUtxo\n ? { script: input.witnessUtxo.script, value: Number(input.witnessUtxo.amount) }\n : undefined;\n\n inputs.push({\n hash: hex.encode(input.txid),\n index: input.index,\n txHex,\n value: witnessUtxo?.value ?? 0,\n witnessUtxo,\n } as UTXOType);\n }\n\n return inputs;\n}\n\n/**\n * Build a toolbox-compatible signer from the existing legacy Ledger UTXO\n * client. The toolbox synthesizes `signAndBroadcastTransaction` on top of\n * `signer.signTransaction(tx) → Transaction`.\n */\nexport function createLegacyPsbtSigner({\n legacyClient,\n chain: _chain,\n address,\n}: {\n legacyClient: { signTransaction: (tx: Transaction, inputUtxos: UTXOType[]) => Promise<string> };\n chain: UTXOChain;\n address: string;\n}) {\n return {\n getAddress: async () => address,\n signTransaction: async (tx: Transaction): Promise<Transaction> => {\n const inputUtxos = await extractInputsFromPsbt(tx);\n const signedTxHex = await legacyClient.signTransaction(tx, inputUtxos);\n\n const { Transaction: TxClass } = await import(\"@swapkit/utxo-signer\");\n // `Transaction.fromRaw` parses a serialised tx (no PSBT envelope) — exactly\n // what `createPaymentTransaction` returns.\n return TxClass.fromRaw(hex.decode(signedTxHex));\n },\n };\n}\n"
|
|
6
|
-
],
|
|
7
|
-
"mappings": "AAAoB,IAApB,yBAgBA,eAAsB,CAAqB,CAAC,EAAsC,CAChF,IAAQ,SAAU,KAAa,gCACzB,EAAqB,CAAC,EAE5B,QAAS,EAAI,EAAG,EAAI,EAAG,aAAc,IAAK,CACxC,IAAM,EAAQ,EAAG,SAAS,CAAC,EAE3B,GAAI,CAAC,EAAM,MAAQ,EAAM,QAAU,OACjC,MAAU,MAAM,cAAc,yBAAyB,EAGzD,IAAM,EAAQ,EAAM,eAAiB,MAAI,OAAO,EAAM,OAAO,EAAM,cAAc,CAAC,EAAI,GAChF,EAAc,EAAM,YACtB,CAAE,OAAQ,EAAM,YAAY,OAAQ,MAAO,OAAO,EAAM,YAAY,MAAM,CAAE,EAC5E,OAEJ,EAAO,KAAK,CACV,KAAM,MAAI,OAAO,EAAM,IAAI,EAC3B,MAAO,EAAM,MACb,QACA,MAAO,GAAa,OAAS,EAC7B,aACF,CAAa,EAGf,OAAO,EAQF,SAAS,CAAsB,EACpC,eACA,MAAO,EACP,WAKC,CACD,MAAO,CACL,WAAY,SAAY,EACxB,gBAAiB,MAAO,IAA0C,CAChE,IAAM,EAAa,MAAM,EAAsB,CAAE,EAC3C,EAAc,MAAM,EAAa,gBAAgB,EAAI,CAAU,GAE7D,YAAa,GAAY,KAAa,gCAG9C,OAAO,EAAQ,QAAQ,MAAI,OAAO,CAAW,CAAC,EAElD",
|
|
8
|
-
"debugId": "E761B05D18A24EBF64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
package/dist/chunk-px09mwnt.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{d as E}from"./chunk-n05bv2n5.js";import{hex as B}from"@scure/base";async function G(q){let{RawTx:D}=await import("@swapkit/utxo-signer"),v=[];for(let j=0;j<q.inputsLength;j++){let f=q.getInput(j);if(!f.txid||f.index===void 0)throw Error(`PSBT input ${j} is missing txid/index`);let A=f.nonWitnessUtxo?B.encode(D.encode(f.nonWitnessUtxo)):"",z=f.witnessUtxo?{script:f.witnessUtxo.script,value:Number(f.witnessUtxo.amount)}:void 0;v.push({hash:B.encode(f.txid),index:f.index,txHex:A,value:z?.value??0,witnessUtxo:z})}return v}function K({legacyClient:q,chain:D,address:v}){return{getAddress:async()=>v,signTransaction:async(j)=>{let f=await G(j),A=await q.signTransaction(j,f),{Transaction:z}=await import("@swapkit/utxo-signer");return z.fromRaw(B.decode(A))}}}export{G as extractInputsFromPsbt,K as createLegacyPsbtSigner};
|
|
2
|
-
|
|
3
|
-
//# debugId=95BF8F59DBE0DD4C64756E2164756E21
|
|
4
|
-
//# sourceMappingURL=chunk-px09mwnt.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/ledger/clients/utxo-legacy-adapter.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import { hex } from \"@scure/base\";\nimport type { UTXOChain } from \"@swapkit/helpers\";\nimport type { UTXOType } from \"@swapkit/toolboxes/utxo\";\nimport type { Transaction } from \"@swapkit/utxo-signer\";\n\n/**\n * Extract per-input metadata from a V3 PSBT in the shape the legacy\n * `@ledgerhq/hw-app-btc.createPaymentTransaction` adapter expects.\n *\n * For segwit inputs the SwapKit V3 API populates `witnessUtxo`; for legacy\n * (BCH/DOGE/DASH) it populates `nonWitnessUtxo` with the full prior-tx bytes.\n * We re-encode the parsed `nonWitnessUtxo` back to hex via `RawTx.encode` so\n * `btcApp.splitTransaction(hex)` can consume it.\n *\n * Single-address account assumption: all inputs share our derivation path.\n */\nexport async function extractInputsFromPsbt(tx: Transaction): Promise<UTXOType[]> {\n const { RawTx } = await import(\"@swapkit/utxo-signer\");\n const inputs: UTXOType[] = [];\n\n for (let i = 0; i < tx.inputsLength; i++) {\n const input = tx.getInput(i);\n\n if (!input.txid || input.index === undefined) {\n throw new Error(`PSBT input ${i} is missing txid/index`);\n }\n\n const txHex = input.nonWitnessUtxo ? hex.encode(RawTx.encode(input.nonWitnessUtxo)) : \"\";\n const witnessUtxo = input.witnessUtxo\n ? { script: input.witnessUtxo.script, value: Number(input.witnessUtxo.amount) }\n : undefined;\n\n inputs.push({\n hash: hex.encode(input.txid),\n index: input.index,\n txHex,\n value: witnessUtxo?.value ?? 0,\n witnessUtxo,\n } as UTXOType);\n }\n\n return inputs;\n}\n\n/**\n * Build a toolbox-compatible signer from the existing legacy Ledger UTXO\n * client. The toolbox synthesizes `signAndBroadcastTransaction` on top of\n * `signer.signTransaction(tx) → Transaction`.\n */\nexport function createLegacyPsbtSigner({\n legacyClient,\n chain: _chain,\n address,\n}: {\n legacyClient: { signTransaction: (tx: Transaction, inputUtxos: UTXOType[]) => Promise<string> };\n chain: UTXOChain;\n address: string;\n}) {\n return {\n getAddress: async () => address,\n signTransaction: async (tx: Transaction): Promise<Transaction> => {\n const inputUtxos = await extractInputsFromPsbt(tx);\n const signedTxHex = await legacyClient.signTransaction(tx, inputUtxos);\n\n const { Transaction: TxClass } = await import(\"@swapkit/utxo-signer\");\n // `Transaction.fromRaw` parses a serialised tx (no PSBT envelope) — exactly\n // what `createPaymentTransaction` returns.\n return TxClass.fromRaw(hex.decode(signedTxHex));\n },\n };\n}\n"
|
|
6
|
-
],
|
|
7
|
-
"mappings": "wCAAA,cAAS,oBAgBT,eAAsB,CAAqB,CAAC,EAAsC,CAChF,IAAQ,SAAU,KAAa,gCACzB,EAAqB,CAAC,EAE5B,QAAS,EAAI,EAAG,EAAI,EAAG,aAAc,IAAK,CACxC,IAAM,EAAQ,EAAG,SAAS,CAAC,EAE3B,GAAI,CAAC,EAAM,MAAQ,EAAM,QAAU,OACjC,MAAU,MAAM,cAAc,yBAAyB,EAGzD,IAAM,EAAQ,EAAM,eAAiB,EAAI,OAAO,EAAM,OAAO,EAAM,cAAc,CAAC,EAAI,GAChF,EAAc,EAAM,YACtB,CAAE,OAAQ,EAAM,YAAY,OAAQ,MAAO,OAAO,EAAM,YAAY,MAAM,CAAE,EAC5E,OAEJ,EAAO,KAAK,CACV,KAAM,EAAI,OAAO,EAAM,IAAI,EAC3B,MAAO,EAAM,MACb,QACA,MAAO,GAAa,OAAS,EAC7B,aACF,CAAa,EAGf,OAAO,EAQF,SAAS,CAAsB,EACpC,eACA,MAAO,EACP,WAKC,CACD,MAAO,CACL,WAAY,SAAY,EACxB,gBAAiB,MAAO,IAA0C,CAChE,IAAM,EAAa,MAAM,EAAsB,CAAE,EAC3C,EAAc,MAAM,EAAa,gBAAgB,EAAI,CAAU,GAE7D,YAAa,GAAY,KAAa,gCAG9C,OAAO,EAAQ,QAAQ,EAAI,OAAO,CAAW,CAAC,EAElD",
|
|
8
|
-
"debugId": "95BF8F59DBE0DD4C64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|