Conversation
Integrate @solana/keychain-* packages so users can sign with AWS KMS, GCP KMS, Fireblocks, Turnkey, Vault, Crossmint, Para, and Privy backends via `keys add --backend <type> --param k=v`. - New KeychainConfig module with backend registry and dynamic imports - Signer widened from KeyPairSigner to TransactionPartialSigner - Uses partiallySignTransactionWithSigners for signer abstraction - keys list/add/delete/edit/use all handle keychain keys - Fix name collision check between keypair and keychain keys Refs: TOO-238
Switch from individual @solana/keychain-* packages to the umbrella @solana/keychain@0.6.1. Peer deps fix (TOO-239) means @solana/signers resolves to 6.5.0 without overrides.
- Unified key namespace: all mutations check both .json and .keychain.json; --overwrite cleans up stale counterpart - Add Signer.loadAddress() for cheap address resolution from cached keychain config; update 7 read-only call sites - Validate --param keys against backend registry, reject unknowns
AaronCQL
left a comment
There was a problem hiding this comment.
Thanks @amilz for the PR - didn't know the solana-keychain pkg exists.
Left a few comments here, but happy to make the adjustments myself if you prefer.
Also, just a side note: bundling all backend SDKs from solana-keychain increases the built JS bundle of this CLI from 532KB to 5.8MB (11x) and startup time from ~50ms to ~100ms (2x). Both are acceptable for now, but worth noting since 100% of users pay this cost while most may barely use a single backend.
- Convert KeychainConfig to static class (codebase convention) - Move helpers into KeysCommand as private static methods - Rename removeStaleCounterpart → removeKey - Simplify delete() to use removeKey directly - Document keychain edit limitation in docs
I pushed the changes in d342ae7 -- but feel free to modify additionally if you'd like.
Ya I don't love that. Each package is importable separately (e.g. @solana/keychain-privy). Looks like AWS and GCP deps are pretty heavy. A couple of ideas:
I'll also see what I can do to cut down on the umbrella bundle size on our side. |
This CLI ships as a pre-built binary (either via npm or a standalone bun binary), so installing pkgs on-demand is impossible for this flow.
Yea, if AWS and GCP are the largest client libs, we could trim it off if there's low usage. But we can leave this for later. For now, the increase in binary and startup time seems to be reasonable. Will release this and test it out first! |
Thanks for OS this repo! @AaronCQL I know this isn't a small change, so happy to hop in a TG chat or something if helpful.
--
Adds support for solana-keychain signers ‚ a unified signing interface that extends
@solana/signerswith 10 remote/managed key backends: AWS KMS, CDP, Crossmint, Dfns, Fireblocks, GCP KMS, Para, Privy, Turnkey, and Vault.Since both
KeyPairSignerandSolanaSignerimplementTransactionPartialSigner, we use kit 6.5'spartiallySignTransactionWithSigners()for a single signing path. Existing keypair behavior is unchanged.Usage:
Changes
package.json‚ Add@solana/keychain@^0.6.1, bump@solana/kitto^6.5.0src/lib/KeychainConfig.ts(new) ‚ Backend registry with per-backend env var mapping, config I/O, factory dispatch (after doing this, I may actually upstream some of this into@solana/keychain)src/lib/Signer.ts‚ Widen fromKeyPairSignertoTransactionPartialSigner; addloadAddress()for cheap read-only resolution from cached keychain configsrc/commands/KeysCommand.ts‚ Extendkeys addwith--backend+--param; unified namespace checks across.json/.keychain.json; unknown param validationsrc/commands/{Spot,Perps,Lend,Predictions}Command.ts‚ UseSigner.loadAddress()for read-only flows (no env vars or signer init needed)docs/keys.md‚ Document all 10 backends with examplesExample
Test plan
bun run cipasses (lint, typecheck, 66 tests)Requires signer keys:
keys addwith--backendcreates.keychain.json, verifies backend availability, caches addresskeys listshows both keypair and keychain keys with type columnkeys add --overwriteacross types cleans up stale counterpart--paramwith unknown keys is rejectedportfolio,positions) work with keychain keys without backend env vars set**