feat: v4.13.0 (evm support & java standardCLI deprecate) - #990
Open
gummy789j wants to merge 42 commits into
Open
feat: v4.13.0 (evm support & java standardCLI deprecate)#990gummy789j wants to merge 42 commits into
gummy789j wants to merge 42 commits into
Conversation
Code Smells for evm-extension
…asUsed union - eslint.config.js: the scripts/**/*.mjs block never applied — scripts/** is in the global ignores, so `eslint .` is byte-identical with and without it. - evm.ts: #send was a one-line pass-through to #request with a single caller; its doc comment moves to #request, which is what it describes. - TxInfoView.gasUsed: production only ever writes String(...), so the `number` half was kept alive solely by a stale test fixture. Fixture aligned to the shape production emits; the rendered output is unchanged (formatInt already handles decimal strings). Claude-Session: https://claude.ai/code/session_01Reu4W1oqGVqUWkMpAjR9Xo
…network API keys Consolidates the TRON and EVM client adapters onto a single HttpTransport (adapters/outbound/http) and builds the per-network credential pair on top of it. Transport - TronRpcClient and EvmRpcClient accept a NetworkDescriptor or an endpoint config; raw fetch calls, URL joining and timeout wiring now live in one place. - tronweb is handed explicit HttpProviders so it carries the same headers. - TronGridHistoryReader goes through the transport; its failures no longer echo the underlying message. Per-network API key - networks.<id>.apiKeyHeader / .apiKey are readable and writable via `config`. Both must be set before a header is sent, and the header name is validated as an RFC 9110 token so a hand-edited config.yaml cannot smuggle in a second header. - apiKey is write-only on every read surface and forces the 0600 check on config.yaml, which now looks inside `networks` rather than only at top level. - Credentialed requests refuse to follow redirects on both the fetch and the tronweb path, so a redirecting endpoint cannot collect the key. Config surface - A network renders as its configurable fields rather than a bare endpoint, so a new field shows up in every view at once. Listings still trim the endpoint to its host; naming one network reveals it in full. - `config` prints the document as a tree. Nested keys carry no trailing colon -- the ids at that level contain colons themselves. Fixes found while re-testing the above on Nile and Sepolia - EVM transport timeouts report `timeout`, not `rpc_error`, matching TRON and the documented meaning of the code. - --args/--verb/--group/--source are rejected as user-typed flags. They are yargs plumbing keys that must stay in the per-command allowlist, so they worked as undocumented aliases: `contract call --args <addr>` bound into a slot the command has not got and answered 0, a wrong result that reads like a real one. The check runs on the raw tokens, before yargs folds the two sources together, and a meta-test pins that no command declares a field by those names. Startup migration - The gate runs ahead of every surface and stops after upgrading rather than running the command that triggered it. Verified on Nile and Sepolia: reads across every transport path, TRX/TRC20 and ETH transfers confirmed on-chain, the credential observed on the wire on all three paths, and the redirect target receiving nothing once one is configured. Claude-Session: https://claude.ai/code/session_01JSxAgrttq54UacDxykm7gy
The source-of-truth doc it named was deleted in 7a33dcd, leaving the one instruction that tells a reader where the boundary rules live pointing at nothing. Split the reference across what actually holds each part now: the table below it for the boundaries, .dependency-cruiser.cjs for enforcement, machine-interface.md for the JSON contract, and docs/adr/ for the reasoning. Claude-Session: https://claude.ai/code/session_01JSxAgrttq54UacDxykm7gy
5389b00 pointed at ts/docs/adr/ after verifying it existed on disk, which is the wrong test: ts/.gitignore:9 ignores it, so it holds zero tracked files and is not there for anyone who clones. That replaced one dead reference with another. What remains is what the repo actually carries: the table, the dependency-cruiser config that enforces it, and machine-interface.md. Claude-Session: https://claude.ai/code/session_01JSxAgrttq54UacDxykm7gy
…sion feat: evm extension
Extracting `tronTxModeFields` out of the shared `txModeFields` moved --permission-id and --expiration behind an explicit opt-in. The commands that serve two families re-added them in their TRON binding (tx send, contract send/deploy) and the governance writes get them via `governanceTxModeFields`, but the 18 single-family TRON writes kept spreading `txModeFields` alone and silently lost both flags. The effect was not cosmetic: signing under a non-owner active permission group — the whole point of TRON multi-sig — became impossible on stake, vote, reward, asset, exchange and account activate/set, and there was no way to extend a transaction's expiry while collecting co-signatures. The same account could still do both through `tx send`, which is what makes this a gap rather than a decision. These commands are single-family, so the fields belong in `baseFields` directly. Not `governanceTxModeFields`: that also overrides --build-only's description, which would change help text on 18 commands as a side effect. Nothing below the CLI layer needed touching — the value already rides `...transactionMode(input)` into the pipeline's `prepare` hook, which is why the services never name it and why the break was invisible to them. Covered by transaction-options.test.ts: both flags present on all 18, identity-equal to the exported field objects so a second copy cannot drift, --build-only's shared description pinned, and argv coercion.
The EVM family went public on this branch — `FAMILY_REGISTRY` now carries `evmFamily`, and `networks` lists seven networks across two families — but ts/docs still described a TRON-only tool. Every page was checked against the running binary rather than against the diff: the current and the merge-base `--json-schema` catalogs were compared to find the 56 commands whose spec actually moved, and every example below was captured from a real run on tron:nile and evm:11155111. Command pages (91) now state, per command, which families serve it: - Portable commands document both families where they genuinely differ — the field SETS, not just the values: `account info` reports resources and permissions on TRON, nonce and code on EVM; `chain prices` answers in energy/bandwidth or in gas and shares no field between them; `tx info` nests `info` or `receipt`; `contract call` returns words or one blob. - TRON-only commands say so, and name `family_mismatch` — the error an EVM network returns before any node call. - Family-scoped flags are split into "TRON only" / "EVM only" tables, since using one on the other family is `invalid_option`. - `contract deploy` is rewritten for the artifact-based interface that replaced --bytecode/--params. - Account pages carry the per-family address model: `addresses` and `derivationPath` are maps now, and text listings show one family at a time while JSON carries every one. machine-interface.md gains the family rules, the discovery call, and a pointer to the published error-code index; the `chain` block note is corrected — `list` and `current` emit one without contacting a node. concepts/networks.md documents the evm-gas model beside tron-resource, and troubleshooting.md keys the new failure modes. Also corrected, pre-dating this branch: the stake info unfreezing tree, `Max delegatable` reporting TRX, the token book's official layer no longer being mainnet-only, and chain params claiming the CLI cannot create proposals. Verified: 0 broken links or anchors across 125 files, every documented flag matches the live JSON Schema, and all 91 pages keep the house layout.
Execution blueprint for removing org.tron.walletcli.cli from the Java implementation, measured against the tree rather than restated from the requirements doc. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
…ckage Standard CLI removal prep. CommandErrorException lives in org.tron.walletcli.cli but leaks into the main sources in 127 places, including REPL-reachable methods (getUSDTBalance, gasFreeTransferInternal). Deleting the cli/ package with the type still inside would not compile. Move it verbatim to org.tron.core.exception, alongside the exceptions signTransactionForCli already throws (CancelException). Package move only: same class name, same semantics. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
BREAKING CHANGE: the only supported invocation is now a bare `java -jar wallet-cli.jar`, which starts the interactive shell. runMain() was a Standard CLI skeleton: GlobalOptions parsing, a JSON-enveloped --version, a --help backed by CommandRegistry, and a StandardCliRunner dispatch. Replace it with the four-case whitelist from the removal plan: no args -> interactive shell, exit 0 --version -> "wallet-cli vX.Y.Z" as plain text, exit 0 --help -> shell usage plus the migration hint, exit 0 anything else -> one-line migration hint on stderr, exit 2 --interactive goes away with it; it was never documented (java/README.md only ever showed the bare invocation) and only existed to escape from the non-interactive entry into the REPL. The hint is deliberately not a JSON envelope: emitting one would let scripts believe the contract is still there. Exit 2 matches the old usage-error code, so "non-zero means failure" keeps holding. Drops the four cli/ imports, the now-unused LinkedHashMap/Map imports, and shouldLaunchInteractiveByDefault / requestsJsonOutput / initRegistry. ClientMainTest is rewritten in the same commit so the test tree never spends a commit broken. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
…r.sign cli/ and the main sources depend on each other both ways: cli/ makes 55 *ForCli calls, while WalletApi and WalletApiWrapper name cli.ledger.LedgerSigner and cli.ledger.LedgerSignOutcome by fully-qualified name at their injection points. Deleting either side first fails to compile, and no reordering fixes that. Move the two types to org.tron.ledger.sign, which is neutral ground next to the Ledger package the interactive shell keeps. That cuts the main-sources -> cli/ edge, so the otherwise atomic removal can be split into a mechanical bulk delete and a surgical one. Both types are deleted again with the rest of the non-interactive Ledger adapter. Package move only, no behavior change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
…urces
BREAKING CHANGE: every non-interactive command is gone. Scripts and CI
should move to the TypeScript CLI, @tron-walletcli/wallet-cli.
The mechanical half of the removal, kept separate from the surgical half so
each can be reviewed on its own terms and a regression can be bisected to the
right side:
- src/main/java/org/tron/walletcli/cli/ (36 files)
- src/test/java/org/tron/walletcli/cli/ (19 test classes)
- src/test/java/org/tron/qa/ (QARunner, QASecretImporter)
- src/main/resources/aliases/{main,nile,shasta}.json
The alias feature goes with the package rather than surviving on its own: it
was reachable only through standard CLI commands (alias-add / alias-remove /
alias-list / alias-resolve), and the REPL never constructs an AliasResolver.
Users may delete the leftover Wallet/aliases/ and Wallet/.active-wallet
themselves; this release does not touch files under their wallet directory.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
The surgical half of the removal. Small diff, dense judgment; kept apart from the bulk delete so a regression bisects to the right side. *ForCli family: 65 names, 101 declarations across WalletApiWrapper (55), WalletApi (45) and ApiClient (1). Client.java referenced none of them; every caller lived in the deleted package. Symbols without the ForCli suffix that were standard-CLI-only all the same: the LAST_CLI_OPERATION_ERROR ThreadLocal and its four accessors (it existed to feed the JSON error envelope), the *OrThrow helpers, throwIfCliOperationFailed / throwCliError / validateCliWalletName, getGasFreeInfoData, gasFreeTraceData, getUSDTBalanceExact, extractTransactionReturnMessage, passwordValidQuiet, deleteFilesQuiet, GasFreeApi.getMessageOrThrow, CliWalletCreationResult, lastGasFreeId, the WalletApiWrapper.setWallet setter, and WalletCreationResult's mnemonicKeystoreName. The printMnemonicPath parameter was only ever false for the CLI, so it collapses to an unconditional print. gasFreeTransferInternal survives — the REPL reaches it through gasFreeTransfer — so its standardCli parameter is folded out branch by branch, including the IllegalStateException catch that named no such variable and was reachable only through getMessageOrThrow. The "GasFreeTransfer result:" line stays; it was guarded by if (!standardCli) and is now unconditional. Ledger: only the non-interactive adapter goes. WalletApi's injected signer field, signTransactionForCli, WalletApiWrapper.setLedgerSigner, the gasfree signing branch, and LedgerEventListener's standardCliQuiet / lastSendResult are removed; the quiet guards fold to always-print, which is what the REPL already saw. All 24 files of org.tron.ledger and every Ledger path in the interactive shell are untouched. Orphaned by the above and removed with it: WalletApi's instance triggerConstantContractExtention, estimateEnergyMessage and estimateEnergyMessageDirect. triggerConstantContractExtentionDirect stays — getUSDTBalance still calls it. Unrelated pre-existing dead code in WalletApi is left alone. Tests follow the same rule: src/main references decide, src/test does not. WalletApiWrapperTest loses seven cases, WalletApiTest one, and ClearWalletUtilsTest is deleted outright. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
qa/ only ever exercised the standard CLI. Every one of its 103 cases invoked `java -jar wallet-cli.jar --network <net> [--output json] <args>`; the "text vs json comparison" compared the standard CLI's two output modes against each other, never the REPL against anything. With the standard CLI gone the harness has no subject left. Removes qa/ (11 files), the qaJar and qaRun gradle tasks, and the four qa/ entries in .gitignore. The QARunner and QASecretImporter classes it drove went with the bulk delete. No CI job referenced any of this. The Java implementation is left without automated end-to-end coverage, which is where it already stood. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
BREAKING CHANGE: MASTER_PASSWORD is no longer read. Keystore passwords come from the terminal prompt only. Five loose ends the package deletion left behind: - The MASTER_PASSWORD channel. The standard CLI read the variable through its own path, but Utils.inputPassword — the shell's own prompt — carried a second reader for it behind a ThreadLocal switch that only tests ever flipped. It was dormant, not live, and a single call to the setter would have made it live again on the interactive path. The branch, resolveEnvPassword, set/isEnvPasswordInputEnabled and UtilsPasswordTest all go. - The wallet chooser. selcetWalletFile and its sibling listed Wallet/ without excluding subdirectories, so a leftover Wallet/aliases/ would appear as a numbered entry, count toward the total, and fail to parse when selected. Both filters now skip directories. This was already wrong for any subdirectory; the alias store just made it easy to hit. The .active-wallet filter stays — it is what keeps that file out of the list. - java/docs/standard-cli-contract-spec.md, which described a contract that no longer exists. - CLAUDE.md: the standard CLI examples, the two-modes section, the contract section, the request flow, the four cli/ key classes, the "adding a command" recipe and the two package rows. The QA section is replaced by a statement of what is actually true — there is no automated end-to-end coverage, and there was none before, since qa/ only ever drove the standard CLI. - VERSION -> v4.13.0, in step with the TypeScript package. Not a major bump, so a pinned build will not be held back by the version alone; the fallback hint and the release notes carry that weight instead. Release notes are added at java/docs/release-notes-v4.13.0.md. They state plainly that Ledger support in the interactive shell is untouched and that only non-interactive Ledger signing is removed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
WalletApiWrapper's only @Setter was on the `wallet` field, removed with setWallet in ed35a6eb; the import stayed behind. Caught in review. WalletApi's unused java.net.URI and SignatureInterface imports are left alone — both were already dead at 3913909, so they are pre-existing, not orphans of this work. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
Round-2 review catch. TransactionUtils.PERMISSION_ID_OVERRIDE and its public set/clear pair existed so standard CLI handlers could supply --permission-id without a prompt. Every caller lived in the deleted package (StandardCliRunner:75 and 14 sites across the *Commands classes), so the mechanism is now unreachable from src/main. It is the same shape as the MASTER_PASSWORD channel D10 removed: dormant, not live, but one call to a public setter away from being live again — and here that setter suppresses the interactive shell's "Please confirm and input your permission id" confirmation on the multisig signing path (WalletApi:941, :3411), or cancels the transaction outright with no prompt at all. The §9.3 grep gates cannot see it; its name matches none of them. Removes the ThreadLocal, the override branch, the tipString == null early return (its only caller was the deleted signTransactionForCli), both public methods, and TransactionUtilsTest, whose single case exercised the null-tip path. Both surviving callers pass a non-null tip, so the prompt behaves exactly as before. No ThreadLocal now remains in src/main. Also collapses the blank-line runs that the deletions left behind in WalletApi, WalletApiWrapper, GasFreeApi and ApiClient, each back to the density it had at 3913909. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
Round-3 review catch. LedgerSignResult.upsertState, .getStateByTxid and HidServicesWrapper.hasAnyLedgerAttached had exactly one caller each at 3913909, all three in cli/ledger/ProductionLedgerPorts, so deleting the non-interactive adapter left them with none. These are orphans this work created, not pre-existing dead code, so CLAUDE.md's "remove what your change made unused" applies. §5.2 requires keeping all 24 files of org.tron.ledger and they are kept — the package still has 24 files and still ships 33 classes; the plan already scoped in-file cleanup inside that package when it folded LedgerEventListener's standardCliQuiet guards. Inert helpers, not switches: the REPL uses the siblings updateState, getLastTransactionState and appendLineIfNotExists, all untouched. No caller, no reflection, no cascade — readAllLines, writeAllLines, getHidServices and LEDGER_VENDOR_ID all remain live. LedgerSignResult's own pre-existing zero-caller methods (getFilePath, fileExists, writeAllLines, getLastTransaction) are left alone: they were already unused at 3913909. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxauSno5mhxX4DmBr39iso
Feat/java remove standard cli
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.