@sidhujag/sysweb3-keyring 1.0.547 → 1.0.548
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/package.json +2 -27
- package/coverage/clover.xml +0 -2875
- package/coverage/coverage-final.json +0 -29468
- package/coverage/lcov-report/base.css +0 -354
- package/coverage/lcov-report/block-navigation.js +0 -85
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -320
- package/coverage/lcov-report/prettify.css +0 -101
- package/coverage/lcov-report/prettify.js +0 -1008
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -191
- package/coverage/lcov-report/src/index.html +0 -276
- package/coverage/lcov-report/src/index.ts.html +0 -114
- package/coverage/lcov-report/src/initial-state.ts.html +0 -558
- package/coverage/lcov-report/src/keyring-manager.ts.html +0 -6279
- package/coverage/lcov-report/src/ledger/bitcoin_client/index.html +0 -178
- package/coverage/lcov-report/src/ledger/bitcoin_client/index.ts.html +0 -144
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/appClient.ts.html +0 -1560
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/bip32.ts.html +0 -276
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/buffertools.ts.html +0 -495
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/clientCommands.ts.html +0 -1138
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/index.html +0 -363
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts.html +0 -289
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkle.ts.html +0 -486
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkleMap.ts.html +0 -240
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/policy.ts.html +0 -342
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/psbtv2.ts.html +0 -2388
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/varint.ts.html +0 -453
- package/coverage/lcov-report/src/ledger/consts.ts.html +0 -177
- package/coverage/lcov-report/src/ledger/index.html +0 -216
- package/coverage/lcov-report/src/ledger/index.ts.html +0 -1371
- package/coverage/lcov-report/src/ledger/utils.ts.html +0 -102
- package/coverage/lcov-report/src/signers.ts.html +0 -591
- package/coverage/lcov-report/src/storage.ts.html +0 -198
- package/coverage/lcov-report/src/transactions/ethereum.ts.html +0 -5826
- package/coverage/lcov-report/src/transactions/index.html +0 -216
- package/coverage/lcov-report/src/transactions/index.ts.html +0 -93
- package/coverage/lcov-report/src/transactions/syscoin.ts.html +0 -1521
- package/coverage/lcov-report/src/trezor/index.html +0 -176
- package/coverage/lcov-report/src/trezor/index.ts.html +0 -2655
- package/coverage/lcov-report/src/types.ts.html +0 -1443
- package/coverage/lcov-report/src/utils/derivation-paths.ts.html +0 -486
- package/coverage/lcov-report/src/utils/index.html +0 -196
- package/coverage/lcov-report/src/utils/psbt.ts.html +0 -159
- package/coverage/lcov-report/test/helpers/constants.ts.html +0 -627
- package/coverage/lcov-report/test/helpers/index.html +0 -176
- package/coverage/lcov.info +0 -4832
- package/dist/package.json +0 -50
- package/examples/basic-usage.js +0 -140
- package/jest.config.js +0 -32
- package/readme.md +0 -201
- package/src/declare.d.ts +0 -7
- package/src/errorUtils.ts +0 -83
- package/src/hardware-wallet-manager.ts +0 -655
- package/src/index.ts +0 -12
- package/src/initial-state.ts +0 -108
- package/src/keyring-manager.ts +0 -2698
- package/src/ledger/bitcoin_client/index.ts +0 -19
- package/src/ledger/bitcoin_client/lib/appClient.ts +0 -405
- package/src/ledger/bitcoin_client/lib/bip32.ts +0 -61
- package/src/ledger/bitcoin_client/lib/buffertools.ts +0 -134
- package/src/ledger/bitcoin_client/lib/clientCommands.ts +0 -356
- package/src/ledger/bitcoin_client/lib/constants.ts +0 -12
- package/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts +0 -65
- package/src/ledger/bitcoin_client/lib/merkle.ts +0 -136
- package/src/ledger/bitcoin_client/lib/merkleMap.ts +0 -49
- package/src/ledger/bitcoin_client/lib/policy.ts +0 -91
- package/src/ledger/bitcoin_client/lib/psbtv2.ts +0 -768
- package/src/ledger/bitcoin_client/lib/varint.ts +0 -120
- package/src/ledger/consts.ts +0 -3
- package/src/ledger/index.ts +0 -685
- package/src/ledger/types.ts +0 -74
- package/src/network-utils.ts +0 -99
- package/src/providers.ts +0 -345
- package/src/signers.ts +0 -158
- package/src/storage.ts +0 -63
- package/src/transactions/__tests__/integration.test.ts +0 -303
- package/src/transactions/__tests__/syscoin.test.ts +0 -409
- package/src/transactions/ethereum.ts +0 -2503
- package/src/transactions/index.ts +0 -2
- package/src/transactions/syscoin.ts +0 -542
- package/src/trezor/index.ts +0 -1050
- package/src/types.ts +0 -366
- package/src/utils/derivation-paths.ts +0 -133
- package/src/utils/psbt.ts +0 -24
- package/src/utils.ts +0 -191
- package/test/README.md +0 -158
- package/test/__mocks__/ledger-mock.js +0 -20
- package/test/__mocks__/trezor-mock.js +0 -75
- package/test/cleanup-summary.md +0 -167
- package/test/helpers/README.md +0 -78
- package/test/helpers/constants.ts +0 -79
- package/test/helpers/setup.ts +0 -714
- package/test/integration/import-validation.spec.ts +0 -588
- package/test/unit/hardware/ledger.spec.ts +0 -869
- package/test/unit/hardware/trezor.spec.ts +0 -828
- package/test/unit/keyring-manager/account-management.spec.ts +0 -970
- package/test/unit/keyring-manager/import-watchonly.spec.ts +0 -181
- package/test/unit/keyring-manager/import-wif.spec.ts +0 -126
- package/test/unit/keyring-manager/initialization.spec.ts +0 -782
- package/test/unit/keyring-manager/key-derivation.spec.ts +0 -996
- package/test/unit/keyring-manager/security.spec.ts +0 -505
- package/test/unit/keyring-manager/state-management.spec.ts +0 -375
- package/test/unit/network/network-management.spec.ts +0 -372
- package/test/unit/transactions/ethereum-transactions.spec.ts +0 -382
- package/test/unit/transactions/syscoin-transactions.spec.ts +0 -615
- package/tsconfig.json +0 -14
- /package/{dist/README.md → README.md} +0 -0
- /package/{dist/cjs → cjs}/errorUtils.js +0 -0
- /package/{dist/cjs → cjs}/errorUtils.js.map +0 -0
- /package/{dist/cjs → cjs}/hardware-wallet-manager.js +0 -0
- /package/{dist/cjs → cjs}/hardware-wallet-manager.js.map +0 -0
- /package/{dist/cjs → cjs}/index.js +0 -0
- /package/{dist/cjs → cjs}/index.js.map +0 -0
- /package/{dist/cjs → cjs}/initial-state.js +0 -0
- /package/{dist/cjs → cjs}/initial-state.js.map +0 -0
- /package/{dist/cjs → cjs}/keyring-manager.js +0 -0
- /package/{dist/cjs → cjs}/keyring-manager.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/index.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/index.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/appClient.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/appClient.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/bip32.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/bip32.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/buffertools.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/buffertools.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/clientCommands.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/clientCommands.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/constants.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/constants.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkle.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkle.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkleMap.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkleMap.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/policy.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/policy.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/psbtv2.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/psbtv2.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/varint.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/varint.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/consts.js +0 -0
- /package/{dist/cjs → cjs}/ledger/consts.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/index.js +0 -0
- /package/{dist/cjs → cjs}/ledger/index.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/types.js +0 -0
- /package/{dist/cjs → cjs}/ledger/types.js.map +0 -0
- /package/{dist/cjs → cjs}/network-utils.js +0 -0
- /package/{dist/cjs → cjs}/network-utils.js.map +0 -0
- /package/{dist/cjs → cjs}/providers.js +0 -0
- /package/{dist/cjs → cjs}/providers.js.map +0 -0
- /package/{dist/cjs → cjs}/signers.js +0 -0
- /package/{dist/cjs → cjs}/signers.js.map +0 -0
- /package/{dist/cjs → cjs}/storage.js +0 -0
- /package/{dist/cjs → cjs}/storage.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/integration.test.js +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/integration.test.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/syscoin.test.js +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/syscoin.test.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/ethereum.js +0 -0
- /package/{dist/cjs → cjs}/transactions/ethereum.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/index.js +0 -0
- /package/{dist/cjs → cjs}/transactions/index.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/syscoin.js +0 -0
- /package/{dist/cjs → cjs}/transactions/syscoin.js.map +0 -0
- /package/{dist/cjs → cjs}/trezor/index.js +0 -0
- /package/{dist/cjs → cjs}/trezor/index.js.map +0 -0
- /package/{dist/cjs → cjs}/types.js +0 -0
- /package/{dist/cjs → cjs}/types.js.map +0 -0
- /package/{dist/cjs → cjs}/utils/derivation-paths.js +0 -0
- /package/{dist/cjs → cjs}/utils/derivation-paths.js.map +0 -0
- /package/{dist/cjs → cjs}/utils/psbt.js +0 -0
- /package/{dist/cjs → cjs}/utils/psbt.js.map +0 -0
- /package/{dist/cjs → cjs}/utils.js +0 -0
- /package/{dist/cjs → cjs}/utils.js.map +0 -0
- /package/{dist/types → types}/errorUtils.d.ts +0 -0
- /package/{dist/types → types}/hardware-wallet-manager.d.ts +0 -0
- /package/{dist/types → types}/index.d.ts +0 -0
- /package/{dist/types → types}/initial-state.d.ts +0 -0
- /package/{dist/types → types}/keyring-manager.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/index.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/appClient.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/bip32.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/buffertools.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/clientCommands.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/constants.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/merkelizedPsbt.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/merkle.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/merkleMap.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/policy.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/psbtv2.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/varint.d.ts +0 -0
- /package/{dist/types → types}/ledger/consts.d.ts +0 -0
- /package/{dist/types → types}/ledger/index.d.ts +0 -0
- /package/{dist/types → types}/ledger/types.d.ts +0 -0
- /package/{dist/types → types}/network-utils.d.ts +0 -0
- /package/{dist/types → types}/providers.d.ts +0 -0
- /package/{dist/types → types}/signers.d.ts +0 -0
- /package/{dist/types → types}/storage.d.ts +0 -0
- /package/{dist/types → types}/transactions/__tests__/integration.test.d.ts +0 -0
- /package/{dist/types → types}/transactions/__tests__/syscoin.test.d.ts +0 -0
- /package/{dist/types → types}/transactions/ethereum.d.ts +0 -0
- /package/{dist/types → types}/transactions/index.d.ts +0 -0
- /package/{dist/types → types}/transactions/syscoin.d.ts +0 -0
- /package/{dist/types → types}/trezor/index.d.ts +0 -0
- /package/{dist/types → types}/types.d.ts +0 -0
- /package/{dist/types → types}/utils/derivation-paths.d.ts +0 -0
- /package/{dist/types → types}/utils/psbt.d.ts +0 -0
- /package/{dist/types → types}/utils.d.ts +0 -0
package/src/ledger/index.ts
DELETED
|
@@ -1,685 +0,0 @@
|
|
|
1
|
-
/* eslint-disable camelcase */
|
|
2
|
-
/* eslint-disable import/no-named-as-default */
|
|
3
|
-
/* eslint-disable import/order */
|
|
4
|
-
import Transport from '@ledgerhq/hw-transport';
|
|
5
|
-
import SysUtxoClient, { DefaultWalletPolicy } from './bitcoin_client';
|
|
6
|
-
import { RECEIVING_ADDRESS_INDEX, WILL_NOT_DISPLAY } from './consts';
|
|
7
|
-
import { getNetworkConfig } from '@sidhujag/sysweb3-network';
|
|
8
|
-
import BIP32Factory from 'bip32';
|
|
9
|
-
import ecc from '@bitcoinerlab/secp256k1';
|
|
10
|
-
import { IEvmMethods, IUTXOMethods, MessageTypes } from './types';
|
|
11
|
-
import LedgerEthClient, { ledgerService } from '@ledgerhq/hw-app-eth';
|
|
12
|
-
import { Transaction } from 'syscoinjs-lib';
|
|
13
|
-
import {
|
|
14
|
-
TypedDataUtils,
|
|
15
|
-
TypedMessage,
|
|
16
|
-
SignTypedDataVersion,
|
|
17
|
-
TypedDataV1,
|
|
18
|
-
} from '@metamask/eth-sig-util';
|
|
19
|
-
import {
|
|
20
|
-
getAccountDerivationPath,
|
|
21
|
-
getAddressDerivationPath,
|
|
22
|
-
isEvmCoin,
|
|
23
|
-
convertExtendedKeyVersion,
|
|
24
|
-
} from '../utils/derivation-paths';
|
|
25
|
-
|
|
26
|
-
import {
|
|
27
|
-
HardwareWalletManager,
|
|
28
|
-
HardwareWalletType,
|
|
29
|
-
} from '../hardware-wallet-manager';
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
export class LedgerKeyring {
|
|
33
|
-
public ledgerEVMClient!: LedgerEthClient;
|
|
34
|
-
public ledgerUtxoClient!: SysUtxoClient;
|
|
35
|
-
private hdPath = "m/44'/57'/0'/0/0";
|
|
36
|
-
public evm: IEvmMethods;
|
|
37
|
-
public utxo: IUTXOMethods;
|
|
38
|
-
public transport: Transport | null = null;
|
|
39
|
-
private hardwareWalletManager: HardwareWalletManager;
|
|
40
|
-
// In-memory cache of registered wallet policy HMACs
|
|
41
|
-
private walletHmacCache: Map<string, Buffer> = new Map();
|
|
42
|
-
|
|
43
|
-
constructor() {
|
|
44
|
-
this.hardwareWalletManager = new HardwareWalletManager();
|
|
45
|
-
|
|
46
|
-
// Set up event listeners
|
|
47
|
-
this.hardwareWalletManager.on('connected', ({ type }) => {
|
|
48
|
-
if (type === HardwareWalletType.LEDGER) {
|
|
49
|
-
console.log('Ledger connected');
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
this.hardwareWalletManager.on('disconnected', ({ type }) => {
|
|
54
|
-
if (type === HardwareWalletType.LEDGER) {
|
|
55
|
-
console.log('Ledger disconnected');
|
|
56
|
-
this.transport = null;
|
|
57
|
-
// Clear clients on disconnect
|
|
58
|
-
this.ledgerEVMClient = null as any;
|
|
59
|
-
this.ledgerUtxoClient = null as any;
|
|
60
|
-
this.walletHmacCache.clear();
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
this.hardwareWalletManager.on('connectionFailed', ({ type, error }) => {
|
|
65
|
-
if (type === HardwareWalletType.LEDGER) {
|
|
66
|
-
console.error('Ledger connection failed:', error);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
this.evm = {
|
|
71
|
-
getEvmAddressAndPubKey: this.getEvmAddressAndPubKey,
|
|
72
|
-
signEVMTransaction: this.signEVMTransaction,
|
|
73
|
-
signPersonalMessage: this.signPersonalMessage,
|
|
74
|
-
signTypedData: this.signTypedData,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
this.utxo = {
|
|
78
|
-
getUtxoAddress: this.getUtxoAddress,
|
|
79
|
-
getXpub: this.getXpub,
|
|
80
|
-
verifyUtxoAddress: this.verifyUtxoAddress,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Ensure Ledger is connected with automatic retry
|
|
86
|
-
* Note: This is automatically called by all operations through executeWithRetry
|
|
87
|
-
* External callers don't need to call this directly
|
|
88
|
-
*/
|
|
89
|
-
public async ensureConnection(): Promise<void> {
|
|
90
|
-
await this.hardwareWalletManager.ensureConnection(
|
|
91
|
-
HardwareWalletType.LEDGER
|
|
92
|
-
);
|
|
93
|
-
this.transport = await this.hardwareWalletManager.getLedgerConnection();
|
|
94
|
-
|
|
95
|
-
// Create clients if transport is available
|
|
96
|
-
if (this.transport && (!this.ledgerEVMClient || !this.ledgerUtxoClient)) {
|
|
97
|
-
this.ledgerEVMClient = new LedgerEthClient(this.transport);
|
|
98
|
-
this.ledgerUtxoClient = new SysUtxoClient(this.transport);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private getUtxoAddress = async ({
|
|
103
|
-
coin,
|
|
104
|
-
index, // account index
|
|
105
|
-
slip44,
|
|
106
|
-
showInLedger,
|
|
107
|
-
}: {
|
|
108
|
-
coin: string;
|
|
109
|
-
index: number;
|
|
110
|
-
showInLedger?: boolean;
|
|
111
|
-
slip44: number;
|
|
112
|
-
}) => {
|
|
113
|
-
return this.executeWithRetry(async () => {
|
|
114
|
-
const fingerprint = await this.ledgerUtxoClient.getMasterFingerprint();
|
|
115
|
-
const xpub = await this.getXpub({ index, coin, slip44 });
|
|
116
|
-
this.setHdPath(coin, index, slip44);
|
|
117
|
-
|
|
118
|
-
// Convert stored/display zpub/vpub to device-friendly xpub/tpub for policy registration using network macros
|
|
119
|
-
const { types: deviceTypes } = getNetworkConfig(slip44, coin);
|
|
120
|
-
const devicePubMagicDec =
|
|
121
|
-
slip44 === 1
|
|
122
|
-
? (deviceTypes.xPubType as any).testnet.vpub
|
|
123
|
-
: deviceTypes.xPubType.mainnet.zpub;
|
|
124
|
-
const devicePubMagicHex = Number(devicePubMagicDec)
|
|
125
|
-
.toString(16)
|
|
126
|
-
.padStart(8, '0');
|
|
127
|
-
const deviceXpub = convertExtendedKeyVersion(xpub, devicePubMagicHex);
|
|
128
|
-
const xpubWithDescriptor = `[${this.hdPath}]${deviceXpub}`.replace(
|
|
129
|
-
'm',
|
|
130
|
-
fingerprint
|
|
131
|
-
);
|
|
132
|
-
const walletPolicy = new DefaultWalletPolicy(
|
|
133
|
-
// Ensure policy template matches BIP84 single-sig wpkh
|
|
134
|
-
'wpkh(@0/**)',
|
|
135
|
-
xpubWithDescriptor
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
const hmac = await this.getOrRegisterHmac(walletPolicy, fingerprint);
|
|
139
|
-
|
|
140
|
-
const address = await this.ledgerUtxoClient.getWalletAddress(
|
|
141
|
-
walletPolicy,
|
|
142
|
-
hmac,
|
|
143
|
-
RECEIVING_ADDRESS_INDEX,
|
|
144
|
-
index,
|
|
145
|
-
!!showInLedger
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
return address;
|
|
149
|
-
}, 'getUtxoAddress');
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
public verifyUtxoAddress = async (
|
|
153
|
-
accountIndex: number,
|
|
154
|
-
currency: string,
|
|
155
|
-
slip44: number
|
|
156
|
-
) =>
|
|
157
|
-
await this.getUtxoAddress({
|
|
158
|
-
coin: currency,
|
|
159
|
-
index: accountIndex,
|
|
160
|
-
slip44: slip44,
|
|
161
|
-
showInLedger: true,
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
private getXpub = async ({
|
|
165
|
-
index,
|
|
166
|
-
coin,
|
|
167
|
-
slip44,
|
|
168
|
-
}: {
|
|
169
|
-
coin: string;
|
|
170
|
-
index: number;
|
|
171
|
-
slip44: number;
|
|
172
|
-
}): Promise<string> => {
|
|
173
|
-
return this.executeWithRetry(async () => {
|
|
174
|
-
this.setHdPath(coin, index, slip44);
|
|
175
|
-
|
|
176
|
-
{
|
|
177
|
-
// Syscoin and general UTXO flow: try silent first, then fall back to on-device display for unusual paths
|
|
178
|
-
try {
|
|
179
|
-
const xpub = await this.ledgerUtxoClient.getExtendedPubkey(
|
|
180
|
-
this.hdPath,
|
|
181
|
-
WILL_NOT_DISPLAY
|
|
182
|
-
);
|
|
183
|
-
// Normalize to BIP84 prefix for Blockbook using network-config magic bytes
|
|
184
|
-
const { types } = getNetworkConfig(slip44, coin);
|
|
185
|
-
const target =
|
|
186
|
-
slip44 === 1
|
|
187
|
-
? (types.zPubType as any).testnet.vpub
|
|
188
|
-
: types.zPubType.mainnet.zpub;
|
|
189
|
-
return convertExtendedKeyVersion(xpub, target);
|
|
190
|
-
} catch (err) {
|
|
191
|
-
// Retry with display=true to allow unusual paths with user approval
|
|
192
|
-
const xpubWithDisplay = await this.ledgerUtxoClient.getExtendedPubkey(
|
|
193
|
-
this.hdPath,
|
|
194
|
-
true
|
|
195
|
-
);
|
|
196
|
-
const { types } = getNetworkConfig(slip44, coin);
|
|
197
|
-
const target =
|
|
198
|
-
slip44 === 1
|
|
199
|
-
? (types.zPubType as any).testnet.vpub
|
|
200
|
-
: types.zPubType.mainnet.zpub;
|
|
201
|
-
return convertExtendedKeyVersion(xpubWithDisplay, target);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}, 'getXpub');
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Sign a UTXO message - public method used by transaction classes
|
|
209
|
-
*/
|
|
210
|
-
public signUtxoMessage = async (path: string, message: string) => {
|
|
211
|
-
return this.executeWithRetry(async () => {
|
|
212
|
-
const bufferMessage = Buffer.from(message);
|
|
213
|
-
const signature = await this.ledgerUtxoClient.signMessage(
|
|
214
|
-
bufferMessage,
|
|
215
|
-
path
|
|
216
|
-
);
|
|
217
|
-
return signature;
|
|
218
|
-
}, 'signUtxoMessage');
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
private signEVMTransaction = async ({
|
|
222
|
-
rawTx,
|
|
223
|
-
accountIndex,
|
|
224
|
-
}: {
|
|
225
|
-
accountIndex: number;
|
|
226
|
-
rawTx: string;
|
|
227
|
-
}) => {
|
|
228
|
-
return this.executeWithRetry(async () => {
|
|
229
|
-
this.setHdPath('eth', accountIndex, 60);
|
|
230
|
-
const resolution = await ledgerService.resolveTransaction(rawTx, {}, {});
|
|
231
|
-
|
|
232
|
-
const signature = await this.ledgerEVMClient.signTransaction(
|
|
233
|
-
this.hdPath.replace(/^m\//, ''), // Remove 'm/' prefix for EVM
|
|
234
|
-
rawTx,
|
|
235
|
-
resolution
|
|
236
|
-
);
|
|
237
|
-
|
|
238
|
-
return signature;
|
|
239
|
-
}, 'signEVMTransaction');
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
private signPersonalMessage = async ({
|
|
243
|
-
message,
|
|
244
|
-
accountIndex,
|
|
245
|
-
}: {
|
|
246
|
-
accountIndex: number;
|
|
247
|
-
message: string;
|
|
248
|
-
}) => {
|
|
249
|
-
return this.executeWithRetry(async () => {
|
|
250
|
-
this.setHdPath('eth', accountIndex, 60);
|
|
251
|
-
|
|
252
|
-
const signature = await this.ledgerEVMClient.signPersonalMessage(
|
|
253
|
-
this.hdPath.replace(/^m\//, ''), // Remove 'm/' prefix for EVM
|
|
254
|
-
message
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
return `0x${signature.r}${signature.s}${signature.v.toString(16)}`;
|
|
258
|
-
}, 'signPersonalMessage');
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
private sanitizeData(data: any): any {
|
|
262
|
-
switch (Object.prototype.toString.call(data)) {
|
|
263
|
-
case '[object Object]': {
|
|
264
|
-
const entries = Object.keys(data).map((k) => [
|
|
265
|
-
k,
|
|
266
|
-
this.sanitizeData(data[k]),
|
|
267
|
-
]);
|
|
268
|
-
return Object.fromEntries(entries);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
case '[object Array]':
|
|
272
|
-
return data.map((v: any[]) => this.sanitizeData(v));
|
|
273
|
-
|
|
274
|
-
case '[object BigInt]':
|
|
275
|
-
return data.toString();
|
|
276
|
-
|
|
277
|
-
default:
|
|
278
|
-
return data;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
private transformTypedData = <T extends MessageTypes>(
|
|
283
|
-
data: TypedMessage<T>,
|
|
284
|
-
version: SignTypedDataVersion
|
|
285
|
-
) => {
|
|
286
|
-
const { types, primaryType, domain, message } = this.sanitizeData(data);
|
|
287
|
-
|
|
288
|
-
const domainSeparatorHash = TypedDataUtils.hashStruct(
|
|
289
|
-
'EIP712Domain',
|
|
290
|
-
this.sanitizeData(domain),
|
|
291
|
-
types,
|
|
292
|
-
version as SignTypedDataVersion.V3 | SignTypedDataVersion.V4
|
|
293
|
-
).toString('hex');
|
|
294
|
-
|
|
295
|
-
let messageHash: string | null = null;
|
|
296
|
-
|
|
297
|
-
if (primaryType !== 'EIP712Domain') {
|
|
298
|
-
messageHash = TypedDataUtils.hashStruct(
|
|
299
|
-
primaryType as string,
|
|
300
|
-
this.sanitizeData(message),
|
|
301
|
-
types,
|
|
302
|
-
version as SignTypedDataVersion.V3 | SignTypedDataVersion.V4
|
|
303
|
-
).toString('hex');
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return {
|
|
307
|
-
domain_separator_hash: domainSeparatorHash,
|
|
308
|
-
message_hash: messageHash,
|
|
309
|
-
...data,
|
|
310
|
-
};
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
private getEvmAddressAndPubKey = async ({
|
|
314
|
-
accountIndex,
|
|
315
|
-
}: {
|
|
316
|
-
accountIndex: number;
|
|
317
|
-
}): Promise<{ address: string; publicKey: string }> => {
|
|
318
|
-
return this.executeWithRetry(async () => {
|
|
319
|
-
this.setHdPath('eth', accountIndex, 60);
|
|
320
|
-
const { address, publicKey } = await this.ledgerEVMClient.getAddress(
|
|
321
|
-
this.hdPath.replace(/^m\//, '') // Remove 'm/' prefix for EVM
|
|
322
|
-
);
|
|
323
|
-
return { address, publicKey };
|
|
324
|
-
}, 'getEvmAddressAndPubKey');
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
private signTypedData = async ({
|
|
328
|
-
version,
|
|
329
|
-
data,
|
|
330
|
-
accountIndex,
|
|
331
|
-
}: {
|
|
332
|
-
accountIndex: number;
|
|
333
|
-
data: TypedMessage<any> | TypedDataV1;
|
|
334
|
-
version: SignTypedDataVersion;
|
|
335
|
-
}) => {
|
|
336
|
-
return this.executeWithRetry(async () => {
|
|
337
|
-
this.setHdPath('eth', accountIndex, 60);
|
|
338
|
-
|
|
339
|
-
// V1 typed data is not supported by hardware wallets
|
|
340
|
-
if (version === SignTypedDataVersion.V1) {
|
|
341
|
-
throw new Error(
|
|
342
|
-
'Ledger: V1 typed data signing is not supported. Please use V3 or V4.'
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const dataWithHashes = this.transformTypedData(
|
|
347
|
-
data as TypedMessage<any>,
|
|
348
|
-
version
|
|
349
|
-
);
|
|
350
|
-
|
|
351
|
-
const { domain_separator_hash, message_hash } = dataWithHashes;
|
|
352
|
-
|
|
353
|
-
const signature = await this.ledgerEVMClient.signEIP712HashedMessage(
|
|
354
|
-
this.hdPath.replace(/^m\//, ''), // Remove 'm/' prefix for EVM
|
|
355
|
-
domain_separator_hash,
|
|
356
|
-
message_hash ? message_hash : ''
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
return `0x${signature.r}${signature.s}${signature.v.toString(16)}`;
|
|
360
|
-
}, 'signTypedData');
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
private getMasterFingerprint = async () => {
|
|
364
|
-
try {
|
|
365
|
-
const masterFingerprint =
|
|
366
|
-
await this.ledgerUtxoClient.getMasterFingerprint();
|
|
367
|
-
return masterFingerprint;
|
|
368
|
-
} catch (error) {
|
|
369
|
-
console.log('Fingerprint error: ', error);
|
|
370
|
-
throw error;
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
// Build a stable cache key for a policy bound to the device and derivation path
|
|
375
|
-
private buildWalletCacheKey(
|
|
376
|
-
fingerprint: string,
|
|
377
|
-
descriptorTemplate: string,
|
|
378
|
-
hdPath: string
|
|
379
|
-
): string {
|
|
380
|
-
return `${fingerprint}|${descriptorTemplate}|${hdPath}`;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Lazily register the wallet policy and cache HMAC in memory only
|
|
384
|
-
private async getOrRegisterHmac(
|
|
385
|
-
walletPolicy: any,
|
|
386
|
-
fingerprint: string
|
|
387
|
-
): Promise<Buffer | null> {
|
|
388
|
-
const cacheKey = this.buildWalletCacheKey(
|
|
389
|
-
fingerprint,
|
|
390
|
-
walletPolicy.descriptorTemplate,
|
|
391
|
-
this.hdPath
|
|
392
|
-
);
|
|
393
|
-
|
|
394
|
-
const cached = this.walletHmacCache.get(cacheKey);
|
|
395
|
-
if (cached) return cached;
|
|
396
|
-
|
|
397
|
-
// If registerWallet is unavailable (tests/mocks), fall back to null HMAC
|
|
398
|
-
const registerWallet: any = (this.ledgerUtxoClient as any)?.registerWallet;
|
|
399
|
-
if (typeof registerWallet !== 'function') {
|
|
400
|
-
return null;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
try {
|
|
404
|
-
// Register once (device approval). If user cancels, error will propagate via retryOperation
|
|
405
|
-
const result = await registerWallet.call(
|
|
406
|
-
this.ledgerUtxoClient,
|
|
407
|
-
walletPolicy
|
|
408
|
-
);
|
|
409
|
-
const walletHMAC = Array.isArray(result) ? result[1] : null;
|
|
410
|
-
if (walletHMAC && Buffer.isBuffer(walletHMAC)) {
|
|
411
|
-
this.walletHmacCache.set(cacheKey, walletHMAC);
|
|
412
|
-
return walletHMAC;
|
|
413
|
-
}
|
|
414
|
-
return null;
|
|
415
|
-
} catch (e) {
|
|
416
|
-
// On failure, proceed without HMAC (device may prompt)
|
|
417
|
-
return null;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
private setHdPath(coin: string, accountIndex: number, slip44: number) {
|
|
422
|
-
if (isEvmCoin(coin, slip44)) {
|
|
423
|
-
// For EVM, the "accountIndex" parameter is actually used as the address index
|
|
424
|
-
// EVM typically uses account 0, and different addresses are at different address indices
|
|
425
|
-
this.hdPath = getAddressDerivationPath(
|
|
426
|
-
coin,
|
|
427
|
-
slip44,
|
|
428
|
-
0, // account is always 0 for EVM
|
|
429
|
-
false, // not a change address
|
|
430
|
-
accountIndex // this is actually the address index for EVM
|
|
431
|
-
);
|
|
432
|
-
} else {
|
|
433
|
-
// For UTXO, use account-level derivation path
|
|
434
|
-
this.hdPath = getAccountDerivationPath(coin, slip44, accountIndex);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
/**
|
|
438
|
-
* Convert PSBT to Ledger format with retry logic
|
|
439
|
-
*/
|
|
440
|
-
public async convertToLedgerFormat(
|
|
441
|
-
psbt: any,
|
|
442
|
-
accountXpub: string,
|
|
443
|
-
accountId: number,
|
|
444
|
-
currency: string,
|
|
445
|
-
slip44: number
|
|
446
|
-
): Promise<any> {
|
|
447
|
-
return this.executeWithRetry(async () => {
|
|
448
|
-
// Ensure Ledger is connected before attempting operations
|
|
449
|
-
// This is now handled by executeWithRetry
|
|
450
|
-
|
|
451
|
-
// Build a bitcoinjs-bip32 network from slip44/currency so zpub/vpub parse directly
|
|
452
|
-
const { networks, types } = getNetworkConfig(slip44, currency);
|
|
453
|
-
const isTestnet = slip44 === 1;
|
|
454
|
-
const pubTypes = isTestnet
|
|
455
|
-
? (types.zPubType as any).testnet
|
|
456
|
-
: types.zPubType.mainnet;
|
|
457
|
-
const baseNetwork = isTestnet ? networks.testnet : networks.mainnet;
|
|
458
|
-
const network = {
|
|
459
|
-
...baseNetwork,
|
|
460
|
-
bip32: {
|
|
461
|
-
public: parseInt(pubTypes.vpub || pubTypes.zpub, 16),
|
|
462
|
-
private: parseInt(pubTypes.vprv || pubTypes.zprv, 16),
|
|
463
|
-
},
|
|
464
|
-
} as any;
|
|
465
|
-
|
|
466
|
-
const bip32 = BIP32Factory(ecc as any);
|
|
467
|
-
const accountNode = bip32.fromBase58(accountXpub, network);
|
|
468
|
-
|
|
469
|
-
// Get master fingerprint
|
|
470
|
-
const fingerprint = await this.getMasterFingerprint();
|
|
471
|
-
|
|
472
|
-
// Enhance each input with bip32Derivation
|
|
473
|
-
const missingInputDerivations: number[] = [];
|
|
474
|
-
for (let i = 0; i < psbt.inputCount; i++) {
|
|
475
|
-
const dataInput = psbt.data.inputs[i];
|
|
476
|
-
|
|
477
|
-
// Skip if already has bip32Derivation
|
|
478
|
-
if (dataInput.bip32Derivation && dataInput.bip32Derivation.length > 0) {
|
|
479
|
-
continue;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// Ensure witnessUtxo is present if nonWitnessUtxo exists
|
|
483
|
-
if (!dataInput.witnessUtxo && dataInput.nonWitnessUtxo) {
|
|
484
|
-
const txBuffer = dataInput.nonWitnessUtxo;
|
|
485
|
-
const tx = Transaction.fromBuffer(txBuffer);
|
|
486
|
-
const vout = psbt.txInputs[i].index;
|
|
487
|
-
|
|
488
|
-
if (tx.outs[vout]) {
|
|
489
|
-
dataInput.witnessUtxo = {
|
|
490
|
-
script: tx.outs[vout].script,
|
|
491
|
-
value: tx.outs[vout].value,
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// Extract path from unknownKeyVals by searching for the key, not using hardcoded index
|
|
497
|
-
let pathFromInput: string | null = null;
|
|
498
|
-
if (dataInput.unknownKeyVals && dataInput.unknownKeyVals.length > 0) {
|
|
499
|
-
for (const kv of dataInput.unknownKeyVals) {
|
|
500
|
-
if (kv.key.equals(Buffer.from('path'))) {
|
|
501
|
-
pathFromInput = kv.value.toString();
|
|
502
|
-
break;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
if (pathFromInput) {
|
|
508
|
-
const fullPath = pathFromInput;
|
|
509
|
-
const accountPath = getAccountDerivationPath(
|
|
510
|
-
currency,
|
|
511
|
-
slip44,
|
|
512
|
-
accountId
|
|
513
|
-
);
|
|
514
|
-
const relativePath = fullPath
|
|
515
|
-
.replace(accountPath, '')
|
|
516
|
-
.replace(/^\//, '');
|
|
517
|
-
const derivationTokens = relativePath.split('/').filter((t) => t);
|
|
518
|
-
|
|
519
|
-
const derivedAccount = derivationTokens.reduce(
|
|
520
|
-
(acc: any, token: string) => {
|
|
521
|
-
const index = parseInt(token);
|
|
522
|
-
if (isNaN(index)) {
|
|
523
|
-
return acc;
|
|
524
|
-
}
|
|
525
|
-
return acc.derive(index);
|
|
526
|
-
},
|
|
527
|
-
accountNode
|
|
528
|
-
);
|
|
529
|
-
|
|
530
|
-
const pubkey = derivedAccount.publicKey;
|
|
531
|
-
|
|
532
|
-
if (pubkey && Buffer.isBuffer(pubkey)) {
|
|
533
|
-
// Add the bip32Derivation that Ledger needs
|
|
534
|
-
const bip32Derivation = {
|
|
535
|
-
masterFingerprint: Buffer.from(fingerprint, 'hex'),
|
|
536
|
-
path: fullPath,
|
|
537
|
-
pubkey: pubkey,
|
|
538
|
-
};
|
|
539
|
-
|
|
540
|
-
psbt.updateInput(i, {
|
|
541
|
-
bip32Derivation: [bip32Derivation],
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
if (
|
|
547
|
-
!dataInput.bip32Derivation ||
|
|
548
|
-
dataInput.bip32Derivation.length === 0
|
|
549
|
-
) {
|
|
550
|
-
missingInputDerivations.push(i);
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
// Enhance each output with bip32Derivation when it's a change/output owned by the wallet
|
|
555
|
-
const missingOutputDerivations: number[] = [];
|
|
556
|
-
for (let i = 0; i < psbt.data.outputs.length; i++) {
|
|
557
|
-
const dataOutput = psbt.data.outputs[i];
|
|
558
|
-
|
|
559
|
-
// Skip if derivation already present
|
|
560
|
-
if (
|
|
561
|
-
dataOutput.bip32Derivation &&
|
|
562
|
-
dataOutput.bip32Derivation.length > 0
|
|
563
|
-
) {
|
|
564
|
-
continue;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
// Extract path from unknownKeyVals by searching for the key 'path'
|
|
568
|
-
let pathFromOutput: string | null = null;
|
|
569
|
-
if (dataOutput.unknownKeyVals && dataOutput.unknownKeyVals.length > 0) {
|
|
570
|
-
for (const kv of dataOutput.unknownKeyVals) {
|
|
571
|
-
if (kv.key.equals(Buffer.from('path'))) {
|
|
572
|
-
pathFromOutput = kv.value.toString();
|
|
573
|
-
break;
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
if (pathFromOutput) {
|
|
579
|
-
const fullPath = pathFromOutput;
|
|
580
|
-
const accountPath = getAccountDerivationPath(
|
|
581
|
-
currency,
|
|
582
|
-
slip44,
|
|
583
|
-
accountId
|
|
584
|
-
);
|
|
585
|
-
const relativePath = fullPath
|
|
586
|
-
.replace(accountPath, '')
|
|
587
|
-
.replace(/^\//, '');
|
|
588
|
-
const derivationTokens = relativePath.split('/').filter((t) => t);
|
|
589
|
-
|
|
590
|
-
const derivedAccount = derivationTokens.reduce(
|
|
591
|
-
(acc: any, token: string) => {
|
|
592
|
-
const index = parseInt(token);
|
|
593
|
-
if (isNaN(index)) {
|
|
594
|
-
return acc;
|
|
595
|
-
}
|
|
596
|
-
return acc.derive(index);
|
|
597
|
-
},
|
|
598
|
-
accountNode
|
|
599
|
-
);
|
|
600
|
-
|
|
601
|
-
const pubkey = derivedAccount.publicKey;
|
|
602
|
-
|
|
603
|
-
if (pubkey && Buffer.isBuffer(pubkey)) {
|
|
604
|
-
const bip32Derivation = {
|
|
605
|
-
masterFingerprint: Buffer.from(fingerprint, 'hex'),
|
|
606
|
-
path: fullPath,
|
|
607
|
-
pubkey: pubkey,
|
|
608
|
-
};
|
|
609
|
-
|
|
610
|
-
psbt.updateOutput(i, {
|
|
611
|
-
bip32Derivation: [bip32Derivation],
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// Track outputs that declared a path but still lack derivation info
|
|
617
|
-
if (pathFromOutput) {
|
|
618
|
-
if (
|
|
619
|
-
!dataOutput.bip32Derivation ||
|
|
620
|
-
dataOutput.bip32Derivation.length === 0
|
|
621
|
-
) {
|
|
622
|
-
missingOutputDerivations.push(i);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// If any wallet-owned inputs/outputs are missing bip32Derivation, fail early with a clear error
|
|
628
|
-
if (
|
|
629
|
-
missingInputDerivations.length > 0 ||
|
|
630
|
-
missingOutputDerivations.length > 0
|
|
631
|
-
) {
|
|
632
|
-
const parts: string[] = [];
|
|
633
|
-
if (missingInputDerivations.length > 0) {
|
|
634
|
-
parts.push(`inputs [${missingInputDerivations.join(', ')}]`);
|
|
635
|
-
}
|
|
636
|
-
if (missingOutputDerivations.length > 0) {
|
|
637
|
-
parts.push(`outputs [${missingOutputDerivations.join(', ')}]`);
|
|
638
|
-
}
|
|
639
|
-
throw new Error(
|
|
640
|
-
`convertToLedgerFormat: Missing bip32Derivation for ${parts.join(
|
|
641
|
-
' and '
|
|
642
|
-
)}. Ensure PSBT includes a 'path' unknownKeyVal or BIP32_DERIVATION for wallet-owned entries.`
|
|
643
|
-
);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
return psbt;
|
|
647
|
-
}, 'convertToLedgerFormat');
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
/**
|
|
651
|
-
* Execute operation with automatic retry
|
|
652
|
-
*/
|
|
653
|
-
private async executeWithRetry<T>(
|
|
654
|
-
operation: () => Promise<T>,
|
|
655
|
-
operationName: string
|
|
656
|
-
): Promise<T> {
|
|
657
|
-
// Ensure connection first
|
|
658
|
-
await this.ensureConnection();
|
|
659
|
-
|
|
660
|
-
// Use hardware wallet manager's retry mechanism
|
|
661
|
-
return this.hardwareWalletManager.retryOperation(operation, operationName, {
|
|
662
|
-
maxRetries: 3,
|
|
663
|
-
baseDelay: 1000,
|
|
664
|
-
maxDelay: 5000,
|
|
665
|
-
backoffMultiplier: 2,
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
/**
|
|
670
|
-
* Get hardware wallet status
|
|
671
|
-
*/
|
|
672
|
-
public getStatus() {
|
|
673
|
-
return this.hardwareWalletManager
|
|
674
|
-
.getStatus()
|
|
675
|
-
.find((s) => s.type === HardwareWalletType.LEDGER);
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
/**
|
|
679
|
-
* Clean up resources
|
|
680
|
-
*/
|
|
681
|
-
public async destroy() {
|
|
682
|
-
await this.hardwareWalletManager.destroy();
|
|
683
|
-
this.transport = null;
|
|
684
|
-
}
|
|
685
|
-
}
|