Skip to content

fix(cli): refuse ambiguous EVM network selection (devnet manifest vs mainnet default)#158

Open
Nic-dorman wants to merge 9 commits into
mainfrom
fix/explicit-evm-network-selection
Open

fix(cli): refuse ambiguous EVM network selection (devnet manifest vs mainnet default)#158
Nic-dorman wants to merge 9 commits into
mainfrom
fix/explicit-evm-network-selection

Conversation

@Nic-dorman

@Nic-dorman Nic-dorman commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the silent-payment-failure trap around --evm-network and completes audit finding #5 (EVM resolution belongs in ant-core). Targets main, mechanically stacked on #157 — the GitHub diff currently includes #157's commits. Merge #157 first, then this branch will be rebased so its diff is the EVM-only delta. CI is green on the stacked branch.

The trap: --evm-network defaulted to arbitrum-one unconditionally, so --devnet-manifest with a custom EVM block but without --evm-network local silently paid against the hardcoded mainnet vault address on the manifest's chain. On Sepolia that address is an EOA: the tx "succeeds" as a no-op, gas is spent, the ANT allowance goes to a useless spender, and every subsequent chunk PUT fails median-payment verification — looking like a payment-protocol bug rather than a flag bug.

Changes:

  • String→EvmNetwork resolution (including manifest evm-block parsing for local) moves to ant_core::config::resolve_evm_network with typed errors (EvmNetworkAmbiguous, UnsupportedEvmNetwork, EvmManifestRequired, InvalidEvmManifest), so every frontend shares one implementation. (EvmNetwork and DevnetManifest are foreign re-exports, so the resolver is a free function in ant_core::config next to resolve_bootstrap_peers rather than an inherent method.)
  • No break for mainnet users: the default stays arbitrum-oneexcept when a devnet manifest carrying an evm block is loaded. That one combination (the only path where the trap fires) now errors and asks for an explicit choice: local to use the manifest's EVM config, or a preset to override it.
  • Selecting a preset while the manifest carries an EVM block prints a warning that the manifest's EVM config is ignored (the one remaining discard path, now loud).
  • ant-cli drops its direct reqwest dependency — the moved URL parse was the last use.

Testing

  • 7 unit tests on resolve_evm_network (mainnet default with no manifest / manifest-without-evm, ambiguous error when manifest has an evm block, preset mapping, local happy path with URL/address round-trip, missing manifest/evm block, unknown name, bad manifest values); full workspace suite passes; clippy/fmt clean.
  • CLI smoke: no flag + no manifest → mainnet address printed; no flag + manifest-with-evm → clear ambiguity error; preset + manifest-with-evm → warning on stderr, result on stdout; local + manifest → resolves; mainnet → unsupported error; local without manifest → manifest-required error.

🤖 Generated with Claude Code

Nic and others added 6 commits July 23, 2026 09:19
… (V2-744)

Port-range parsing ("12000" / "12000-12004") lived in ant-cli while the
PortRange type lives in ant-core, so every frontend had to reimplement
it. Parse via the standard FromStr trait next to the type instead; the
CLI now just calls .parse().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every frontend passing env vars to AddNodeOpts needs the same KEY=VALUE
parsing the CLI hand-rolled; expose it as AddNodeOpts::parse_env_vars.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…(V2-742)

