solana-wasi 0.1.0

Solana primitives that actually compile to wasm32-wasip2: pubkeys, PDAs, JSON-RPC over a swappable transport, SPL Token / Token-2022 account parsing, and unsigned v0 transaction construction. No solana-sdk, no C toolchain, no async runtime.
Documentation
//! Solana primitives that compile to `wasm32-wasip2`.
//!
//! `solana-sdk` and `solana-client` do not build inside a WebAssembly component
//! without a fight, and the parts of them a tool plugin needs are small. This
//! crate is those parts, written against the wire formats directly: pubkeys and
//! PDAs, a typed JSON-RPC client over a swappable transport, SPL Token and
//! Token-2022 account parsing including the full extension set, unsigned v0
//! transaction construction, durable nonces, and the output-shaping helpers
//! that keep a tool's answer inside a model's context budget.
//!
//! # Three properties, on purpose
//!
//! **It cannot sign.** There is no keypair type, no signer trait, and no path
//! from an instruction to a signature. A plugin built on this crate can hold at
//! most an RPC URL. Signing belongs to a wallet, a human, or a multisig.
//!
//! **It is host-testable.** Everything except [`transport::WakiTransport`] is
//! pure Rust with no wasm dependency. A plugin's `cargo test` runs on the host
//! against [`transport::MockTransport`], with no wasm toolchain and no live
//! network, which is what ZeroClaw's plugin CI requires.
//!
//! **It treats the chain as hostile input.** Token names, symbols and metadata
//! URIs are written by whoever deployed the mint. [`sanitize`] exists because
//! those strings end up in a language model's context, and a tool that forwards
//! them verbatim is an injection vector with an RPC bill.
//!
//! # Example
//!
//! ```
//! use solana_wasi::prelude::*;
//!
//! # fn main() -> solana_wasi::Result<()> {
//! let transport = MockTransport::new().on(
//!     "getAccountInfo",
//!     serde_json::json!({
//!         "context": { "slot": 1 },
//!         "value": {
//!             "lamports": 1_000_000_000u64,
//!             "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
//!             // 82 zero bytes: a mint with no authorities.
//!             "data": [base64_of_82_zero_bytes(), "base64"],
//!             "executable": false,
//!             "rentEpoch": 0
//!         }
//!     }),
//! );
//!
//! let rpc = RpcClient::new("https://api.mainnet-beta.solana.com", transport);
//! let mint_address = Pubkey::from_base58("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")?;
//! let account = rpc.require_account(&mint_address)?;
//! let state = MintState::parse(mint_address, &account)?;
//!
//! assert_eq!(state.program, TokenProgram::Legacy);
//! assert!(state.mint.freeze_authority.is_none());
//! # Ok(())
//! # }
//! # fn base64_of_82_zero_bytes() -> String {
//! #     use base64::Engine;
//! #     base64::engine::general_purpose::STANDARD.encode([0u8; 82])
//! # }
//! ```

#![forbid(unsafe_code)]
#![warn(missing_docs)]

pub mod error;
pub mod metadata;
pub mod nonce;
pub mod pubkey;
pub mod rpc;
pub mod sanitize;
pub mod shape;
pub mod token;
pub mod transport;
pub mod tx;

pub use error::{Error, Result};

/// Everything a plugin's pure core typically imports.
///
/// One caveat, and it costs an hour if you hit it blind: this re-exports the
/// crate's `Result<T>` alias, which fixes the error type. Do not glob-import
/// the prelude inside a `wit_bindgen::generate!` module — a WIT export returns
/// `Result<ToolResult, String>`, and the alias shadows it with a "type alias
/// takes 1 generic argument but 2 were supplied" error that points at the
/// wrong line. Import what the shim needs by name instead.
pub mod prelude {
    pub use crate::error::{Error, Result};
    pub use crate::pubkey::{ids, Pubkey};
    pub use crate::rpc::{Account, Commitment, RpcClient};
    pub use crate::sanitize::{untrusted_text, untrusted_uri, Sanitized};
    pub use crate::shape::{parse_amount, percent_of, ui_amount, Budget};
    pub use crate::token::{associated_token_address, MintState, TokenAccount, TokenProgram};
    pub use crate::transport::{MockTransport, Transport};
    #[cfg(target_family = "wasm")]
    pub use crate::transport::WakiTransport;
    pub use crate::tx::{instructions, AccountMeta, Instruction, Message, UnsignedTransaction};
}