leptos-solana
Pure-Rust Wallet Standard
bindings for Leptos. Discover, connect to, and sign with
Phantom, Backpack, Solflare, Glow, Ledger Live, and any other Wallet
Standard-compliant Solana wallet — no hand-written JavaScript shipped with the
crate, no npm, no wallet-adapter wrappers.
[]
= "0.1"
= { = "0.8", = ["csr"] }
Status
Early. Works for mainstream single-signer flows: connect, sign message,
sign + send (legacy or versioned) transactions. API may still change
between 0.1.x releases. See Roadmap for what is deliberately
missing.
Why
The JS Solana wallet stack is layered:
@wallet-standard/app → @solana/wallet-adapter-base → @solana/wallet-adapter-react
→ @solana/wallet-adapter-react-ui. Using any of it from a Leptos (or
generally pure-Rust) app means shipping privy.js / wallet-adapter.js
bundles, running esbuild as a pre-build step, and bridging every call back
into Rust via wasm-bindgen extern blocks.
leptos-solana replaces the first three layers with a Rust library. Wallets
are still JavaScript objects living in the browser — that's how they're
delivered — but the crate reaches them with js-sys/web-sys the same way
wasm-bindgen reaches fetch or localStorage. No .js shim is written by
hand, no package.json required. UI is not provided; build it yourself with
Leptos components (see demo/).
Features
- Spec-compliant discovery. Runs the Wallet Standard event handshake
(
wallet-standard:app-ready+wallet-standard:register-wallet). Every wallet that registers shows up in a reactiveWalletListsignal. - Typed Solana feature wrappers.
standard:connect,standard:disconnect,solana:signMessage,solana:signTransaction,solana:signAndSendTransaction. - VersionedTransaction-first. The wallet-signing API is versioned-only;
Address Lookup Tables work. Legacy
Transactionvalues convert viaIntowith identical wire format. - Reactive Leptos context. Signals for
wallets/selected/account/chain; async methods forconnect/sign_*/disconnect. - Auto-reconnect. Remembers the last wallet via
localStorageand silent-connects on page load. - Minimal JSON-RPC.
getLatestBlockhash,getBalance,sendTransactionovergloo-net. Nosolana-client, notokio. - Clean teardown.
discovery::startreturns a handle that removes the event listener onDrop; the context ties its lifetime to the Leptos owner. - Tiny dep closure. Built on Anza's split Solana crates
(
solana-pubkey,solana-hash,solana-instruction,solana-message,solana-transaction,solana-signature,solana-commitment-config). Nosolana-sdkumbrella.
Quick start
use *;
use *;
use CHAIN_MAINNET;
Signing and submitting a transaction
use *;
// Build any instruction — here, SystemProgram::transfer by hand (disc 2, u64 LE).
let mut data = Vecwith_capacity;
data.extend_from_slice;
data.extend_from_slice;
let ix = Instruction ;
let rpc = devnet;
let blockhash = rpc.get_latest_blockhash.await?;
let msg = new_with_blockhash;
let tx: VersionedTransaction = new_unsigned.into;
let sig: = wallet.sign_and_send.await?;
Just signing (no submit)
let signed: VersionedTransaction = wallet.sign_transaction.await?;
Raw bytes escape hatch
If you already have pre-serialized transaction bytes (e.g. from a backend):
let signed_bytes: = wallet.sign_transaction_raw.await?;
let submit_sig: = wallet.sign_and_send_raw.await?;
Sign-in message
let sig: = wallet.sign_message.await?;
Demo
The repo includes a runnable demo in demo/ — wallet picker,
message signing, and a 0.0001 SOL self-transfer on devnet.
&&
# then open http://127.0.0.1:3001
Roadmap
Not yet implemented; contributions welcome:
signAllTransactions(bulk sign)confirmTransaction/ signature status pollingsimulateTransaction(preflight)- Sign-In with Solana (
solana:signIn) - Richer RPC surface (
getAccountInfo,getTokenAccountsByOwner,requestAirdrop, …) - Error code taxonomy beyond
UserRejected(wallet locked, wrong chain, insufficient funds, …) - Optional feature-gated Anchor discriminator helpers
License
Dual-licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions.