Skip to content

Commit 460435a

Browse files
committed
fixed ledger service after rebase
1 parent 8568617 commit 460435a

File tree

1 file changed

+60
-57
lines changed

1 file changed

+60
-57
lines changed

packages/core-mobile/app/services/ledger/LedgerService.ts

Lines changed: 60 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,47 @@ import { networks } from 'bitcoinjs-lib'
1414
import Logger from 'utils/Logger'
1515
import bs58 from 'bs58'
1616
import {
17-
LedgerAppType,
17+
LEDGER_TIMEOUTS,
18+
getSolanaDerivationPath
19+
} from 'new/features/ledger/consts'
20+
import { assertNotNull } from 'utils/assertions'
21+
import {
22+
AddressInfo,
1823
ExtendedPublicKey,
19-
LedgerReturnCode,
2024
PublicKeyInfo,
21-
AddressInfo
25+
LedgerAppType,
26+
LedgerReturnCode,
27+
AppInfo
2228
} from './types'
2329

24-
export interface AppInfo {
25-
applicationName: string
26-
version: string
27-
}
28-
2930
export class LedgerService {
30-
private transport: TransportBLE | null = null
31+
#transport: TransportBLE | null = null
3132
private currentAppType: LedgerAppType = LedgerAppType.UNKNOWN
3233
private appPollingInterval: number | null = null
3334
private appPollingEnabled = false
3435

36+
// Transport getter/setter with automatic error handling
37+
private get transport(): TransportBLE {
38+
assertNotNull(
39+
this.#transport,
40+
'Ledger transport is not initialized. Please connect to a device first.'
41+
)
42+
return this.#transport
43+
}
44+
45+
private set transport(transport: TransportBLE) {
46+
this.#transport = transport
47+
}
48+
3549
// Connect to Ledger device (transport only, no apps)
3650
async connect(deviceId: string): Promise<void> {
3751
try {
3852
Logger.info('Starting BLE connection attempt with deviceId:', deviceId)
39-
// Use a longer timeout for connection (30 seconds)
40-
this.transport = await TransportBLE.open(deviceId, 30000)
53+
// Use a longer timeout for connection
54+
this.transport = await TransportBLE.open(
55+
deviceId,
56+
LEDGER_TIMEOUTS.CONNECTION_TIMEOUT
57+
)
4158
Logger.info('BLE transport connected successfully')
4259
this.currentAppType = LedgerAppType.UNKNOWN
4360

@@ -62,7 +79,7 @@ export class LedgerService {
6279
this.appPollingEnabled = true
6380
this.appPollingInterval = setInterval(async () => {
6481
try {
65-
if (!this.transport || !this.transport.isConnected) {
82+
if (!this.#transport || !this.#transport.isConnected) {
6683
this.stopAppPolling()
6784
return
6885
}
@@ -80,7 +97,7 @@ export class LedgerService {
8097
Logger.error('Error polling app info', error)
8198
// Don't stop polling on error, just log it
8299
}
83-
}, 2000) // Poll every 2 seconds like the extension
100+
}, LEDGER_TIMEOUTS.APP_POLLING_INTERVAL) // Poll every 2 seconds like the extension
84101
}
85102

86103
// Stop passive app detection polling
@@ -94,10 +111,6 @@ export class LedgerService {
94111

95112
// Get current app info from device
96113
private async getCurrentAppInfo(): Promise<AppInfo> {
97-
if (!this.transport) {
98-
throw new Error('Transport not initialized')
99-
}
100-
101114
return await getLedgerAppInfo(this.transport as Transport)
102115
}
103116

@@ -121,7 +134,10 @@ export class LedgerService {
121134
}
122135

123136
// Wait for specific app to be open (passive approach)
124-
async waitForApp(appType: LedgerAppType, timeoutMs = 30000): Promise<void> {
137+
async waitForApp(
138+
appType: LedgerAppType,
139+
timeoutMs = LEDGER_TIMEOUTS.APP_WAIT_TIMEOUT
140+
): Promise<void> {
125141
const startTime = Date.now()
126142
Logger.info(`Waiting for ${appType} app (timeout: ${timeoutMs}ms)...`)
127143

@@ -135,8 +151,10 @@ export class LedgerService {
135151
return
136152
}
137153

138-
// Wait 1 second before next check
139-
await new Promise(resolve => setTimeout(resolve, 1000))
154+
// Wait before next check
155+
await new Promise(resolve =>
156+
setTimeout(resolve, LEDGER_TIMEOUTS.APP_CHECK_DELAY)
157+
)
140158
}
141159

142160
Logger.error(`Timeout waiting for ${appType} app after ${timeoutMs}ms`)
@@ -161,7 +179,7 @@ export class LedgerService {
161179
private async reconnectIfNeeded(deviceId: string): Promise<void> {
162180
Logger.info('Checking if reconnection is needed')
163181

164-
if (!this.transport || !this.transport.isConnected) {
182+
if (!this.#transport || !this.#transport.isConnected) {
165183
Logger.info('Transport is disconnected, attempting reconnection')
166184
try {
167185
await this.connect(deviceId)
@@ -180,10 +198,6 @@ export class LedgerService {
180198
evm: ExtendedPublicKey
181199
avalanche: ExtendedPublicKey
182200
}> {
183-
if (!this.transport) {
184-
throw new Error('Transport not initialized')
185-
}
186-
187201
Logger.info('=== getExtendedPublicKeys STARTED ===')
188202
Logger.info('Current app type:', this.currentAppType)
189203

@@ -306,7 +320,7 @@ export class LedgerService {
306320

307321
// Check if Solana app is open
308322
async checkSolanaApp(): Promise<boolean> {
309-
if (!this.transport) {
323+
if (!this.#transport) {
310324
return false
311325
}
312326

@@ -325,15 +339,19 @@ export class LedgerService {
325339
}
326340
}
327341

342+
// Get Solana address for a specific derivation path
343+
async getSolanaAddress(derivationPath: string): Promise<{ address: Buffer }> {
344+
await this.waitForApp(LedgerAppType.SOLANA)
345+
const transport = await this.getTransport()
346+
const solanaApp = new AppSolana(transport as Transport)
347+
return await solanaApp.getAddress(derivationPath, false)
348+
}
349+
328350
// Get Solana public keys using SDK function (like extension)
329351
async getSolanaPublicKeys(
330352
startIndex: number,
331353
count: number
332354
): Promise<PublicKeyInfo[]> {
333-
if (!this.transport) {
334-
throw new Error('Transport not initialized')
335-
}
336-
337355
// Create a fresh AppSolana instance for each call (like the SDK does)
338356
const transport = await this.getTransport()
339357
const freshSolanaApp = new AppSolana(transport as Transport)
@@ -342,7 +360,7 @@ export class LedgerService {
342360
try {
343361
for (let i = startIndex; i < startIndex + count; i++) {
344362
// Use correct Solana derivation path format
345-
const derivationPath = `44'/501'/0'/0'/${i}`
363+
const derivationPath = getSolanaDerivationPath(i)
346364

347365
// Simple direct call to get Solana address using fresh instance
348366
const result = await freshSolanaApp.getAddress(derivationPath, false)
@@ -374,10 +392,6 @@ export class LedgerService {
374392
startIndex: number,
375393
_count: number
376394
): Promise<PublicKeyInfo[]> {
377-
if (!this.transport) {
378-
throw new Error('Transport not initialized')
379-
}
380-
381395
try {
382396
// Use the SDK function directly (like the extension does)
383397
const publicKey = await getSolanaPublicKeyFromLedger(
@@ -388,7 +402,7 @@ export class LedgerService {
388402
const publicKeys: PublicKeyInfo[] = [
389403
{
390404
key: publicKey.toString('hex'),
391-
derivationPath: `44'/501'/0'/0'/${startIndex}`,
405+
derivationPath: getSolanaDerivationPath(startIndex),
392406
curve: 'ed25519'
393407
}
394408
]
@@ -441,10 +455,6 @@ export class LedgerService {
441455
startIndex: number,
442456
count: number
443457
): Promise<PublicKeyInfo[]> {
444-
if (!this.transport) {
445-
throw new Error('Transport not initialized')
446-
}
447-
448458
// Connect to Avalanche app
449459
await this.waitForApp(LedgerAppType.AVALANCHE)
450460

@@ -515,10 +525,6 @@ export class LedgerService {
515525
startIndex: number,
516526
count: number
517527
): Promise<AddressInfo[]> {
518-
if (!this.transport) {
519-
throw new Error('Transport not initialized')
520-
}
521-
522528
// Connect to Avalanche app
523529
await this.waitForApp(LedgerAppType.AVALANCHE)
524530

@@ -634,31 +640,28 @@ export class LedgerService {
634640

635641
// Disconnect from Ledger device
636642
async disconnect(): Promise<void> {
637-
if (this.transport) {
638-
await this.transport.close()
639-
this.transport = null
643+
if (this.#transport) {
644+
await this.#transport.close()
645+
this.#transport = null
640646
this.currentAppType = LedgerAppType.UNKNOWN
641647
this.stopAppPolling() // Stop polling on disconnect
642648
}
643649
}
644650

645-
// Get current transport (for wallet usage)
646-
getTransport(): TransportBLE {
647-
if (!this.transport) {
648-
throw new Error('Transport not initialized. Call connect() first.')
649-
}
650-
return this.transport
651-
}
652-
653651
// Check if transport is available and connected
654652
isConnected(): boolean {
655-
return this.transport !== null && this.transport.isConnected
653+
return this.#transport !== null && this.#transport.isConnected
656654
}
657655

658656
// Ensure connection is established for a specific device
659657
async ensureConnection(deviceId: string): Promise<TransportBLE> {
660658
await this.reconnectIfNeeded(deviceId)
661-
return this.getTransport()
659+
return this.transport
660+
}
661+
662+
// Get the current transport (for compatibility with existing code)
663+
async getTransport(): Promise<TransportBLE> {
664+
return this.transport
662665
}
663666
}
664667

0 commit comments

Comments
 (0)