MCPcopy Index your code
hub / github.com/JamiiDao/SolanaWalletAdapter

github.com/JamiiDao/SolanaWalletAdapter @v1.4.2

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.4.2 ↗ · + Follow
1,395 symbols 2,563 edges 214 files 371 documented · 27%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Wallet-Adapter

Solana Rust Wallet-Adapter Logo

crates.ioDocsRustLicensePassively Maintained

A lightweight Rust Solana Wallet that can be used in Rust based frontends and WebAssembly.

This project was supported by the Solana Foundation.

Read the book at: https://jamiidao.github.io/SolanaWalletAdapter/

Documentation Links

Usage

Building the project requires a web-assembly environment.

See Template Usage for more details

Initializing Register and AppReady

This is done automatically when calling WalletAdapter::init(). The Register and AppReady events are registered to the browser window and document in the current page allowing browser extension wallet to register themselves as specified in the wallet standard.

use wallet_adapter::{WalletAdapter, WalletResult};

async fn foo() -> WalletResult<()>{
    // Initializing the wallet adapter with default channel capacity of `5`.
    // This library uses async-channel in order to listen for background tasks like
    // connect, disconnect and re-connect
    let adapter = WalletAdapter::init()?;

    // Initializing the wallet adapter with a custom channel
    let adapter = WalletAdapter::init_with_channel_capacity(
        10, // Custom capacity
    )?;

    // Initializing the wallet adapter with a
    // `Window` and `Document` that might have been initialized
    // elsewhere.
    let window = web_sys::window().unwrap();
    let document = window.document().unwrap();
    let adapter = WalletAdapter::init_custom(
        window, // web_sys::Window,
        document, // web_sys::Document
    )?;

    // Initializing the wallet adapter with a custom channel,
    // and `Window` and `Document` that might have been initialized
    // elsewhere.
    let window = web_sys::window().unwrap();
    let document = window.document().unwrap();
    let adapter = WalletAdapter::init_with_channel_capacity_window_and_document(
        10, // Custom capacity
        window, // web_sys::Window,
        document, // web_sys::Document
    )?;

    // Get the event receiver that you can use to listen
    // for `Register`, `Disconnected` and other wallet events.
    if let Ok(wallet_event) = adapter.events().recv().await {
        // Do something with the wallet event
    }

    // Get wallets registered
    adapter.wallets();

    // Get a wallet by name
    adapter.get_wallet("Phantom");

    // Get connection information.
    // Returns a `ConnectionInfo` struct which contains the
    // connected wallet and connected account. It is wrapped in an
    // async `RwLock` so you can safely pass it around in background
    // browser tasks
    adapter.connection_info();

    // Get the storage where the registered wallets are stored
    adapter.storage();

    // Expose the browser window
    adapter.window();
    // Expose the browser document
    adapter.document();

    Ok(())
}

In-memory storage for registered wallets.

wallet_adapter::WalletStorage handles storage of registered wallets. The in-memory storage is a HashMap<hash, Wallet> where the hash is the hash of the wallet name.

use wallet_adapter::WalletStorage;

    let storage = WalletStorage::default();

    // Get all registered wallets
    storage.get_wallets();

    // Get a wallet by its name
    storage.get_wallet("Phantom");

    // Clone the storage inside a closure, method or function that moves variables out of their environment
    // `WalletStorage` internally representation is `Rc<RefCell<HashMap<hash, Wallet>>>`
    // this makes it cheap to clone `WalletStorage` where one needs to access `HashMap<hash, Wallet>`
    storage.clone_inner();

Connecting to a browser extension wallet and checking for features

use wallet_adapter::{WalletAdapter, WalletResult};