The explicit-peers > devnet-manifest > bootstrap_peers.toml priority
logic (with manifest-peer socket-addr filtering) lived in ant-cli, but
it's business logic every frontend needs. Move it to
config::resolve_bootstrap_peers; the no-source case is now a typed
Error::NoBootstrapPeers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ant node add / ant node reset hand-rolled reqwest POSTs against the
daemon while every other endpoint goes through
ant_core::node::daemon::client. Add client::add_node and client::reset
and use them from the CLI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ant node start/stop --service-name read node_registry.json directly to
translate name -> ID even while the daemon (the registry's owner) is
running, so the daemon could mutate the registry between the CLI's read
and the API call. Add client::resolve_node_id_by_name, which resolves
through GET /nodes/status, and drop the CLI's direct registry read.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CliProgress (node add, unicode bar to stdout) and CliUpdateProgress
(self-update, plain percent to stderr) were near-identical impls of the
same trait. Keep one CliProgress in ant-cli/src/progress.rs, writing to
stderr like the rest of the progress UI.

Also fixes: ant node add --json no longer interleaves download-progress
output with the JSON result (NoopProgress in JSON mode, matching
ant update).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Nic-dorman
Nic-dorman changed the base branch from fix/cli-audit-thinning to main July 23, 2026 08:47
@Nic-dorman
Nic-dorman force-pushed the fix/explicit-evm-network-selection branch 2 times, most recently from e308d08 to 04cd79a Compare July 23, 2026 08:56

@dirvine dirvine left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head 4ba6f8d276ab7c8008708e9fe6cd21229a1deed2, including the one-commit EVM-selection delta separately from #157. The EVM resolver logic looks sound: mainnet remains the default without manifest EVM config, the ambiguous manifest case fails before payment, explicit presets override loudly, local validates manifest values, and read-only file/chunk operations do not resolve EVM. All 12 CI checks are green; focused EVM resolver tests and cargo check --all-targets also pass locally.

Hold this until #157 is corrected and merged/rebased. This PR currently targets main and carries all seven #157 commits, including the same unrelated vendor/**/.cache, lock and .orig artifacts and the empty-manifest resolve_bootstrap_peers -> Ok([]) contract issue described on #157. If #158 merged first, it would merge those issues too.

Please also update the PR body: it says this is stacked on closed #155 and that CI will run after retargeting, but the live PR targets main, is mechanically stacked on #157, and CI is already green. Once #157 lands with the two fixes, rebase/refresh #158 so its GitHub diff is the intended EVM-only delta.

No blocker was found in #158's own EVM-selection code.

Nic and others added 2 commits July 23, 2026 11:45
…tifacts

resolve_bootstrap_peers now returns NoBootstrapPeers when a selected
manifest is empty or every entry is filtered out, instead of Ok([]) —
a selected manifest never falls back to the public config. Also removes
accidentally committed vendor cache/.orig files and ignores them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t-core (V2-743, V2-471)

--evm-network defaulted to arbitrum-one unconditionally, so a user
passing --devnet-manifest with a custom EVM block (but not
--evm-network local) silently paid against the mainnet vault address on
the manifest's chain: the tx 'succeeds' as a no-op against an EOA, gas
is spent, ANT allowance goes to a useless spender, and every chunk PUT
then fails median-payment verification. The failure reads like a
payment-protocol bug, not a flag bug (V2-471).

- string->EvmNetwork resolution (incl. manifest evm-block parsing for
  'local') moves to ant_core::config::resolve_evm_network with typed
  errors, per the V2-189 audit (finding #5) — frontends share one
  implementation
- the default stays arbitrum-one EXCEPT when a devnet manifest carrying
  an evm block is loaded: that combination now errors
  (Error::EvmNetworkAmbiguous) and asks for an explicit choice, so the
  trap path fails loudly before any tokens move while plain mainnet
  usage is unchanged
- selecting a preset while the manifest carries an EVM block warns that
  the manifest's EVM config is ignored
- ant-cli drops its direct reqwest dependency (last use was the moved
  URL parse)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Nic-dorman
Nic-dorman force-pushed the fix/explicit-evm-network-selection branch from 4ba6f8d to 243a462 Compare July 23, 2026 10:47
@Nic-dorman

Copy link
Copy Markdown
Contributor Author

Rebased onto the corrected #157 head (ec6d5d5), so this branch now carries the vendor-artifact removal and the resolve_bootstrap_peers empty-manifest fix; the EVM commit is unchanged (now 243a462). PR body updated to reflect the real state: targets main, mechanically stacked on #157, CI green.

Holding this until #157 merges, then I'll rebase onto main so the GitHub diff collapses to the EVM-only delta.

@dirvine dirvine left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed current head 243a462fb625c28a69756984c1e0f13d891ed886. The branch now has corrected #157 head ec6d5d5d7992cd1a1f2296dec26568137b3d1076 as its exact parent, and the sole EVM-selection delta is semantically unchanged from the previously reviewed commit. The inherited artifact/bootstrap findings are resolved, and no blocker was found in the EVM logic.

Verified locally on this exact head: cargo fmt --all -- --check, four bootstrap resolver tests, six EVM resolver tests, and cargo check --all-targets all pass. The EVM behavior remains correct for default mainnet, ambiguous manifest config, explicit presets, local, malformed manifest values, and read-only operations.

Current CI is 10/12 green with no failures; macOS and Ubuntu E2E remain in progress. Merge #157 first, then rebase/refresh this branch onto main so the final diff is EVM-only. Subject to that ordering and the remaining E2E jobs finishing green, code review is clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants