Skip to content

feat(cli): offline signing, integrity guard, durable nonces, scan-all claims & JSON manifest - #5

Open
exp0nge wants to merge 3 commits into
jito-foundation:masterfrom
exp0nge:master
Open

feat(cli): offline signing, integrity guard, durable nonces, scan-all claims & JSON manifest#5
exp0nge wants to merge 3 commits into
jito-foundation:masterfrom
exp0nge:master

Conversation

@exp0nge

@exp0nge exp0nge commented Jun 17, 2026

Copy link
Copy Markdown

Adds safe, automatable BAM Boost claiming on top of the base CLI:

  • Offline / unsigned signing (--address): build an unsigned transaction with no keypair on the machine; sign and submit it elsewhere. Signed mode (--signer: build + sign + submit) remains the default.
  • Program-integrity guard (--assert-deploy-slot), on by default as "auto": resolves the BAM Boost ProgramData deploy slot from RPC and prepends a Lighthouse assertion so the claim rolls back atomically if the program is upgraded. Accepts an explicit slot to pin, or "off".
  • Durable nonces (--nonce / --nonce-authority): comma-separated lists. Nonces are single-use, so scan-all assigns one per eligible epoch and fails closed (before building) if too few are provided.
  • Scan-all claims: omit --epoch to claim every eligible epoch through the current epoch; omit --first-epoch too and the CLI walks back to the earliest published merkle tree (no hardcoded launch epoch). Idempotent: already-claimed / no-tree / no-allocation epochs are skipped.
  • JSON manifest (--output json): emits a single array on stdout carrying only the serialized transaction (unsigned_tx_base58/base64) — no sidecar metadata; signers verify by decoding the bytes. Logs go to stderr so stdout stays clean for automation (e.g. Ansible).
  • Keep stdout clean: merkle-tree diagnostics moved to stderr.

… claims & JSON manifest

Adds safe, automatable BAM Boost claiming on top of the base CLI:

- Offline / unsigned signing (--address): build an unsigned transaction
  with no keypair on the machine; sign and submit it elsewhere. Signed
  mode (--signer: build + sign + submit) remains the default.
- Program-integrity guard (--assert-deploy-slot), on by default as
  "auto": resolves the BAM Boost ProgramData deploy slot from RPC and
  prepends a Lighthouse assertion so the claim rolls back atomically if
  the program is upgraded. Accepts an explicit slot to pin, or "off".
- Durable nonces (--nonce / --nonce-authority): comma-separated lists.
  Nonces are single-use, so scan-all assigns one per eligible epoch and
  fails closed (before building) if too few are provided.
- Scan-all claims: omit --epoch to claim every eligible epoch through the
  current epoch; omit --first-epoch too and the CLI walks back to the
  earliest published merkle tree (no hardcoded launch epoch). Idempotent:
  already-claimed / no-tree / no-allocation epochs are skipped.
- JSON manifest (--output json): emits a single array on stdout carrying
  only the serialized transaction (unsigned_tx_base58/base64) — no
  sidecar metadata; signers verify by decoding the bytes. Logs go to
  stderr so stdout stays clean for automation (e.g. Ansible).
- Keep stdout clean: merkle-tree diagnostics moved to stderr.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the BAM Boost CLI to support safer/automatable claiming workflows: offline unsigned transaction construction, optional program-integrity assertions via Lighthouse, durable nonce support, scan-all epoch claiming, and clean stdout/JSON manifest output for automation.

Changes:

  • Add offline mode (--address) plus --output text|json to emit unsigned transaction encodings cleanly on stdout (logs/diagnostics to stderr).
  • Add Lighthouse-based deploy-slot integrity guard (--assert-deploy-slot auto|<slot>|off) and support durable nonces (--nonce, --nonce-authority) including scan-all nonce assignment.
  • Implement scan-all claiming (omit --epoch) with auto-discovery of earliest published merkle tree epoch; move merkle-tree diagnostics to stderr.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