async fn foo() -> WalletResult<()> {

    let mut adapter = WalletAdapter::init()?;

    // Lookup a wallet from the registered wallet by it's name
    // and then use that wallet entry to perform a connection request
    adapter.connect_by_name("Phantom").await?;

    // Assuming in a frontend application you have a list of 
    // registered wallets to iterate through in order to show a modal
    // or a dropdown of registered wallets and you are building an
    // onclick event to do a connection, you cal use the `WalletAdapter::connect()` method instead

    for wallet in adapter.wallets() {
        // An onclick event from any frontend framework
        // onclick:move|_| {
            adapter.connect(wallet).await?; // The `wallet` can be used inside the onclick event
        // }
    }

    // Get all clusters supported by a connected wallet
    adapter.clusters().await?;

    // Is MainNet cluster supported
    adapter.mainnet().await?;

    // Is DevNet cluster supported
    adapter.devnet().await?;

    // Is TestNet cluster supported
    adapter.testnet().await?;

    // Is LocalNet cluster supported
    adapter.localnet().await?;

    // Is `standard:connect` feature specified in wallet standard supported
    adapter.standard_connect().await?;

    // Is `standard:disconnect` feature specified in wallet standard supported
    adapter.standard_disconnect().await;

    // Is `standard:events` feature specified in wallet standard supported
    adapter.standard_events().await?;

    // Is `solana:signIn` feature specified in wallet standard supported
    adapter.solana_signin().await?;

    // Is `solana:signMessage` feature specified in wallet standard supported
    adapter.solana_sign_message().await?;

    // Is `solana:signTransaction` feature specified in wallet standard supported
    adapter.solana_sign_transaction().await?;

    // Is `solana:signAndSendTransaction` feature specified in wallet standard supported
    adapter.solana_sign_and_send_transaction().await?;

    Ok(())
}

Disconnecting from the wallet

use wallet_adapter::{WalletAdapter, WalletResult, SigninInput};

async fn foo() -> WalletResult<()> {
    let mut adapter = WalletAdapter::init()?;
    adapter.connect_by_name("Phantom").await?;

    // Disconnect from the wallet
    adapter.disconnect().await;

    Ok(())
}

Sign In With Solana (SIWS)

use wallet_adapter::{WalletAdapter, WalletResult, SigninInput};

async fn foo() -> WalletResult<()> {
    let mut adapter = WalletAdapter::init()?;
    adapter.connect_by_name("Phantom").await?;

    // The message to show the user
    let statement = "Login To Dev Website";

    // Get the public key bytes of the connected account within the connected wallet
    let public_key = adapter.connection_info().await.connected_account()?.public_key();
    // Get the address of the connected account within the connected wallet
    let address = adapter.connection_info().await.connected_account()?.address().to_string();

    let mut signin_input = SigninInput::new();
    signin_input
        .set_domain(&adapter.window())?
        .set_statement(statement)
        .set_chain_id(wallet_adapter::Cluster::DevNet)
        // NOTE: Some wallets require this field or the wallet adapter
        // will return an error `MessageResponseMismatch` which is as
        // a result of the sent message not corresponding with the signed message
        .set_address(&address)?;

    // Get the public key in bytes of the connected 
    let signin_output = adapter.sign_in(&signin_input, public_key).await.unwrap();

    Ok(())
}

Sign In With Solana (SIWS) supports more options for the Sign In With Solana Standard. Check the methods on the [SigninInput] struct. NOTE that an error is thrown by the library in case the message signed, public key don't match or if the signature is not valid for the signing public key.

Sign Message

All messages must be UTF-8 encoded string of bytes

use wallet_adapter::{WalletAdapter, WalletResult, SigninInput};

async fn foo() -> WalletResult<()> {
    let mut adapter = WalletAdapter::init()?;
    adapter.connect_by_name("Phantom").await?;
    // Check if the wallet supports signing a message
    if adapter.solana_sign_message().await? {
        adapter.sign_message(b"SOLANA ROCKS!!!").await?;
    }else {
        // Tell user Sign message is not supported
    }
    Ok(())
}

NOTE that an error is thrown by the library in case the message, public key don't match or if the signature is not valid for the signing public key.

Sign Transaction

Here, we simulate signing a SOL transfer instruction

use wallet_adapter::{WalletAdapter, WalletResult, Cluster, Utils,};
use solana_sdk::{
    native_token::LAMPORTS_PER_SOL, pubkey::Pubkey, transaction::Transaction,
};
use solana_system_interface::instruction::transfer;


