feat: ResolvedSigner — typed signer resolution with cached classification#31
Merged
0xLeo-sqds merged 3 commits intofeat/external-signaturesfrom Apr 15, 2026
Merged
Conversation
34bf580 to
fc1695d
Compare
…verify API Replace per-instruction verify_signer() calls and ClassifiedSigner with a single ResolvedSigner type that wraps AccountInfo + OnceCell<Pubkey>. All instruction handlers now use creator.verify() / signer.verify() which delegates to Consensus::verify_signer() and caches the canonical key for later use via resolved_key(). - ResolvedSigner: lazy key resolution with Anchor trait impls - Eliminated ClassifiedSigner enum, inlined verify logic into verify_signer - Updated all 16 instruction files to use ResolvedSigner::verify() API - Removed unused Consensus imports - Regenerated IDL and fixed buffer test expectations
fc1695d to
5472ba4
Compare
…nique discriminators Addresses three sync-path vulnerabilities: 1. remaining_accounts now included in signed hash (prevents account swap) 2. account_index now included in signed hash (prevents vault swap) 3. Split 'squads-sync' into 'sync_transaction_v2', 'sync_transaction_legacy', and 'sync_settings_tx_v2' (prevents cross-instruction replay)
7e341be to
2d7832d
Compare
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
What
New
ResolvedSignerAnchor account type that replaces rawAccountInfofor all signer/creator fields in async instructions. Provides type-safe signer classification and key resolution withOnceCellcaching.Why
Every V2 instruction that stores or emits a signer key had to manually call
resolve_canonical_key()— scattered across 16 instructions, each doing its own classification scan of the signers list. Session keys needed resolution to parent keys, external signers needed classification for crypto verification. The pattern was error-prone (/// CHECKboilerplate, forgotten resolution calls, double classification in validate + handler).How it works
ResolvedSignerwraps anAccountInfowith twoOnceCells:The
Accountstrait is implemented manually — no owner check, noAccountNotInitializedguard (external signers can have 0 lamports). Anchor's CPI/client module boilerplate lives ininstructions/mod.rsas directmoddeclarations (required for Anchor's derive macro to find them as siblings).verify_classified_signeris extracted fromverify_signeron the Consensus trait. It accepts a pre-classified&ClassifiedSignerand skips the signer list scan entirely — goes straight to crypto verification, nonce/counter updates, and permission checks.Changes
state/resolved_signer.rs— the type:OnceCell-backed resolve/classified/resolved_key, manual Anchor trait impls, Bumps typeinterface/consensus_trait.rs—ClassifiedSignergetsClone+resolved_key(),verify_classified_signerextracted,resolve_canonical_keyrenamed toresolve_signer_keyAccountInfo→ResolvedSigner,verify_signer→resolve+verify_classified_signer, handlerresolve_signer_key→resolved_key()resolve_canonical_key→resolve_signer_key)utils/context_validation.rs— variable renames (canonical_key→resolved_key)instructions/mod.rs— Anchor CPI/client boilerplate modulesWhat doesn't change
smart_account_create(creator: Signer, no consensus account)use_spending_limit(signer: Signer, not consensus-based)increment_account_indexV1 (signer: Signer, native only)transaction_buffer_closecreator staysAccountInfo(Anchor'sclose = creatorneeds it)ResolvedSigner(signers come fromremaining_accounts)ResolvedSignerconsumes 1 account from the slice, same asAccountInfoTest plan
anchor build -- --features=testingcompiles clean