Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,6 @@ cd java
./qa-repl/cli-boundary.sh build/libs/wallet-cli.jar # entry point takes only --version/--help
```

See `java/qa-repl/README.md`. The older `qa/` harness only ever drove the standard
CLI, which was removed in v4.13.0.

## Architecture

This is a **TRON blockchain CLI wallet** built on the [Trident SDK](https://github.com/tronprotocol/trident). It communicates with TRON nodes via gRPC.
Expand Down
2 changes: 1 addition & 1 deletion java/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ plugins {
}

group 'Tron'
version '4.13.0'
version '4.13.1'

apply plugin: 'java'
apply plugin: 'com.google.protobuf'
Expand Down
2 changes: 1 addition & 1 deletion java/src/main/java/org/tron/common/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public class Utils {

public static final int MIN_LENGTH = 2;
public static final int MAX_LENGTH = 14;
public static final String VERSION = " v4.13.0";
public static final String VERSION = " v4.13.1";
public static final String TRANSFER_METHOD_ID = "a9059cbb";

private static SecureRandom random = new SecureRandom();
Expand Down
15 changes: 12 additions & 3 deletions ts/docs/commands/backup.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,18 @@ With an account, `backup` writes that account's secret material and metadata to

Two formats:

- **Native** (default) — the wallet's own backup JSON. A seed account exports its recovery phrase, so the whole seed moves with it.
- **Native** — the wallet's own backup JSON. A seed account exports its recovery phrase, so the whole seed moves with it.
- **`--keystore`** — a standard Web3 keystore JSON, importable by TronLink and others, encrypted with **your master password**. A keystore holds a **single private key**: an HD account exports only its current derived key, and that key arrives elsewhere as a standalone account with nothing derivable from it. Use the native format to move a seed.

In a fully interactive terminal, omitting `--keystore` opens a format selector before the password prompt. Commands using `--password-stdin`, and other non-interactive invocations, keep native as the default so scripts never stop for this choice.

The native export may warn that some stored accounts need a separate `--keystore` export. Follow
that warning before deleting anything; see [Recover addresses after
`legacy_derivation`](../troubleshooting/legacy-derivation-recovery.md).

The warning means this version's default mnemonic import and derive flow will not recreate those
TRON addresses. The recovery phrase can still derive their keys at the listed legacy paths.

**A keystore also holds one key per *family*.** A seed account derives a different key for TRON (coin type 195) and for EVM (coin type 60), and a keystore can carry only one of them, so `--network` selects which — falling back to `config.defaultNetwork` when omitted. The receipt names the family that was written, and the export log records it. A private-key account has a single key and ignores the selection; the native backup covers every family at once, so it needs no choice and reports none.

**Files land in the current working directory** by default — `./<accountId>-<timestamp>.json`, or `./<accountId>-<timestamp>.keystore.json` with `--keystore`. `--out` overrides the path.
Expand All @@ -40,7 +49,7 @@ The positional account is the exception: it means different things in the two fo
| Option | Description |
|---|---|
| `<account>` | Account to export, by accountId, label, or address. Required unless `--records`; **with** `--records` it filters the log instead, like `--account` |
| `--keystore` | Export as a standard Web3 keystore instead of the native format |
| `--keystore` | Export as a standard Web3 keystore instead of the native format. Omit in a fully interactive terminal to choose |
| `--out <path>` | Output file path; mode 0600, never overwritten (default: the current directory, see above) |
| `--password-stdin` | Master password from stdin (fd 0) |
| `--network <id>` | With `--keystore`, which family's key to export (`tron:3448148188` → the TRON key, `eip155:1` → the EVM key). No node is contacted |
Expand Down Expand Up @@ -140,7 +149,7 @@ Both forms are local and contact no node, but `backup` has an optional network d
| `index` | number \| null | HD derivation index; `null` for private-key accounts |
| `active` | boolean | Whether it is the active account |
| `addresses` | object | One entry per family the account can produce: `tron` and/or `evm` |
| `derivationPath` | object \| null | Per-family BIP44 path for `seed` accounts; `null` for `privateKey` |
| `derivationPath` | object \| null | The verified BIP44 path behind each address. A seed backup unlocks the seed and reports every family's actual path, including the pre-4.13.1 TRON path for a stranded account; a private-key account reports `null` |
| `family` | string | With `--keystore`, which family's key was written; absent for a native backup, which covers every family |
| `seedId` | string | Owning seed wallet id (`seed` accounts only) |
| `secretType` | string | Kind of exported secret — `mnemonic`, or `privateKey` with `--keystore` |
Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/create.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ printf '%s' "$PW" | wallet-cli create --label main --password-stdin -o json
| `index` | number | HD derivation index (0 for the first account) |
| `active` | boolean | Whether it became the active account |
| `addresses` | object | One address per family the account can produce: `tron` (base58) and `evm` (`0x`, EIP-55 checksummed) |
| `derivationPath` | object | The BIP44 path each address came from: `{"tron":"m/44'/195'/<index>'/0/0","evm":"m/44'/60'/0'/0/<index>"}` |
| `derivationPath` | object | The BIP44 path each address came from — `m/44'/<coin>'/0'/0/<index>` per family. `create` only ever makes index 0: `{"tron":"m/44'/195'/0'/0/0","evm":"m/44'/60'/0'/0/0"}` |
| `seedId` | string | Owning seed wallet id |

