Skip to content

feat(solana): add list_solana_validators ranking helper (#436) - #512

Merged
szhygulin merged 1 commit into
mainfrom
feat/list-solana-validators
Apr 28, 2026
Merged

feat(solana): add list_solana_validators ranking helper (#436)#512
szhygulin merged 1 commit into
mainfrom
feat/list-solana-validators

Conversation

@szhygulin

Copy link
Copy Markdown
Collaborator

Summary

Adds a read-only list_solana_validators tool — the Solana parallel to list_tron_witnesses — so agents can surface a ranked menu before calling prepare_native_stake_delegate instead of forcing the user to leave for stakewiz / validators.app and paste back a vote pubkey. Smoke-test script 040 was the trigger.

Closes #436.

What changes

  • New module src/modules/solana/validators.ts (~250 LoC + zod schema + types).
    • Wraps the stakewiz.com public feed (https://api.stakewiz.com/validators, no API key required).
    • Filters: commissionMaxPct, excludeDelinquent (default true), excludeSuperminority (default false), minActivatedStakeSol, mevEnabled.
    • Sort: score (default — wiz_score desc), apy, stake, commission.
    • Default limit 25, max 100.
  • Tool registration in src/index.ts next to prepare_native_stake_delegate. Cross-references the new tool from the delegate description ("To pick a validator, call list_solana_validators first").
  • Scope gating: src/config/scope.ts adds explicit name === "list_solana_validators" to the Solana family block; matching test/scope.test.ts row.
  • 14 new unit tests in test/list-solana-validators.test.ts covering filters, sorts, limit, fetch failure, and Inv Add Base network support (chainId 8453) #14 notes.

Why stakewiz, not validators.app

  • validators.app requires a per-user API token; stakewiz is open.
  • stakewiz exposes both total_apy (inflation + MEV) AND the composite wiz_score, covering all four sortBy modes directly.

Invariant #14 awareness

The vote pubkey is a "durable on-chain object selected from a multi-candidate set" — exactly the b040 attack class Inv #14 (#460) defends against. This tool is a HELPER, not a source-of-truth replacement. A compromised MCP could swap the list. Two concrete defenses are baked in:

  1. Per-validator stakewizUrl in every row — the user pastes it into a browser to re-verify activated stake / commission / delinquent status against an authority outside the MCP enumeration.
  2. notes[] array on every response surfaces verbatim Inv Add Base network support (chainId 8453) #14 instructions: re-verify on stakewiz.com / validators.app, then byte-equality-check the votePubkey in the prepare_native_stake_delegate response against the one confirmed in step 1.

The tool description in src/index.ts also references Invariant #14 explicitly so agents pass the gate through to the user.

Caching

CACHE_TTL.YIELD (600s / 10 min). Validator rankings don't change rapidly between epochs (~2 days each); 10-min staleness is acceptable for a "where should I delegate" comparison and amortizes the ~1.5MB feed payload.

Test plan

  • npm run build clean
  • npx tsc --noEmit clean
  • npx vitest run — all 2382 tests pass locally (14 new + 2368 prior)
  • CI green
  • Manual: list_solana_validators({}) returns top-25 by wiz_score
  • Manual: list_solana_validators({sortBy:"apy", filters:{mevEnabled:true, commissionMaxPct:5}, limit:10}) returns top-10 Jito-enabled, commission≤5% validators by APY
  • Manual: feed unreachable (e.g. block stakewiz.com via /etc/hosts) → empty validators[] + clear unreachable note

🤖 Generated with Claude Code

Adds a read-only `list_solana_validators` tool that wraps the
stakewiz.com public feed (no API key required) and returns a filtered
+ sorted list of Solana validators with the columns most relevant to
delegation:

  - composite quality (`wizScore`)
  - commission (`commissionPct`) + Jito-MEV commission (`mevCommissionBps`)
  - total APY estimate (inflation + MEV)
  - activated stake, delinquent flag, superminority penalty flag
  - skip rate, uptime, version, country
  - per-validator stakewiz.com profile URL for browser-side verification

Mirrors the role `list_tron_witnesses` plays for TRON SR voting.
Smoke-test script 040 was the trigger ("Delegate 100 SOL to a top
validator using native staking" — agent had no list_solana_validators
to call; correctly refused to pick from training-data memory).

## Why stakewiz over validators.app

  - validators.app needs a per-user API token; stakewiz is open.
  - stakewiz exposes both `total_apy` (inflation + MEV) AND the
    composite `wiz_score`, covering performance / stake / commission
    sortBy directly without a separate ranking pass.

## Filter / sort defaults

  - excludeDelinquent: true (delinquent validators don't earn rewards)
  - sortBy: "score" (wiz_score descending — best quality first)
  - limit: 25 (max 100)
  - excludeSuperminority: false (delegating away from superminority is a
    network-health choice, not a yield choice — surface, don't hide)

## Invariant #14 awareness

The validator vote pubkey is a "durable on-chain object selected from a
multi-candidate set" — exactly the b040 attack class Inv #14 (#460)
defends against. This tool is a HELPER, not a source-of-truth
replacement: a compromised MCP could swap the list. The response's
`notes[]` field surfaces verbatim instructions for the user:

  1. Re-verify the chosen validator on stakewiz.com or validators.app
     independently via browser (the per-row `stakewizUrl` is the
     direct deep-link).
  2. Byte-equality-check the `votePubkey` in the
     `prepare_native_stake_delegate` response against the one
     confirmed in step 1.

Tool description in src/index.ts also references Invariant #14
explicitly so agents pass the gate through to users.

Cache: 600s via `CACHE_TTL.YIELD` — stakewiz updates more frequently
than that for delinquency / skip rate, but for a "where should I
delegate" comparison even 10-min stale data is fine, and 1956
validators × ~70 fields ≈ 1.5MB per fetch warrants amortization.

Closes #436.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@szhygulin
szhygulin merged commit b15bb27 into main Apr 28, 2026
4 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 28, 2026
@szhygulin
szhygulin deleted the feat/list-solana-validators branch May 19, 2026 04:25
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add validator-ranking helper for prepare_native_stake_delegate

1 participant