1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Pure-Rust [Wallet Standard](https://github.com/wallet-standard/wallet-standard)
//! bindings for [Leptos](https://leptos.dev). 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.
//!
//! # Quick start
//!
//! Add the crate alongside Leptos:
//!
//! ```toml
//! [dependencies]
//! leptos-solana = "0.1"
//! leptos = { version = "0.8", features = ["csr"] }
//! ```
//!
//! Install the context once at the app root, then call [`use_wallet`](prelude::use_wallet)
//! from any component:
//!
//! ```ignore
//! use leptos::prelude::*;
//! use leptos_solana::prelude::*;
//! use leptos_solana::wallet::CHAIN_MAINNET;
//!
//! #[component]
//! fn App() -> impl IntoView {
//! provide_wallet_context(CHAIN_MAINNET);
//! let wallet = use_wallet();
//!
//! view! {
//! <ul>
//! {move || wallet.wallets.get().0.into_iter().map(|w| {
//! let name = w.name();
//! let ctx = wallet.clone();
//! view! {
//! <li><button on:click=move |_| ctx.select(w.clone())>{name}</button></li>
//! }
//! }).collect_view()}
//! </ul>
//! }
//! }
//! ```
//!
//! Signing and submitting a transaction:
//!
//! ```ignore
//! use leptos_solana::prelude::*;
//!
//! let ix = Instruction {
//! program_id,
//! accounts: vec![
//! AccountMeta::new(from, true),
//! AccountMeta::new(to, false),
//! ],
//! data,
//! };
//!
//! let rpc = RpcClient::devnet();
//! let blockhash = rpc.get_latest_blockhash(CommitmentConfig::confirmed()).await?;
//!
//! let msg = Message::new_with_blockhash(&[ix], Some(&from), &blockhash);
//! let tx: VersionedTransaction = Transaction::new_unsigned(msg).into();
//!
//! let sig: Vec<u8> = wallet.sign_and_send(&tx).await?;
//! ```
//!
//! # Design notes
//!
//! - **Wallet Standard is a JS spec.** Wallets register themselves via
//! `CustomEvent`s on `window`. The crate reaches those objects with
//! `wasm_bindgen`/`js_sys` — no `.js` shim is written by hand and no
//! `npm`/`esbuild` is needed. [`discovery::start`] runs the spec-compliant
//! `app-ready` + `register-wallet` handshake.
//!
//! - **VersionedTransaction only.** The wallet-signing API is
//! [`VersionedTransaction`](solana_transaction::versioned::VersionedTransaction)-only.
//! Legacy `Transaction` values can still be constructed and converted via
//! `Into` — the Legacy variant of `VersionedMessage` serializes to the
//! exact same wire bytes, so there is no behavior change for programs
//! that do not need address lookup tables.
//!
//! - **Tiny dep closure.** No `solana-sdk`, no `solana-client`, no `tokio`.
//! Pure Rust transaction construction via Anza's split crates
//! (`solana-pubkey`, `solana-message`, `solana-transaction`, `solana-instruction`),
//! bincode v1 for wire format, `gloo-net` for JSON-RPC.
//!
//! - **Reactive state.** [`WalletContext`](context::WalletContext) exposes
//! `wallets`/`selected`/`account`/`chain` as Leptos signals. The context's
//! `connect`/`disconnect`/`sign_*` methods are `async` and can be called
//! from `spawn_local`.
//!
//! - **Auto-reconnect.** On successful `connect`, the wallet name is
//! persisted to `localStorage`; on [`provide_wallet_context`](context::provide_wallet_context),
//! if that wallet registers during discovery it is silently reconnected
//! without prompting.
//!
//! - **Clean teardown.** [`discovery::start`] returns a [`DiscoveryHandle`](discovery::DiscoveryHandle)
//! that removes the event listener in `Drop`. [`provide_wallet_context`](context::provide_wallet_context)
//! ties the handle's lifetime to the Leptos owner.
//!
//! # Comparison with the JS stack
//!
//! The JS wallet ecosystem is layered:
//! `@wallet-standard/app` → `@solana/wallet-adapter-base` → `@solana/wallet-adapter-react`
//! → `@solana/wallet-adapter-react-ui`. This crate provides the first three
//! layers for Leptos (discovery, signer primitives, and a reactive context).
//! No UI components ship with the crate.
//!
//! # Modules
//!
//! - [`context`] Leptos `WalletContext`, signals, `connect`/`sign_*` methods.
//! - [`discovery`] Wallet Standard event-based discovery.
//! - [`features`] Typed wrappers over Solana feature methods.
//! - [`rpc`] Minimal JSON-RPC client (`gloo-net`).
//! - [`storage`] `localStorage` persistence for last-connected wallet.
//! - [`tx`] `VersionedTransaction` bincode serialize/deserialize.
//! - [`wallet`] `wasm_bindgen` extern types matching the Wallet Standard spec.
//! - [`error`] Crate-wide error type.
//! - [`prelude`] `use leptos_solana::prelude::*;` brings in everything callers need.
pub use ;
/// One-stop import for common callers: `use leptos_solana::prelude::*;`.
///
/// Brings in the Leptos context functions, the wallet types, the RPC client,
/// the tx serde helpers, and every Anza `solana-*` type you'd normally
/// `use` by hand.