celo-org / celo-org/developer-tooling
--ledgerLiveMode iterates the BIP-44 change index instead of the hardened account index
- 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
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