feat(solana): add list_solana_validators ranking helper (#436) - #512
Merged
Conversation
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>
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Summary
Adds a read-only
list_solana_validatorstool — the Solana parallel tolist_tron_witnesses— so agents can surface a ranked menu before callingprepare_native_stake_delegateinstead 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
src/modules/solana/validators.ts(~250 LoC + zod schema + types).https://api.stakewiz.com/validators, no API key required).commissionMaxPct,excludeDelinquent(default true),excludeSuperminority(default false),minActivatedStakeSol,mevEnabled.score(default —wiz_scoredesc),apy,stake,commission.src/index.tsnext toprepare_native_stake_delegate. Cross-references the new tool from the delegate description ("To pick a validator, calllist_solana_validatorsfirst").src/config/scope.tsadds explicitname === "list_solana_validators"to the Solana family block; matchingtest/scope.test.tsrow.test/list-solana-validators.test.tscovering filters, sorts, limit, fetch failure, and Inv Add Base network support (chainId 8453) #14 notes.Why stakewiz, not validators.app
total_apy(inflation + MEV) AND the compositewiz_score, covering all foursortBymodes 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:
stakewizUrlin every row — the user pastes it into a browser to re-verify activated stake / commission / delinquent status against an authority outside the MCP enumeration.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 thevotePubkeyin theprepare_native_stake_delegateresponse against the one confirmed in step 1.The tool description in
src/index.tsalso 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 buildcleannpx tsc --noEmitcleannpx vitest run— all 2382 tests pass locally (14 new + 2368 prior)list_solana_validators({})returns top-25 by wiz_scorelist_solana_validators({sortBy:"apy", filters:{mevEnabled:true, commissionMaxPct:5}, limit:10})returns top-10 Jito-enabled, commission≤5% validators by APY🤖 Generated with Claude Code