## Exit status
Expand Down
4 changes: 2 additions & 2 deletions ts/docs/commands/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ wallet-cli current -o json
```

```json
{"schema":"wallet-cli.result.v1","success":true,"command":"current","data":{"accountId":"wlt_z259a1hq.0","label":"main","type":"seed","index":0,"active":true,"addresses":{"tron":"TE9kPMtaMjfZN95CuPRsCHUQGWwx9EcJW8","evm":"0x7B28FE10FBccE88c3967ff0Fd64f1ffB46b46C9C"},"seedId":"wlt_z259a1hq","derivationPath":{"tron":"m/44'/195'/0'/0/0","evm":"m/44'/60'/0'/0/0"}},"meta":{"durationMs":14,"warnings":[]},"chain":{"family":"tron","network":"tron:728126428","chainId":"728126428"}}
{"schema":"wallet-cli.result.v1","success":true,"command":"current","data":{"accountId":"wlt_z259a1hq.0","label":"main","type":"seed","index":0,"active":true,"addresses":{"tron":"TE9kPMtaMjfZN95CuPRsCHUQGWwx9EcJW8","evm":"0x7B28FE10FBccE88c3967ff0Fd64f1ffB46b46C9C"},"seedId":"wlt_z259a1hq","derivationPath":null},"meta":{"durationMs":14,"warnings":[]},"chain":{"family":"tron","network":"tron:728126428","chainId":"728126428"}}
```

With no active account yet, it fails with `missing_wallet_address` (exit 1):
Expand All @@ -89,7 +89,7 @@ error [missing_wallet_address]: no active account; import one first
| `index` | number \| null | HD derivation index; `null` for non-HD accounts |
| `active` | boolean | `true` for the active account; `false` when `--account` selected a different one |
| `addresses` | object | One entry per family the account can produce: `tron` (base58) and/or `evm` (`0x`, EIP-55 checksummed) |
| `derivationPath` | object \| null | The BIP32 path behind each address: every family for a `seed` account, the single chosen path for a `ledger` account; `null` for `privateKey` and `watch`, which were never derived |
| `derivationPath` | null | Always `null`; `current` does not unlock the seed or provide derivation information |
| `seedId` | string | Owning seed wallet id (`seed` accounts only) |
| `family` | string | Chain family this account is bound to — single-family accounts (`watch`, `ledger`) only |
| `receiveAddress` | string | Present in JSON only when `--qr` was requested; address selected by `--network` |
Expand Down
2 changes: 1 addition & 1 deletion ts/docs/commands/delete.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Plus [global options](index.md).

## Notes

Deleting an HD wallet cascades from the seed root — all derived accounts go with it. On-chain assets are untouched; re-import the mnemonic to regain access. Back up first. Metadata-only — no master password needed.
Deleting an HD wallet cascades from the seed root — all derived accounts go with it. On-chain assets are untouched. Run [`backup`](backup.md) first and follow any warning it reports. Metadata-only — no master password needed.

## Examples

Expand Down
41 changes: 28 additions & 13 deletions ts/docs/commands/derive.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# wallet-cli derive

Derive the next HD account from a seed wallet (by --seed-id).
Derive the next HD account from a seed wallet.

## Synopsis

```
wallet-cli derive --seed-id <wlt_…> [--index <n>] [--label <l>] [options]
wallet-cli derive [--seed-id <wlt_…>] [--account <account>] [--index <n>] [--label <l>] [options]
```

## Options

| Option | Description |
|---|---|
| `--seed-id <string>` | seed id of the HD wallet to derive from — the HD group header in `list` [required] |
| `--seed-id <string>` | seed id of the HD wallet to derive from. Takes precedence over `--account` |
| `--account <string>` | account ID, label, or address belonging to the HD wallet. Defaults to the active account |
| `--index <number>` | explicit HD account index; omit to use the next free index. An index that already exists is not re-derived — the existing account is made active and `status` comes back `"existing"` |
| `--label <string>` | label for the new account, 1-64 chars; omit to auto-generate |
| `--password-stdin` | read the master password from stdin (fd 0) |
Expand All @@ -21,32 +22,46 @@ Plus [global options](index.md).

## Notes

Private-key and Ledger accounts have no seed and cannot derive. See [Accounts & HD](../concepts/accounts-and-hd.md).
You can select the wallet through any of its HD accounts; it does not have to be index 0. When both selectors are present, `--seed-id` takes precedence. Without either selector, `derive` uses the active account.

Private-key, Ledger, and watch-only accounts have no seed and cannot derive. Select an HD account or pass `--seed-id`. See [Accounts & HD](../concepts/accounts-and-hd.md).

When creating a new index, `derive` refuses a wallet containing an unsupported stored TRON derivation with `legacy_derivation`. A stored address that does not match the seed fails with `derivation_mismatch`.

If `--index` selects an existing slot, no new key is derived. A verified account is made active and returns `status: "existing"`; an address that does not match the seed fails with `derivation_mismatch` before the active account changes. Reselecting a legacy slot succeeds but warns that default mnemonic recovery will not recreate its TRON address. The phrase can still derive the key at the reported path; follow [Recover addresses after `legacy_derivation`](../troubleshooting/legacy-derivation-recovery.md).

## Examples

In the examples, `$PW` is your master password (from an environment variable, password manager, etc.), fed on stdin via `--password-stdin`.

```bash
printf '%s' "$PW" | wallet-cli derive --seed-id wlt_y8cz6xda --password-stdin
printf '%s' "$PW" | wallet-cli derive --password-stdin
```

```bash
printf '%s' "$PW" | wallet-cli derive --account main-1 --password-stdin
```

```bash
printf '%s' "$PW" | wallet-cli derive --seed-id wlt_vy5n6qhh --password-stdin
```

```console
✅ Derived sub-account "main-1"
Account ID wlt_y8cz6xda.1
Account ID wlt_vy5n6qhh.1
Index 1
TRON address TWCa1W6BkcXZnRGxeZZw9jh8eNgULDVGzj
EVM address 0x2395227A93465175c6D6EAF2B9d37c2cC0BaB60c
TRON address TKpmAZmDcGhJBugwAhbJ1ubWeTM4VZgRbK
EVM address 0x7Fee0863cB70a3C7c937A292220dD0C52E2526e0
Active yes
Note shares master mnemonic; no separate backup needed
Note shares the wallet's recovery phrase
```

```bash
printf '%s' "$PW" | wallet-cli derive --seed-id wlt_y8cz6xda --password-stdin -o json
printf '%s' "$PW" | wallet-cli derive --seed-id wlt_vy5n6qhh --password-stdin -o json
```

```json
{"schema":"wallet-cli.result.v1","success":true,"command":"derive","data":{"status":"created","accountId":"wlt_y8cz6xda.1","label":"main-1","type":"seed","index":1,"active":true,"addresses":{"tron":"TWCa1W6BkcXZnRGxeZZw9jh8eNgULDVGzj","evm":"0x2395227A93465175c6D6EAF2B9d37c2cC0BaB60c"},"seedId":"wlt_y8cz6xda","derivationPath":{"tron":"m/44'/195'/1'/0/0","evm":"m/44'/60'/0'/0/1"}},"meta":{"durationMs":1013,"warnings":[]}}
{"schema":"wallet-cli.result.v1","success":true,"command":"derive","data":{"status":"created","accountId":"wlt_vy5n6qhh.1","label":"main-1","type":"seed","index":1,"active":true,"addresses":{"tron":"TKpmAZmDcGhJBugwAhbJ1ubWeTM4VZgRbK","evm":"0x7Fee0863cB70a3C7c937A292220dD0C52E2526e0"},"seedId":"wlt_vy5n6qhh","derivationPath":{"tron":"m/44'/195'/0'/0/1","evm":"m/44'/60'/0'/0/1"}},"meta":{"durationMs":980,"warnings":[]}}
```

## Output
Expand All @@ -62,12 +77,12 @@ printf '%s' "$PW" | wallet-cli derive --seed-id wlt_y8cz6xda --password-stdin -o
| `index` | number | HD derivation index |
| `active` | boolean | Always `true` (the new account is made active) |
| `addresses` | object | One address per family the account can produce: `tron` (base58) and `evm` (`0x`, EIP-55 checksummed) |
| `derivationPath` | object | The BIP44 path each address came from: `{"tron":"m/44'/195'/<index>'/0/0","evm":"m/44'/60'/0'/0/<index>"}` |
| `derivationPath` | object | The verified BIP44 path each address came from. A newly created account reports `m/44'/<coin>'/0'/0/<index>` for both families; `--index` naming an existing account reports that account's actual current or legacy path |
| `seedId` | string | Owning seed wallet id |

