@swapkit/wallet-hardware 4.8.1 → 4.8.3

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.
Files changed (34) hide show
  1. package/package.json +3 -3
  2. package/src/index.ts +1 -0
  3. package/src/keepkey/chains/cosmos.ts +69 -0
  4. package/src/keepkey/chains/evm.ts +141 -0
  5. package/src/keepkey/chains/mayachain.ts +98 -0
  6. package/src/keepkey/chains/ripple.ts +88 -0
  7. package/src/keepkey/chains/thorchain.ts +93 -0
  8. package/src/keepkey/chains/utxo.ts +364 -0
  9. package/src/keepkey/coins.ts +67 -0
  10. package/src/keepkey/index.ts +174 -0
  11. package/src/ledger/clients/cosmos.ts +84 -0
  12. package/src/ledger/clients/evm.ts +186 -0
  13. package/src/ledger/clients/near.ts +63 -0
  14. package/src/ledger/clients/sui.ts +130 -0
  15. package/src/ledger/clients/thorchain/common.ts +93 -0
  16. package/src/ledger/clients/thorchain/helpers.ts +120 -0
  17. package/src/ledger/clients/thorchain/index.ts +87 -0
  18. package/src/ledger/clients/thorchain/lib.ts +258 -0
  19. package/src/ledger/clients/thorchain/utils.ts +69 -0
  20. package/src/ledger/clients/tron.ts +85 -0
  21. package/src/ledger/clients/utxo-legacy-adapter.ts +71 -0
  22. package/src/ledger/clients/utxo-psbt.ts +145 -0
  23. package/src/ledger/clients/utxo.ts +359 -0
  24. package/src/ledger/clients/xrp.ts +50 -0
  25. package/src/ledger/cosmosTypes.ts +98 -0
  26. package/src/ledger/helpers/getLedgerAddress.ts +76 -0
  27. package/src/ledger/helpers/getLedgerClient.ts +124 -0
  28. package/src/ledger/helpers/getLedgerTransport.ts +102 -0
  29. package/src/ledger/helpers/index.ts +3 -0
  30. package/src/ledger/index.ts +546 -0
  31. package/src/ledger/interfaces/CosmosLedgerInterface.ts +54 -0
  32. package/src/ledger/types.ts +42 -0
  33. package/src/trezor/evmSigner.ts +210 -0
  34. package/src/trezor/index.ts +847 -0
