Draft
Conversation
Adds `cmd/heimdall/` package with the root `heimdall` cobra command (aliased `h`) and embedded usage.md. Wires it into `NewPolycliCommand`. No subcommands yet — those land in W1. Refs: HEIMDALLCAST_PLAN.md §2.1
Adds internal/heimdall/config package. Resolves runtime config by layering preset -> optional ~/.polycli/heimdall.toml -> env vars -> flags, with --mainnet/--amoy/--network shortcuts. Registers persistent flags on HeimdallCmd so every future subcommand inherits --rest-url / --rpc-url / --chain-id / --json / --curl / --color / --raw etc. The amoy preset falls back to the in-cluster test-node addresses from HEIMDALLCAST_REQUIREMENTS.md §2; mainnet uses the community-documented heimdall.polygon.technology endpoints. Both are marked with a TODO for operator verification before the first user-facing release. Refs: HEIMDALLCAST_PLAN.md §2.2
Adds internal/heimdall/client with: - RESTClient.Get/Post returning raw bytes + status code - RPCClient.Call issuing JSON-RPC 2.0 envelopes over HTTP - Transport abstraction with HTTPTransport (wire) and CurlTransport (dumps equivalent curl one-liner instead of executing) - Typed errors (HTTPError, NetworkError, UsageError, RPCError) plus ExitCode() mapper for cast-style exit codes (1/2/3/4) Neither client decodes response bodies; callers choose between typed decode and JSON passthrough. Insecure TLS and custom headers wired through the constructors. Refs: HEIMDALLCAST_PLAN.md §2.3
Adds internal/heimdall/render with: - RenderKV (right-aligned key/value, mirrors requirements §4.1) - RenderTable (column-aligned for list payloads) - RenderJSON with bytes->0x-hex normalization (suppressed by --raw) and uint64-string preservation per requirements §4.2 - --field plucker with dot-path support; bare output for single field - Watch() wrapper with timer.NewTimer + defer timer.Stop (CLAUDE.md timer-leak rule) and context-driven exit - Hint catalogue for the known misleading responses in §4.5 - Timestamp annotation helper (cast-style "1776640801 (date, 2h ago)") Color handling honours --color auto|always|never and NO_COLOR. Refs: HEIMDALLCAST_PLAN.md §2.4
Adds scripts/capture-heimdall-fixtures.sh that hits the live test node
(172.19.0.2) for every REST path and CometBFT method referenced in the
requirements and writes pretty-printed JSON to
internal/heimdall/client/testdata/{rest,rpc}. Idempotent: rerun
overwrites in place.
Captured success-case fixtures for 33 REST endpoints and 11 RPC
methods. A handful are skipped because they need specific node state
this test node lacks (clerk latest-id + topup endpoints require
`eth_rpc_url`; tx_search times out on wide queries) — the script
reports those failures and continues.
TestFixturesAreValidJSON verifies every committed fixture parses and
RPC fixtures carry the expected envelope keys.
Refs: HEIMDALLCAST_PLAN.md §2.5
The internal/heimdall/config loader parses the optional ~/.polycli/heimdall.toml via pelletier/go-toml/v2. Move the dep from indirect to direct since the heimdall package imports it. Refs: HEIMDALLCAST_PLAN.md §2.2
Resolves the TODO placeholders with the confirmed public endpoints: - mainnet REST: https://heimdall-api.polygon.technology - mainnet RPC: https://tendermint-api.polygon.technology - amoy REST: https://heimdall-api-amoy.polygon.technology - amoy RPC: https://tendermint-api-amoy.polygon.technology Verified each URL returns 200 on a representative endpoint.
Implement the seven cast-familiar CometBFT-facing subcommands of `polycli heimdall` as specified in requirements section 3.1: `block`, `block-number`, `age`, `find-block`, `chain-id`, `chain`, `client`. All calls target the CometBFT JSON-RPC endpoint and share the heimdall config resolver, RPC client, and renderer. `find-block` does a context-cancellable binary search and accepts unix or RFC3339 timestamps. Height resolution honors `latest`/`earliest` and rejects Ethereum-only tags with a usage hint. Adds unit tests with fixtures (including a new block_earliest.json capture from Amoy) and integration tests gated by the `heimdall_integration` build tag.
Replace the placeholder /tx error fixture with a real successful MsgTopupTx response captured from 172.19.0.2:26657, and add a matching /tx_search fixture for two entries queried descendingly. Used by the tx/receipt/logs unit tests in cmd/heimdall/tx.
Introduces the W1b tx-group read-only subcommands at the top level of
the heimdall command tree (mirroring cast's flat layout):
- tx <HASH> / t - CometBFT /tx, with --raw to preserve
the base64 TxRaw body
- receipt <HASH> / re - same /tx call but renders events and
logs; --confirmations N polls /status
until tip >= tx.height + N, honouring
context cancellation
- logs <QUERY> - CometBFT /tx_search with --limit and
--page pagination
- nonce <ADDRESS> - REST /cosmos/auth/v1beta1/accounts/
{addr}.sequence
- sequence <ADDRESS> - synonym of nonce
- balance <ADDRESS> / b - REST by-denom balance; default raw
integer, --human formats with decimals
- rpc <METHOD> [KEY=VALUE...] - raw CometBFT JSON-RPC passthrough with
JSON-aware key=value argument parsing
- publish <TX> - broadcasts a base64/hex TxRaw via REST
/cosmos/tx/v1beta1/txs; state-changing,
so requires --yes (prints the equivalent
wire payload and fails with usage error
otherwise)
Hash handling tolerates the 0x prefix and base64-encodes for the
CometBFT JSON-RPC /tx endpoint (reflect-based RPC expects []byte as
base64, not hex).
Unit tests cover fixture-driven happy paths, argument validation,
--confirmations wait + cancel behaviour, and tx-bytes normalization;
integration tests (heimdall_integration build tag) resolve a recent
MsgTopupTx hash via tx_search on the live node and round-trip
tx/receipt/nonce/balance/rpc/logs end-to-end.
Run: make gen-doc regenerated the top-level heimdall doc and added
per-subcommand doc files for each new command.
…xtures Add REST fixtures for checkpoint module tests: live prepare-next and empty-buffer captures, plus synthetic code:13 (L1 unavailable) and code:5 (not-set) envelopes used by unit tests to exercise the hint and error paths without depending on node state.
Introduce the checkpoint umbrella (alias cp) wiring ten subcommands against Heimdall v2's x/checkpoint REST endpoints: params, count, latest, get, buffer, last-no-ack, next, list, signatures, overview. Bare numeric args to checkpoint shortcut to get. root_hash is rendered as 0x-hex by default and --raw preserves base64. Human affordances: buffer prints 'empty' with a hint when the proposer is the zero address or empty string; next maps gRPC code 13 to an L1-not-configured hint on stderr; last-no-ack annotates unix seconds with human age; list paginates via Cosmos pagination.* params and reports next_key on stderr. Unit tests exercise all subcommands against recorded fixtures plus a hash-normalization helper and the buffer-empty / L1 detection predicates. Integration tests (build tag heimdall_integration) run against a live Amoy node.
…ures Add canned REST responses captured from a live Heimdall v2 node so the span subcommand unit tests can exercise producer-votes-by-id, planned downtime (populated), and planned downtime (not-found / gRPC code 5) code paths without hitting the network.
Add a span umbrella command (alias sp) under polycli heimdall that
exposes the Heimdall v2 x/bor REST surface:
- params, latest, get <ID> (and bare span <ID> shorthand)
- list [--limit N] [--reverse] [--page KEY]
- producers <ID> (derived from span's selected_producers)
- seed <ID>
- votes [VAL_ID]
- downtime <PRODUCER_ID> (prints "none" on 404)
- scores (sorted desc, numeric tiebreak)
- find <BOR_BLOCK> (binary-searches the covering span, computes
designated producer via (block-start)/sprint mod len(producers),
prints a Veblop rotation caveat on stderr)
Unit tests cover find edge cases (at start_block, at end_block, sprint
boundary, mid-sprint, span 0, last span, before any span, after
latest, span with no producers). Integration tests (guarded by the
heimdall_integration build tag) exercise params, latest, find, scores,
votes, list and downtime against a live Heimdall v2 node. Docs are
regenerated via make gen-doc.
…ixtures Captured from http://172.19.0.2:1317: - milestones_out_of_range.json — HTTP 404 body for /milestones/0 ("code: 5 milestone number out of range"); used to drive the valid-range hint in `milestone get`. - milestones_by_number_one.json — milestone #1 on Amoy, whose `milestone_id` is a `uuid - 0x…` string (genesis artefact) and therefore cannot be confused with its URL-path sequence number. Drives the `number` vs `milestone_id` footgun rendering test.
Implements HEIMDALLCAST_REQUIREMENTS.md §3.2.3 under a new
`cmd/heimdall/milestone` package. Subcommands:
- `milestone params` → /milestones/params
- `milestone count` → /milestones/count (bare integer on stdout)
- `milestone latest` → /milestones/latest (hash rendered as 0x-hex)
- `milestone get <NUMBER>` and bare `milestone <NUMBER>` →
/milestones/{number}; prints both the URL-path `number` and the
response-body `milestone_id` (they are distinct — see footgun in
§3.2.3).
On a 404 from /milestones/{number}, the command fetches
/milestones/count and, if the requested number is 0 or > count,
emits `hint: valid range is 1..<count>` on stderr. If the count
lookup itself fails the original 404 is returned unchanged.
Unit tests exercise all four subcommands against the captured
fixtures including the number-vs-milestone_id rendering and both
the "zero" and "far above count" out-of-range hint paths. An
integration test file (//go:build heimdall_integration) hits
172.19.0.2:1317 directly to confirm the same behaviour on real data.
make gen-doc re-run; docs regenerated.
Adds `polycli heimdall validator` (alias `val`) + the top-level `validators` alias covering the Heimdall v2 x/stake module: - `validator set` / `validators` (sorted power desc by default, with --sort power|id|signer and --limit) - `validator total-power` - `validator get <ID>` (plus bare `validator <ID>` shorthand) - `validator signer <ADDR>` (tolerates missing 0x prefix) - `validator status <ADDR>` (renames upstream is_old to is_current; emits a hint explaining the rename) - `validator proposer` - `validator proposers [N]` (N defaults to 1) - `validator is-old-stake-tx <HASH> <LOG_INDEX>` (prints the L1-not-configured hint on gRPC code 13 / connection refused) Includes unit tests with captured REST fixtures and integration tests gated by the heimdall_integration build tag.
Output of make gen-doc after adding cmd/heimdall/validator and the top-level validators alias.
Extend the clerk REST fixtures with cases the W1g state-sync tree needs: a gRPC code-13 latest-id / sequence / is-old-tx response for L1-less nodes, a HTTP-500 "not found" for event-record lookups (the upstream returns code 13 rather than 404 for a missing id), the page=0 HTTP-400 error from /clerk/event-records/list (upstream rejects page 0 because the endpoint is page-based, not cosmos), and a /clerk/time response with from_id + to_time + pagination.limit.
Implement the x/clerk umbrella per requirements §3.2.5 under the
canonical name state-sync, with aliases clerk and ss. Subcommands:
- count: bare integer from /clerk/event-records/count.
- latest-id: /clerk/event-records/latest-id, surfacing the
L1-not-configured hint on gRPC code 13.
- get <ID> / bare state-sync <ID>: /clerk/event-records/{id}. The
`data` field renders as 0x-hex by default; --base64 (or the
global --raw) preserves the upstream base64.
- list [--page N] [--limit N]: /clerk/event-records/list. PAGE-
BASED pagination (bare `page` + `limit` query params), not
cosmos-pagination — the upstream rejects page=0 with HTTP 400,
so --page defaults to 1. When --limit is omitted the
pagination-limit hint is surfaced on stderr.
- range --from-id ID [--to-time T] [--limit N]: /clerk/time.
Unlike /list, this endpoint goes through cosmos-pagination on
the server side, so --limit is forwarded as `pagination.limit`.
--from-id is required; the server rejects an empty query.
- sequence / is-old <TX_HASH> <LOG_INDEX>: /clerk/sequence and
/clerk/is-old-tx respectively. Both fan out to L1 on the
server; the L1-not-configured hint is surfaced on gRPC code 13
or transport-level `dial tcp` / `connection refused`.
Register under cmd/heimdall/heimdall.go init() and regenerate
doc/polycli_heimdall_state-sync*.md.
Capture real responses from the Amoy heimdall-v2 node at 172.19.0.2:1317 for the x/topup endpoints: dividend-account-root (success), dividend-account (not-found), account-proof (L1-unconfigured), verify (false + bad-proof), sequence / is-old-tx (L1-unconfigured). Success-case dividend-account / account-proof / sequence / is-old-tx bodies are synthesized from the heimdall-v2 proto shapes since the live test node lacks L1 RPC and has no dividend accounts.
Implements `polycli heimdall topup` with six subcommands targeting
Heimdall v2's x/topup module, per HEIMDALLCAST_REQUIREMENTS.md §3.2.6.
All routes are confirmed from heimdall-v2 proto/heimdallv2/topup/query.proto:
- topup root -> GET /topup/dividend-account-root
- topup account -> GET /topup/dividend-account/{address}
- topup proof -> GET /topup/account-proof/{address}
- topup verify -> GET /topup/account-proof/{address}/verify?proof=...
- topup sequence -> GET /topup/sequence?tx_hash=...&log_index=...
- topup is-old -> GET /topup/is-old-tx?tx_hash=...&log_index=...
The proof/sequence/is-old endpoints fan out to L1 on the server side;
gRPC code 13 (or a connection-refused transport error) is surfaced as
the shared L1-not-configured hint on stderr before propagating the
error, matching the clerk umbrella's shape.
Default human output renders bytes as 0x-hex; --raw preserves the
upstream base64, and --json emits the raw server payload. Addresses,
tx hashes, and proofs are validated and normalized before the URL is
built.
The `verify` route uses GET (not POST) with the proof in the
`proof` query parameter — confirmed from the upstream gateway proto.
Unit tests (24): fixture-backed httptest server exercises each subcommand's happy path, L1-unconfigured hint path, address/tx-hash validation, proof query-param shape, --json / --raw flag behaviour, and error propagation for not-found (404/500) responses. Integration tests (8, build tag heimdall_integration) talk to the live Heimdall v2 node at 172.19.0.2:1317. The proof / sequence / is-old tests skip rather than fail if the node ever gains L1 RPC connectivity. The root / verify tests exercise the non-L1 path end to end. `go test -race ./cmd/heimdall/topup/...` and `go test -tags heimdall_integration -race ./cmd/heimdall/topup/...` both pass.
Captured from the live Heimdall v2 Amoy node at 172.19.0.2:1317: - chainmanager_params.json — GET /chainmanager/params success body with the chain_params envelope, all ten *_address fields, and the two tx confirmation depths. - chainmanager_not_implemented.json — gRPC-gateway code 12 body used to exercise the 501 error path for unknown routes.
Implements `polycli heimdall chainmanager` (alias `cm`) targeting the Heimdall v2 x/chainmanager module, per HEIMDALLCAST_REQUIREMENTS.md §3.2.7. Subcommands: - `chainmanager params` — GET /chainmanager/params. Default KV output unwraps the `params` envelope; --json preserves it; --field uses dot-notation paths against the raw server shape. - `chainmanager addresses` — derived view over the same response, surfacing the two chain ids and every `*_address` field from params.chain_params as `<name>=<value>` lines (alphabetized). Hides the tx confirmation depths that clutter the etherscan paste workflow. Only one HTTP route exists upstream; confirmed from heimdall-v2/proto/heimdallv2/chainmanager/query.proto. The package directory is named `chainparams` to avoid colliding with the top-level `chain` command (W1a). Registered on the heimdall root via chainparams.Register.
- helpers_test.go — shared httptest fixture server + cobra runner, mirroring cmd/heimdall/topup/helpers_test.go. - chainparams_test.go — 10 unit tests covering default KV output, --json passthrough, --field dot-path plucking over the envelope, the derived addresses view (including alphabetized ordering and confirmation-depth exclusion), malformed-body handling, and the `cm` alias. - integration_test.go (build tag heimdall_integration) — 4 tests against the live Amoy node at 172.19.0.2:1317 exercising params shape, --field plucking, the addresses derived view, and alias routing end-to-end. All tests pass with -race under both build modes.
Adds `polycli heimdall util` with four offline helpers: addr (hex↔bech32 address conversion using the default cosmos prefix, overridable via --hrp), b64 (hex↔base64 with auto-direction detection and --to override), version (polycli build metadata with optional --node /status lookup via CometBFT RPC), and completions (bash, zsh, fish, powershell via cobra's stock generators). Bech32 encoding piggybacks on github.com/btcsuite/btcd/btcutil/bech32, already in the module graph as an indirect dep, so no new top-level dependencies are introduced. The `cosmos` prefix is confirmed from heimdall-v2/API_REFERENCE.md and the absence of a sdk.Config.SetBech32PrefixForAccount override in heimdalld's commands.
Covers addr (round-trip vectors for three known Heimdall addresses plus a custom --hrp smoke test, plus invalid-input table), b64 (auto and explicit conversion, URL-safe base64 acceptance, round-trip, invalid inputs), version (plain + --json + --field paths, plus a heimdall_integration-tagged test hitting 172.19.0.2:26657 for --node), and completions smoke tests for all four supported shells that verify cobra's output contains shell-specific markers. 22 unit test functions, 1 integration test function, 42 invocations once subtests are expanded. go test -race ./cmd/heimdall/util/... passes clean.
Capture real /status, /health, /net_info, /abci_info, /commit, /validators, /num_unconfirmed_txs and /unconfirmed_txs responses from the Amoy-backed node at 172.19.0.2:26657, plus the error envelope that node returns for /dump_consensus_state (consensus endpoints are disabled by default). Add a synthetic dump_consensus_state.json so rendering logic remains unit-testable on a fixture even when the live node refuses.
Introduce 'polycli heimdall ops' grouping the operator-facing CometBFT JSON-RPC commands: status, health, peers, consensus, tx-pool, abci-info, commit and validators-cometbft. All calls use the existing RPCClient (with --curl and config resolution) and render via the heimdall KV/JSON/table renderers. Notes: - consensus warns before the call, since dump_consensus_state is expensive and frequently disabled on production nodes. - validators-cometbft prints a stderr hint directing operators to 'heimdall validator' for the x/stake view so the two commands don't get confused. - tx-pool --list decodes base64 mempool blobs to sha256 tx hashes (matches how CometBFT computes tx hashes over the wire payload).
Unit tests drive each subcommand against an httptest.Server backed by the captured fixtures: summary rendering, --json passthrough, --field plucking, error surfaces (health RPC error, consensus endpoint disabled, bad height, bad --limit), and the base64 mempool hash helper. Integration tests (behind the heimdall_integration build tag) exercise every subcommand against the live 172.19.0.2:26657 node and treat the consensus-endpoint-disabled response as a pass of the error path rather than a failure.
Implements `polycli heimdall wallet` with 13 subcommands compatible with Foundry's `cast wallet` v3 JSON keystore format: new, new-mnemonic, address, derive, sign, verify, import, list, remove, public-key, decrypt-keystore, change-password, private-key. Hardware wallets, vanity, and sign-auth are rejected with helpful pointers to cast. Keystore directory precedence: --keystore-dir flag > ETH_KEYSTORE env > ~/.foundry/keystores/ (if exists) > ~/.polycli/keystores/ (created on demand). Signing defaults to EIP-191 personal_sign; --raw signs a 32-byte hash. Plaintext key export is gated by --i-understand-the-risks. All operations are offline. Tests use t.TempDir() and never touch real keystore directories. Coverage includes a known BIP-39 derivation vector, sign/verify round-trip, foundry keystore fixture decryption, and keystore precedence across all four levels.
Add a hand-rolled proto-encoding subset sufficient for the heimdall tx builder: Any, Coin, PubKey wrapper, TxBody, AuthInfo, SignerInfo, ModeInfo, Fee, TxRaw, SignDoc, and MsgWithdrawFeeTx. Uses google.golang.org/protobuf/encoding/protowire (already a direct dep); no cosmos-sdk / cometbft / go-ethereum replace directives required. See internal/heimdall/proto/README.md for rationale and escape hatch to buf generate if the surface grows.
Add the internal/heimdall/tx package implementing the shared builder used by `mktx`, `send`, and `estimate` (W3). The builder fills a cosmos.tx.v1beta1.TxRaw with one or more messages, resolves account_number/sequence through a REST AccountFetcher (or explicit overrides), and signs using PubKeySecp256k1eth (keccak256 digest, r||s 64-byte sig). Direct and amino-JSON sign modes are both supported; amino-JSON serializes a canonicalized StdSignDoc with sorted keys. Additional helpers: - Broadcast via POST /cosmos/tx/v1beta1/txs in SYNC or ASYNC mode. - WaitForInclusion polls CometBFT /tx until inclusion or ctx cancel. - WaitForConfirmations polls /status until tip passes txHeight + N. - Simulate via POST /cosmos/tx/v1beta1/simulate. - RequireForce refuses L1-mirroring Msg types unless --force is set, with wording from HEIMDALLCAST_REQUIREMENTS.md §3.3. Only MsgWithdrawFeeTx is wired in this wave (as the exemplar Msg); W3/W4 add the remaining operator-reachable messages using the same pattern.
Unit tests (go test -race) cover: - Deterministic TxBody/AuthInfo bytes across builds with identical inputs, plus the derived 64-byte r||s signature length. - Sign mode switch: SIGN_MODE_DIRECT and SIGN_MODE_LEGACY_AMINO_JSON produce different AuthInfo + signature bytes but share TxBody. - Signature verifies against the signer's 65-byte uncompressed pubkey using keccak256 digest (PubKeySecp256k1eth). - AccountFetcher integration: populates account_number/sequence, preserves explicit sequence overrides, propagates fetch errors. - Builder input validation: missing messages, chain id, gas limit, or private key each fail with an explicit error. - Broadcast happy path and non-zero-code surfacing. - Simulate happy path returns gas_used / gas_wanted. - WaitForInclusion honours context cancellation and deadline; polls until the tx appears. - RequireForce flags the L1-mirroring Msg types and allows safe types, with the requirements-§3.3 wording. - Proto encoder round-trips for Any, MsgWithdrawFeeTx, TxRaw, SignDoc and emits zero bytes for a zero-valued message. Integration tests (//go:build heimdall_integration) against 172.19.0.2:1317 fetch a known signer's account and build a TxRaw without broadcasting. Broadcasting is gated behind HEIMDALL_TEST_ALLOW_BROADCAST=1.
Wire three top-level subcommands for the `polycli heimdall` tree: `mktx` builds and prints a signed TxRaw without broadcasting; `send` builds, signs, broadcasts, and (by default) waits for inclusion; `estimate` simulates a tx against /cosmos/tx/v1beta1/simulate and reports gas usage. Child msg subcommands (e.g. `withdraw`) live under cmd/heimdall/tx/msgs and register themselves into a package-level factory map via RegisterFactory(name, factory). BuildChildren(mode, flags) produces a fresh subtree per umbrella because cobra commands are single-parent. Shared flag bag TxOpts plus RegisterFlags(cmd, opts, mode) apply the wallet / gas+fee / account-override / sign+broadcast / force flags per spec §3.3; Execute(cmd, opts, mode, plan) is the single call point that resolves config, runs the L1-force guard, signs, and dispatches per mode. All new files are scoped to cmd/heimdall/tx and cmd/heimdall/tx/msgs -- nothing under internal/heimdall is touched.
Register a `withdraw` factory under mktx/send/estimate that emits a MsgWithdrawFeeTx. The proposer field defaults to the signer's Eth-style address (derived by resolving --from / --account / --private-key / --mnemonic via ResolveSigningKey); callers can override with --user. --amount defaults to "0", which Heimdall interprets as "withdraw the full accumulated balance". MsgWithdrawFeeTx is not L1-mirrored, so requireEthAddress is local and RequireForce returns nil -- no --force prompt needed.
Add msgs_test.go (default build tag) covering: - registry shape and BuildChildren safety - mktx withdraw emits 0x-prefixed TxRaw hex and a stable JSON envelope - body-bytes determinism across repeated invocations - send --dry-run does not POST; non-dry-run POSTs /cosmos/tx/v1beta1/txs - estimate withdraw round-trips simulate and computes fee from gas price - L1-mirroring guard exempts MsgWithdrawFeeTx - Sign-mode gating: DIRECT ok, AMINO_JSON ok, garbage rejected - Flag validation (missing chain-id, missing signer, unknown msg) Integration suite gated by `heimdall_integration` tag defaults to the documented 172.19.0.2 compose node with overrides (HEIMDALL_TEST_REST_URL / HEIMDALL_TEST_RPC_URL / HEIMDALL_TEST_CHAIN_ID). Broadcasting test further gated by HEIMDALL_TEST_ALLOW_BROADCAST=1 so CI doesn't accidentally emit txs.
Adds hand-rolled proto encoders and decoders for the Heimdall v2 Msg types needed by the per-Msg subcommands: MsgCheckpoint, MsgCpAck, MsgCpNoAck, MsgProposeSpan, MsgBackfillSpans, MsgVoteProducers, MsgSetProducerDowntime, MsgValidatorJoin, MsgStakeUpdate, MsgSignerUpdate, MsgValidatorExit, MsgEventRecord, MsgTopupTx. Also adds the sidetxs VoteExtension for `decode ve`. Introduces internal/heimdall/proto/registry.go which exposes the set of known type URLs and a single Decode(typeURL, bytes) entry point so both the decode CLI and future broadcast flows can round-trip an Any.
Wraps each new proto Msg behind a wire-interface adapter exposed by internal/heimdall/tx/msgs.go so the shared tx builder can marshal them into the outer TxBody without per-module plumbing. Extends the L1-mirroring guard list to cover MsgEventRecord, matching the W4 clerk-record subcommand which mirrors a bridge event recorded on L1.
Drops 13 per-Msg subcommands into cmd/heimdall/tx/msgs/ so every W4 Msg type gains a first-class CLI: checkpoint (gated behind --i-am-a-validator), checkpoint-ack, checkpoint-noack, span-propose, span-backfill, span-vote-producers, span-set-downtime, topup, stake-join, stake-update, signer-update, stake-exit, and clerk-record. L1-mirroring Msg types reuse the force guard wired in the previous commit; checkpoint-ack additionally requires --l1-tx since the Heimdall-side ack is only meaningful when the L1 ack transaction hash is known. Shared flag helpers (parseHexBytes, requireNonEmptyString, lowerEthAddress) keep the per-command files small and consistent.
Adds cmd/heimdall/decode with four offline subcommands:
* decode tx - unmarshal a TxRaw, resolve each Any via the proto
registry, and print a human-readable or --json view
of body, auth_info, signatures, and the CometBFT
SHA-256 tx hash.
* decode msg - decode a single Any.value for a type URL; --list
prints every registered type URL for discovery.
* decode hash-tx - compute the CometBFT SHA-256 hash of a raw tx.
* decode ve - decode heimdallv2.sidetxs.VoteExtension bytes from
CometBFT logs (hex by default, base64 accepted).
All decoders accept hex (0x-prefixed or bare) and base64 (std/url,
padded or raw) uniformly. The umbrella is created fresh per Register
call so tests can build throwaway roots without piling duplicate
subcommands onto a package-level variable.
Adds round-trip tests for every new proto Msg, asserts that every type URL exposed by the per-Msg files appears in the registry, and exercises the full Decode() lookup path for one Msg per module. On the CLI side, covers subcommand registration, the L1-mirroring force guard, and the validator-only gate on checkpoint. Happy-path mktx assertions prove that span-propose and topup actually build a transaction when all required flags are supplied; negative tests confirm stake-join, topup, and checkpoint-ack refuse to build without --force / --l1-tx. decode_test.go round-trips a MsgWithdrawFeeTx through `decode msg`, a TxRaw containing it through `decode tx` (both human and --json), verifies the SHA-256 from `decode hash-tx` against a known digest, and round-trips a VoteExtension through `decode ve`.
Introduce render.EnableWatch / render.EnableWatchTree helpers that wrap a cobra command's RunE with a cancellable watch loop. Each umbrella's Register() invokes EnableWatchTree on its freshly built tree (or EnableWatch on individual leaves for tx/tx.go where publish/rpc must stay one-shot) so every read-only subcommand now accepts `--watch DURATION` without touching its RunE. The watch loop renders into a bytes.Buffer per tick and clears the screen with VT100 sequences when stdout is a TTY, so `polycli heimdall tx <hash> --watch 2s` and friends behave like `cast` / `watch -n`. Transient errors are printed to stderr and do not abort the loop.
Walk the heimdall subtree at init-time and wrap every RunE so that on failure the process exits with the cast-style code returned by client.ExitCode: 1 node error, 2 network error, 3 usage error, 4 signing error. Operators scripting against polycli can now distinguish the four failure classes instead of collapsing them onto cobra's single rc=1. Setting SilenceUsage + SilenceErrors on the subtree keeps cobra from printing the usage blob and a duplicate error line; the wrapper prints "Error: <msg>" itself before os.Exit so the familiar cast output survives.
…/wallet Move the duplicated BIP-39/BIP-32 derivation helpers (DeriveFromMnemonic, ParseDerivationPath, DefaultDerivationPath) and v3 keystore helpers (NewKeyStore, FindAccount, AddressFromKeystoreFile, DecryptKeystoreAccount, ResolveKeystoreDir) into a new internal/heimdall/wallet package shared by `polycli heimdall wallet` and `polycli heimdall tx/mktx/send/estimate`. ResolveKeystoreDir gains a createDefault bool so the wallet management surface keeps its "materialise ~/.polycli/keystores on first use" behaviour while the signing surface treats a missing default dir as a clear "account not found" error instead of silently creating empty dirs. cmd/heimdall/wallet keeps thin wrappers so the local package does not ripple through every call site; cmd/heimdall/tx/msgs/key.go now calls the shared package directly. The stale cmd/heimdall/wallet/ json.go helper is dropped.
Tighten Short strings that significantly exceeded the ~50 char help menu target so `polycli heimdall --help` columns stay readable on 80-wide terminals. No behavioural change; the L1-mirroring Short suffixes on mktx/send msg subcommands are kept verbatim because the marker is load-bearing for operators.
`make gen-doc` output after the watch-flag wiring, exit-code wrapping, and Short description trims. Picks up the new chainmanager/decode/estimate/mktx/send/ops/util/wallet subtrees and the --watch flag rows.
Adds docs/heimdall.md covering: - Quick-start invocations for the cast-familiar surface. - Umbrella command list with one-line intent per umbrella. - --watch DURATION, --curl, and exit-code tables. - Keystore directory precedence (flag > ETH_KEYSTORE > ~/.foundry/keystores > ~/.polycli/keystores), with a note on createDefault behaviour across wallet vs signing surfaces. - Verbatim L1-mirroring warning and the list of subcommands that carry it. The per-subcommand reference remains under doc/ (generated by `make gen-doc`); this file is the human-readable index.
|
| case float64: | ||
| // json.Unmarshal yields float64 for numbers; render as int | ||
| // when integral to match cast output style. | ||
| if vv == float64(int64(vv)) { |
| // json.Unmarshal yields float64 for numbers; render as int | ||
| // when integral to match cast output style. | ||
| if vv == float64(int64(vv)) { | ||
| return fmt.Sprintf("%d", int64(vv)) |
| // pure unsigned integer that does not also look like an address. | ||
| if n, err := strconv.ParseUint(identifier, 10, 32); err == nil { | ||
| list := ks.Accounts() | ||
| if int(n) >= len(list) { |
| Msg: fmt.Sprintf("keystore has %d accounts; index %d out of range", len(list), n), | ||
| } | ||
| } | ||
| return list[int(n)], nil |
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.




wip