diff --git a/.github/workflows/build-artifact.yml b/.github/workflows/build-artifact.yml new file mode 100644 index 000000000..9b50bb6fa --- /dev/null +++ b/.github/workflows/build-artifact.yml @@ -0,0 +1,60 @@ +name: Build Artifact + +on: + push: + branches: + - "release_*" + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + name: Build wallet-cli artifact + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "8" + cache: gradle + + - name: Build + run: ./gradlew clean build shadowJar shadowDistZip + + - name: Package artifacts + shell: bash + run: | + set -euo pipefail + + version="${GITHUB_REF_NAME#release_}" + if [ "$version" = "$GITHUB_REF_NAME" ]; then + version="dev" + fi + + artifact_dir="artifacts" + artifact_base="wallet-cli-${version}-rc.${GITHUB_RUN_NUMBER}" + artifact_name="wallet-cli-artifact-${GITHUB_REF_NAME}" + + mkdir -p "$artifact_dir" + cp build/libs/wallet-cli.jar "$artifact_dir/${artifact_base}.jar" + cp build/distributions/*shadow*.zip "$artifact_dir/${artifact_base}.zip" + git rev-parse HEAD > "$artifact_dir/git-sha.txt" + echo "ARTIFACT_NAME=${artifact_name}" >> "$GITHUB_ENV" + + ( + cd "$artifact_dir" + shasum -a 256 "${artifact_base}.jar" "${artifact_base}.zip" git-sha.txt > checksums.txt + ) + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ARTIFACT_NAME }} + path: artifacts/* diff --git a/.gitignore b/.gitignore index 54175c1f5..bfa1474f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.claude/settings.local.json .DS_Store build out @@ -11,4 +12,27 @@ src/gen tools src/main/resources/static/js/tronjs/tron-protoc.js logs +docs +!docs/ +!docs/standard-cli-contract-spec.md FileTest +bin + +# Wallet keystore files created at runtime +Wallet/ +Mnemonic/ +wallet_data/ + +# QA runtime output +qa/results/ +qa/runtime/ +qa/report.txt +qa/.verify.lock/ + +# claude +.claude/ + +.private/ + +# graphify +graphify-out/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..67bc9fcb0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,124 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Build & Run + +```bash +# Build the project (generates protobuf sources into src/main/gen/) +./gradlew build + +# Build fat JAR (output: build/libs/wallet-cli.jar) +./gradlew shadowJar + +# Run in REPL 交互模式 (human-friendly, interactive prompts) +./gradlew run +# Or after building: java -jar build/libs/wallet-cli.jar + +# Run in standard CLI mode (non-interactive, scriptable) +java -jar build/libs/wallet-cli.jar --network nile get-account --address TXyz... +java -jar build/libs/wallet-cli.jar --output json --network nile get-account --address TXyz... + +# Run tests +./gradlew test + +# Run a single test class +./gradlew test --tests "org.tron.keystore.StringUtilsTest" + +# Clean (also removes src/main/gen/) +./gradlew clean +``` + +Java 8 source/target compatibility. Protobuf sources are in `src/main/protos/` and generate into `src/main/gen/` — this directory is git-tracked but rebuilt on `clean`. + +## QA Verification + +The `qa/` directory contains shell-based parity tests that compare interactive REPL output vs standard CLI (text and JSON modes). Requires a funded Nile testnet account. + +```bash +# Run QA verification (needs TRON_TEST_PRIVATE_KEY env var for private key) +TRON_TEST_PRIVATE_KEY= bash qa/run.sh verify + +# QA config is in qa/config.sh; test commands are in qa/commands/*.sh +# MASTER_PASSWORD env var is used for keystore auto-login (default: testpassword123A) +``` + +## 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. + +### Two CLI Modes + +1. **REPL 交互模式** (human-friendly) — `Client` class with JCommander `@Parameters` inner classes. Entry point: `org.tron.walletcli.Client`. Features tab completion, interactive prompts, and conversational output. This is the largest file (~4700 lines). Best for manual exploration and day-to-day wallet management by humans. +2. **Standard CLI 模式** (AI-agent-friendly) — `StandardCliRunner` with `CommandRegistry`/`CommandDefinition` pattern in `org.tron.walletcli.cli.*`. Supports `--output json`, `--network`, `--quiet` flags. Commands are registered in `cli/commands/` classes (e.g., `WalletCommands`, `TransactionCommands`, `QueryCommands`). Designed for automation: deterministic exit codes, structured JSON output, no interactive prompts, and env-var-based authentication — ideal for AI agents, scripts, and CI/CD pipelines. + +The standard CLI suppresses all stray stdout/stderr in JSON mode to ensure machine-parseable output. Authentication is automatic via `MASTER_PASSWORD` env var + keystore files in `Wallet/`. + +### Standard CLI Contract + +Before changing parser behavior, auth flow, JSON output, command success/failure semantics, or `qa/` expectations for +the standard CLI, read: + +- `docs/standard-cli-contract-spec.md` + +Treat that file as the source of truth for the standard CLI contract unless the repository owner explicitly decides to +revise it. + +### Request Flow + +``` +# Standard CLI mode: +User Input → GlobalOptions → StandardCliRunner → CommandRegistry → CommandHandler → WalletApiWrapper → WalletApi → Trident SDK → gRPC → TRON Node + +# Interactive REPL mode: +User Input → Client (JCommander) → WalletApiWrapper → WalletApi → Trident SDK → gRPC → TRON Node +``` + +### Key Classes + +- **`org.tron.walletcli.Client`** — Legacy REPL entry point and CLI command dispatcher. Each command is a JCommander `@Parameters` inner class. +- **`org.tron.walletcli.cli.StandardCliRunner`** — New standard CLI executor. Handles network init, auto-authentication, JSON stream suppression, and command dispatch. +- **`org.tron.walletcli.cli.CommandRegistry`** — Maps command names/aliases to `CommandDefinition` instances. Supports fuzzy suggestion on typos. +- **`org.tron.walletcli.cli.CommandDefinition`** — Immutable command metadata (name, aliases, options, handler). Built via fluent `Builder` API. +- **`org.tron.walletcli.cli.OutputFormatter`** — Formats output as text or JSON. In JSON mode, wraps results in `{"success":true,"data":...}` envelope. +- **`org.tron.walletcli.WalletApiWrapper`** — Orchestration layer between CLI and core wallet logic. Handles transaction construction, signing, and broadcasting. +- **`org.tron.walletserver.WalletApi`** — Core wallet operations: account management, transaction creation, proposals, asset operations. Delegates gRPC calls to Trident. +- **`org.tron.walletcli.ApiClientFactory`** — Creates gRPC client instances for different networks (mainnet, Nile testnet, Shasta testnet, custom). + +### Adding a New Standard CLI Command + +1. Create or extend a class in `cli/commands/` (e.g., `TransactionCommands.java`) +2. Build a `CommandDefinition` via `CommandDefinition.builder()` with name, aliases, options, and handler +3. Register it in the appropriate `register(CommandRegistry)` method +4. The handler receives `(ParsedOptions, WalletApiWrapper, OutputFormatter)` — use `formatter.success()/error()` for output + +### Package Organization + +| Package | Purpose | +|---------|---------| +| `walletcli` | CLI entry points, API wrapper | +| `walletcli.cli` | Standard CLI framework: registry, definitions, options, formatter | +| `walletcli.cli.commands` | Standard CLI command implementations by domain | +| `walletserver` | Core wallet API and gRPC communication | +| `common` | Crypto utilities, encoding, enums, shared helpers | +| `core` | Configuration, data converters, DAOs, exceptions, managers | +| `keystore` | Wallet file encryption/decryption, key management | +| `ledger` | Ledger hardware wallet integration via HID | +| `mnemonic` | BIP39 mnemonic seed phrase support | +| `multi` | Multi-signature transaction handling | +| `gasfree` | GasFree transaction API (transfer tokens without gas) | + +### Configuration + +- **Network config:** `src/main/resources/config.conf` (HOCON format via Typesafe Config) +- **Logging:** `src/main/resources/logback.xml` (Logback, INFO level console + rolling file) +- **Lombok:** `lombok.config` — uses `logger` as the log field name (not the default `log`) + +### Key Frameworks & Libraries + +- **Trident SDK 0.10.0** — All gRPC API calls to TRON nodes +- **JCommander 1.82** — CLI argument parsing (REPL 交互模式) +- **JLine 3.25.0** — Interactive terminal/readline +- **BouncyCastle** — Cryptographic operations +- **Protobuf 3.25.5 / gRPC 1.60.0** — Protocol definitions and transport +- **Lombok** — `@Getter`, `@Setter`, `@Slf4j` etc. (annotation processing) diff --git a/build.gradle b/build.gradle index 63b4e6696..c2aadba5c 100644 --- a/build.gradle +++ b/build.gradle @@ -130,6 +130,10 @@ protobuf { } } +tasks.named("processResources") { + dependsOn tasks.named("generateProto") +} + clean.doFirst { delete "src/main/gen" } @@ -146,3 +150,19 @@ shadowJar { version = null mergeServiceFiles() // https://github.com/grpc/grpc-java/issues/10853 } + +task qaJar(type: Jar, dependsOn: [shadowJar, testClasses]) { + from zipTree(shadowJar.archiveFile) + from sourceSets.test.output + archiveBaseName.set('wallet-cli-qa') + archiveClassifier.set('') + archiveVersion.set('') + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +task qaRun(type: JavaExec) { + classpath = sourceSets.test.runtimeClasspath + mainClass = 'org.tron.qa.QARunner' + args = project.hasProperty('qaArgs') ? project.property('qaArgs').split(' ') : ['list'] + standardInput = System.in +} diff --git a/docs/standard-cli-contract-spec.md b/docs/standard-cli-contract-spec.md new file mode 100644 index 000000000..42cc65767 --- /dev/null +++ b/docs/standard-cli-contract-spec.md @@ -0,0 +1,980 @@ +# Standard CLI Contract Spec + +This document defines the intended contract for the standard CLI path under `org.tron.walletcli.cli.*`. +When changing parser behavior, command execution, machine-readable output, authentication, or QA coverage, +follow this spec unless the repository owner explicitly decides to revise it. + +## Scope + +This spec applies to: + +- `GlobalOptions` +- `StandardCliRunner` +- `CommandDefinition` / `ParsedOptions` +- `OutputFormatter` +- `cli/commands/*` +- `WalletApiWrapper` behavior as exposed through the standard CLI +- `qa/` verification for the standard CLI + +This spec does not require the legacy REPL path in `Client` to match the same UX or parsing behavior exactly. + +## Design Goals + +The standard CLI is intended to be: + +- deterministic +- scriptable +- machine-readable in JSON mode +- strict about malformed input +- explicit about authentication behavior + +The standard CLI should not rely on "best effort" guessing for ambiguous user input. + +## Request Flow + +The standard CLI request flow is: + +1. Parse global options +2. Resolve the command name +3. Parse command-local options +4. Apply runner-level setup such as network and auth policy +5. Execute the command handler +6. Emit a single structured success or error outcome + +## Option Layering + +The standard CLI has two distinct option layers: + +- global options +- command-local options + +### Global Options + +Global options affect the overall execution environment before the command is known. + +Examples: + +- output mode +- network selection +- wallet override +- grpc endpoint override +- quiet / verbose behavior +- global help / version handling + +Global options are parsed by `GlobalOptions.parse(String[] args)`. + +### Command-Local Options + +Command-local options belong to a specific command and are meaningful only after the command has been resolved. + +Examples: + +- `get-balance --address T...` +- `send-coin --to T... --amount 1` +- `trigger-constant-contract --contract T... --method "balanceOf(address)"` + +Command-local options are parsed by `CommandDefinition.parseArgs(String[] args)`. + +### Layer Boundary + +- global options configure how the CLI run is executed +- command-local options configure what the chosen command does +- global parsing happens first +- command-local parsing happens only after the command token is known +- a token must not be interpreted as both a global option and a command-local option in the same pass + +## Contract 1: Global Option Parsing + +`GlobalOptions.parse(String[] args)` is responsible only for parsing options that affect the whole run before +the command is known. + +### Parsing Model + +Global option parsing is a left-to-right first-pass scan. + +The parser consumes tokens until one of these happens: + +1. it reaches the first command token +2. it reaches the end of input +3. it encounters a malformed global option and fails with a usage error + +This pass is intentionally narrow. It must not inspect or reinterpret command-local options. + +### Supported Syntax + +Supported global options are: + +- valueless flags: + - `--interactive` + - `--help` + - `-h` + - `--version` + - `--quiet` + - `--verbose` +- valued options: + - `--output ` + - `--network ` + - `--wallet ` + - `--grpc-endpoint ` + +Long options may be provided in either of these equivalent forms when the option accepts a value: + +- `--name value` +- `--name=value` + +For Contract 1, this applies to valued global options only. + +### Boundary Rules + +- Global options are only recognized before the command token. +- The first token before command resolution that does not begin with `-` is the command token. +- The command token is normalized to lowercase for registry lookup. +- After the command token is found, all remaining tokens are passed through unchanged as command arguments. +- Tokens after the command token are never reinterpreted as global options, even if they look like global flags. + +Examples: + +- `wallet-cli --output json --network nile get-balance --address T...` + - global options: `--output json`, `--network nile` + - command: `get-balance` + - command args: `--address T...` +- `wallet-cli --output=json --network=nile get-balance --address T...` + - global options: `--output=json`, `--network=nile` + - command: `get-balance` + - command args: `--address T...` +- `wallet-cli get-balance --network nile` + - command: `get-balance` + - command args: `--network nile` + - `--network` is not treated as a global option because it appears after the command token +- `wallet-cli get-balance --network=nile` + - command: `get-balance` + - command args: `--network=nile` + - `--network=nile` is not treated as a global option because it appears after the command token + +### No-Command Cases + +The global parser may produce no command token when the invocation is global-only, such as: + +- `wallet-cli --help` +- `wallet-cli -h` +- `wallet-cli --version` +- `wallet-cli --interactive` + +In those cases, the parser succeeds and leaves handling to the runner / entrypoint. + +If no command is present and the invocation is not a supported global-only mode, the runner should treat that as a +usage error. + +### Help Flag Semantics + +`--help` and `-h` are reserved for help behavior. + +Rules: + +- before the command token, `--help` and `-h` request global help +- after the command token, `--help` and `-h` are passed through for command help handling +- `-h` is not available for unrelated global short-option meanings +- the global parser must not reinterpret `-h` as a command token +- standard CLI commands should treat trailing `--help` and `-h` as command-help requests, not as normal business + options + +Examples: + +- `wallet-cli -h` + - global help +- `wallet-cli --help` + - global help +- `wallet-cli get-balance -h` + - `get-balance` command help +- `wallet-cli get-balance --help` + - `get-balance` command help + +### Error Rules + +The following are usage errors at the global parsing layer: + +- unknown global option before the command token +- missing value for a valued global option +- invalid value for a constrained global option +- malformed global syntax before the command token + +Specific expectations: + +- `--outputt json get-balance` + - usage error: unknown global option `--outputt` +- `--outputt=json get-balance` + - usage error: unknown global option `--outputt` +- `--network get-balance` + - usage error: invalid value for `--network` +- `--network=get-balance` + - usage error: invalid value for `--network` +- `--network --output json` + - usage error: missing value for `--network` +- `--grpc-endpoint` + - usage error: missing value for `--grpc-endpoint` +- `--output=` + - usage error: missing or empty value for `--output` +- `--quiet=true` + - usage error: option `--quiet` does not take a value + +Error classification for valued global options: + +- if the next token does not exist: missing value +- if the next token is another long option token such as `--output`: missing value +- if the next token exists but is not allowed for a constrained option: invalid value +- if the option is provided as `--name=` with an empty value: missing or empty value +- if a valueless flag is provided as `--flag=value`: option does not take a value + +### Valued Option Rules + +For valued global options: + +- the value may be the next token or may be provided inline as `--name=value` +- the value must not itself be another long option token such as `--output` +- constrained options must validate their allowed values during global parsing, not later + +For valueless global flags: + +- the presence of the flag means `true` +- `--flag=value` is not allowed +- `--flag=` is not allowed + +Examples: + +- `--output=json` is valid +- `--network=nile` is valid +- `--wallet=/tmp/keystore.json` is valid +- `--output=` is invalid +- `--quiet=true` is invalid + +For now, the standard CLI contract does not require support for: + +- combined short flags +- `--` as a special end-of-options sentinel + +These may be added later only if the spec is updated explicitly. + +### Global and Command Parser Consistency + +The standard CLI should not support `--name=value` in one parsing layer but reject it in the other. + +If long-option inline-value syntax is supported for global parsing, it should also be supported consistently for +command-local parsing where the command option accepts a value. + +### Value-Detection Heuristic + +The global parser and command parser use intentionally different heuristics to detect whether the next token is a +missing value or a legitimate option value: + +- the global parser treats any token starting with `-` as a non-value token (rejects `-anything` as a value) +- the command parser treats only tokens starting with `--` as a non-value token (allows `-anything` as a value) + +This difference is deliberate. Command-local options include numeric types (`LONG`) where negative values such as +`-5` are legitimate. Global valued options (`--output`, `--network`, `--wallet`, `--grpc-endpoint`) never accept +negative numbers or dash-prefixed values, so the stricter heuristic is safe and catches more user errors early. + +### Repetition Rules + +Repeated global options must behave deterministically. + +- repeated valued global options are a usage error + - example: `--network nile --network main` is an error + - example: `--output json --output text` is an error + - example: `--wallet a.json --wallet b.json` is an error +- repeated boolean flags are idempotent when they do not conflict + - example: `--verbose --verbose` is equivalent to `--verbose` +- conflicting boolean flags are a usage error + - example: `--quiet --verbose` is an error + +### Explicit Non-Goals + +- Do not silently reinterpret unknown global options as command arguments. +- Do not allow a malformed global option to fall through into downstream command execution errors. +- Do not support "guessing" whether a token was meant to be a global option or a command option. +- Do not let downstream command parsing decide whether a pre-command token was a valid global option. + +## Contract 2: Command Option Parsing + +`CommandDefinition.parseArgs(String[] args)` parses only command-local options using the schema declared by the +command definition. + +### Scope + +`CommandDefinition.parseArgs(String[] args)` is responsible only for command-local syntax parsing. + +It is responsible for: + +- recognizing declared command options +- extracting option values +- performing parser-level validation of token shape and option syntax +- producing `ParsedOptions` + +It is not responsible for: + +- global option parsing +- auth, network, or output-mode policy +- command execution +- domain validation beyond parser-level type and shape checks + +### Supported Syntax + +Command-local options should support: + +- `--name value` +- `--name=value` +- boolean options as valueless flags, such as `--multi` +- boolean options with explicit values: + - `--multi=true` + - `--multi=false` + - `--multi=1` + - `--multi=0` + - `--multi=yes` + - `--multi=no` +- `-m` only for commands that explicitly declare the `multi` option + +Command-local parsing does not support: + +- arbitrary short-option aliases +- combined short flags +- positional arguments +- unknown short flags + +### Boundary Rules + +- command parsing starts only after the runner has already resolved the command token +- command parsing operates only on command arguments +- command parsing does not reinterpret tokens as global options +- command parsing does not guess whether a token was intended as a global option +- if the runner reserves `--help` or `-h` for command-help handling, those tokens should not be treated as normal + business options by generic command parsing +- unexpected bare tokens are usage errors unless positional arguments are explicitly introduced by a future spec + +### Error Rules + +The following are usage errors at the command parsing layer: + +- unknown command option +- non-boolean option missing value +- non-boolean option empty value +- boolean option with an invalid explicit value +- option provided in an unsupported form +- option that does not take a value being provided as `--name=value` +- empty option name such as `--` +- unexpected bare token + +Specific expectations: + +- a non-boolean option must never fall back to `"true"` when its value is missing +- malformed input should fail in the parser layer, not later during command execution +- `--contract --method balanceOf(address)` must fail as a parser usage error +- `--contract=` must fail as a parser usage error +- `--multi=maybe` must fail as a parser usage error + +### Repetition Rules + +Repeated command options must behave deterministically and strictly. + +- repeated valued options are a usage error +- repeated boolean options with the same effective meaning are idempotent +- repeated boolean options with conflicting explicit values are a usage error + +Examples: + +- `--amount 1 --amount 2` + - usage error +- `--multi --multi` + - valid, equivalent to `--multi` +- `--multi=true --multi=false` + - usage error + +### Parser vs Semantic Validation + +Parser-level validation and semantic validation are distinct. + +Parser-level validation is responsible for: + +- whether an option name exists +- whether an option requires a value +- whether a token is in a supported parser form +- whether a boolean literal is valid +- whether the basic shape of the argument list is valid + +Semantic validation is responsible for: + +- address validity +- numeric range checks +- command-specific business rules +- relationships between multiple options that depend on command semantics + +Examples: + +- `--contract --method balanceOf(address)` + - parser error +- `--contract=` + - parser error +- `--address abc` + - semantic validation error unless a stricter command-specific parser rule is added +- malformed vote counts or domain-specific numeric constraints + - semantic or command-specific pre-execution validation + +Command-specific validation that runs immediately after parsing may still surface as `usage_error` when the problem +is malformed user input rather than runtime execution failure. + +### Rationale + +This contract prevents malformed input such as `--contract --method balanceOf(address)` from being treated as +`contract=true` and then failing later with a misleading execution error. + +## Contract 3: Authentication Policy + +`StandardCliRunner` controls whether automatic authentication is attempted for a command. + +### Rules + +- Auto-auth is a runner policy decision, not a side effect of arbitrary wrapper calls. +- Commands that do not require a logged-in wallet must not fail purely because wallet auto-auth setup is absent. +- Commands that require a wallet should authenticate deterministically or fail with an explicit execution error. +- `--wallet` must be honored as an explicit override even if the local `Wallet/` directory is absent or empty. +- Authentication skip conditions should be surfaced as text-mode info messages when appropriate. + +### Policy Shape + +Each command should have one clear auth policy: + +- never auto-auth +- require auto-auth +- conditional auto-auth based on specific options + +Avoid ad hoc checks spread across handlers. + +### Decision Point + +Auth policy is resolved only after: + +1. global options have been parsed +2. the command has been resolved +3. command-local options have been parsed + +The runner then decides whether the command instance for this invocation is: + +- `NEVER` +- `REQUIRE` + +If a command has conditional auth behavior, that condition must be evaluated from parsed command options and must +resolve deterministically to either `NEVER` or `REQUIRE` before handler execution begins. + +### Policy Semantics + +`NEVER` means: + +- the runner must not attempt wallet discovery +- the runner must not read active-wallet state for authentication +- the runner must not load or decrypt a keystore for authentication +- the runner must not require `MASTER_PASSWORD` +- the command must be allowed to execute even if wallet auth setup is absent or broken + +`REQUIRE` means: + +- the runner must resolve an authentication target before handler execution +- the runner must successfully complete keystore loading and password verification before handler execution +- if authentication cannot be completed, the handler must not run +- failure to authenticate is an execution error, not a silent skip + +### Resolution Order + +When auth policy resolves to `REQUIRE`, the runner must resolve the target wallet in this order: + +1. explicit `--wallet` override +2. active wallet selection + +`--wallet` is authoritative for that invocation and takes precedence over active-wallet state. + +### `--wallet` Override Rules + +When `--wallet` is present, the runner must try to resolve it as: + +1. an explicit filesystem path +2. a file entry under local `Wallet/` +3. a wallet name + +Specific rules: + +- an explicit filesystem path must be honored even if the local `Wallet/` directory does not exist +- `--wallet` must not be ignored merely because the current working directory has no keystore directory +- if `--wallet` is ambiguous or does not resolve to a keystore, the command must fail with an explicit execution error + +### Active Wallet Rules + +If `--wallet` is absent and auth policy resolves to `REQUIRE`, active-wallet resolution is authoritative. + +Rules: + +- unreadable or malformed active-wallet state must not be silently treated as "unset" +- an active wallet pointing to a missing keystore must not silently fall back to another wallet +- wallet-required commands must fail explicitly when the selected active wallet cannot be used + +For commands whose auth policy resolves to `NEVER`, active-wallet problems must not block execution. + +Commands whose purpose is wallet inspection or recovery may intentionally use a more lenient read of active-wallet +state, but that behavior must be explicit in command design rather than an accidental side effect of runner auth. + +### Skip vs Fail + +For invocations whose resolved auth policy is `NEVER`: + +- auth may be skipped without error +- text-mode info messages may explain why auth was skipped +- JSON mode does not need to surface skip info as a top-level result +- the runner may still pass through the already-parsed global `--wallet` value as an explicit target selector for + command-specific business logic, as long as that does not trigger runner-managed authentication semantics + +For invocations whose resolved auth policy is `REQUIRE`: + +- missing wallet directory is an execution error unless an explicit `--wallet` path resolves successfully +- missing keystore is an execution error +- missing `MASTER_PASSWORD` is an execution error +- invalid password is an execution error +- unreadable wallet metadata or keystore content is an execution error +- the standard CLI must not fall back to interactive password prompts, wallet-selection prompts, permission prompts, + confirmation prompts, or other interactive auth flows +- "skip auto-login and let the handler fail later" is not allowed + +### Handler Boundary + +- handlers must not re-decide runner auth policy ad hoc +- handlers may still perform command-specific checks about whether a logged-in wallet is acceptable for the requested + operation +- handlers must be able to rely on the runner guarantee that `REQUIRE` commands either start authenticated or do not + start at all +- when a `NEVER` command intentionally uses global `--wallet` as a business-level target selector, that behavior + must be explicit in command design and must not implicitly fall back into runner-style auth or `MASTER_PASSWORD` + requirements + +### Standard CLI vs REPL + +This contract applies only to the standard CLI path. + +Rules: + +- changes made to satisfy this auth contract must not silently change legacy REPL auth behavior +- REPL prompt flow, password prompting, and legacy interactive recovery behavior remain separate compatibility concerns +- if standard CLI needs stricter auth handling than the REPL, isolate that behavior in `StandardCliRunner` or other + standard-CLI-only code paths rather than changing shared legacy behavior by accident + +## Contract 4: Result and Error Model + +The standard CLI must have one clear source of truth for success, failure, and exit code behavior. + +### Rules + +- Usage mistakes map to a usage error and exit code `2`. +- Execution failures map to an execution error and exit code `1`. +- Success maps to exit code `0`. +- A command must not report success if the underlying operation merely printed a warning and returned early. +- The standard CLI path must not depend on legacy direct `System.out.println(...)` calls to signal success or failure. + +### Recommended Responsibility Split + +- Command handlers decide the public CLI outcome. +- `WalletApiWrapper` should return structured results or throw explicit exceptions for failure cases. +- `OutputFormatter` is the only place that should emit standard CLI envelopes and terminal-facing error formatting. + +### Outcome Ownership + +For the standard CLI path, the public outcome of a command is determined by the standard CLI layer, not by legacy +printing side effects. + +Rules: + +- a command invocation must end in exactly one public outcome: + - success + - usage error + - execution error +- a handler must not rely on legacy stdout/stderr text to imply success +- a handler must not report success merely because no exception was thrown +- if an underlying operation returns early, reports failure, or leaves the command without a real result, the handler + must map that to a non-success outcome + +### Usage Error vs Execution Error + +`usage_error` covers malformed CLI input, including: + +- invalid option syntax +- missing required arguments +- parser-level invalid values +- command-specific malformed user input detected before execution + +`execution_error` covers failures after the invocation is otherwise well-formed, including: + +- authentication failure +- keystore resolution or loading failure +- RPC or network failure +- chain rejection +- wrapper-level operational failure +- command execution that cannot produce the promised result + +The standard CLI must prefer early `usage_error` classification for malformed input rather than letting parser problems +leak into downstream execution failures. + +### Single-Outcome Rule + +The standard CLI invocation model is single-outcome. + +Rules: + +- one invocation must not emit multiple competing terminal outcomes +- once a command has emitted a terminal success or error outcome, no later layer should reinterpret that invocation +- handlers must not emit success and then continue into a later failure path +- if a handler returns without establishing a valid outcome for the requested operation, that is a standard CLI + contract violation and should surface as an execution error rather than silent success + +### Legacy Integration Boundary + +The standard CLI may call shared legacy layers such as `WalletApiWrapper`, but legacy behavior is not the public +result contract for the standard CLI. + +Rules: + +- direct prints from shared legacy code are compatibility details, not the standard CLI source of truth +- if a shared wrapper method only prints warnings or status text, the standard CLI must not treat that as sufficient + success signaling +- if a shared wrapper method cannot express failure cleanly enough for the standard CLI contract, the standard CLI + should adapt it explicitly rather than inheriting ambiguous behavior + +### Additive Change Preference + +Because `WalletApiWrapper` and related utilities are shared with the legacy REPL path, changes to shared layers should +prefer additive evolution. + +Rules: + +- prefer adding new structured return paths, helper methods, adapters, or standard-CLI-specific wrappers +- avoid silently changing the meaning of existing shared methods that the REPL already depends on +- do not require an immediate rewrite of legacy REPL-oriented wrapper behavior just to satisfy the standard CLI + contract +- if a non-additive shared-layer change becomes necessary, it must be evaluated explicitly for REPL compatibility and + called out in the spec or PR discussion + +### Standard CLI vs REPL + +This result contract applies to the standard CLI public surface. + +Rules: + +- tightening result semantics for the standard CLI must not silently change legacy REPL success/failure behavior +- if stricter standard CLI outcome handling is needed, isolate that logic in handlers, adapters, runner code, or + formatter-controlled paths before changing shared REPL behavior + +## Contract 5: Machine-Readable Output + +JSON mode exists to provide a stable machine-readable contract. + +### Rules + +- JSON mode must emit one structured success envelope or one structured error envelope. +- Commands participating in standard CLI mode must not bypass `OutputFormatter` for their public result. +- Stray legacy stdout/stderr may be suppressed in JSON mode, but this is only a containment mechanism, not the + primary success path. +- Command behavior in JSON mode must not rely on legacy printing side effects being visible to the caller. + +### Formal Interface + +For the standard CLI path, `--output json` is a formal machine-readable interface, not an incidental alternate +display format. + +Rules: + +- if `--output` is omitted, the standard CLI defaults to text mode +- text mode is the formal human-facing interface +- new standard CLI commands must treat JSON output as a maintained contract +- changes to existing standard CLI commands must preserve JSON-mode contract compatibility unless the spec is revised +- machine consumers that require a stable structured contract must explicitly request `--output json` +- callers must be able to determine success or failure from the JSON envelope itself without inspecting suppressed + legacy output + +### Single JSON Output Rule + +Each standard CLI invocation in JSON mode must emit exactly one top-level JSON envelope to `stdout`. + +Rules: + +- `stdout` must contain one terminal JSON result +- JSON mode must not emit multiple competing top-level JSON outcomes +- empty `stdout` in JSON mode is never a valid success outcome +- legacy or debug output that would otherwise pollute `stdout` is a bug to contain, not part of the public contract + +### Output Ownership + +For the standard CLI path, `OutputFormatter` is the only valid public JSON emitter. + +Rules: + +- command handlers must route their public outcome through `OutputFormatter` +- shared legacy code may still print internally, but those prints are not part of the JSON contract +- suppressing stray legacy output does not convert it into valid JSON output +- if a shared legacy method cannot produce a standard-CLI-safe result directly, the standard CLI should adapt it + explicitly +- a command that bypasses `OutputFormatter` is outside the standard CLI JSON contract until adapted + +### Envelope Shape + +The top-level JSON envelope is stable and must not vary by command. + +Success: + +```json +{ + "success": true, + "data": {} +} +``` + +Error: + +```json +{ + "success": false, + "error": "usage_error|execution_error|domain_specific_code", + "message": "human-readable explanation" +} +``` + +### Field Stability + +The JSON contract distinguishes stable machine-readable fields from human-oriented fields. + +Rules: + +- `success` is the stable top-level discriminator +- `error` is a stable machine-readable error code when `success` is `false` +- `message` is human-readable explanation text and must not be the only machine contract +- command-specific machine-readable payload belongs under `data` +- future command output expansion should prefer additive changes inside `data` rather than changing the top-level + envelope shape + +### Broadcast Command Payload + +On-chain broadcast commands (send-coin, transfer-asset, trigger-contract, deploy-contract, +freeze-balance, vote-witness, etc.) include transaction-specific fields under `data` when the +broadcast succeeds. + +Rules: + +- a successful single-sign broadcast must include `"txid"` under `data` +- a successful multi-sign submission must not include `"txid"` under `data` because multi-sign + submits a partially-signed transaction to a coordinator, not directly to the network; no txid + is generated at broadcast time +- deploy-contract must additionally include `"contract_address"` (base58Check) under `data` +- callers that require a txid must check that `data.txid` is present; its absence means the + transaction was submitted for multi-sign coordination + +### Text and JSON Consistency + +Text mode and JSON mode are two renderings of the same command outcome. + +Rules: + +- text mode and JSON mode must not represent different success/failure semantics for the same invocation +- a command must not succeed in text mode but produce empty output in JSON mode +- a command must not fail in text mode while reporting JSON success for the same underlying outcome +- machine-readable payload richness may differ from text formatting, but outcome classification must remain aligned + +### Command Participation + +A command is considered compliant with the standard CLI JSON contract only if all of the following are true: + +- it emits its public result through `OutputFormatter` +- it produces one valid JSON envelope in JSON mode +- it does not require callers to inspect suppressed legacy output to determine success or failure + +If a command cannot yet satisfy these rules cleanly, it should be adapted explicitly or treated as outside the +guaranteed JSON contract until that work is completed. + +Such commands being temporarily outside the guaranteed JSON contract does not relax the standard CLI JSON contract +itself. It means those commands are not yet compliant and must not be used to redefine the contract for compliant +commands. + +## Contract 6: Standard CLI vs Legacy Interactive Behavior + +The standard CLI is not a thin alias for the legacy REPL path. + +### Rules + +- Standard CLI behavior takes precedence over legacy prompt-oriented behavior when the two conflict. +- Interactive viewers, prompts, and direct prints from legacy code are compatibility hazards in the standard CLI path. +- If a legacy path cannot satisfy the standard CLI contract cleanly, either adapt it explicitly or exclude it from + the standard CLI guarantees. +- Hidden stdin scripting, prompt auto-confirmation, or injected prompt answers are not allowed as standard CLI + behavior. + +### Interface Identity + +The standard CLI and the legacy REPL are separate public interfaces with different operating models. + +Rules: + +- the standard CLI is a non-interactive command interface intended for deterministic terminal use, scripts, agents, + and automation +- the legacy REPL is an interactive prompt-oriented interface intended for human-driven sessions +- shared implementation is allowed, but shared UX and behavioral contract must not be assumed automatically + +### Contract Precedence + +When standard CLI requirements conflict with inherited REPL behavior, the standard CLI contract wins for the standard +CLI path. + +Rules: + +- standard CLI parser rules are not constrained by legacy REPL parsing quirks +- standard CLI auth behavior is not defined by legacy prompt flow +- standard CLI result and exit-code behavior are not defined by legacy print side effects +- standard CLI JSON behavior is not defined by what the legacy interactive path happens to print + +### Interactive Boundary + +Interactive behavior is not part of the intended standard CLI contract unless explicitly designed into a future spec +revision. + +Rules: + +- prompts, menus, viewer UIs, and multi-step confirmations from legacy code must not be treated as standard CLI + contract behavior +- if a command capability currently depends on interactive legacy flow, it should be adapted explicitly before being + considered fully standard-CLI-compliant +- hidden stdin feeding, prompt auto-confirmation, prompt suppression, or interactive fallback are not valid standard + CLI implementation techniques + +### Adaptation Strategy + +When standard CLI needs capabilities that currently exist only in legacy interactive form, prefer explicit adaptation +over behavioral inheritance. + +Rules: + +- prefer additive adapters, standard-CLI-safe wrapper methods, or dedicated handler logic +- do not force standard CLI callers to emulate REPL interactions as part of the public contract +- do not silently redefine REPL behavior just to satisfy standard CLI requirements + +### Temporary Compatibility Mechanisms + +Some temporary containment techniques may be necessary while migrating legacy functionality. + +Rules: + +- temporary shims must be understood as migration aids, not as the target design +- code comments, tests, and PR descriptions should avoid presenting temporary compatibility hacks as the intended + long-term contract +- when a command still depends on such a shim, that command is not standard-CLI-compliant and the dependency should be + treated as technical debt to retire + +## Contract 7: QA Verification Scope + +The purpose of `qa/` for the standard CLI is to validate the public CLI contract, not to preserve incidental +legacy side effects. + +### Rules + +- QA should primarily validate observable CLI outcomes: + - exit code behavior + - text-mode success/failure semantics + - JSON envelope correctness + - meaningful parity between text and JSON where appropriate +- QA should not claim coverage for flows that are known stale, retired, or outside the supported standard CLI path. +- If a QA path no longer represents real supported behavior, retire it instead of keeping a misleading green check. + +### QA Purpose + +Standard CLI QA exists to validate contract behavior at the CLI boundary. + +Rules: + +- QA should verify what callers can observe from the standard CLI interface +- QA should not treat incidental legacy stdout/stderr behavior as the thing being preserved +- QA should not elevate temporary migration shims into the supported contract merely because they currently exist + +### Priority Coverage Areas + +QA for the standard CLI should prioritize coverage for: + +- global option parsing behavior +- command-local parsing behavior +- authentication policy behavior +- success/failure classification +- exit code behavior +- JSON envelope correctness +- text/JSON outcome consistency +- help and other public top-level CLI flows + +### Contract-Level Bias + +Contract-level verification is more valuable than reproducing isolated implementation details. + +Rules: + +- prefer tests that validate user-visible contract guarantees at the CLI boundary +- when a bug is fixed, add regression coverage at the contract boundary if feasible +- avoid overfitting QA to temporary implementation quirks that are not part of the intended contract + +### Text and JSON Verification + +Text and JSON outputs should be validated according to their roles. + +Rules: + +- JSON-mode QA should validate both envelope shape and command outcome semantics +- text-mode QA should validate human-facing success/failure behavior without requiring brittle formatting snapshots +- text/JSON parity should primarily mean semantic outcome parity, not exact string equality +- if text and JSON intentionally differ in presentation detail, QA should still ensure they agree on success/failure + and core public meaning + +### Coverage Integrity + +QA reporting must reflect real supported coverage. + +Rules: + +- do not represent stale, broken, or unsupported flows as validated simply because a script still runs +- if a command is not yet fully compliant with the standard CLI contract, QA should either mark that gap clearly or + exclude the command from compliance claims +- a passing QA check must not rely on output that actually indicates an internal failure path + +### Shared Layer vs CLI Boundary + +Tests at different layers serve different purposes. + +Rules: + +- shared-layer unit tests are useful but do not replace CLI-boundary contract tests +- standard CLI QA should not assume that a passing wrapper or utility test proves public CLI correctness +- REPL-oriented tests do not count as standard CLI contract coverage unless they explicitly exercise the standard CLI + surface + +### Maintenance Expectations + +QA should evolve with the contract. + +Rules: + +- when behavior covered by this spec changes, QA should be updated in the same change +- new standard CLI commands should add or extend contract-relevant coverage +- if a QA path becomes misleading, retire or rewrite it rather than keeping nominal coverage + +## Reviewer Expectations Captured by This Spec + +Review feedback in this area has consistently pushed toward: + +- early parser failures instead of downstream surprises +- explicit auth policy instead of implicit side effects +- one reliable machine-readable output path +- one reliable success/failure model +- QA that validates supported behavior instead of historical implementation details + +## Change Management + +When changing behavior covered by this spec: + +1. Update this document first or in the same change. +2. Update tests to reflect the intended contract. +3. Prefer contract-level tests over narrowly reproducing only the latest reported bug. + +If a change intentionally violates this spec, document the reason in the PR and revise this file in the same patch. diff --git a/docs/standard-cli-user-manual.md b/docs/standard-cli-user-manual.md new file mode 100644 index 000000000..cdeb03b57 --- /dev/null +++ b/docs/standard-cli-user-manual.md @@ -0,0 +1,2882 @@ +# wallet-cli Standard CLI User Manual + +> Complete reference for the TRON wallet-cli command-line interface (Standard CLI mode). +> This manual covers every supported command, organized by category. + +--- + +## Table of Contents + +1. [Introduction](#1-introduction) +2. [Getting Started](#2-getting-started) +3. [Key Concepts](#3-key-concepts) +4. [General Usage](#4-general-usage) +5. [Global Options](#5-global-options) +6. [Authentication](#6-authentication) +7. [Wallet Management](#7-wallet-management) (9 commands) +8. [Transfers & Transactions](#8-transfers--transactions) (12 commands) +9. [Staking & Resources](#9-staking--resources) (10 commands) +10. [Query - Account & Balance](#10-query---account--balance) (7 commands) +11. [Query - Blockchain](#11-query---blockchain) (8 commands) +12. [Query - Assets & Tokens](#12-query---assets--tokens) (6 commands) +13. [Query - Network & Chain Info](#13-query---network--chain-info) (6 commands) +14. [Query - Delegation & Staking Info](#14-query---delegation--staking-info) (7 commands) +15. [Query - Witnesses, Proposals & Exchanges](#15-query---witnesses-proposals--exchanges) (10 commands) +16. [Query - Market Orders](#16-query---market-orders) (5 commands) +17. [Query - GasFree](#17-query---gasfree) (2 commands) +18. [Smart Contracts](#18-smart-contracts) (9 commands) +19. [Witnesses & Voting](#19-witnesses--voting) (4 commands) +20. [Proposals](#20-proposals) (3 commands) +21. [DEX & Exchanges](#21-dex--exchanges) (5 commands) +22. [Help](#22-help) (1 command) +23. [Common Scenarios](#23-common-scenarios) +24. [Exit Codes & Error Handling](#24-exit-codes--error-handling) +25. [Appendix](#25-appendix) + +--- + +## 1. Introduction + +**wallet-cli** is a command-line wallet for the [TRON](https://tron.network/) blockchain. It lets you create wallets, send TRX and tokens, stake resources, vote for Super Representatives, deploy smart contracts, and query on-chain data -- all from your terminal. + +The **Standard CLI mode** is designed for scripting, automation, and AI-agent integration. It features: + +- **No interactive prompts** -- every input is provided via flags and environment variables +- **Structured JSON output** -- machine-parseable results via `--output json` +- **Deterministic exit codes** -- `0` for success, `1` for execution errors, `2` for usage errors +- **Environment-based authentication** -- `MASTER_PASSWORD` env var for wallet unlock + +--- + +## 2. Getting Started + +### Prerequisites + +- **Java 8** or later installed on your system + +### Build + +```bash +./gradlew shadowJar +``` + +This produces `build/libs/wallet-cli.jar`. + +### Run Your First Command + +```bash +# Check the current network +java -jar build/libs/wallet-cli.jar --network nile current-network +``` + +Throughout this manual we use `wallet-cli` as a shorthand for `java -jar build/libs/wallet-cli.jar`. You can create an alias for convenience: + +```bash +alias wallet-cli='java -jar /path/to/wallet-cli.jar' +``` + +### Quick Start: Create a Wallet and Check Balance + +```bash +# 1. Create a new wallet (password is set via environment variable) +export MASTER_PASSWORD="YourStrongPassword123" +wallet-cli register-wallet --name my-wallet + +# 2. List your wallets +wallet-cli list-wallet + +# 3. Check your balance (on Nile testnet) +wallet-cli --network nile get-balance + +# 4. Send 1 TRX to another address (1 TRX = 1,000,000 SUN) +wallet-cli --network nile send-coin --to TRecipientAddress... --amount 1000000 +``` + +--- + +## 3. Key Concepts + +### SUN and TRX + +TRX is the native currency of the TRON blockchain. Amounts in wallet-cli are specified in **SUN**, the smallest unit: + +| TRX | SUN | +|-----|-----| +| 1 TRX | 1,000,000 SUN | +| 0.1 TRX | 100,000 SUN | +| 0.000001 TRX | 1 SUN | + +**Example:** To send 10 TRX, use `--amount 10000000`. + +### Addresses + +TRON addresses are in **Base58Check** format, starting with `T`. Example: `TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL` + +### Networks + +| Network | Description | Use Case | +|---------|-------------|----------| +| `main` | TRON Mainnet | Real transactions with real TRX | +| `nile` | Nile Testnet | Testing and development (free test TRX) | +| `shasta` | Shasta Testnet | Legacy testnet | +| `custom` | Custom node | Private/local nodes | + +### Resources: Bandwidth and Energy + +TRON uses two resources to process transactions: +- **Bandwidth** -- consumed by all transactions (data transfer) +- **Energy** -- consumed by smart contract calls + +You obtain these resources by **staking (freezing) TRX**. Resource type codes: +- `0` = Bandwidth +- `1` = Energy + +--- + +## 4. General Usage + +``` +wallet-cli [global-options] [command-options] +``` + +- **Global options** must come **before** the command name +- **Command options** come **after** the command name +- Option values can use space or `=` syntax: `--network nile` or `--network=nile` +- Boolean options default to `false` and can be specified as: `--multi`, `--multi=true`, `--multi=yes`, `--multi=1` + +### Getting Help + +```bash +# Global help (lists all commands) +wallet-cli --help + +# Help for a specific command +wallet-cli send-coin --help +``` + +### Command Aliases + +Every command has a no-dash alias for convenience. For example, `send-coin` can also be written as `sendcoin`. Both are equivalent. + +--- + +## 5. Global Options + +These flags apply to **all commands** and must appear **before** the command name. + +| Flag | Value | Default | Description | +|------|-------|---------|-------------| +| `--output` | `text` or `json` | `text` | Output format. Use `json` for machine-parseable output. | +| `--network` | `main`, `nile`, `shasta`, `custom` | (from config) | Select which TRON network to connect to. | +| `--wallet` | name or file path | (active wallet) | Choose which wallet file to authenticate with. | +| `--grpc-endpoint` | `host:port` | (from network) | Override the gRPC endpoint for both fullnode and soliditynode communication. | +| `--quiet` | (none) | off | Suppress informational messages on stderr. | +| `--verbose` | (none) | off | Enable debug-level logging. | +| `-h`, `--help` | (none) | off | Show help information. | +| `--version` | (none) | off | Show version information. | +| `--interactive` | (none) | off | Launch the interactive REPL mode instead. | + +**Notes:** +- `--quiet` and `--verbose` cannot be used together. +- `--output json` wraps all output in a JSON envelope (see [Exit Codes & Error Handling](#24-exit-codes--error-handling)). + +### Examples + +```bash +# Query in JSON format on Nile testnet +wallet-cli --output json --network nile get-balance --address TNPee... + +# Use a specific wallet file +wallet-cli --wallet my-trading-wallet get-address + +# Connect to a custom node +wallet-cli --network custom --grpc-endpoint 192.168.1.100:50051 get-block +``` + +--- + +## 6. Authentication + +Some commands require wallet authentication (signing transactions, reading private keys). Authentication is handled entirely through the `MASTER_PASSWORD` environment variable. + +### How It Works + +1. **Set your password** as an environment variable: + ```bash + export MASTER_PASSWORD="YourWalletPassword" + ``` + +2. **wallet-cli** automatically uses this password to unlock the active wallet keystore file. + +3. If `MASTER_PASSWORD` is not set and the command requires authentication, it fails with an error. + +### Authentication Requirement Levels + +| Level | Description | Example Commands | +|-------|-------------|------------------| +| **Required** | Must be authenticated. Fails without `MASTER_PASSWORD`. | `send-coin`, `freeze-balance-v2`, `deploy-contract` | +| **Conditional** | Required only when certain options are omitted. | `get-balance` (required if `--address` not provided) | +| **Not required** | No authentication needed. | `get-account`, `get-block`, `list-witnesses` | + +### Wallet Selection + +Wallets are stored as encrypted keystore files in the `Wallet/` directory. The CLI determines which wallet to use in this order: + +1. `--wallet` flag (explicit override) +2. The active wallet (set via `set-active-wallet`) +3. Error if neither is available + +### Security Tips + +- Never hardcode `MASTER_PASSWORD` in scripts checked into version control. +- Use environment variable injection from a secrets manager in CI/CD pipelines. +- Consider using `env -i MASTER_PASSWORD=... wallet-cli ...` to limit exposure. + +--- + +## 7. Wallet Management + +Commands for creating, listing, and managing local wallet files. + +--- + +### `register-wallet` + +Create a new wallet with a mnemonic seed phrase. + +| | | +|---|---| +| **Alias** | `registerwallet` | +| **Auth** | Not required (but `MASTER_PASSWORD` must be set to encrypt the keystore) | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--name` | Yes | string | Display name for the wallet | +| `--words` | No | number | Mnemonic word count: `12` or `24` (default: `12`) | + +```bash +export MASTER_PASSWORD="MySecurePass123" +wallet-cli register-wallet --name "my-main-wallet" +wallet-cli register-wallet --name "high-security" --words 24 +``` + +**Output (JSON):** +```json +{ + "success": true, + "data": { + "keystore": "UTC--2024-01-01T00-00-00.000000000Z--TAddress.json", + "address": "TXyz...", + "wallet_name": "my-main-wallet", + "mnemonic_keystore": "mnemonic--TXyz....json" + } +} +``` + +--- + +### `list-wallet` + +List all wallets in the `Wallet/` directory with their active status. + +| | | +|---|---| +| **Alias** | `listwallet` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli list-wallet +``` + +**Output (text):** +``` +Name Address Active +my-main-wallet TXyz...abc * +trading-wallet TAbc...xyz +``` + +> **Note:** If a keystore file in `Wallet/` is corrupt or unreadable, it still appears in the list with an `error` field in JSON mode (and `[ERROR]` placeholder in text mode) rather than failing the entire command. + +--- + +### `set-active-wallet` + +Set the active wallet for subsequent commands. Provide either `--address` or `--name`, not both. + +| | | +|---|---| +| **Alias** | `setactivewallet` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | One of address/name | string | Wallet address (Base58Check) | +| `--name` | One of address/name | string | Wallet display name | + +```bash +wallet-cli set-active-wallet --address TXyz...abc +wallet-cli set-active-wallet --name "trading-wallet" +``` + +--- + +### `get-active-wallet` + +Display the currently active wallet. + +| | | +|---|---| +| **Alias** | `getactivewallet` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli get-active-wallet +``` + +--- + +### `modify-wallet-name` + +Change the display name of the currently authenticated wallet. + +| | | +|---|---| +| **Alias** | `modifywalletname` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--name` | Yes | string | New wallet display name | + +```bash +wallet-cli modify-wallet-name --name "my-new-name" +``` + +--- + +### `generate-sub-account` + +Generate a sub-account (child wallet) from the parent wallet's mnemonic using HD derivation. + +| | | +|---|---| +| **Alias** | `generatesubaccount` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--index` | Yes | number | Derivation path index (0-99) | +| `--name` | Yes | string | Display name for the sub-account | + +```bash +wallet-cli generate-sub-account --index 0 --name "sub-wallet-0" +``` + +--- + +### `clear-wallet-keystore` + +Delete the keystore file of the currently authenticated wallet. + +| | | +|---|---| +| **Alias** | `clearwalletkeystore` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--force` | No | boolean | Skip confirmation (required in non-interactive CLI mode) | + +```bash +wallet-cli clear-wallet-keystore --force +``` + +> **Warning:** This permanently deletes the wallet keystore file. Make sure you have your mnemonic backed up. + +--- + +### `reset-wallet` + +Delete **all** wallet and mnemonic files. This is a destructive operation that requires an explicit confirmation token. + +| | | +|---|---| +| **Alias** | `resetwallet` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--confirm` | No | string | Must be exactly `delete-all-wallets` to proceed | + +```bash +# Dry run -- shows what would be deleted +wallet-cli reset-wallet + +# Actually delete all wallets +wallet-cli reset-wallet --confirm delete-all-wallets +``` + +> **Note:** Without `--confirm`, this command performs a dry run. The dry-run output includes `files` (wallet/mnemonic keystores), `ledger_files` (Ledger device metadata), and `config_files` (e.g., `.active-wallet`) — showing everything that would be deleted. + +> **Warning:** This permanently deletes ALL wallet and mnemonic files, Ledger metadata, and active wallet configuration. There is no undo. + +--- + +## 8. Transfers & Transactions + +Commands for sending TRX, transferring tokens, and managing accounts. + +--- + +### `send-coin` + +Send TRX to another address. + +| | | +|---|---| +| **Alias** | `sendcoin` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--to` | Yes | address | Recipient address | +| `--amount` | Yes | number | Amount in SUN (1 TRX = 1,000,000 SUN) | +| `--owner` | No | address | Sender address (default: current wallet) | +| `--permission-id` | No | number | Permission ID for multi-sig signing (default: 0) | +| `--multi` | No | boolean | Enable multi-signature mode | + +```bash +# Send 10 TRX +wallet-cli --network nile send-coin --to TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL --amount 10000000 + +# Send with JSON output +wallet-cli --output json --network nile send-coin --to TNPee... --amount 1000000 +``` + +--- + +### `transfer-usdt` + +Transfer USDT (TRC20 token). Automatically estimates energy and calculates the fee limit. + +| | | +|---|---| +| **Alias** | `transferusdt` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--to` | Yes | address | Recipient address | +| `--amount` | Yes | number | Amount in smallest unit (1 USDT = 1,000,000 units) | +| `--owner` | No | address | Sender address (default: current wallet) | +| `--permission-id` | No | number | Permission ID for multi-sig signing (default: 0) | +| `--multi` | No | boolean | Enable multi-signature mode | + +```bash +# Transfer 1 USDT +wallet-cli --network nile transfer-usdt --to TNPee... --amount 1000000 +``` + +> **Note:** This command is only available on networks that have a known USDT contract address (mainnet and Nile). + +--- + +### `transfer-asset` + +Transfer a TRC10 token. + +| | | +|---|---| +| **Alias** | `transferasset` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--to` | Yes | address | Recipient address | +| `--asset` | Yes | string | Asset name or ID | +| `--amount` | Yes | number | Amount to transfer | +| `--owner` | No | address | Sender address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile transfer-asset --to TNPee... --asset "MyToken" --amount 100 +``` + +--- + +### `create-account` + +Create a new account on the TRON blockchain (activates an address on-chain). + +| | | +|---|---| +| **Alias** | `createaccount` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | The new account address to activate | +| `--owner` | No | address | Creator address (pays the fee) | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile create-account --address TNewAddress... +``` + +--- + +### `update-account` + +Set or update the name of an account on-chain. An account name can only be set once. + +| | | +|---|---| +| **Alias** | `updateaccount` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--name` | Yes | string | Account name | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile update-account --name "MyAccountName" +``` + +--- + +### `set-account-id` + +Set a unique account ID for your account. + +| | | +|---|---| +| **Alias** | `setaccountid` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | string | Account ID | +| `--owner` | No | address | Owner address | + +```bash +wallet-cli --network nile set-account-id --id "my-unique-id" +``` + +--- + +### `asset-issue` + +Create (issue) a new TRC10 token. + +| | | +|---|---| +| **Alias** | `assetissue` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--name` | Yes | string | Token name | +| `--abbr` | Yes | string | Token abbreviation | +| `--total-supply` | Yes | number | Total supply | +| `--trx-num` | Yes | number | TRX amount per token unit in ICO | +| `--ico-num` | Yes | number | Token amount per TRX unit in ICO | +| `--start-time` | Yes | number | ICO start time (Unix timestamp in milliseconds) | +| `--end-time` | Yes | number | ICO end time (Unix timestamp in milliseconds) | +| `--url` | Yes | string | Project URL | +| `--free-net-limit` | Yes | number | Free bandwidth limit per account | +| `--public-free-net-limit` | Yes | number | Total public free bandwidth limit | +| `--precision` | No | number | Token precision / decimal places (default: 0) | +| `--description` | No | string | Token description | +| `--owner` | No | address | Issuer address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile asset-issue \ + --name "MyToken" \ + --abbr "MTK" \ + --total-supply 1000000000 \ + --trx-num 1 \ + --ico-num 1 \ + --start-time 1735689600000 \ + --end-time 1738368000000 \ + --url "https://mytoken.example.com" \ + --free-net-limit 5000 \ + --public-free-net-limit 50000 \ + --precision 6 \ + --description "My awesome token" +``` + +--- + +### `update-asset` + +Update parameters of an existing TRC10 token you own. + +| | | +|---|---| +| **Alias** | `updateasset` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--description` | Yes | string | New token description | +| `--url` | Yes | string | New project URL | +| `--new-limit` | Yes | number | New free bandwidth limit per account | +| `--new-public-limit` | Yes | number | New total public free bandwidth limit | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile update-asset \ + --description "Updated description" \ + --url "https://newurl.example.com" \ + --new-limit 10000 \ + --new-public-limit 100000 +``` + +--- + +### `participate-asset-issue` + +Participate in a TRC10 token ICO by purchasing tokens from the issuer. + +| | | +|---|---| +| **Alias** | `participateassetissue` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--to` | Yes | address | Asset issuer's address | +| `--asset` | Yes | string | Asset name | +| `--amount` | Yes | number | Amount of TRX to spend | +| `--owner` | No | address | Participant address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile participate-asset-issue \ + --to TIssuerAddress... \ + --asset "MyToken" \ + --amount 1000000 +``` + +--- + +### `update-account-permission` + +Update account permissions to configure multi-signature control. + +| | | +|---|---| +| **Alias** | `updateaccountpermission` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--owner` | Yes | address | Account address to update | +| `--permissions` | Yes | string | Permissions configuration as a JSON string | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile update-account-permission \ + --owner TMyAddress... \ + --permissions '{"owner":{"type":0,"permission_name":"owner","threshold":2,"keys":[{"address":"TAddr1...","weight":1},{"address":"TAddr2...","weight":1}]}}' +``` + +--- + +### `broadcast-transaction` + +Broadcast a pre-signed transaction to the network. + +| | | +|---|---| +| **Alias** | `broadcasttransaction` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--transaction` | Yes | string | Signed transaction as a hex string | + +```bash +wallet-cli --network nile broadcast-transaction --transaction 0a8e010a... +``` + +--- + +### `gas-free-transfer` + +Transfer tokens using the GasFree service (the sender does not pay gas fees). + +| | | +|---|---| +| **Alias** | `gasfreetransfer` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--to` | Yes | address | Recipient address | +| `--amount` | Yes | number | Amount to transfer | + +```bash +wallet-cli --network nile gas-free-transfer --to TNPee... --amount 1000000 +``` + +--- + +## 9. Staking & Resources + +Commands for freezing/unfreezing TRX, delegating resources, and managing the Stake 2.0 system. + +--- + +### `freeze-balance-v2` + +Freeze TRX to obtain bandwidth or energy using **Stake 2.0** (the current staking mechanism). + +| | | +|---|---| +| **Alias** | `freezebalancev2` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--amount` | Yes | number | Amount to freeze in SUN | +| `--resource` | No | number | Resource type: `0` = Bandwidth, `1` = Energy (default: `0`) | +| `--owner` | No | address | Owner address | +| `--permission-id` | No | number | Permission ID for multi-sig signing (default: 0) | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +# Freeze 100 TRX for energy +wallet-cli --network nile freeze-balance-v2 --amount 100000000 --resource 1 + +# Freeze 50 TRX for bandwidth +wallet-cli --network nile freeze-balance-v2 --amount 50000000 --resource 0 +``` + +--- + +### `unfreeze-balance-v2` + +Unfreeze previously frozen TRX under **Stake 2.0**. Unfrozen TRX enters a waiting period before it can be withdrawn. + +| | | +|---|---| +| **Alias** | `unfreezebalancev2` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--amount` | Yes | number | Amount to unfreeze in SUN | +| `--resource` | No | number | Resource type: `0` = Bandwidth, `1` = Energy (default: `0`) | +| `--owner` | No | address | Owner address | +| `--permission-id` | No | number | Permission ID for multi-sig signing (default: 0) | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile unfreeze-balance-v2 --amount 50000000 --resource 1 +``` + +--- + +### `withdraw-expire-unfreeze` + +Withdraw TRX that has completed the unfreeze waiting period. + +| | | +|---|---| +| **Alias** | `withdrawexpireunfreeze` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile withdraw-expire-unfreeze +``` + +--- + +### `cancel-all-unfreeze-v2` + +Cancel all pending unfreeze operations, returning the TRX to frozen state. + +| | | +|---|---| +| **Alias** | `cancelallunfreezev2` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile cancel-all-unfreeze-v2 +``` + +--- + +### `delegate-resource` + +Delegate bandwidth or energy to another address. The recipient can use the resources, but the TRX remains yours. + +| | | +|---|---| +| **Alias** | `delegateresource` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--amount` | Yes | number | Amount of frozen TRX to delegate (in SUN) | +| `--resource` | Yes | number | Resource type: `0` = Bandwidth, `1` = Energy | +| `--receiver` | Yes | address | Receiver address | +| `--lock` | No | boolean | Lock the delegation (cannot be undelegated during lock period) | +| `--lock-period` | No | number | Lock period in blocks (only with `--lock`) | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +# Delegate 100 TRX worth of energy to another address +wallet-cli --network nile delegate-resource \ + --amount 100000000 \ + --resource 1 \ + --receiver TReceiverAddr... + +# Delegate with lock +wallet-cli --network nile delegate-resource \ + --amount 50000000 \ + --resource 0 \ + --receiver TReceiverAddr... \ + --lock \ + --lock-period 28800 +``` + +--- + +### `undelegate-resource` + +Reclaim previously delegated bandwidth or energy from another address. + +| | | +|---|---| +| **Alias** | `undelegateresource` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--amount` | Yes | number | Amount to undelegate in SUN | +| `--resource` | Yes | number | Resource type: `0` = Bandwidth, `1` = Energy | +| `--receiver` | Yes | address | Address to reclaim from | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile undelegate-resource \ + --amount 100000000 \ + --resource 1 \ + --receiver TReceiverAddr... +``` + +--- + +### `withdraw-balance` + +Withdraw witness (Super Representative) block rewards. + +| | | +|---|---| +| **Alias** | `withdrawbalance` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--owner` | No | address | Witness address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile withdraw-balance +``` + +--- + +### `freeze-balance` (deprecated) + +Freeze TRX using the legacy Stake 1.0 system. **Use `freeze-balance-v2` instead.** + +| | | +|---|---| +| **Alias** | `freezebalance` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--amount` | Yes | number | Amount to freeze in SUN | +| `--duration` | Yes | number | Freeze duration in days | +| `--resource` | No | number | Resource type: `0` = Bandwidth, `1` = Energy (default: `0`) | +| `--receiver` | No | address | Delegate the frozen resources to this address | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile freeze-balance --amount 100000000 --duration 3 --resource 1 +``` + +--- + +### `unfreeze-balance` (deprecated) + +Unfreeze TRX under the legacy Stake 1.0 system. **Use `unfreeze-balance-v2` instead.** + +| | | +|---|---| +| **Alias** | `unfreezebalance` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--resource` | No | number | Resource type: `0` = Bandwidth, `1` = Energy (default: `0`) | +| `--receiver` | No | address | Receiver address (if resources were delegated) | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile unfreeze-balance --resource 1 +``` + +--- + +### `unfreeze-asset` + +Unfreeze a previously frozen TRC10 asset. + +| | | +|---|---| +| **Alias** | `unfreezeasset` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile unfreeze-asset +``` + +--- + +## 10. Query - Account & Balance + +Commands for querying account information and balances. These do **not** require authentication when an explicit address is provided. + +--- + +### `get-address` + +Display the address of the currently logged-in wallet. + +| | | +|---|---| +| **Alias** | `getaddress` | +| **Auth** | Required | + +No options. + +```bash +wallet-cli get-address +``` + +--- + +### `get-balance` + +Get the TRX balance of an address. Returns both SUN and TRX values. + +| | | +|---|---| +| **Alias** | `getbalance` | +| **Auth** | Required if `--address` is omitted; not required if `--address` is provided | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | No | address | Address to query (default: current wallet) | + +```bash +# Query own wallet balance (requires auth) +wallet-cli --network nile get-balance + +# Query any address (no auth needed) +wallet-cli --network nile get-balance --address TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL + +# JSON output +wallet-cli --output json --network nile get-balance --address TNPee... +``` + +**JSON output:** +```json +{ + "success": true, + "data": { + "balance_sun": 1000000, + "balance_trx": "1.000000" + } +} +``` + +--- + +### `get-usdt-balance` + +Get the USDT (TRC20) balance of an address. + +| | | +|---|---| +| **Alias** | `getusdtbalance` | +| **Auth** | Required if `--address` is omitted; not required if `--address` is provided | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | No | address | Address to query (default: current wallet) | + +```bash +wallet-cli --network nile get-usdt-balance --address TNPee... +``` + +--- + +### `get-account` + +Get detailed account information including balance, assets, permissions, and more. + +| | | +|---|---| +| **Alias** | `getaccount` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Address to query | + +```bash +wallet-cli --network nile get-account --address TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL +``` + +--- + +### `get-account-by-id` + +Get account information using an account ID (set via `set-account-id`). + +| | | +|---|---| +| **Alias** | `getaccountbyid` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | string | Account ID | + +```bash +wallet-cli --network nile get-account-by-id --id "my-unique-id" +``` + +--- + +### `get-account-net` + +Get bandwidth (net) information for an account. + +| | | +|---|---| +| **Alias** | `getaccountnet` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Address to query | + +```bash +wallet-cli --network nile get-account-net --address TNPee... +``` + +--- + +### `get-account-resource` + +Get resource information (bandwidth and energy) for an account. + +| | | +|---|---| +| **Alias** | `getaccountresource` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Address to query | + +```bash +wallet-cli --network nile get-account-resource --address TNPee... +``` + +--- + +## 11. Query - Blockchain + +Commands for querying blocks and transactions. + +--- + +### `get-block` + +Get a block by number, or the latest block if no number is specified. + +| | | +|---|---| +| **Alias** | `getblock` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--number` | No | number | Block number (default: latest block) | + +```bash +# Get the latest block +wallet-cli --network nile get-block + +# Get a specific block +wallet-cli --network nile get-block --number 1000000 +``` + +--- + +### `get-block-by-id` + +Get a block by its hash (block ID). + +| | | +|---|---| +| **Alias** | `getblockbyid` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | string | Block hash / ID | + +```bash +wallet-cli --network nile get-block-by-id --id 00000000001e8480... +``` + +--- + +### `get-block-by-id-or-num` + +Get a block by either its hash or number (auto-detected). + +| | | +|---|---| +| **Alias** | `getblockbyidornum` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--value` | Yes | string | Block number or block hash | + +```bash +wallet-cli --network nile get-block-by-id-or-num --value 1000000 +wallet-cli --network nile get-block-by-id-or-num --value 00000000001e8480... +``` + +--- + +### `get-block-by-latest-num` + +Get the most recent N blocks. + +| | | +|---|---| +| **Alias** | `getblockbylatestnum` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--count` | Yes | number | Number of blocks to retrieve | + +```bash +wallet-cli --network nile get-block-by-latest-num --count 5 +``` + +--- + +### `get-block-by-limit-next` + +Get blocks in a range `[start, end)`. + +| | | +|---|---| +| **Alias** | `getblockbylimitnext` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--start` | Yes | number | Start block number (inclusive) | +| `--end` | Yes | number | End block number (exclusive) | + +```bash +wallet-cli --network nile get-block-by-limit-next --start 1000000 --end 1000005 +``` + +--- + +### `get-transaction-by-id` + +Get a transaction by its transaction ID (hash). + +| | | +|---|---| +| **Alias** | `gettransactionbyid` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | string | Transaction ID | + +```bash +wallet-cli --network nile get-transaction-by-id --id abc123def456... +``` + +--- + +### `get-transaction-info-by-id` + +Get detailed transaction execution info (fee, energy usage, logs, etc.). + +| | | +|---|---| +| **Alias** | `gettransactioninfobyid` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | string | Transaction ID | + +```bash +wallet-cli --network nile get-transaction-info-by-id --id abc123def456... +``` + +--- + +### `get-transaction-count-by-block-num` + +Get the number of transactions in a specific block. + +| | | +|---|---| +| **Alias** | `gettransactioncountbyblocknum` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--number` | Yes | number | Block number | + +```bash +wallet-cli --network nile get-transaction-count-by-block-num --number 1000000 +``` + +--- + +## 12. Query - Assets & Tokens + +Commands for querying TRC10 asset information. + +--- + +### `get-asset-issue-by-account` + +Get all TRC10 assets issued by a specific account. + +| | | +|---|---| +| **Alias** | `getassetissuebyaccount` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Issuer account address | + +```bash +wallet-cli --network nile get-asset-issue-by-account --address TIssuer... +``` + +--- + +### `get-asset-issue-by-id` + +Get a TRC10 asset by its numeric ID. + +| | | +|---|---| +| **Alias** | `getassetissuebyid` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | string | Asset ID | + +```bash +wallet-cli --network nile get-asset-issue-by-id --id "1000001" +``` + +--- + +### `get-asset-issue-by-name` + +Get a TRC10 asset by name (returns the first match). + +| | | +|---|---| +| **Alias** | `getassetissuebyname` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--name` | Yes | string | Asset name | + +```bash +wallet-cli --network nile get-asset-issue-by-name --name "MyToken" +``` + +--- + +### `get-asset-issue-list-by-name` + +Get all TRC10 assets matching a name (may return multiple). + +| | | +|---|---| +| **Alias** | `getassetissuelistbyname` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--name` | Yes | string | Asset name | + +```bash +wallet-cli --network nile get-asset-issue-list-by-name --name "MyToken" +``` + +--- + +### `list-asset-issue` + +List all TRC10 assets on the network. + +| | | +|---|---| +| **Alias** | `listassetissue` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile list-asset-issue +``` + +--- + +### `list-asset-issue-paginated` + +List TRC10 assets with pagination. + +| | | +|---|---| +| **Alias** | `listassetissuepaginated` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--offset` | Yes | number | Starting offset | +| `--limit` | Yes | number | Number of results per page | + +```bash +wallet-cli --network nile list-asset-issue-paginated --offset 0 --limit 20 +``` + +--- + +## 13. Query - Network & Chain Info + +Commands for querying network parameters and chain state. + +--- + +### `current-network` + +Display the currently connected network name. + +| | | +|---|---| +| **Alias** | `currentnetwork` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile current-network +``` + +--- + +### `get-chain-parameters` + +Get all TRON chain parameters (proposal-adjustable settings). + +| | | +|---|---| +| **Alias** | `getchainparameters` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile get-chain-parameters +``` + +--- + +### `get-bandwidth-prices` + +Get the history of bandwidth prices on the network. + +| | | +|---|---| +| **Alias** | `getbandwidthprices` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile get-bandwidth-prices +``` + +--- + +### `get-energy-prices` + +Get the history of energy prices on the network. + +| | | +|---|---| +| **Alias** | `getenergyprices` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile get-energy-prices +``` + +--- + +### `get-memo-fee` + +Get the current fee for adding a memo to transactions. + +| | | +|---|---| +| **Alias** | `getmemofee` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile get-memo-fee +``` + +--- + +### `get-next-maintenance-time` + +Get the timestamp of the next maintenance period (when votes are tallied). + +| | | +|---|---| +| **Alias** | `getnextmaintenancetime` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile get-next-maintenance-time +``` + +--- + +## 14. Query - Delegation & Staking Info + +Commands for querying resource delegation and staking status. + +--- + +### `get-delegated-resource` + +Get resources delegated between two addresses (Stake 1.0). + +| | | +|---|---| +| **Alias** | `getdelegatedresource` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--from` | Yes | address | Delegator address | +| `--to` | Yes | address | Recipient address | + +```bash +wallet-cli --network nile get-delegated-resource --from TFrom... --to TTo... +``` + +--- + +### `get-delegated-resource-v2` + +Get resources delegated between two addresses (Stake 2.0). + +| | | +|---|---| +| **Alias** | `getdelegatedresourcev2` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--from` | Yes | address | Delegator address | +| `--to` | Yes | address | Recipient address | + +```bash +wallet-cli --network nile get-delegated-resource-v2 --from TFrom... --to TTo... +``` + +--- + +### `get-delegated-resource-account-index` + +Get the list of addresses that have delegated resources to/from a given address (Stake 1.0). + +| | | +|---|---| +| **Alias** | `getdelegatedresourceaccountindex` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Address to query | + +```bash +wallet-cli --network nile get-delegated-resource-account-index --address TAddr... +``` + +--- + +### `get-delegated-resource-account-index-v2` + +Get the list of addresses that have delegated resources to/from a given address (Stake 2.0). + +| | | +|---|---| +| **Alias** | `getdelegatedresourceaccountindexv2` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Address to query | + +```bash +wallet-cli --network nile get-delegated-resource-account-index-v2 --address TAddr... +``` + +--- + +### `get-can-delegated-max-size` + +Get the maximum amount of a resource type that can be delegated. + +| | | +|---|---| +| **Alias** | `getcandelegatedmaxsize` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--owner` | Yes | address | Owner address | +| `--type` | Yes | number | Resource type: `0` = Bandwidth, `1` = Energy | + +```bash +wallet-cli --network nile get-can-delegated-max-size --owner TAddr... --type 1 +``` + +--- + +### `get-available-unfreeze-count` + +Get how many unfreeze operations are currently available for an address. + +| | | +|---|---| +| **Alias** | `getavailableunfreezecount` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Address to query | + +```bash +wallet-cli --network nile get-available-unfreeze-count --address TAddr... +``` + +--- + +### `get-can-withdraw-unfreeze-amount` + +Get the amount of TRX that can be withdrawn from expired unfreeze operations. + +| | | +|---|---| +| **Alias** | `getcanwithdrawunfreezeamount` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Address to query | +| `--timestamp` | No | number | Timestamp in milliseconds (default: current time) | + +```bash +wallet-cli --network nile get-can-withdraw-unfreeze-amount --address TAddr... +``` + +--- + +## 15. Query - Witnesses, Proposals & Exchanges + +Commands for querying Super Representatives, governance proposals, and on-chain exchanges. + +--- + +### `list-nodes` + +List all nodes connected to the current node. + +| | | +|---|---| +| **Alias** | `listnodes` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile list-nodes +``` + +--- + +### `list-witnesses` + +List all Super Representatives (witnesses) on the network. + +| | | +|---|---| +| **Alias** | `listwitnesses` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile list-witnesses +``` + +--- + +### `get-brokerage` + +Get the brokerage ratio (commission rate) of a witness. + +| | | +|---|---| +| **Alias** | `getbrokerage` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Witness address | + +```bash +wallet-cli --network nile get-brokerage --address TWitness... +``` + +--- + +### `get-reward` + +Get the unclaimed voting reward for an address. + +| | | +|---|---| +| **Alias** | `getreward` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Address to query | + +```bash +wallet-cli --network nile get-reward --address TAddr... +``` + +--- + +### `list-proposals` + +List all governance proposals. + +| | | +|---|---| +| **Alias** | `listproposals` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile list-proposals +``` + +--- + +### `list-proposals-paginated` + +List governance proposals with pagination. + +| | | +|---|---| +| **Alias** | `listproposalspaginated` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--offset` | Yes | number | Starting offset | +| `--limit` | Yes | number | Number of results per page | + +```bash +wallet-cli --network nile list-proposals-paginated --offset 0 --limit 10 +``` + +--- + +### `get-proposal` + +Get details of a specific governance proposal. + +| | | +|---|---| +| **Alias** | `getproposal` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | number | Proposal ID | + +```bash +wallet-cli --network nile get-proposal --id 1 +``` + +--- + +### `list-exchanges` + +List all on-chain Bancor exchanges. + +| | | +|---|---| +| **Alias** | `listexchanges` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile list-exchanges +``` + +--- + +### `list-exchanges-paginated` + +List on-chain exchanges with pagination. + +| | | +|---|---| +| **Alias** | `listexchangespaginated` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--offset` | Yes | number | Starting offset | +| `--limit` | Yes | number | Number of results per page | + +```bash +wallet-cli --network nile list-exchanges-paginated --offset 0 --limit 10 +``` + +--- + +### `get-exchange` + +Get details of a specific on-chain exchange. + +| | | +|---|---| +| **Alias** | `getexchange` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | string | Exchange ID | + +```bash +wallet-cli --network nile get-exchange --id "1" +``` + +--- + +## 16. Query - Market Orders + +Commands for querying the on-chain decentralized market. + +--- + +### `get-market-order-by-account` + +Get all market orders placed by a specific account. + +| | | +|---|---| +| **Alias** | `getmarketorderbyaccount` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Account address | + +```bash +wallet-cli --network nile get-market-order-by-account --address TAddr... +``` + +--- + +### `get-market-order-by-id` + +Get a specific market order by its ID. + +| | | +|---|---| +| **Alias** | `getmarketorderbyid` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | string | Order ID (hex) | + +```bash +wallet-cli --network nile get-market-order-by-id --id abc123... +``` + +--- + +### `get-market-order-list-by-pair` + +Get all market orders for a specific trading pair. + +| | | +|---|---| +| **Alias** | `getmarketorderlistbypair` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--sell-token` | Yes | string | Sell token name (use `_` for TRX) | +| `--buy-token` | Yes | string | Buy token name (use `_` for TRX) | + +```bash +wallet-cli --network nile get-market-order-list-by-pair --sell-token _ --buy-token MyToken +``` + +--- + +### `get-market-pair-list` + +List all available market trading pairs. + +| | | +|---|---| +| **Alias** | `getmarketpairlist` | +| **Auth** | Not required | + +No options. + +```bash +wallet-cli --network nile get-market-pair-list +``` + +--- + +### `get-market-price-by-pair` + +Get the current market price for a trading pair. + +| | | +|---|---| +| **Alias** | `getmarketpricebypair` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--sell-token` | Yes | string | Sell token name (use `_` for TRX) | +| `--buy-token` | Yes | string | Buy token name (use `_` for TRX) | + +```bash +wallet-cli --network nile get-market-price-by-pair --sell-token _ --buy-token MyToken +``` + +--- + +## 17. Query - GasFree + +Commands for the GasFree service (gasless transfers). + +--- + +### `gas-free-info` + +Get GasFree service eligibility and configuration info for an address. + +| | | +|---|---| +| **Alias** | `gasfreeinfo` | +| **Auth** | Required if `--address` is omitted; not required if `--address` is provided | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | No | string | Address to query (default: current wallet) | + +```bash +wallet-cli --network nile gas-free-info --address TAddr... +``` + +--- + +### `gas-free-trace` + +Trace the status of a GasFree transaction. + +| | | +|---|---| +| **Alias** | `gasfreetrace` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | string | GasFree transaction ID | + +```bash +wallet-cli --network nile gas-free-trace --id "gasfree-tx-id..." +``` + +--- + +## 18. Smart Contracts + +Commands for deploying, calling, and managing smart contracts. + +--- + +### `deploy-contract` + +Deploy a new smart contract to the blockchain. + +| | | +|---|---| +| **Alias** | `deploycontract` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--name` | Yes | string | Contract name | +| `--abi` | Yes | string | Contract ABI as a JSON string | +| `--bytecode` | Yes | string | Contract bytecode (hex) | +| `--fee-limit` | Yes | number | Maximum fee in SUN | +| `--constructor` | No | string | Constructor signature (e.g., `constructor(uint256,address)`) | +| `--params` | No | string | Constructor parameters (provide with `--constructor`) | +| `--consume-user-resource-percent` | No | number | Caller's resource share percent, 0-100 (default: 0) | +| `--origin-energy-limit` | No | number | Max energy the deployer will provide (default: 10,000,000) | +| `--value` | No | number | TRX sent with deployment in SUN (default: 0) | +| `--token-value` | No | number | TRC10 token value (default: 0) | +| `--token-id` | No | string | TRC10 token ID | +| `--library` | No | string | Library link in format `LibName:TAddress` | +| `--compiler-version` | No | string | Solidity compiler version | +| `--owner` | No | address | Deployer address | +| `--multi` | No | boolean | Multi-signature mode | + +> **Note:** `--constructor` and `--params` must be provided together. + +```bash +wallet-cli --network nile deploy-contract \ + --name "MyContract" \ + --abi '[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"}]' \ + --bytecode "608060405234801561001057600080fd5b50..." \ + --fee-limit 1000000000 \ + --consume-user-resource-percent 50 \ + --origin-energy-limit 10000000 +``` + +--- + +### `trigger-contract` + +Call a smart contract function that modifies state (sends a transaction). + +| | | +|---|---| +| **Alias** | `triggercontract` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--contract` | Yes | address | Contract address | +| `--method` | Yes | string | Method signature (e.g., `transfer(address,uint256)`) | +| `--fee-limit` | Yes | number | Maximum fee in SUN | +| `--params` | No | string | Method parameters | +| `--value` | No | number | TRX to send with the call in SUN (default: 0) | +| `--token-value` | No | number | TRC10 token value (default: 0) | +| `--token-id` | No | string | TRC10 token ID | +| `--owner` | No | address | Caller address | +| `--permission-id` | No | number | Permission ID for multi-sig signing (default: 0) | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +# Call a contract method +wallet-cli --network nile trigger-contract \ + --contract TContractAddr... \ + --method "transfer(address,uint256)" \ + --params '"TRecipient...",1000000' \ + --fee-limit 100000000 +``` + +--- + +### `trigger-constant-contract` + +Call a read-only (view/pure) smart contract function. Does not create a transaction or cost resources. + +| | | +|---|---| +| **Alias** | `triggerconstantcontract` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--contract` | Yes | address | Contract address | +| `--method` | Yes | string | Method signature (e.g., `balanceOf(address)`) | +| `--params` | No | string | Method parameters | +| `--owner` | No | address | Caller address | + +```bash +# Check USDT balance of an address (read-only call) +wallet-cli --network nile trigger-constant-contract \ + --contract TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf \ + --method "balanceOf(address)" \ + --params '"TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL"' \ + --owner TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL +``` + +--- + +### `estimate-energy` + +Estimate how much energy a contract call would consume, without actually executing it. + +| | | +|---|---| +| **Alias** | `estimateenergy` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--contract` | Yes | address | Contract address | +| `--method` | Yes | string | Method signature | +| `--params` | No | string | Method parameters | +| `--value` | No | number | Call value in SUN (default: 0) | +| `--token-value` | No | number | Token value (default: 0) | +| `--token-id` | No | string | Token ID | +| `--owner` | No | address | Caller address | + +```bash +wallet-cli --network nile estimate-energy \ + --contract TContractAddr... \ + --method "transfer(address,uint256)" \ + --params '"TRecipient...",1000000' \ + --owner TMyAddr... +``` + +--- + +### `get-contract` + +Get the smart contract definition (ABI, bytecode, etc.) by its address. + +| | | +|---|---| +| **Alias** | `getcontract` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Contract address | + +```bash +wallet-cli --network nile get-contract --address TContractAddr... +``` + +--- + +### `get-contract-info` + +Get smart contract metadata including energy settings. + +| | | +|---|---| +| **Alias** | `getcontractinfo` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--address` | Yes | address | Contract address | + +```bash +wallet-cli --network nile get-contract-info --address TContractAddr... +``` + +--- + +### `clear-contract-abi` + +Remove the ABI from a smart contract you own. + +| | | +|---|---| +| **Alias** | `clearcontractabi` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--contract` | Yes | address | Contract address | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile clear-contract-abi --contract TContractAddr... +``` + +--- + +### `update-setting` + +Update the `consume_user_resource_percent` setting of a smart contract you own. + +| | | +|---|---| +| **Alias** | `updatesetting` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--contract` | Yes | address | Contract address | +| `--consume-user-resource-percent` | Yes | number | New percentage (0-100) | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile update-setting --contract TContractAddr... --consume-user-resource-percent 50 +``` + +--- + +### `update-energy-limit` + +Update the `origin_energy_limit` setting of a smart contract you own. + +| | | +|---|---| +| **Alias** | `updateenergylimit` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--contract` | Yes | address | Contract address | +| `--origin-energy-limit` | Yes | number | New energy limit | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile update-energy-limit --contract TContractAddr... --origin-energy-limit 10000000 +``` + +--- + +## 19. Witnesses & Voting + +Commands for Super Representative (witness) operations and voting. + +--- + +### `create-witness` + +Apply to become a Super Representative (witness). Requires 9,999 TRX to be burned. + +| | | +|---|---| +| **Alias** | `createwitness` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--url` | Yes | string | Your witness website URL | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile create-witness --url "https://mywitness.example.com" +``` + +--- + +### `update-witness` + +Update the URL of an existing witness. + +| | | +|---|---| +| **Alias** | `updatewitness` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--url` | Yes | string | New witness URL | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile update-witness --url "https://new-url.example.com" +``` + +--- + +### `vote-witness` + +Vote for one or more Super Representatives using your frozen TRX as voting power. + +| | | +|---|---| +| **Alias** | `votewitness` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--votes` | Yes | string | Space-separated pairs: `address1 count1 address2 count2 ...` | +| `--owner` | No | address | Voter address | +| `--permission-id` | No | number | Permission ID for multi-sig signing (default: 0) | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +# Vote for two witnesses +wallet-cli --network nile vote-witness \ + --votes "TWitness1... 1000 TWitness2... 500" +``` + +> **Note:** Each vote replaces your previous votes entirely. Your total vote count cannot exceed your frozen TRX amount. + +--- + +### `update-brokerage` + +Update the brokerage (commission) ratio as a witness. This determines what percentage of voter rewards you keep. + +| | | +|---|---| +| **Alias** | `updatebrokerage` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--brokerage` | Yes | number | Brokerage ratio (0-100). E.g., 20 means keep 20%, distribute 80%. | +| `--owner` | No | address | Witness address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile update-brokerage --brokerage 20 +``` + +--- + +## 20. Proposals + +Commands for TRON governance proposals. Only Super Representatives can create proposals. + +--- + +### `create-proposal` + +Create a new governance proposal to change chain parameters. + +| | | +|---|---| +| **Alias** | `createproposal` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--parameters` | Yes | string | Space-separated pairs: `paramId1 value1 paramId2 value2 ...` | +| `--owner` | No | address | Proposer address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +# Create a proposal to change parameter #0 to value 100000 +wallet-cli --network nile create-proposal --parameters "0 100000" +``` + +--- + +### `approve-proposal` + +Vote to approve or disapprove an existing proposal. + +| | | +|---|---| +| **Alias** | `approveproposal` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | number | Proposal ID | +| `--approve` | Yes | boolean | `true` to approve, `false` to disapprove | +| `--owner` | No | address | Voter address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile approve-proposal --id 1 --approve true +``` + +--- + +### `delete-proposal` + +Delete a proposal you created (only before it is approved). + +| | | +|---|---| +| **Alias** | `deleteproposal` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--id` | Yes | number | Proposal ID | +| `--owner` | No | address | Proposer address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile delete-proposal --id 1 +``` + +--- + +## 21. DEX & Exchanges + +Commands for the on-chain Bancor exchange and decentralized market. + +--- + +### `exchange-create` + +Create a new Bancor exchange pair between two tokens. + +| | | +|---|---| +| **Alias** | `exchangecreate` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--first-token` | Yes | string | First token ID (use `_` for TRX) | +| `--first-balance` | Yes | number | Initial balance of the first token | +| `--second-token` | Yes | string | Second token ID | +| `--second-balance` | Yes | number | Initial balance of the second token | +| `--owner` | No | address | Creator address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile exchange-create \ + --first-token _ \ + --first-balance 10000000000 \ + --second-token "1000001" \ + --second-balance 10000000 +``` + +--- + +### `exchange-inject` + +Add liquidity to an existing exchange. + +| | | +|---|---| +| **Alias** | `exchangeinject` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--exchange-id` | Yes | number | Exchange ID | +| `--token-id` | Yes | string | Token to inject | +| `--quant` | Yes | number | Amount to inject | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile exchange-inject --exchange-id 1 --token-id _ --quant 1000000000 +``` + +--- + +### `exchange-withdraw` + +Withdraw liquidity from an exchange. + +| | | +|---|---| +| **Alias** | `exchangewithdraw` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--exchange-id` | Yes | number | Exchange ID | +| `--token-id` | Yes | string | Token to withdraw | +| `--quant` | Yes | number | Amount to withdraw | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile exchange-withdraw --exchange-id 1 --token-id _ --quant 500000000 +``` + +--- + +### `market-sell-asset` + +Place a limit sell order on the decentralized market. + +| | | +|---|---| +| **Alias** | `marketsellasset` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--sell-token` | Yes | string | Token to sell (use `_` for TRX) | +| `--sell-quantity` | Yes | number | Amount to sell | +| `--buy-token` | Yes | string | Token to buy (use `_` for TRX) | +| `--buy-quantity` | Yes | number | Expected amount to buy (sets the price) | +| `--owner` | No | address | Seller address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile market-sell-asset \ + --sell-token _ \ + --sell-quantity 1000000 \ + --buy-token "1000001" \ + --buy-quantity 500 +``` + +--- + +### `market-cancel-order` + +Cancel a previously placed market order. + +| | | +|---|---| +| **Alias** | `marketcancelorder` | +| **Auth** | Required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--order-id` | Yes | string | Order ID (hex) | +| `--owner` | No | address | Owner address | +| `--multi` | No | boolean | Multi-signature mode | + +```bash +wallet-cli --network nile market-cancel-order --order-id abc123def... +``` + +--- + +## 22. Help + +### `help` + +Display help information. + +| | | +|---|---| +| **Alias** | `help` | +| **Auth** | Not required | + +| Option | Required | Type | Description | +|--------|----------|------|-------------| +| `--command` | No | string | Specific command to show help for | + +```bash +wallet-cli help +wallet-cli --help +wallet-cli send-coin --help +``` + +--- + +## 23. Common Scenarios + +### Scenario 1: Create a Wallet and Fund It + +```bash +# Set your wallet password +export MASTER_PASSWORD="SecurePass123!" + +# Create a new wallet on Nile testnet +wallet-cli register-wallet --name "test-wallet" +# Save the mnemonic phrase displayed! It's your backup. + +# Check your address +wallet-cli get-address + +# Fund it from the Nile testnet faucet (external step) +# Then verify your balance +wallet-cli --network nile get-balance +``` + +### Scenario 2: Send TRX to Someone + +```bash +export MASTER_PASSWORD="SecurePass123!" + +# Send 5 TRX (= 5,000,000 SUN) +wallet-cli --network nile send-coin \ + --to TRecipientAddress... \ + --amount 5000000 + +# Verify the transaction +wallet-cli --network nile get-transaction-info-by-id --id +``` + +### Scenario 3: Transfer USDT + +```bash +export MASTER_PASSWORD="SecurePass123!" + +# Transfer 10 USDT (= 10,000,000 in smallest unit) +wallet-cli --network nile transfer-usdt \ + --to TRecipientAddress... \ + --amount 10000000 +``` + +### Scenario 4: Stake TRX for Energy + +```bash +export MASTER_PASSWORD="SecurePass123!" + +# Freeze 100 TRX for energy (Stake 2.0) +wallet-cli --network nile freeze-balance-v2 --amount 100000000 --resource 1 + +# Check your resources +wallet-cli --network nile get-account-resource --address TYourAddress... +``` + +### Scenario 5: Delegate Energy to Another Address + +```bash +export MASTER_PASSWORD="SecurePass123!" + +# Delegate 50 TRX worth of energy to a friend +wallet-cli --network nile delegate-resource \ + --amount 50000000 \ + --resource 1 \ + --receiver TFriendAddress... + +# Later, reclaim it +wallet-cli --network nile undelegate-resource \ + --amount 50000000 \ + --resource 1 \ + --receiver TFriendAddress... +``` + +### Scenario 6: Vote for a Super Representative + +```bash +export MASTER_PASSWORD="SecurePass123!" + +# First, check available witnesses +wallet-cli --network nile list-witnesses + +# Vote (you need frozen TRX for voting power) +wallet-cli --network nile vote-witness \ + --votes "TWitnessAddr1... 500 TWitnessAddr2... 300" + +# Check unclaimed rewards later +wallet-cli --network nile get-reward --address TYourAddress... +``` + +### Scenario 7: Call a Read-Only Smart Contract (No Fee) + +```bash +# Check USDT balance -- no wallet auth needed (read-only, no fee) +wallet-cli --network nile trigger-constant-contract \ + --contract TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf \ + --method "balanceOf(address)" \ + --params '"TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL"' \ + --owner TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL +``` + +### Scenario 8: JSON Output for Scripting + +```bash +# Get balance as JSON and extract with jq +wallet-cli --output json --network nile get-balance --address TNPee... \ + | jq '.data.balance_trx' + +# Check if command succeeded +wallet-cli --output json --network nile get-account --address TNPee... \ + | jq '.success' +``` + +--- + +## 24. Exit Codes & Error Handling + +### Exit Codes + +| Code | Meaning | Description | +|------|---------|-------------| +| `0` | Success | Command completed successfully | +| `1` | Execution Error | Runtime failure (network error, authentication failure, transaction rejected) | +| `2` | Usage Error | Invalid arguments, unknown command, missing required options | + +### JSON Output Envelope + +In `--output json` mode, all responses follow this structure: + +**Success:** +```json +{ + "success": true, + "data": { + "key": "value" + } +} +``` + +**Error:** +```json +{ + "success": false, + "error": "error_code", + "message": "Human-readable error description" +} +``` + +Common error codes: +- `usage_error` -- invalid arguments or syntax +- `execution_error` -- runtime failure +- `query_failed` -- a query returned no data +- `missing_env` -- required environment variable is not set +- `not_found` -- requested resource not found +- `not_logged_in` -- authentication required but not provided + +### Troubleshooting Tips + +| Problem | Solution | +|---------|----------| +| "MASTER_PASSWORD is required..." | Set the `MASTER_PASSWORD` environment variable | +| "No active wallet selected..." | Run `set-active-wallet` or use `--wallet` flag | +| "Unknown global option..." | Global options must come before the command name | +| "Missing value for --network" | Provide one of: `main`, `nile`, `shasta`, `custom` | +| "Invalid value for --output" | Must be `text` or `json` | +| Command not found | Check spelling. Try the no-dash alias (e.g., `sendcoin` instead of `send-coin`) | + +--- + +## 25. Appendix + +### A. SUN / TRX Conversion Table + +| TRX | SUN | +|-----|-----| +| 0.000001 | 1 | +| 0.001 | 1,000 | +| 0.01 | 10,000 | +| 0.1 | 100,000 | +| 1 | 1,000,000 | +| 10 | 10,000,000 | +| 100 | 100,000,000 | +| 1,000 | 1,000,000,000 | + +**Formula:** SUN = TRX x 1,000,000 + +### B. Resource Type Codes + +| Code | Resource | Used By | +|------|----------|---------| +| `0` | Bandwidth | All transactions (data transfer) | +| `1` | Energy | Smart contract calls | + +### C. Network Endpoints + +| Network | Description | +|---------|-------------| +| `main` | TRON Mainnet (production) | +| `nile` | Nile Testnet (recommended for development) | +| `shasta` | Shasta Testnet (legacy) | +| `custom` | Custom node (use with `--grpc-endpoint`) | + +### D. Multi-Signature Usage + +Many transaction commands support multi-signature mode via the `--multi` (or `-m`) flag. When enabled: + +1. The command creates the transaction but does **not** broadcast it immediately. +2. Instead, it outputs the transaction for additional signatures. +3. After all required parties have signed, use `broadcast-transaction` to submit it. + +To set up multi-sig, use `update-account-permission` to configure the account's permission structure first. + +### E. Complete Command Index + +| # | Command | Category | Auth | +|---|---------|----------|------| +| 1 | `register-wallet` | Wallet | No* | +| 2 | `list-wallet` | Wallet | No | +| 3 | `set-active-wallet` | Wallet | No | +| 4 | `get-active-wallet` | Wallet | No | +| 5 | `modify-wallet-name` | Wallet | Yes | +| 6 | `generate-sub-account` | Wallet | Yes | +| 7 | `clear-wallet-keystore` | Wallet | Yes | +| 8 | `reset-wallet` | Wallet | No | +| 9 | `send-coin` | Transaction | Yes | +| 10 | `transfer-usdt` | Transaction | Yes | +| 11 | `transfer-asset` | Transaction | Yes | +| 12 | `create-account` | Transaction | Yes | +| 13 | `update-account` | Transaction | Yes | +| 14 | `set-account-id` | Transaction | Yes | +| 15 | `asset-issue` | Transaction | Yes | +| 16 | `update-asset` | Transaction | Yes | +| 17 | `participate-asset-issue` | Transaction | Yes | +| 18 | `update-account-permission` | Transaction | Yes | +| 19 | `broadcast-transaction` | Transaction | No | +| 20 | `gas-free-transfer` | Transaction | Yes | +| 21 | `freeze-balance-v2` | Staking | Yes | +| 22 | `unfreeze-balance-v2` | Staking | Yes | +| 23 | `withdraw-expire-unfreeze` | Staking | Yes | +| 24 | `cancel-all-unfreeze-v2` | Staking | Yes | +| 25 | `delegate-resource` | Staking | Yes | +| 26 | `undelegate-resource` | Staking | Yes | +| 27 | `withdraw-balance` | Staking | Yes | +| 28 | `freeze-balance` | Staking | Yes | +| 29 | `unfreeze-balance` | Staking | Yes | +| 30 | `unfreeze-asset` | Staking | Yes | +| 31 | `get-address` | Query | Yes | +| 32 | `get-balance` | Query | Conditional | +| 33 | `get-usdt-balance` | Query | Conditional | +| 34 | `get-account` | Query | No | +| 35 | `get-account-by-id` | Query | No | +| 36 | `get-account-net` | Query | No | +| 37 | `get-account-resource` | Query | No | +| 38 | `current-network` | Query | No | +| 39 | `get-block` | Query | No | +| 40 | `get-block-by-id` | Query | No | +| 41 | `get-block-by-id-or-num` | Query | No | +| 42 | `get-block-by-latest-num` | Query | No | +| 43 | `get-block-by-limit-next` | Query | No | +| 44 | `get-transaction-by-id` | Query | No | +| 45 | `get-transaction-info-by-id` | Query | No | +| 46 | `get-transaction-count-by-block-num` | Query | No | +| 47 | `get-asset-issue-by-account` | Query | No | +| 48 | `get-asset-issue-by-id` | Query | No | +| 49 | `get-asset-issue-by-name` | Query | No | +| 50 | `get-asset-issue-list-by-name` | Query | No | +| 51 | `list-asset-issue` | Query | No | +| 52 | `list-asset-issue-paginated` | Query | No | +| 53 | `get-chain-parameters` | Query | No | +| 54 | `get-bandwidth-prices` | Query | No | +| 55 | `get-energy-prices` | Query | No | +| 56 | `get-memo-fee` | Query | No | +| 57 | `get-next-maintenance-time` | Query | No | +| 58 | `get-contract` | Contract | No | +| 59 | `get-contract-info` | Contract | No | +| 60 | `get-delegated-resource` | Query | No | +| 61 | `get-delegated-resource-v2` | Query | No | +| 62 | `get-delegated-resource-account-index` | Query | No | +| 63 | `get-delegated-resource-account-index-v2` | Query | No | +| 64 | `get-can-delegated-max-size` | Query | No | +| 65 | `get-available-unfreeze-count` | Query | No | +| 66 | `get-can-withdraw-unfreeze-amount` | Query | No | +| 67 | `get-brokerage` | Query | No | +| 68 | `get-reward` | Query | No | +| 69 | `list-nodes` | Query | No | +| 70 | `list-witnesses` | Query | No | +| 71 | `list-proposals` | Query | No | +| 72 | `list-proposals-paginated` | Query | No | +| 73 | `get-proposal` | Query | No | +| 74 | `list-exchanges` | Query | No | +| 75 | `list-exchanges-paginated` | Query | No | +| 76 | `get-exchange` | Query | No | +| 77 | `get-market-order-by-account` | Query | No | +| 78 | `get-market-order-by-id` | Query | No | +| 79 | `get-market-order-list-by-pair` | Query | No | +| 80 | `get-market-pair-list` | Query | No | +| 81 | `get-market-price-by-pair` | Query | No | +| 82 | `gas-free-info` | Query | Conditional | +| 83 | `gas-free-trace` | Query | No | +| 84 | `deploy-contract` | Contract | Yes | +| 85 | `trigger-contract` | Contract | Yes | +| 86 | `trigger-constant-contract` | Contract | No | +| 87 | `estimate-energy` | Contract | No | +| 88 | `clear-contract-abi` | Contract | Yes | +| 89 | `update-setting` | Contract | Yes | +| 90 | `update-energy-limit` | Contract | Yes | +| 91 | `create-witness` | Witness | Yes | +| 92 | `update-witness` | Witness | Yes | +| 93 | `vote-witness` | Witness | Yes | +| 94 | `update-brokerage` | Witness | Yes | +| 95 | `create-proposal` | Proposal | Yes | +| 96 | `approve-proposal` | Proposal | Yes | +| 97 | `delete-proposal` | Proposal | Yes | +| 98 | `exchange-create` | Exchange | Yes | +| 99 | `exchange-inject` | Exchange | Yes | +| 100 | `exchange-withdraw` | Exchange | Yes | +| 101 | `market-sell-asset` | Exchange | Yes | +| 102 | `market-cancel-order` | Exchange | Yes | +| 103 | `help` | Misc | No | + +\* `register-wallet` requires `MASTER_PASSWORD` to be set (for keystore encryption) but does not authenticate against an existing wallet. + +**Auth legend:** Yes = always required | No = never required | Conditional = depends on options provided diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..336465ced --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +org.gradle.console=plain diff --git a/qa/config.sh b/qa/config.sh new file mode 100644 index 000000000..38c83821d --- /dev/null +++ b/qa/config.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +NETWORK="${TRON_NETWORK:-nile}" +PRIVATE_KEY="${TRON_TEST_PRIVATE_KEY:-}" +MNEMONIC="${TRON_TEST_MNEMONIC:-}" +TRON_PRIVATE_KEY="${TRON_PRIVATE_KEY:-$PRIVATE_KEY}" +TRON_MNEMONIC="${TRON_MNEMONIC:-$MNEMONIC}" +MASTER_PASSWORD="${MASTER_PASSWORD:-testpassword123A}" +ALT_PASSWORD="${QA_ALT_PASSWORD:-TempPass123!B}" +GASFREE_API_KEY="${GASFREE_API_KEY:-}" +GASFREE_API_SECRET="${GASFREE_API_SECRET:-}" + +WALLET_JAR="$PROJECT_DIR/build/libs/wallet-cli.jar" +QA_JAR="$PROJECT_DIR/build/libs/wallet-cli-qa.jar" +RESULTS_DIR="$PROJECT_DIR/qa/results" +RUNTIME_DIR="$PROJECT_DIR/qa/runtime" +REPORT_FILE="$PROJECT_DIR/qa/report.txt" +MANIFEST_FILE="$PROJECT_DIR/qa/manifest.tsv" +CONTRACTS_FILE="$PROJECT_DIR/qa/contracts.tsv" + +TARGET_ADDR="${TRON_QA_TARGET_ADDR:-TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL}" +USDT_NILE="${TRON_QA_USDT_NILE:-TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf}" +FAKE_ID_64="0000000000000000000000000000000000000000000000000000000000000001" + +export NETWORK PRIVATE_KEY MNEMONIC MASTER_PASSWORD ALT_PASSWORD +export TRON_PRIVATE_KEY TRON_MNEMONIC +export WALLET_JAR QA_JAR RESULTS_DIR RUNTIME_DIR REPORT_FILE MANIFEST_FILE CONTRACTS_FILE +export TARGET_ADDR USDT_NILE FAKE_ID_64 PROJECT_DIR +export GASFREE_API_KEY GASFREE_API_SECRET + +qa_has_private_key() { + [ -n "$PRIVATE_KEY" ] +} + +qa_has_mnemonic() { + [ -n "$MNEMONIC" ] +} + +qa_requires_available() { + case "$1" in + none|"") + return 0 + ;; + private_key) + qa_has_private_key + ;; + mnemonic) + qa_has_mnemonic + ;; + *) + return 1 + ;; + esac +} diff --git a/qa/contracts.tsv b/qa/contracts.tsv new file mode 100644 index 000000000..47de55da0 --- /dev/null +++ b/qa/contracts.tsv @@ -0,0 +1,46 @@ +# label|template|requires|env_mode|stream_mode|expectation|args_json|json_path_exists|json_path_absent|error_code|text_contains|text_absent|preflight|workspace_path_exists|workspace_path_absent +global-help|empty|none|default|dual|help_dual|["--help"]|data.help|||Usage:,TRON Wallet CLI|Error:| +version-flag|empty|none|default|text|success|["--version"]||||wallet-cli|| +missing-command|empty|none|default|json|usage|["--output","json"]|||usage_error||| +unknown-global-option|empty|none|default|json|usage|["--output","json","--outputt","json","get-balance"]|||usage_error||| +unknown-command|empty|none|default|text|usage|["sendkon"]||||Did you mean|| +contract__global_network_separate|empty|none|default|text|success|["--network","nile","current-network"]||||Current network:|| +contract__global_network_inline_json|empty|none|default|json|success|["--output","json","--network=nile","current-network"]|||||| +contract__global_missing_network_value_json|empty|none|default|json|usage|["--output","json","--network"]|||usage_error||| +contract__global_empty_output_value_json|empty|none|default|text|usage|["--output="]||||Missing or empty value for --output|| +contract__global_invalid_network_value_json|empty|none|default|json|usage|["--output","json","--network=beta","current-network"]|||usage_error||| +contract__global_flag_with_value_json|empty|none|default|json|usage|["--output","json","--quiet=true","current-network"]|||usage_error||| +contract__global_repeated_network_json|empty|none|default|json|usage|["--output","json","--network","nile","--network","main","current-network"]|||usage_error||| +contract__global_quiet_verbose_conflict_json|empty|none|default|json|usage|["--output","json","--quiet","--verbose","current-network"]|||usage_error||| +contract__post_command_global_like_token_text|empty|none|default|text|usage|["current-network","--network","nile"]||||Unknown option: --network|| +contract__command_missing_required_value_text|empty|none|default|text|usage|["get-block-by-latest-num","--count"]||||Missing value for --count|| +contract__command_empty_required_value_json|empty|none|default|json|usage|["--output","json","get-block-by-latest-num","--count="]|||usage_error||| +contract__command_boolean_flag_exec|empty|none|default|text|execution|["freeze-balance-v2","--amount","1","--multi"]|||execution_error|Error:|| +contract__command_boolean_true_exec|empty|none|default|json|execution|["--output","json","freeze-balance-v2","--amount","1","--multi=true"]|||execution_error||| +contract__command_boolean_false_exec|empty|none|default|json|execution|["--output","json","freeze-balance-v2","--amount","1","--multi=false"]|||execution_error||| +contract__command_boolean_invalid_text|empty|none|default|text|usage|["freeze-balance-v2","--amount","1","--multi=maybe"]||||requires a boolean value|| +contract__command_repeated_value_text|empty|none|default|text|usage|["freeze-balance-v2","--amount","1","--amount","2"]||||Repeated option: --amount|| +contract__command_repeated_boolean_same_exec|empty|none|default|json|execution|["--output","json","freeze-balance-v2","--amount","1","--multi","--multi"]|||execution_error||| +contract__command_repeated_boolean_conflict_text|empty|none|default|text|usage|["freeze-balance-v2","--amount","1","--multi=true","--multi=false"]||||Conflicting values for option: --multi|| +contract__command_unknown_option_text|empty|none|default|text|usage|["get-block","--wat"]||||Unknown option: --wat|| +contract__command_unexpected_argument_text|empty|none|default|text|usage|["get-block","oops"]||||Unexpected argument: oops|| +contract__command_help_short_text|empty|none|default|text|help_text|["get-balance","-h"]||||Usage:,wallet-cli get-balance|Error:| +contract__command_help_short_json|empty|none|default|json|help_json|["--output","json","get-balance","-h"]|data.help||||| +contract__command_help_not_option_value_text|empty|none|default|text|help_text|["get-balance","--address","--help"]||||Usage:,wallet-cli get-balance|Error:| +contract__auth_never_without_wallet_text|empty|none|default|text|success|["current-network"]||||Current network:|| +contract__auth_require_without_wallet_json|empty|none|default|json|execution|["--output","json","get-address"]|||execution_error||| +contract__auth_require_no_password_text|auth|private_key|no-password|text|execution|["get-address"]||||MASTER_PASSWORD is required|| +contract__auth_wallet_override_without_active_text|auth-no-active|private_key|default|text|success|["--network","nile","--wallet","mywallet","get-address"]||||GetAddress successful,address =|| +contract__auth_wallet_override_missing_text|auth-no-active|private_key|default|text|execution|["--network","nile","--wallet","missing-wallet","get-address"]||||No wallet found for --wallet|| +contract__auth_wallet_bad_active_text|auth-bad-active|private_key|default|text|execution|["--network","nile","get-address"]||||Could not read active wallet config|| +contract__clear_wallet_external_target_text|auth-external-wallet|private_key|default|text|success|["--network","nile","--wallet","./External/{{FIRST_WALLET_FILE}}","clear-wallet-keystore","--force"]||||ClearWalletKeystore successful !!|||Wallet/.active-wallet|External/{{FIRST_WALLET_FILE}} +contract__auth_get_usdt_balance_with_address_json|empty|none|default|json|success|["--output","json","--network","nile","get-usdt-balance","--address","{{TARGET_ADDR}}"]|||||| +contract__auth_get_usdt_balance_without_address_json|empty|none|default|json|execution|["--output","json","--network","nile","get-usdt-balance"]|||execution_error||| +contract__auth_trigger_constant_with_owner_json|empty|none|default|json|success|["--output","json","--network","nile","trigger-constant-contract","--contract","{{USDT_NILE}}","--method","balanceOf(address)","--params","\"{{TARGET_ADDR}}\"","--owner","{{TARGET_ADDR}}"]|||||| +contract__auth_trigger_constant_without_owner_json|empty|none|default|json|success|["--output","json","--network","nile","trigger-constant-contract","--contract","{{USDT_NILE}}","--method","balanceOf(address)","--params","\"{{TARGET_ADDR}}\""]|||||| +contract__auth_estimate_energy_with_owner_json|empty|none|default|json|success|["--output","json","--network","nile","estimate-energy","--contract","{{USDT_NILE}}","--method","transfer(address,uint256)","--params","\"{{TARGET_ADDR}}\",1","--owner","{{TARGET_ADDR}}"]|||||| +contract__auth_estimate_energy_without_owner_json|empty|none|default|json|execution|["--output","json","--network","nile","estimate-energy","--contract","{{USDT_NILE}}","--method","transfer(address,uint256)","--params","\"{{TARGET_ADDR}}\",1"]|||query_failed||| +# ForCli migration: verify create-account, vote-witness reach chain via ForCli path and return proper execution_error +# asset-issue is omitted: valid params can succeed on a fresh account (non-idempotent), making it unreliable as expected-execution-error +contract__create_account_forcli_exec|auth|private_key|default|dual|execution|["--network","{{NETWORK}}","create-account","--address","{{TARGET_ADDR}}"]|||execution_error|Error:|| +contract__vote_witness_forcli_exec|auth|private_key|default|dual|execution|["--network","{{NETWORK}}","vote-witness","--votes","{{TARGET_ADDR}} 1"]|||execution_error|Error:|| diff --git a/qa/lib/case_resolver.py b/qa/lib/case_resolver.py new file mode 100644 index 000000000..b24536ef9 --- /dev/null +++ b/qa/lib/case_resolver.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python3 +import json +import os +import shlex +import sys + + +def read_table(path): + rows = [] + if not os.path.exists(path): + return rows + with open(path, "r", encoding="utf-8") as fh: + for raw_line in fh: + line = raw_line.rstrip("\n") + if not line or line.lstrip().startswith("#"): + continue + rows.append(line.split("|")) + return rows + + +def find_row(rows, label): + for row in rows: + if row and row[0] == label: + return row + return None + + +def load_seeds(path): + result = {} + if not path or not os.path.exists(path): + return result + with open(path, "r", encoding="utf-8") as fh: + for raw_line in fh: + line = raw_line.strip() + if not line or "=" not in line: + continue + key, value = line.split("=", 1) + try: + tokens = shlex.split(value) + result[key] = tokens[0] if tokens else "" + except Exception: + result[key] = value + return result + + +def substitute_token(token, values): + updated = token + for key, value in values.items(): + updated = updated.replace("{{%s}}" % key, value) + return updated + + +def placeholder_tokens(token): + found = [] + start = 0 + while True: + open_idx = token.find("{{", start) + if open_idx < 0: + break + close_idx = token.find("}}", open_idx + 2) + if close_idx < 0: + break + found.append(token[open_idx:close_idx + 2]) + start = close_idx + 2 + return found + + +def unresolved_tokens(tokens): + missing = [] + for token in tokens: + missing.extend(placeholder_tokens(token)) + return missing + + +def missing_placeholders(tokens, values): + missing = [] + seen = set() + for token in tokens: + for placeholder in placeholder_tokens(token): + key = placeholder[2:-2] + if values.get(key, "") == "" and placeholder not in seen: + missing.append(placeholder) + seen.add(placeholder) + return missing + + +def split_csv(value): + if not value: + return [] + return [item.strip() for item in value.split(",") if item.strip()] + + +def smoke_expectation(case_type): + mapping = { + "offline-success": "success", + "noauth-success": "success", + "noauth-help": "help_dual", + "auth-success": "success", + "stateful-success": "success", + "stateful-replay-execution": "stateful_replay_execution", + "expected-usage-error": "usage", + "expected-execution-error": "execution", + "excluded-interactive": "skip", + } + return mapping.get(case_type, "invalid") + + +def build_smoke_case(label, row, values): + case_type = row[1] if len(row) > 1 else "" + template = row[2] if len(row) > 2 else "empty" + requires = row[3] if len(row) > 3 else "none" + args_string = row[4] if len(row) > 4 else "" + json_path_exists = split_csv(row[5] if len(row) > 5 else "") + json_path_absent = split_csv(row[6] if len(row) > 6 else "") + error_code = row[7] if len(row) > 7 else "" + text_contains = split_csv(row[8] if len(row) > 8 else "") + preflight = split_csv(row[9] if len(row) > 9 else "") + stream_mode = row[10] if len(row) > 10 and row[10] else "dual" + if stream_mode not in ("text", "json", "dual"): + raise SystemExit("Invalid stream mode for manifest case %s: %s" % (label, stream_mode)) + + raw_tokens = shlex.split(args_string) if args_string else [] + unresolved = missing_placeholders(raw_tokens, values) + resolved_tokens = [substitute_token(token, values) for token in raw_tokens] + unresolved.extend(token for token in unresolved_tokens(resolved_tokens) if token not in unresolved) + + command_tokens = [label] + resolved_tokens + text_argv = [] + json_argv = [] + if stream_mode in ("text", "dual"): + text_argv = ["--network", values["NETWORK"]] + command_tokens + if stream_mode in ("json", "dual"): + json_argv = ["--output", "json", "--network", values["NETWORK"]] + command_tokens + return { + "label": label, + "suite": "stateful" if case_type.startswith("stateful-") else "smoke", + "template": template or "empty", + "requires": requires or "none", + "env_mode": "default", + "expectation": smoke_expectation(case_type), + "text_argv": text_argv, + "json_argv": json_argv, + "json_path_exists": json_path_exists, + "json_path_absent": json_path_absent, + "error_code": error_code, + "text_contains": text_contains, + "text_absent": ["Error:", "Usage:"] if smoke_expectation(case_type) == "success" + else ["Error:"] if smoke_expectation(case_type) == "help_dual" else [], + "preflight": preflight, + "unresolved_placeholders": unresolved, + "excluded": case_type == "excluded-interactive", + } + + +def build_help_case(label, values): + return { + "label": "help__%s" % label, + "suite": "help", + "template": "empty", + "requires": "none", + "env_mode": "default", + "expectation": "help_dual", + "text_argv": ["--network", values["NETWORK"], label, "--help"], + "json_argv": ["--output", "json", "--network", values["NETWORK"], label, "--help"], + "json_path_exists": ["data.help"], + "json_path_absent": [], + "error_code": "", + "text_contains": ["Usage:", "wallet-cli %s" % label], + "text_absent": ["Error:"], + "preflight": [], + "unresolved_placeholders": [], + "excluded": False, + } + + +def build_contract_case(label, row, values): + template = row[1] if len(row) > 1 else "empty" + requires = row[2] if len(row) > 2 else "none" + env_mode = row[3] if len(row) > 3 else "default" + stream_mode = row[4] if len(row) > 4 else "text" + expectation = row[5] if len(row) > 5 else "success" + args_json = row[6] if len(row) > 6 else "[]" + json_path_exists = split_csv(row[7] if len(row) > 7 else "") + json_path_absent = split_csv(row[8] if len(row) > 8 else "") + error_code = row[9] if len(row) > 9 else "" + text_contains = split_csv(row[10] if len(row) > 10 else "") + text_absent = split_csv(row[11] if len(row) > 11 else "") + preflight = split_csv(row[12] if len(row) > 12 else "") + workspace_path_exists = split_csv(row[13] if len(row) > 13 else "") + workspace_path_absent = split_csv(row[14] if len(row) > 14 else "") + + raw_tokens = json.loads(args_json) + if not isinstance(raw_tokens, list) or not all(isinstance(item, str) for item in raw_tokens): + raise SystemExit("Contract args_json must be an array of strings: %s" % label) + unresolved = missing_placeholders(raw_tokens, values) + resolved_tokens = [substitute_token(token, values) for token in raw_tokens] + unresolved.extend(token for token in unresolved_tokens(resolved_tokens) if token not in unresolved) + + text_argv = None + json_argv = None + if stream_mode in ("text", "dual"): + text_argv = resolved_tokens + if stream_mode in ("json", "dual"): + if stream_mode == "dual" and "--output" not in resolved_tokens and not any( + token.startswith("--output=") for token in resolved_tokens): + json_argv = ["--output", "json"] + resolved_tokens + else: + json_argv = list(resolved_tokens) + + return { + "label": label, + "suite": "contract", + "template": template or "empty", + "requires": requires or "none", + "env_mode": env_mode or "default", + "expectation": expectation, + "text_argv": text_argv, + "json_argv": json_argv, + "json_path_exists": json_path_exists, + "json_path_absent": json_path_absent, + "error_code": error_code, + "text_contains": text_contains, + "text_absent": text_absent, + "preflight": preflight, + "workspace_path_exists": workspace_path_exists, + "workspace_path_absent": workspace_path_absent, + "unresolved_placeholders": unresolved, + "excluded": False, + } + + +def main(): + if len(sys.argv) != 3: + raise SystemExit("Usage: case_resolver.py