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
//! 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])
//! # }
//! ```
pub use ;
/// 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.