## Exit status

`0` success · `1` execution failure · `2` usage error. See [machine-interface](../machine-interface.md).
`0` success · `1` execution failure, including `legacy_derivation` and `derivation_mismatch` (see Notes) · `2` usage error. See [machine-interface](../machine-interface.md).

## See also

Expand Down
9 changes: 6 additions & 3 deletions ts/docs/commands/import/ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ wallet-cli import ledger --app <tron|ethereum> [--index <n> | --path <bip32> | -
| Option | Description |
|---|---|
| `--app <tron\|ethereum>` | **Required.** Ledger app to open on the device; this is what selects the chain family and the derivation scheme |
| `--index <number>` | Account index under wallet-cli's family path template. Mutually exclusive with `--path` / `--address` |
| `--index <number>` | Account index under **Ledger Live's** template (`m/44'/<coin>'/<n>'/0/0`), not the software one `derive` uses. Mutually exclusive with `--path` / `--address` |
| `--path <string>` | Explicit derivation path, e.g. `m/44'/195'/0'/0/0` (TRON) or `m/44'/60'/0'/0/0` (Ethereum) |
| `--address <string>` | Known address to locate by bounded scan |
| `--scan-limit <number>` | Indexes to scan with `--address` (default 20) |
Expand All @@ -28,7 +28,9 @@ Creates a watch-only entry; no secret is stored. Requires the device unlocked wi

When all three locators are omitted, an attached TTY opens a paged account selector (five derived addresses at a time). In non-interactive use there is no selector and the command falls back to index 0; pass `--index`, `--path`, or `--address` explicitly in scripts.

For Ethereum, `--index <n>` uses wallet-cli's MetaMask-style path `m/44'/60'/0'/0/<n>`. Ledger Live commonly uses `m/44'/60'/<n>'/0/0`; use an explicit `--path` when importing an account created under that scheme.
`--index <n>` follows **Ledger Live's** template on both chains — `m/44'/195'/<n>'/0/0` for TRON and `m/44'/60'/<n>'/0/0` for Ethereum. The interactive picker walks the same template and prints each path beside its address.

Software accounts instead use `m/44'/<coin>'/0'/0/<n>`. The two templates agree only at index 0. Use `--path` to register any other device derivation scheme; `--address` and `--scan-limit` search only the Ledger Live template.

`--app` is what makes a Ledger account **single-family**: the TRON app registers a `tron` account and the Ethereum app an `evm` one, and the resulting account has only that one address. Import the same device twice, once per app, to hold both. See [Ledger guide](../../guide/ledger.md).

Expand Down Expand Up @@ -59,7 +61,7 @@ wallet-cli import ledger --app tron --index 0 --label cold -o json
```

```json
{"schema":"wallet-cli.result.v1","success":true,"command":"import.ledger","data":{"status":"created","accountId":"wlt_7h2k9d3m","label":"cold","type":"ledger","index":null,"active":true,"addresses":{"tron":"TMSgJxtPw29AFEHMXsjGo4kWV7UwbCToHJ"},"family":"tron","path":"m/44'/195'/0'/0/0"},"meta":{"durationMs":812,"warnings":[]}}
{"schema":"wallet-cli.result.v1","success":true,"command":"import.ledger","data":{"status":"created","accountId":"wlt_7h2k9d3m","label":"cold","type":"ledger","index":null,"active":true,"addresses":{"tron":"TMSgJxtPw29AFEHMXsjGo4kWV7UwbCToHJ"},"family":"tron","path":"m/44'/195'/0'/0/0","derivationPath":{"tron":"m/44'/195'/0'/0/0"}},"meta":{"durationMs":812,"warnings":[]}}
```

## Output
Expand All @@ -77,6 +79,7 @@ wallet-cli import ledger --app tron --index 0 --label cold -o json
| `addresses` | object | The single address, keyed by its family — `{"tron":"T…"}` for the TRON app, `{"evm":"0x…"}` for the Ethereum app |
| `family` | string | Chain family selected by `--app` — `tron` or `evm` |
| `path` | string | Derivation path on the device |
| `derivationPath` | object | The same verified device path, keyed by its chain family for the common account descriptor shape |

## Exit status

Expand Down
3 changes: 2 additions & 1 deletion ts/docs/commands/import/watch.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ wallet-cli import watch --address TMSgJxtPw29AFEHMXsjGo4kWV7UwbCToHJ --label col
```

```json
{"schema":"wallet-cli.result.v1","success":true,"command":"import.watch","data":{"status":"created","accountId":"wlt_jsyq8fxe","label":"cold","type":"watch","index":null,"active":false,"addresses":{"tron":"TMSgJxtPw29AFEHMXsjGo4kWV7UwbCToHJ"},"family":"tron"},"meta":{"durationMs":36,"warnings":[]}}
{"schema":"wallet-cli.result.v1","success":true,"command":"import.watch","data":{"status":"created","accountId":"wlt_jsyq8fxe","label":"cold","type":"watch","index":null,"active":false,"addresses":{"tron":"TMSgJxtPw29AFEHMXsjGo4kWV7UwbCToHJ"},"family":"tron","derivationPath":null},"meta":{"durationMs":36,"warnings":[]}}
```

## Output
Expand All @@ -63,6 +63,7 @@ wallet-cli import watch --address TMSgJxtPw29AFEHMXsjGo4kWV7UwbCToHJ --label col
| `active` | boolean | Whether this account is already the current active account. Registering a watch-only account does not select it; use [`use`](../use.md) explicitly |
| `addresses` | object | The single address, keyed by its family — `{"tron":"T…"}` or `{"evm":"0x…"}` |
| `family` | string | Chain family detected from the address — `tron` or `evm` |
| `derivationPath` | null | Always `null`; a watch-only address was not derived by this wallet |

## Exit status

Expand Down
Loading