| Crates.io | wallet_standard |
| lib.rs | wallet_standard |
| version | 0.5.1 |
| created_at | 2024-09-12 14:54:26.315271+00 |
| updated_at | 2025-11-07 11:17:22.59571+00 |
| description | An implementation of the solana wallet standard in rust |
| homepage | https://github.com/ifiokjr/wallet_standard |
| repository | https://github.com/ifiokjr/wallet_standard |
| max_upload_size | |
| id | 1372844 |
| size | 104,877 |
wallet_standardAn implementation of the Solana wallet standard in Rust.
The wallet_standard crate provides a Rust implementation of the Wallet Standard for Solana. It defines a set of traits and types that create a consistent interface for wallets and dApps to interact with the Solana blockchain.
To install you can use the following command:
cargo add wallet_standard
Or directly add the following to your Cargo.toml:
[dependencies]
wallet_standard = "0.5.1"
| Feature | Description |
|---|---|
browser |
Enables browser-specific functionality with wasm-bindgen support |
solana |
Enables Solana-specific functionality |
The Wallet Standard defines several key concepts:
Wallet: The base trait for all wallet implementationsWalletInfo: Provides information about the wallet (name, icon, supported chains)WalletAccountInfo: Provides information about wallet accountsWalletStandard: Combines the core wallet functionalityWalletStandardConnect: For connecting to a wallet and authorizing accountsWalletStandardDisconnect: For disconnecting from a walletConnectedWalletStandardEvents: For listening to wallet eventsWalletSolanaSignMessage: For signing arbitrary messagesWalletSolanaSignTransaction: For signing transactionsWalletSolanaSignAndSendTransaction: For signing and sending transactionsWalletSolanaSignIn: For implementing Sign-In With Solana (SIWS)WalletExperimentalEncrypt: For encrypting dataWalletExperimentalDecrypt: For decrypting datause async_trait::async_trait;
use wallet_standard::prelude::*;
// Define your wallet structure
struct MyWallet {
name: String,
icon: String,
accounts: Vec<MyAccount>,
current_account: Option<MyAccount>,
}
// Define your account structure
#[derive(Clone)]
struct MyAccount {
address: String,
public_key: Vec<u8>,
}
// Implement WalletAccountInfo for your account
impl WalletAccountInfo for MyAccount {
fn address(&self) -> String {
self.address.clone()
}
fn public_key(&self) -> Vec<u8> {
self.public_key.clone()
}
fn chains(&self) -> Vec<String> {
vec!["solana:mainnet".to_string()]
}
fn features(&self) -> Vec<String> {
vec![
STANDARD_CONNECT.to_string(),
STANDARD_DISCONNECT.to_string(),
SOLANA_SIGN_MESSAGE.to_string(),
]
}
fn label(&self) -> Option<String> {
Some("My Account".to_string())
}
fn icon(&self) -> Option<String> {
None
}
}
// Implement WalletInfo for your wallet
impl WalletInfo for MyWallet {
type Account = MyAccount;
fn version(&self) -> String {
"1.0.0".to_string()
}
fn name(&self) -> String {
self.name.clone()
}
fn icon(&self) -> String {
self.icon.clone()
}
fn chains(&self) -> Vec<String> {
vec!["solana:mainnet".to_string()]
}
fn features(&self) -> Vec<String> {
vec![
STANDARD_CONNECT.to_string(),
STANDARD_DISCONNECT.to_string(),
SOLANA_SIGN_MESSAGE.to_string(),
]
}
fn accounts(&self) -> Vec<Self::Account> {
self.accounts.clone()
}
}
// Implement Wallet for your wallet
impl Wallet for MyWallet {
type Account = MyAccount;
type Wallet = Self;
fn wallet(&self) -> Self::Wallet {
self.clone()
}
fn wallet_account(&self) -> Option<Self::Account> {
self.current_account.clone()
}
}
// Implement WalletStandardConnect
#[async_trait(?Send)]
impl WalletStandardConnect for MyWallet {
async fn connect(&mut self) -> WalletResult<Vec<Self::Account>> {
// Implement connection logic
// For example, prompt the user to select an account
if let Some(account) = self.accounts.first().cloned() {
self.current_account = Some(account.clone());
Ok(vec![account])
} else {
Err(WalletError::WalletConnection)
}
}
async fn connect_with_options(
&mut self,
_options: StandardConnectInput,
) -> WalletResult<Vec<Self::Account>> {
self.connect().await
}
}
// Implement WalletStandardDisconnect
#[async_trait(?Send)]
impl WalletStandardDisconnect for MyWallet {
async fn disconnect(&mut self) -> WalletResult<()> {
self.current_account = None;
Ok(())
}
}
use solana_signature::Keypair;
use solana_signature::Signature;
use solana_signer::Signer;
use wallet_standard::prelude::*;
// Assuming MyWallet is defined as above
// Define a custom output type for sign message
struct MySignMessageOutput {
signature: Signature,
signed_message: Vec<u8>,
}
impl SolanaSignatureOutput for MySignMessageOutput {
fn try_signature(&self) -> WalletResult<Signature> {
Ok(self.signature)
}
fn signature(&self) -> Signature {
self.signature
}
}
impl SolanaSignMessageOutput for MySignMessageOutput {
fn signed_message(&self) -> Vec<u8> {
self.signed_message.clone()
}
fn signature_type(&self) -> Option<String> {
None
}
}
// Implement WalletSolanaSignMessage
#[async_trait(?Send)]
impl WalletSolanaSignMessage for MyWallet {
type Output = MySignMessageOutput;
async fn sign_message_async(&self, message: impl Into<Vec<u8>>) -> WalletResult<Self::Output> {
let message_bytes = message.into();
// In a real implementation, you would use the wallet's signing mechanism
// This is just a placeholder example using a keypair
let keypair = Keypair::new(); // In reality, this would be the user's keypair
let signature = keypair.sign_message(&message_bytes);
Ok(MySignMessageOutput {
signature,
signed_message: message_bytes,
})
}
async fn sign_messages<M: Into<Vec<u8>>>(
&self,
messages: Vec<M>,
) -> WalletResult<Vec<Self::Output>> {
let mut results = Vec::new();
for message in messages {
results.push(self.sign_message_async(message).await?);
}
Ok(results)
}
}
The library provides a comprehensive error handling system through the WalletError enum:
use wallet_standard::prelude::*;
fn handle_wallet_operation() -> WalletResult<()> {
// Attempt some wallet operation
let result = some_wallet_function();
match result {
Ok(_) => Ok(()),
Err(e) => {
match e {
WalletError::WalletNotConnected => {
// Handle not connected error
Err(WalletError::WalletNotConnected)
}
WalletError::InvalidSignature => {
// Handle invalid signature error
Err(WalletError::InvalidSignature)
}
// Handle other error types
_ => Err(e),
}
}
}
}
For more advanced usage, including implementing experimental features or custom wallet behaviors, please refer to the API documentation.
A full example of how to use this crate can be found in the wallet_standard_browser crate.