@@ -0,0 +1,546 @@
1
+ import {
2
+ type AssetValue,
3
+ Chain,
4
+ type DerivationPathArray,
5
+ derivationPathToString,
6
+ FeeOption,
7
+ filterSupportedChains,
8
+ type GenericTransferParams,
9
+ getRPCUrl,
10
+ NetworkDerivationPath,
11
+ SwapKitError,
12
+ THORConfig,
13
+ type UTXOChain,
14
+ WalletOption,
15
+ } from "@swapkit/helpers";
16
+ import type { ThorchainDepositParams } from "@swapkit/toolboxes/cosmos";
17
+ import {
18
+ addInputsAndOutputs,
19
+ assertDerivationIndex,
20
+ compileMemo,
21
+ createHDWalletHelpers,
22
+ getUTXOAccountIndexFromPath,
23
+ getUTXOAccountPath,
24
+ getUTXOAddressPath,
25
+ getUtxoApi,
26
+ type UTXOBuildTxParams,
27
+ type UTXOForMultiAddressTransfer,
28
+ } from "@swapkit/toolboxes/utxo";
29
+ import type { Transaction } from "@swapkit/utxo-signer";
30
+ import { createWallet, getWalletSupportedChains } from "@swapkit/wallet-core";
31
+ import { getLedgerAddress, getLedgerClient } from "./helpers";
32
+
33
+ export const ledgerWallet = createWallet({
34
+ connect: ({ addChain, supportedChains, walletType }) =>
35
+ async function connectLedger(chains: Chain[], derivationPath?: DerivationPathArray) {
36
+ const [chain] = filterSupportedChains({ chains, supportedChains, walletType });
37
+
38
+ if (!chain) return false;
39
+
40
+ const resolvedPath = derivationPath ?? (NetworkDerivationPath[chain] as DerivationPathArray | undefined);
41
+ const walletMethods = await getWalletMethods({ chain, derivationPath: resolvedPath });
42
+
43
+ addChain({ ...walletMethods, chain, walletType: WalletOption.LEDGER });
44
+
45
+ return true;
46
+ },
47
+ directSigningSupport: {
48
+ [Chain.Arbitrum]: true,
49
+ [Chain.Aurora]: true,
50
+ [Chain.Avalanche]: true,
51
+ [Chain.Base]: true,
52
+ [Chain.Berachain]: true,
53
+ [Chain.BinanceSmartChain]: true,
54
+ [Chain.Ethereum]: true,
55
+ [Chain.Gnosis]: true,
56
+ [Chain.Monad]: true,
57
+ [Chain.Bitcoin]: true,
58
+ [Chain.BitcoinCash]: true,
59
+ [Chain.Cosmos]: true,
60
+ [Chain.Dash]: true,
61
+ [Chain.Dogecoin]: true,
62
+ [Chain.Litecoin]: true,
63
+ [Chain.Near]: true,
64
+ [Chain.Optimism]: true,
65
+ [Chain.Polygon]: true,
66
+ [Chain.Ripple]: true,
67
+ [Chain.Sui]: true,
68
+ [Chain.Tron]: true,
69
+ [Chain.XLayer]: true,
70
+ // ZEC: still on bespoke signPCZT path
71
+ // THORChain: needs signAmino added to THORChainLedger (V3 plan PR)
72
+ },
73
+ name: "connectLedger",
74
+ supportedChains: [
75
+ Chain.Arbitrum,
76
+ Chain.Aurora,
77
+ Chain.Avalanche,
78
+ Chain.Base,
79
+ Chain.Berachain,
80
+ Chain.BinanceSmartChain,
81
+ Chain.Bitcoin,
82
+ Chain.BitcoinCash,
83
+ Chain.Cosmos,
84
+ Chain.Dash,
85
+ Chain.Dogecoin,
86
+ Chain.Ethereum,
87
+ Chain.Gnosis,
88
+ Chain.Litecoin,
89
+ Chain.Monad,
90
+ Chain.Near,
91
+ Chain.Optimism,
92
+ Chain.Polygon,
93
+ Chain.Ripple,
94
+ Chain.Sui,
95
+ Chain.THORChain,
96
+ Chain.XLayer,
97
+ Chain.Tron,
98
+ Chain.Zcash,
99
+ ],
100
+ walletType: WalletOption.LEDGER,
101
+ });
102
+
103
+ export const LEDGER_SUPPORTED_CHAINS = getWalletSupportedChains(ledgerWallet);
104
+
105
+ // reduce memo length by removing trade limit
106
+ function reduceMemo(memo?: string, affiliateAddress = "t") {
107
+ if (!memo?.includes("=:")) return memo;
108
+
109
+ const removedAffiliate = memo.includes(`:${affiliateAddress}:`) ? memo.split(`:${affiliateAddress}:`)[0] : memo;
110
+
111
+ return removedAffiliate?.substring(0, removedAffiliate.lastIndexOf(":"));
112
+ }
113
+
114
+ function recursivelyOrderKeys(unordered: any) {
115
+ // If it's an array - recursively order any
116
+ // dictionary items within the array
117
+ if (Array.isArray(unordered)) {
118
+ unordered.forEach((item, index) => {
119
+ unordered[index] = recursivelyOrderKeys(item);
120
+ });
121
+ return unordered;
122
+ }
123
+
124
+ // If it's an object - let's order the keys
125
+ if (typeof unordered !== "object") return unordered;
126
+ const ordered: any = {};
127
+ const sortedKeys = Object.keys(unordered).sort();
128
+
129
+ for (const key of sortedKeys) {
130
+ ordered[key] = recursivelyOrderKeys(unordered[key]);
131
+ }
132
+
133
+ return ordered;
134
+ }
135
+
136
+ function stringifyKeysInOrder(data: any) {
137
+ return JSON.stringify(recursivelyOrderKeys(data));
138
+ }
139
+
140
+ async function getWalletMethods({ chain, derivationPath }: { chain: Chain; derivationPath?: DerivationPathArray }) {
141
+ switch (chain) {
142
+ case Chain.BitcoinCash:
143
+ case Chain.Bitcoin:
144
+ case Chain.Dash:
145
+ case Chain.Dogecoin:
146
+ case Chain.Litecoin:
147
+ case Chain.Zcash: {
148
+ const { getUtxoToolbox } = await import("@swapkit/toolboxes/utxo");
149
+ const utxoChain = chain as UTXOChain;
150
+
151
+ const signer = await getLedgerClient({ chain, derivationPath });
152
+
153
+ const address = await getLedgerAddress({ chain, ledgerClient: signer });
154
+
155
+ // V3 toolbox signer:
156
+ // - BTC/LTC use the modern `ledger-bitcoin` AppClient with native PSBT signing.
157
+ // - BCH/DOGE/DASH use the legacy `hw-app-btc` adapter that pulls
158
+ // `nonWitnessUtxo` (full prev-tx hex) out of the API PSBT.
159
+ // - ZEC stays on the bespoke `signPCZT` flow for now.
160
+ let toolboxSigner:
161
+ | { getAddress: () => Promise<string>; signTransaction: (tx: Transaction) => Promise<Transaction> }
162
+ | undefined;
163
+ if (chain === Chain.Bitcoin || chain === Chain.Litecoin) {
164
+ const { BitcoinPsbtLedger, LitecoinPsbtLedger } = await import("./clients/utxo-psbt");
165
+ const psbtClient =
166
+ chain === Chain.Bitcoin ? BitcoinPsbtLedger(derivationPath) : LitecoinPsbtLedger(derivationPath);
167
+ toolboxSigner = { getAddress: psbtClient.getAddress, signTransaction: psbtClient.signTransaction };
168
+ } else if (chain === Chain.BitcoinCash || chain === Chain.Dogecoin || chain === Chain.Dash) {
169
+ const { createLegacyPsbtSigner } = await import("./clients/utxo-legacy-adapter");
170
+ toolboxSigner = createLegacyPsbtSigner({ address, chain: utxoChain, legacyClient: signer });
171
+ }
172
+
173
+ const toolbox = toolboxSigner
174
+ ? await getUtxoToolbox(utxoChain, { signer: toolboxSigner })
175
+ : getUtxoToolbox(utxoChain);
176
+
177
+ const transfer = async (params: UTXOBuildTxParams) => {
178
+ const feeRate = params.feeRate || (await toolbox.getFeeRates())[FeeOption.Average];
179
+ const memo = [Chain.Bitcoin].includes(chain as typeof Chain.Bitcoin) ? params.memo : reduceMemo(params.memo);
180
+
181
+ const { tx, inputs } = await toolbox.createTransaction({
182
+ ...params,
183
+ feeRate,
184
+ fetchTxHex: true,
185
+ memo,
186
+ sender: address,
187
+ });
188
+
189
+ // Cast tx to Transaction - signTransaction handles both Transaction and ZcashTransaction
190
+ // via tx.unsignedTx which exists on both types
191
+ const txHex = await signer.signTransaction(tx as Transaction, inputs);
192
+ const txHash = await toolbox.broadcastTx(txHex);
193
+
194
+ return txHash;
195
+ };
196
+
197
+ async function getExtendedPublicKeyInfo({ accountIndex }: { accountIndex?: number } = {}) {
198
+ if (!signer.getExtendedPublicKey) return undefined;
199
+
200
+ const accountPath = getUTXOAccountPath({ accountIndex, chain: utxoChain, derivationPath });
201
+ const path = derivationPathToString(accountPath);
202
+ const ledgerPath = chain === Chain.Bitcoin || chain === Chain.Litecoin ? path : path.replace(/^m\//, "");
203
+ const xpub = await signer.getExtendedPublicKey(ledgerPath);
204
+
205
+ return { accountIndex: getUTXOAccountIndexFromPath(accountPath), path, xpub };
206
+ }
207
+
208
+ function getExtendedPublicKey() {
209
+ return getExtendedPublicKeyInfo();
210
+ }
211
+
212
+ async function deriveAddressAtIndex({
213
+ accountIndex,
214
+ index,
215
+ change = false,
216
+ }: {
217
+ accountIndex?: number;
218
+ index: number;
219
+ change?: boolean;
220
+ }) {
221
+ try {
222
+ const fullPath = getUTXOAddressPath({ accountIndex, chain: utxoChain, change, derivationPath, index });
223
+
224
+ const indexedSigner = await getLedgerClient({ chain: utxoChain, derivationPath: fullPath });
225
+ const derivedAddress = await getLedgerAddress({ chain: utxoChain, ledgerClient: indexedSigner });
226
+
227
+ return {
228
+ accountIndex: getUTXOAccountIndexFromPath(fullPath),
229
+ address: derivedAddress,
230
+ change,
231
+ index,
232
+ path: derivationPathToString(fullPath),
233
+ pubkey: "",
234
+ };
235
+ } catch {
236
+ return undefined;
237
+ }
238
+ }
239
+
240
+ async function deriveAddresses({
241
+ accountIndex,
242
+ count,
243
+ startIndex = 0,
244
+ change = false,
245
+ }: {
246
+ accountIndex?: number;
247
+ count: number;
248
+ startIndex?: number;
249
+ change?: boolean;
250
+ }) {
251
+ assertDerivationIndex("count", count);
252
+ assertDerivationIndex("startIndex", startIndex);
253
+
254
+ const addresses = await Promise.all(
255
+ Array.from({ length: count }, (_, i) =>
256
+ deriveAddressAtIndex({ accountIndex, change, index: startIndex + i }),
257
+ ),
258
+ );
259
+
260
+ return addresses.filter((address) => !!address);
261
+ }
262
+
263
+ const hdHelpers = createHDWalletHelpers({
264
+ chain: utxoChain,
265
+ deriveAddress: deriveAddressAtIndex,
266
+ getBalance: toolbox.getBalance,
267
+ getUtxos: (addr: string) => getUtxoApi(utxoChain).getUtxos({ address: addr, fetchTxHex: true }),
268
+ });
269
+
270
+ async function transferFromMultipleAddresses({
271
+ utxos,
272
+ recipient,
273
+ assetValue,
274
+ memo,
275
+ feeRate,
276
+ feeOptionKey,
277
+ changeAddress,
278
+ }: {
279
+ utxos: UTXOForMultiAddressTransfer[];
280
+ recipient: string;
281
+ assetValue: AssetValue;
282
+ memo?: string;
283
+ feeRate?: number;
284
+ feeOptionKey?: FeeOption;
285
+ changeAddress?: string;
286
+ }) {
287
+ if (!utxos.length) {
288
+ throw new SwapKitError("wallet_ledger_invalid_params", {
289
+ message: "No UTXOs provided for multi-address transfer",
290
+ });
291
+ }
292
+
293
+ const txFeeRate = feeRate || (await toolbox.getFeeRates())[feeOptionKey || FeeOption.Fast];
294
+ const memoScript = memo ? compileMemo(memo) : null;
295
+
296
+ const targetOutputs: Array<{ address: string; value: number } | { script: Uint8Array; value: number }> = [
297
+ { address: recipient, value: assetValue.getBaseValue("number") },
298
+ ];
299
+ if (memoScript) {
300
+ targetOutputs.push({ script: memoScript, value: 0 });
301
+ }
302
+
303
+ const basicUtxos = utxos.map(({ hash, index, value, txHex, witnessUtxo }) => ({
304
+ hash,
305
+ index,
306
+ txHex,
307
+ value,
308
+ witnessUtxo,
309
+ }));
310
+
311
+ const { inputs: selectedInputs, outputs } = toolbox.accumulative({
312
+ chain: utxoChain,
313
+ feeRate: txFeeRate,
314
+ inputs: basicUtxos,
315
+ outputs: targetOutputs,
316
+ });
317
+
318
+ if (!(selectedInputs && outputs)) {
319
+ throw new SwapKitError("wallet_ledger_connection_error", {
320
+ message: "Insufficient balance for multi-address transfer",
321
+ });
322
+ }
323
+
324
+ const { Transaction } = await import("@swapkit/utxo-signer");
325
+ const tx = new Transaction({ allowLegacyWitnessUtxo: true, version: 1 });
326
+ const senderAddress = changeAddress || utxos[0]?.address || recipient;
327
+
328
+ addInputsAndOutputs({
329
+ chain: utxoChain,
330
+ compiledMemo: memoScript,
331
+ inputs: selectedInputs,
332
+ outputs,
333
+ sender: senderAddress,
334
+ tx,
335
+ });
336
+
337
+ const basePath = getUTXOAccountPath({ chain: utxoChain, derivationPath });
338
+ const inputDerivationPaths = selectedInputs.map((input: { hash: string; index: number }) => {
339
+ const utxoInfo = utxos.find((u) => u.hash === input.hash && u.index === input.index);
340
+ const derivationIndex = utxoInfo?.derivationIndex ?? 0;
341
+ const isChange = utxoInfo?.isChange ?? false;
342
+ const fullPath = [...basePath, Number(isChange), derivationIndex] as unknown as DerivationPathArray;
343
+ return derivationPathToString(fullPath);
344
+ });
345
+
346
+ if (!signer.signTransactionWithMultiplePaths) {
347
+ throw new SwapKitError("wallet_ledger_method_not_supported", { method: "signTransactionWithMultiplePaths" });
348
+ }
349
+
350
+ const txHex = await signer.signTransactionWithMultiplePaths(tx, selectedInputs, inputDerivationPaths);
351
+ return toolbox.broadcastTx(txHex);
352
+ }
353
+
354
+ return {
355
+ ...toolbox,
356
+ ...hdHelpers,
357
+ address,
358
+ deriveAddressAtIndex,
359
+ deriveAddresses,
360
+ getExtendedPublicKey,
361
+ getExtendedPublicKeyInfo,
362
+ transfer,
363
+ transferFromMultipleAddresses,
364
+ };
365
+ }
366
+
367
+ case Chain.Ethereum:
368
+ case Chain.Avalanche:
369
+ case Chain.Arbitrum:
370
+ case Chain.Berachain:
371
+ case Chain.Optimism:
372
+ case Chain.Polygon:
373
+ case Chain.BinanceSmartChain:
374
+ case Chain.Base:
375
+ case Chain.Aurora:
376
+ case Chain.Gnosis:
377
+ case Chain.Monad:
378
+ case Chain.XLayer: {
379
+ const { getEvmToolboxAsync } = await import("@swapkit/toolboxes/evm");
380
+ const signer = await getLedgerClient({ chain, derivationPath });
381
+ const address = await getLedgerAddress({ chain, ledgerClient: signer });
382
+ const toolbox = await getEvmToolboxAsync(chain, { signer });
383
+
384
+ return { ...toolbox, address };
385
+ }
386
+
387
+ case Chain.Cosmos: {
388
+ const { createSigningStargateClient, getMsgSendDenom, getCosmosToolbox } = await import(
389
+ "@swapkit/toolboxes/cosmos"
390
+ );
391
+ const signer = await getLedgerClient({ chain, derivationPath });
392
+ const address = await getLedgerAddress({ chain, ledgerClient: signer });
393
+ const toolbox = await getCosmosToolbox(Chain.Cosmos, { signer });
394
+
395
+ const transfer = async ({ assetValue, recipient, memo }: GenericTransferParams) => {
396
+ if (!assetValue) throw new SwapKitError("wallet_ledger_invalid_asset");
397
+
398
+ const sendCoinsMessage = {
399
+ amount: [
400
+ {
401
+ amount: assetValue.getBaseValue("string"),
402
+ denom: getMsgSendDenom(`u${assetValue.symbol}`).toLowerCase(),
403
+ },
404
+ ],
405
+ fromAddress: address,
406
+ toAddress: recipient,
407
+ };
408
+
409
+ const rpcUrl = await getRPCUrl(chain);
410
+ const signingClient = await createSigningStargateClient(rpcUrl, signer, "0.007uatom");
411
+
412
+ const { transactionHash } = await signingClient.signAndBroadcast(
413
+ address,
414
+ [{ typeUrl: "/cosmos.bank.v1beta1.MsgSend", value: sendCoinsMessage }],
415
+ 2,
416
+ memo,
417
+ );
418
+
419
+ return transactionHash;
420
+ };
421
+
422
+ return { ...toolbox, address, transfer };
423
+ }
424
+
425
+ case Chain.THORChain: {
426
+ const { SignMode } = await import("cosmjs-types/cosmos/tx/signing/v1beta1/signing.js");
427
+ const { TxRaw } = await import("cosmjs-types/cosmos/tx/v1beta1/tx.js");
428
+ const importedSigning = await import("@cosmjs/proto-signing");
429
+ const encodePubkey = importedSigning.encodePubkey ?? importedSigning.default?.encodePubkey;
430
+ const makeAuthInfoBytes = importedSigning.makeAuthInfoBytes ?? importedSigning.default?.makeAuthInfoBytes;
431
+ const {
432
+ createStargateClient,
433
+ buildEncodedTxBody,
434
+ getCosmosToolbox,
435
+ buildAminoMsg,
436
+ getDefaultChainFee,
437
+ fromBase64,
438
+ parseAminoMessageForDirectSigning,
439
+ } = await import("@swapkit/toolboxes/cosmos");
440
+ const toolbox = getCosmosToolbox(chain);
441
+ const signer = await getLedgerClient({ chain, derivationPath });
442
+ const address = await getLedgerAddress({ chain, ledgerClient: signer });
443
+
444
+ const fee = getDefaultChainFee(chain);
445
+ const { pubkey: value, signTransaction, sign: signMessage } = signer;
446
+
447
+ // ANCHOR (@Chillios): Same parts in methods + can extract StargateClient init to toolbox
448
+ const thorchainTransfer = async ({
449
+ memo = "",
450
+ assetValue,
451
+ ...rest
452
+ }: GenericTransferParams | ThorchainDepositParams) => {
453
+ const account = await toolbox.getAccount(address);
454
+ if (!account) throw new SwapKitError("wallet_ledger_invalid_account");
455
+ if (!assetValue) throw new SwapKitError("wallet_ledger_invalid_asset");
456
+ if (!value) throw new SwapKitError("wallet_ledger_pubkey_not_found");
457
+
458
+ const { accountNumber, sequence: sequenceNumber } = account;
459
+ const sequence = (sequenceNumber || 0).toString();
460
+
461
+ const orderedMessages = recursivelyOrderKeys([buildAminoMsg({ assetValue, memo, sender: address, ...rest })]);
462
+
463
+ // get tx signing msg
464
+ const rawSendTx = stringifyKeysInOrder({
465
+ account_number: accountNumber?.toString(),
466
+ chain_id: THORConfig.chainId,
467
+ fee,
468
+ memo,
469
+ msgs: orderedMessages,
470
+ sequence,
471
+ });
472
+
473
+ const signatures = await signTransaction(rawSendTx, sequence);
474
+ if (!signatures) throw new SwapKitError("wallet_ledger_signing_error");
475
+
476
+ const pubkey = encodePubkey({ type: "tendermint/PubKeySecp256k1", value });
477
+ const msgs = orderedMessages.map(parseAminoMessageForDirectSigning);
478
+ const bodyBytes = await buildEncodedTxBody({ chain, memo, msgs });
479
+
480
+ const authInfoBytes = makeAuthInfoBytes(
481
+ [{ pubkey, sequence: Number(sequence) }],
482
+ fee.amount,
483
+ Number.parseInt(fee.gas, 10),
484
+ undefined,
485
+ undefined,
486
+ SignMode.SIGN_MODE_LEGACY_AMINO_JSON,
487
+ );
488
+
489
+ const signature = signatures?.[0]?.signature ? fromBase64(signatures[0].signature) : Uint8Array.from([]);
490
+
491
+ const txRaw = TxRaw.fromPartial({ authInfoBytes, bodyBytes, signatures: [signature] });
492
+ const txBytes = TxRaw.encode(txRaw).finish();
493
+ const rpcUrl = await getRPCUrl(Chain.THORChain);
494
+
495
+ const broadcaster = await createStargateClient(rpcUrl);
496
+ const { transactionHash } = await broadcaster.broadcastTx(txBytes);
497
+
498
+ return transactionHash;
499
+ };
500
+
501
+ const transfer = (params: GenericTransferParams) => thorchainTransfer(params);
502
+ const deposit = (params: ThorchainDepositParams) => thorchainTransfer(params);
503
+
504
+ return { ...toolbox, address, deposit, signMessage, transfer };
505
+ }
506
+
507
+ case Chain.Near: {
508
+ const { getNearToolbox } = await import("@swapkit/toolboxes/near");
509
+ const signer = await getLedgerClient({ chain, derivationPath });
510
+ const accountId = await signer.getAddress();
511
+ const toolbox = getNearToolbox({ signer });
512
+
513
+ return { ...toolbox, address: accountId };
514
+ }
515
+
516
+ case Chain.Ripple: {
517
+ const { getRippleToolbox } = await import("@swapkit/toolboxes/ripple");
518
+ const signer = await getLedgerClient({ chain, derivationPath });
519
+ const address = signer.getAddress();
520
+ const toolbox = getRippleToolbox({ signer });
521
+
522
+ return { ...toolbox, address };
523
+ }
524
+
525
+ case Chain.Tron: {
526
+ const { getTronToolbox } = await import("@swapkit/toolboxes/tron");
527
+ const signer = await getLedgerClient({ chain, derivationPath });
528
+ const address = await getLedgerAddress({ chain, ledgerClient: signer });
529
+ const toolbox = getTronToolbox({ signer });
530
+
531
+ return { ...toolbox, address };
532
+ }
533
+
534
+ case Chain.Sui: {
535
+ const { getSuiToolbox } = await import("@swapkit/toolboxes/sui");
536
+ const signer = await getLedgerClient({ chain, derivationPath });
537
+ const address = await getLedgerAddress({ chain, ledgerClient: signer });
538
+ const toolbox = getSuiToolbox({ signer });
539
+
540
+ return { ...toolbox, address };
541
+ }
542
+
543
+ default:
544
+ throw new SwapKitError("wallet_ledger_chain_not_supported", { chain });
545
+ }
546
+ }
@@ -0,0 +1,54 @@
1
+ import { type DerivationPathArray, LedgerErrorCode, NetworkDerivationPath, SwapKitError } from "@swapkit/helpers";
2
+
3
+ import { THORChainApp } from "../clients/thorchain/lib";
4
+ import { getLedgerTransport } from "../helpers/getLedgerTransport";
5
+
6
+ export abstract class CosmosLedgerInterface {
7
+ ledgerTimeout = 50000;
8
+ derivationPath: DerivationPathArray | string = NetworkDerivationPath.GAIA;
9
+ transport: any;
10
+ ledgerApp: any;
11
+ chain: "thor" | "cosmos" = "thor";
12
+
13
+ checkOrCreateTransportAndLedger = async (forceReconnect = false) => {
14
+ if (!forceReconnect && this.transport && this.ledgerApp) return;
15
+
16
+ try {
17
+ this.transport = forceReconnect || !this.transport ? await getLedgerTransport() : this.transport;
18
+
19
+ switch (this.chain) {
20
+ case "thor": {
21
+ this.ledgerApp = forceReconnect || !this.ledgerApp ? new THORChainApp(this.transport) : this.ledgerApp;
22
+
23
+ break;
24
+ }
25
+
26
+ case "cosmos": {
27
+ const CosmosApp = (await import("@ledgerhq/hw-app-cosmos")).default;
28
+ this.ledgerApp = forceReconnect || !this.ledgerApp ? new CosmosApp(this.transport) : this.ledgerApp;
29
+ }
30
+ }
31
+
32
+ return this.ledgerApp;
33
+ } catch (error: unknown) {
34
+ throw new SwapKitError("wallet_ledger_connection_error", error);
35
+ }
36
+ };
37
+
38
+ validateResponse = (errorCode: LedgerErrorCode, message?: string) => {
39
+ switch (errorCode) {
40
+ case LedgerErrorCode.NoError:
41
+ return;
42
+
43
+ case LedgerErrorCode.LockedDevice:
44
+ throw new SwapKitError("wallet_ledger_device_locked", { message: `Ledger is locked: ${message}` });
45
+
46
+ case LedgerErrorCode.TC_NotFound:
47
+ throw new SwapKitError("wallet_ledger_device_not_found");
48
+
49
+ default: {
50
+ break;
51
+ }
52
+ }
53
+ };
54
+ }
@@ -0,0 +1,42 @@
1
+ import type { CosmosLedger } from "./clients/cosmos";
2
+ import type {
3
+ ArbitrumLedger,
4
+ AuroraLedger,
5
+ AvalancheLedger,
6
+ BaseLedger,
7
+ BinanceSmartChainLedger,
8
+ EthereumLedger,
9
+ GnosisLedger,
10
+ OptimismLedger,
11
+ PolygonLedger,
12
+ } from "./clients/evm";
13
+ import type { SuiLedger } from "./clients/sui";
14
+ import type { THORChainLedger } from "./clients/thorchain";
15
+ import type { TronLedger } from "./clients/tron";
16
+ import type { BitcoinCashLedger, BitcoinLedger, DogecoinLedger, LitecoinLedger } from "./clients/utxo";
17
+
18
+ export type UTXOLedgerClients =
19
+ | ReturnType<typeof BitcoinLedger>
20
+ | ReturnType<typeof BitcoinCashLedger>
21
+ | ReturnType<typeof DogecoinLedger>
22
+ | ReturnType<typeof LitecoinLedger>;
23
+ export type CosmosLedgerClients = CosmosLedger | THORChainLedger;
24
+ export type EVMLedgerClients =
25
+ | ReturnType<typeof ArbitrumLedger>
26
+ | ReturnType<typeof AuroraLedger>
27
+ | ReturnType<typeof AvalancheLedger>
28
+ | ReturnType<typeof BaseLedger>
29
+ | ReturnType<typeof BinanceSmartChainLedger>
30
+ | ReturnType<typeof GnosisLedger>
31
+ | ReturnType<typeof EthereumLedger>
32
+ | ReturnType<typeof OptimismLedger>
33
+ | ReturnType<typeof PolygonLedger>;
34
+ export type TronLedgerClient = ReturnType<typeof TronLedger>;
35
+ export type SuiLedgerClient = ReturnType<typeof SuiLedger>;
36
+
37
+ export type GetAddressAndPubKeyResponse = {
38
+ bech32_address: string;
39
+ compressed_pk: any;
40
+ error_message: string;
41
+ return_code: number;
42
+ };