async fn foo() -> WalletResult<()> {
    let mut adapter = WalletAdapter::init()?;
    adapter.connect_by_name("Phantom").await?;

    // Construct a transaction in a manner that the browser wallet extension
    // can deserialize the transaction from bytes.
    // Here we will use `solana-sdk` crate since it can be converted to
    // bytes using a crate like `bincode` that understands serializing
    // and deserializing the transaction to and from bytes.
    //
    // Get the public key bytes from the connected account
    let public_key = adapter.connection_info().await.connected_account()?.public_key();

    // Convert the public key bytes of the sender to a `solana_sdk::pubkey::Pubkey`
    let pubkey = Pubkey::new_from_array(public_key);

    // Convert the public key bytes of the recipient to a `solana_sdk::pubkey::Pubkey`.
    // Here we use `wallet_adapter::Utils::public_key_rand()` to generate unique public key bytes
    // for testing. Make sure you use a valid public key with corresponding private key
    // or your funds will be lost.
    let recipient_pubkey = Pubkey::new_from_array(Utils::public_key_rand());

    // How many SOL to send.
    // The `solana_sdk::native_token::LAMPORTS_PER_SOL` constant contains the number of lamports
    // equal to `1 SOL` so calculating `2 SOL` can be achieved using `2 * LAMPORTS_PER_SOL`
    let sol = LAMPORTS_PER_SOL;

    // Create an instruction to transfer the SOL
    let instr = transfer(&pubkey, &recipient_pubkey, sol);
    // Create a new unsigned transaction
    let tx = Transaction::new_with_payer(&[instr], Some(&pubkey));
    // Serialize the transaction into bytes using `bincode`
    let tx_bytes = bincode::serialize(&tx).unwrap();

    // Specify to use devnet cluster
    let cluster = Cluster::DevNet;

    // You can check if a wallet is connected first to display
    // a certain view to a user or make a user connect first if the account was disconnected
    if adapter.is_connected().await {
        // Request the browser wallet to sign the transaction.
        let output = adapter.sign_transaction(&tx_bytes, Some(cluster)).await?;

        // Deserialize the signed transaction bytes back into a transaction
        let deser_tx_output = bincode::deserialize::<Transaction>(&output[0]).unwrap();
    }

    Ok(())
}

Remember to add the necessary dependencies for this part in the Cargo.toml manifest.

[dependencies]
# Add latest versions of these crates
solana-sdk = "^2.1.2"
bincode = "^1.3.3"

NOTE that if the signed transaction is verified by the library and an error is thrown in case of signature mismatch.

Sign And Send Transaction

Here, we simulate signing and sending a SOL transfer instruction ```rust use std::str::FromStr;

use wallet_adapter::{WalletAdapter, WalletResult, Cluster, Utils, SendOptions}; use serde::Deserialize; use solana_sdk::{ native_token::LAMPORTS_PER_SOL, pubkey::Pubkey, transaction::Transaction, }; use wasm_bindgen_futures::JsFuture; use web_sys::{wasm_bindgen::JsCast, Headers, Request, RequestInit, Response}; use solana_system_interface::instruction::transfer;

async fn foo() -> WalletResult<()> { let mut adapter = WalletAdapter::init()?; adapter.connect_by_name("Phantom").await?;

// The variables for the code is the same as the one for Sign Transaction

let public_key = adapter.connection_info().await.connected_account()?

Extension points exported contracts — how you extend this code

Version (Interface)
(no doc) [2 implementers]
base/src/version.rs
SignTransactionOutput (Interface)
Represents a `signedTransaction` type in JSON that can be deserialized
base/src/sign_transaction.rs
SignAndSendTransactionOutput (Interface)
Input should be the same as [SignTransactionInput]
base/src/sign_transaction.rs
StandardFeatures (Interface)
(no doc) [1 implementers]
base/src/events.rs
Cluster (Interface)
(no doc) [1 implementers]
base/src/clusters.rs

Core symbols most depended-on inside this repo

clone
called by 165
crate/src/utils.rs
into
called by 102
common/src/commitment.rs
as_str
called by 83
crate/src/commitment.rs
connected_account
called by 63
crate/src/adapter.rs
address
called by 32
base/src/sign_in.rs
asset_base64_svg
called by 29
templates/sycamore-adapter/src/svg_assets.rs
asset_base64_svg
called by 29
templates/sycamore-adapter-anchor/frontend/src/svg_assets.rs
connection_info
called by 26
crate/src/adapter.rs

Shape

Method 689
Function 504
Class 160
Enum 29
Interface 13

Languages

Rust100%
TypeScript1%

Modules by API surface

crate/src/adapter.rs45 symbols
base/src/sign_in.rs43 symbols
wallet-adapter-common/src/signin_standard/signin.rs42 symbols
crate/src/wallet_ser_der/signin_standard.rs41 symbols
wallet-adapter-common/src/wallet.rs33 symbols
crate/src/utils.rs33 symbols
templates/yew-adapter/src/svg_assets.rs31 symbols
templates/yew-adapter-anchor/frontend/src/svg_assets.rs31 symbols
templates/sycamore-adapter/src/svg_assets.rs31 symbols
templates/sycamore-adapter-anchor/frontend/src/svg_assets.rs31 symbols
templates/dioxus-adapter/src/svg_assets.rs30 symbols
templates/dioxus-adapter-anchor/frontend/src/svg_assets.rs30 symbols

For agents

$ claude mcp add SolanaWalletAdapter \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact