Willow
Willow is a Rust + JS framework for Solana programs that generates a clean JS SDK without an IDL.
You define instructions, accounts, and state in Rust — Willow extracts the layout and produces:
- Rust auto‑parsing for instruction args (handlers receive typed args)
- PDA / Token PDA helpers (auto‑creation on-chain + JS derivation)
- JS instruction builders with strict args/accounts validation
- JS account decoders + fetchers (dataSize‑filtered)
No manual packing/unpacking. No IDL.
Install
Rust workspace (this repo):
willow/– Rust crate + CLIwillow-runtime/– JS runtime helpers (published:@neuron1/willow-runtime)willow-derive/– proc-macro crate (required by Rust; re-exported bywillow)
Note: Rust proc-macros must live in a separate crate, so willow-derive cannot be fully merged into willow.
We keep it internal and re-export everything from willow so devs only depend on willow.
CLI usage:
willow init [--name <program_name>] [--path <dir>]
willow build [--path <program_dir>] [--no-raydium] [--runtime <spec>] [--runtime-pkg <name>]
willow gen [--path <program_dir>] [--runtime <spec>] [--runtime-pkg <name>]
willow deploy [--path <program_dir>] [--keypair <path>] [--program-id <path>]
Runtime dependency controls:
--runtime <spec>: version / file spec (e.g.^0.1.0,file:../willow-runtime)--runtime-pkg <name>: package name (default@neuron1/willow-runtime)
Project Structure
When you run willow gen, the SDK is generated as:
<program>_sdk/
_gen/ # auto‑generated (flat files)
instructions/ # dev‑editable wrappers (NOT overwritten if already exists)
accounts/ # dev‑editable wrappers (NOT overwritten if already exists)
Examples:
vault_sdk/_gen/deposit.js
vault_sdk/instructions/deposit.js
vault_sdk/_gen/vault.js
vault_sdk/accounts/vault.js
Rust: Accounts & Instructions
Accounts (input context)
use AccountInfo;
use *;
State (serialized account data)
use Pubkey;
use *;
Instructions
use *;
✅ Args are auto‑parsed and injected by the macro
✅ No manual data decoding in handlers
✅ Accounts have parse() generated automatically
JS SDK (Generated)
Generated instruction functions:
export const deposit_args = ;
export const deposit_accounts = ;
export
Strict Validation
Willow throws if:
- missing args fields
- unknown args fields
- wrong arg types
- missing accounts
- unknown accounts
Account Fetchers (dataSize‑filtered)
const vault = await ;
const allVaults = await ; // auto dataSize filter
PDA Helpers
On-chain: PDAs are auto‑created by Willow’s generated auto‑pda module.
In JS:
const = agentic_vault_sdk..;
const = await agentic_vault_sdk..;
Token PDA helpers are exported as verbs (e.g. derive_agent_usdc_account).
JS Runtime (@neuron1/willow-runtime)
Runtime provides:
reader,writer- strict
assertArgs,assertAccounts - big number helpers
- PDA helpers (
findPda,findAta) - tx helpers (
externInstruction,createExternTransaction,buildExternTransactions,execute,serializeExternTransaction)
Example flow:
const ix = ;
const tx = ;
const sig = await ;
CPI Support (Rust)
Willow provides CPI builder + struct‑based arg packing:
use *;
let data = SwapArgs .to_bytes?;
let mut cpi = new;
cpi
.account
.account
.remaining_writable;
cpi.invoke_signed?;
Supported CPI arg types:
- integers (
u8/u16/u32/u64/i*) u128/i128boolPubkeyStringVec<u8>[u8; N]FixedString<N>FixedBytes<N>
Remaining Accounts
If an instruction supports remaining accounts, pass:
;
Publish / Release Flow
JS runtime
OTP=123456 /Users/winjun/Documents/pino_kit_vault/scripts/publish_runtime.sh
Rust crates
/Users/winjun/Documents/pino_kit_vault/scripts/publish_willow_crate.sh
Sync SDKs to published runtime
/Users/winjun/Documents/pino_kit_vault/scripts/sync_runtime_to_sdk.sh \
/Users/winjun/Documents/pino_kit_vault/agentic_vault ^0.1.0 @neuron1/willow-runtime
Notes
- Program ID is embedded in generated JS; you never pass it.
- SDK uses ESM.
_genfiles are overwritten onwillow gen; dev folders are not.- Strings in state use
#[willow_string](decoded to JS string; bytes remain raw).
Next
Tell me what you want to add:
- more CPI helpers
- more JS runtime utilities
- template improvements
- deeper build.rs split