willow-core 0.1.0

Rust + JS framework for Solana programs without IDL
Documentation
# 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 + CLI
- `willow-runtime/` – JS runtime helpers (published: `@neuron1/willow-runtime`)
- `willow-derive/` – proc-macro crate (required by Rust; re-exported by `willow`)

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)
```rust
use pinocchio::account_info::AccountInfo;
use willow::prelude::*;

#[willow_accounts(
    vault_account(writable),
    authority_account(signer),
    system_program
)]
pub struct DepositAccounts<'a> {
    pub vault_account: &'a AccountInfo,
    pub authority_account: &'a AccountInfo,
    pub system_program: &'a AccountInfo,
}
```

### State (serialized account data)
```rust
use pinocchio::pubkey::Pubkey;
use willow::prelude::*;

#[repr(C)]
#[willow_account(pda(const("vault"), pubkey(owner)))]
pub struct Vault {
    pub owner: Pubkey,
    pub total_assets: u64,
    #[willow_string]
    pub name: [u8; 32], // decoded to string in JS
}
```

### Instructions
```rust
use willow::prelude::*;

#[willow_instruction(
    id = 1,
    accounts = DepositAccounts,
    args = [amount: u64]
)]
pub fn deposit_handler(
    program_id: &Pubkey,
    accounts: &DepositAccounts,
    args: &crate::__willow_args::DepositArgs,
) -> ProgramResult {
    // use args.amount, accounts.vault_account, etc
    Ok(())
}
```

✅ 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:
```js
export const deposit_args = { amount: "u64" };
export const deposit_accounts = {
  vault_account: { signer: false, writable: true },
  authority_account: { signer: true, writable: false },
};

export async function deposit(accounts, args) {
  assertAccounts(accounts, deposit_accounts, { allowRemaining: false });
  assertArgs(args, deposit_args);
  ...
}
```

### Strict Validation
Willow throws if:
- missing args fields
- unknown args fields
- wrong arg types
- missing accounts
- unknown accounts

### Account Fetchers (dataSize‑filtered)
```js
const vault = await fetchVault(connection, vaultPda);
const allVaults = await fetchVaults(connection); // auto dataSize filter
```

---

## PDA Helpers

**On-chain:** PDAs are auto‑created by Willow’s generated auto‑pda module.

**In JS:**
```js
const [vaultPda, bump] = agentic_vault_sdk.pdas.Vault.pda({ owner });
const [agentUsdcPda] = await agentic_vault_sdk.pdas.derive_agent_usdc_account({
  agent_account: agentPda,
  usdc_mint_account: USDC_MINT,
});
```

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:
```js
const ix = deposit({ vault_account, authority }, { amount: 5n });
const tx = buildExternTransactions([ix]);
const sig = await execute(connection, tx, wallet, []);
```

---

## CPI Support (Rust)

Willow provides **CPI builder + struct‑based arg packing**:
```rust
use willow::prelude::*;

#[willow_cpi_args(discriminator = [43,4,237,11,26,201,30,98])]
pub struct SwapArgs {
    pub amount_in: u64,
    pub min_amount_out: u64,
    pub sqrt_price_limit_x64: u128,
    pub is_base_input: bool,
}

let data = SwapArgs { ... }.to_bytes()?;
let mut cpi = CpiBuilder::new(clmm_program.key(), data);
cpi
  .account(payer, true, false)
  .account(pool_state, false, true)
  .remaining_writable(&remaining_accounts);
cpi.invoke_signed(&signer_seeds)?;
```

Supported CPI arg types:
- integers (`u8/u16/u32/u64/i*`)
- `u128/i128`
- `bool`
- `Pubkey`
- `String`
- `Vec<u8>`
- `[u8; N]`
- `FixedString<N>`
- `FixedBytes<N>`

---

## Remaining Accounts
If an instruction supports remaining accounts, pass:
```js
deposit({
  vault_account,
  authority,
  remaining: [
    { pubkey: extra1, isSigner: false, isWritable: true },
  ],
}, { amount: 5n });
```

---

## 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.
- `_gen` files are overwritten on `willow 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