Files

4.2 KiB

Context

See proposal.md for motivation. SolanaWalletImpl invokes the external jup CLI only when signing, while the Hub constructs and registers several wallet instances during passive component initialization. The constructor currently has no checked-exception contract, and the existing signing flow already validates the signer address returned after an actual transaction is signed.

Goals / Non-Goals

Goals:

  • Establish all locally knowable CLI and signer invariants when a wallet is constructed.
  • Preserve clear startup propagation without expanding the public wallet API.
  • Keep diagnostics useful while exposing no private key data.

Non-Goals:

  • Supporting multiple jup versions or a compatibility range.
  • Installing, updating, importing, selecting, or repairing jup keys.
  • Replacing the existing per-transaction signer-address check.
  • Adding automated tests or changing Detag configuration.

Decisions

Require an exact CLI version and fail construction on mismatch

The constructor runs jup --version and accepts only 0.10.1. Exact failure is chosen over a warning because the CLI arguments and JSON representation form an external integration contract that has only been verified for that version. Allowing construction after a mismatch would weaken the component-readiness guarantee that motivates the change.

A version constant remains next to the wallet implementation so a future CLI upgrade requires an intentional source change and review. A compatibility range was rejected because no evidence currently establishes compatibility with other versions.

Validate the key catalogue instead of signing a probe transaction

After the version check, construction runs jup -f json keys list. The JSON catalogue provides the signer name and public address needed to prove configuration without creating, signing, or submitting a transaction. A signing probe was rejected because it would require manufacturing transaction data and would couple startup to additional Solana semantics.

The catalogue is read as a JSON tree and only the name and address fields are inspected. This tolerates unrelated metadata added by jup while still rejecting a missing array, missing signer, or invalid address. Raw catalogue output is not copied into diagnostics so future CLI additions cannot accidentally disclose credential material.

Preserve constructor signatures with unchecked configuration failures

External process, decoding, version, key, and address failures are wrapped in descriptive IllegalStateExceptions. This preserves existing constructor and Hub method signatures while allowing the failure to propagate out of passive graph construction and prevent the Hub from announcing itself online.

Invalid direct constructor arguments retain argument/null exception categories. If process waiting is interrupted, the child process is terminated, the interrupted status is restored, and construction fails with the interruption retained as the cause.

Retain post-signing address verification

Construction-time validation proves the configured key catalogue at one point in time. The existing check of the signer address returned by every later signing response remains necessary defence in depth against configuration changes or unexpected CLI behavior after construction.

Risks / Trade-offs

  • [Each wallet construction starts two subprocesses] → Accept the small startup cost so every instance validates current external state independently.
  • [An otherwise compatible future jup release stops startup] → Make upgrades explicit by reviewing the CLI contract and updating the expected version constant.
  • [The key catalogue changes after construction] → Retain runtime signer-address validation for every signed transaction.
  • [A process produces more output than expected] → Keep preflight commands narrowly scoped to version and key metadata and fail on command or read errors.

Migration Plan

Before deployment, install jup version 0.10.1 and import every configured signer under its expected name and wallet address. Start Nenjim and allow constructor validation to gate the remaining startup sequence. If deployment must be rolled back, restore the previous application artifact; no persisted application data or public API migration is involved.