celo-org / celo-org/developer-tooling

--ledgerLiveMode iterates the BIP-44 change index instead of the hardened account index

Open
#789 0 comments 0 reactions 0 assignees View on GitHub
bug celocli
Dominant language
TypeScript
Stars
44
Forks
36
PR merge metrics
No merged PRs in 30d

Description

### Package

- `@celo/celocli` 9.0.1
- `@celo/wallet-ledger` 8.0.4

Both packages are up to date.

### Environment

- macOS on Apple Silicon
- Ledger Nano X

### Command

```bash
celocli account:list --useLedger --ledgerAddresses 3 --local --ledgerLiveMode
```

### Describe the bug

`--ledgerLiveMode` does not discover Ledger Live accounts beyond the first account.

With the default Ethereum base path `m/44'/60'/0'`, the command above derives:

```text
m/44'/60'/0'/0/0
m/44'/60'/0'/1/0
m/44'/60'/0'/2/0
```

Ledger Live's standard BIP-44 account paths are instead:

```text
m/44'/60'/0'/0/0
m/44'/60'/1'/0/0
m/44'/60'/2'/0/0
```

I confirmed this directly against a Ledger Nano X. The expected third Ledger Live account was returned for `m/44'/60'/2'/0/0`, but not by `celocli --ledgerLiveMode --ledgerAddresses 3`.

#### Expected behavior

`--ledgerLiveMode --ledgerAddresses 3` should retrieve hardened account indexes 0, 1, and 2:

```text
m/44'/60'/0'/0/0
m/44'/60'/1'/0/0
m/44'/60'/2'/0/0
```

#### Actual behavior

It fixes the account component at `0'` and iterates the non-hardened change component. Only the first Ledger Live account is therefore discoverable. Transactions from later accounts fail because the `--from` address is not loaded into the Ledger wallet.

### Likely cause

In [`packages/cli/src/base.ts`](https://github.com/celo-org/developer-tooling/blob/master/packages/cli/src/base.ts), Ledger Live mode maps the requested indexes to `changeIndexes`:

```ts
derivationPathIndexes: isLedgerLiveMode ? [0] : indicesToIterateOver,
changeIndexes: isLedgerLiveMode ? indicesToIterateOver : [0],
```

In [`packages/sdk/wallets/wallet-ledger/src/ledger-wallet.ts`](https://github.com/celo-org/developer-tooling/blob/master/packages/sdk/wallets/wallet-ledger/src/ledger-wallet.ts), the account component is fixed by `baseDerivationPath`:

```ts
const [purpose, coinType, account] = this.baseDerivationPath.split('/')
for (const changeIndex of this.changeIndexes) {
for (const addressIndex of this.derivationPathIndexes) {
const derivationPath =
`${purpose}/${coinType}/${account}/${changeIndex}/${addressIndex}`
}
}
```

This prevents `--ledgerLiveMode` from iterating the hardened account component.

Ledger Live's default scheme is `44'/'/'//

`:

- [Ledger Live derivation implementation](https://github.com/LedgerHQ/ledger-live/blob/8e6b1e1b4cd3a8e547dad0afa2c59e3320d2e75c/libs/ledger-wallet-framework/src/derivation.ts#L337-L354)
- [BIP-44 path levels](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
- [`--ledgerLiveMode` introduction: PR #488](https://github.com/celo-org/developer-tooling/pull/488)
- [Original issue #448](https://github.com/celo-org/developer-tooling/issues/448)

### Suggested fix

Support iterating `accountIndexes`, producing:

```ts
`${purpose}/${coinType}/${accountIndex}'/${changeIndex}/${addressIndex}`
```

Ledger Live mode should effectively use:

```ts
accountIndexes: indicesToIterateOver
changeIndexes: [0]
derivationPathIndexes: [0]
```

Tests should include account index 1 or 2; index 0 cannot distinguish the incorrect path from the Ledger Live path.

### Workaround

Set the desired account as the base path and do not use `--ledgerLiveMode`:

```bash
celocli config:set --derivationPath "m/44'/60'/2'"
celocli account:list --useLedger --ledgerAddresses 1 --local
```

This derives `m/44'/60'/2'/0/0`. Restore the default afterward with:

```bash
celocli config:set --derivationPath eth
```

Contributor guide

Open the contributing guide

Research direction

Start in packages/cli/src/base.ts and packages/sdk/wallets/wallet-ledger/src/ledger-wallet.ts, tracing how Ledger Live indexes become derivation paths. Add coverage for account index 1 or 2, then run the relevant CLI and wallet tests; done means --ledgerLiveMode --ledgerAddresses 3 derives account paths 0'/0/0, 1'/0/0, and 2'/0/0.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.