README.md New security model + detailed usage docs for offline signing, integrity guard, durable nonces, scan-all, and JSON manifest output.
merkle-tree/src/bam_boost_merkle_tree.rs Route merkle-tree diagnostic prints to stderr to keep stdout clean.
cli/src/lighthouse.rs Introduce Lighthouse instruction builder + ProgramData deploy-slot parsing with unit tests.
cli/src/lib.rs Export the new lighthouse module.
cli/src/cli_config.rs Add address: Option<Pubkey> to support offline mode.
cli/src/cli_args.rs Add new flags/types: --address, --output, --assert-deploy-slot, --nonce, --nonce-authority + parsing tests.
cli/src/bin/main.rs Wire new args into handler; parse/resolve comma-separated nonce specs.
cli/src/bam_boost.rs Make --epoch optional and add --first-epoch for scan-all.
cli/src/bam_boost_handler.rs Core logic: eligibility checks, scan-all flow, unsigned tx building/encoding, integrity guard resolution, durable nonce support.
cli/Cargo.toml Add deps needed for new functionality (e.g., bs58, solana-system-interface, solana-hash).
Cargo.toml Add workspace deps for bs58/bincode and solana-system-interface feature usage.
Cargo.lock Lockfile updates for added dependencies.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cli/src/cli_args.rs Outdated
Comment on lines +13 to +14
/// A JSON array pairing each epoch with its unsigned transaction and metadata.
Json,
Comment thread cli/src/cli_args.rs Outdated
global = true,
value_enum,
default_value_t = OutputFormat::Text,
help = "Output format for built unsigned transactions: 'text' (base58 lines) or 'json' (manifest of epoch + unsigned tx + metadata, for automation)"
Comment thread cli/src/bam_boost_handler.rs Outdated
Comment on lines +665 to +669
if let Some((nonce_account, authority)) = nonce {
ixs.push(
solana_system_interface::instruction::advance_nonce_account(
&nonce_account,
&authority,
Comment thread README.md Outdated
Comment on lines +107 to +109
**Step 2** — Sign the transaction on the box that holds the identity keypair.

The signature is an ed25519 signature over the transaction message bytes, spliced into the wire format the CLI emits (`[numSignatures][64-byte sigs...][message]`). Note that the stock `solana` CLI **cannot** sign an externally-built transaction like this (`sign-offchain-message` signs off-chain messages only, in a different domain), so use a hardware wallet, HSM, or a minimal ed25519 signer on that box. Pair with `--nonce` (below) so the unsigned transaction doesn't expire before it's signed.
exp0nge and others added 2 commits June 24, 2026 12:30
…ch output

Removes durable nonce support entirely (--nonce / --nonce-authority, the
advance-nonce instruction, nonce-hash parsing, comma-separated list
handling, and the scan-all per-epoch nonce assignment / fail-closed
logic). Transactions now always use a recent blockhash.

Also addresses the PR jito-foundation#5 review:
- Drop the now-orphaned solana-system-interface dependency (it was only
  used to build advance_nonce_account).
- Fix the OutputFormat::Json docstring and the --output help text, which
  still claimed JSON contained "epoch + metadata"; JSON emits only
  {unsigned_tx_base58, unsigned_tx_base64}.
- The review's nonce-authority signing concerns are moot now that durable
  nonce support is gone.
- README: remove the durable-nonce feature row, usage sections, flag
  reference rows, and instruction-order entry; note that unsigned
  transactions use a recent blockhash (~60-90s) and should be signed and
  submitted promptly.

Collapses the two-pass scan (which existed to pre-assign nonces) into a
single eligibility-then-build pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Route every RPC call through a single `with_rpc` helper that tries the
primary `--rpc-url` first and, on error/timeout, falls back to the public
keyless endpoint `solana-rpc.publicnode.com`. This keeps a run from
aborting when the (often rate-limited) public mainnet endpoint fails to
fetch the ProgramData deploy slot for the integrity guard.

- Add an ordered `rpc_urls` list (primary + fallback, deduped) and the
  `with_rpc` wrapper; apply it to account reads, epoch info, blockhash
  fetches, and transaction submission. Resending a signed tx to a second
  endpoint is safe (signature dedup + claim-status guard).
- Use get_account_with_commitment for the claim-status existence check so
  a transport error is no longer silently treated as "not claimed"
  (value == None means eligible; Err fails over instead).
- README: document the fallback (feature row + --rpc-url note).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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