-
-
Notifications
You must be signed in to change notification settings - Fork 257
feat: add Solana signer abstraction layer #579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
fengtality
wants to merge
7
commits into
development
Choose a base branch
from
feat/solana-keychain-signers
base: development
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Conversation
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
Introduces a pluggable signer architecture for Solana transactions: - SolanaSigner interface modeled after @solana/keychain-core - KeypairSigner for existing encrypted file-based wallets - LedgerSigner wrapping existing hardware wallet support - SignerFactory for auto-detecting wallet type and creating signers - Typed errors with SignerErrorCode for better error handling This lays the groundwork for: - Unified signing across all connectors - Future support for AWS KMS, Fireblocks, and other custody solutions - Cleaner connector code without duplicated signing logic 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- getSigner(address) returns abstract SolanaSigner for any wallet type - signAndSend(tx, signer) provides unified sign + simulate + send flow - Connectors can now use these methods instead of handling signing themselves Usage: const signer = await solana.getSigner(walletAddress); const result = await solana.signAndSend(transaction, signer); 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add buildUnsignedSwapTransaction method for unified signing pattern - Deprecate buildSwapTransactionForHardwareWallet in favor of new method - Simplify executeQuote route using getSigner and signAndSend - Remove direct hardware wallet detection logic from connector 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Test SignerError with error codes and cause - Test KeypairSigner creation, signing transactions, and signing messages - Test LedgerSigner creation and hardware wallet integration - Test SignerFactory for automatic wallet type detection - Mock fs-extra and wallet utils for isolated testing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update all Meteora CLMM routes to use getSigner and signAndSend - Add hardware wallet support to addLiquidity, removeLiquidity, openPosition, closePosition, collectFees, and executeSwap - Update signAndSend to accept additionalKeypairs for multi-signer txs - Update getBalance to accept PublicKey in addition to Keypair - Update execute-swap tests to mock new signer pattern 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update SignerErrorCode values to use SIGNER_ prefix for keychain-core compatibility - Add new error codes: PARSING_ERROR, HTTP_ERROR, REMOTE_API_ERROR, IO_ERROR, EXPECTED_SOLANA_SIGNER - Add SignerErrorContext interface for structured error context - Update SignerError to accept either string message or context object - Add utility functions matching keychain-core patterns: - createSignerError() - create error without throwing - throwSignerError() - create and throw immediately - isSolanaSigner() - type guard for SolanaSigner interface - assertIsSolanaSigner() - type assertion function - Export new types and utilities from signers/index.ts These changes prepare for future migration to @solana/keychain when it's published to npm, while maintaining full backward compatibility. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.
Summary
This PR introduces a pluggable signer abstraction layer for Solana, modeled after the
@solana/keychainlibrary patterns. The abstraction provides a unified interface for signing transactions regardless of wallet type (hot wallet, hardware wallet, or future integrations like AWS KMS).Relationship to @solana/keychain
The
@solana/keychainlibrary from the Solana Foundation provides a standardized signer abstraction for the Solana ecosystem. However, it is not yet published to npm and uses the new@solana/kit(v2) SDK which would require a significant migration from our current@solana/web3.js(v1) implementation.This PR implements the same patterns and interfaces from
@solana/keychain-coreadapted for@solana/web3.jsv1:SolanaSignerinterface - Matches keychain-core's unified signer interface withsignTransactions(),signMessages(),isAvailable(), andaddresspropertiesSignerErrorCodeenum - UsesSIGNER_prefixed codes matching keychain-core (e.g.,SIGNER_SIGNING_FAILED,SIGNER_NOT_AVAILABLE)createSignerError()/throwSignerError()- Error creation helpersisSolanaSigner()/assertIsSolanaSigner()- Type guardsWhen
@solana/keychainis published to npm, we can migrate to use it directly with minimal changes.Key Changes
New signer interface and implementations (
src/chains/solana/signers/)SolanaSignerinterface with standardized methods for signingKeypairSignerfor hot wallets (encrypted keypair files)LedgerSignerfor hardware wallets (wraps existing HardwareWalletService)SignerFactoryfor automatic wallet type detectionSolana chain enhancements (
src/chains/solana/solana.ts)getSigner(address)method to get appropriate signer for any walletsignAndSend(transaction, signer, options)for unified transaction signing and submissionadditionalKeypairsoption for multi-signer transactions (e.g., new position accounts)getBalanceto acceptPublicKeyin addition toKeypairJupiter connector update (
src/connectors/jupiter/)buildUnsignedSwapTransaction()methodexecuteQuoteroute using new signer patternMeteora connector update (
src/connectors/meteora/clmm-routes/)addLiquidity- now supports hardware walletsremoveLiquidity- now supports hardware walletsopenPosition- now supports hardware wallets (with additionalKeypairs for position account)closePosition- now supports hardware walletscollectFees- now supports hardware walletsexecuteSwap- now supports hardware walletsBenefits
SignerErrorwith error codes across all implementations@solana/keychainfor easy migration when availableUsage Example
Test plan
GATEWAY_TEST_MODE=dev npx jest test/chains/solana/signers/(32 passed)GATEWAY_TEST_MODE=dev npx jest test/connectors/jupiter/(25 passed)GATEWAY_TEST_MODE=dev npx jest test/chains/solana/(102 passed)GATEWAY_TEST_MODE=dev npx jest test/connectors/meteora/(44 passed)🤖 Generated with Claude Code