4 releases (breaking)
| 0.4.0 | Dec 23, 2025 |
|---|---|
| 0.3.0 | Dec 22, 2025 |
| 0.2.0 | Dec 22, 2025 |
| 0.1.0 | Dec 21, 2025 |
#3 in #solana-anchor
240KB
5K
SLoC
uncpi
"ok unc, optimize my anchor uwu" (c) clanker
Production-ready Anchor → Pinocchio transpiler for 85%+ binary size reduction.
✅ Validated against official Solana programs (4,557+ stars) ✅ Tested with patterns from Raydium, Jupiter, Marinade ✅ 80% success rate on real-world programs
Why?
| Metric | Anchor | Pinocchio | Savings |
|---|---|---|---|
| Binary Size | ~600-900 KB | ~50-100 KB | 85-90% |
| Deploy Cost | ~10 SOL | ~1 SOL | $1,100+ |
| Compute Units | ~300-600 CU | ~100-150 CU | 60-75% |
Install
From crates.io (recommended)
cargo install uncpi
From source
git clone https://github.com/openSVM/uncpi.git
cd uncpi
cargo install --path .
Pre-built binaries
Download pre-built binaries for Linux, macOS, and Windows from the releases page.
Usage
# Convert a program
uncpi programs/my_program/src/lib.rs -o programs/my_program_pino/
# With options
uncpi programs/my_program/src/lib.rs \
--no-alloc \ # Use no_allocator! for max savings
--inline-cpi \ # Inline CPI calls
--lazy-entrypoint \ # Use lazy_program_entrypoint!
-o output/
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ uncpi Pipeline │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Parse │───▶│ Analyze │───▶│Transform │───▶│ Emit │ │
│ │ Anchor │ │ AST │ │ IR │ │Pinocchio │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ lib.rs Account Graph Pinocchio IR lib.rs │
│ (Anchor) + Constraints + Validation (Pinocchio) │
│ │
└─────────────────────────────────────────────────────────────────┘
Conversion Examples
Program Entry Point
Anchor:
#[program]
pub mod my_program {
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
// ...
}
}
Pinocchio:
use pinocchio::{lazy_program_entrypoint, program_error::ProgramError};
lazy_program_entrypoint!(process_instruction);
fn process_instruction(
program_id: &[u8; 32],
accounts: &[[u8; 32]],
instruction_data: &[u8],
) -> Result<(), ProgramError> {
let discriminator = instruction_data[0];
match discriminator {
0 => initialize(accounts, &instruction_data[1..]),
_ => Err(ProgramError::InvalidInstructionData),
}
}
Account Validation
Anchor:
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(
init,
payer = authority,
space = 8 + State::INIT_SPACE,
seeds = [b"state"],
bump
)]
pub state: Account<'info, State>,
#[account(mut)]
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}
Pinocchio:
fn initialize(accounts: &[AccountInfo], _data: &[u8]) -> Result<(), ProgramError> {
let state_info = &accounts[0];
let authority_info = &accounts[1];
let system_program = &accounts[2];
// Signer check
if !authority_info.is_signer() {
return Err(ProgramError::MissingRequiredSignature);
}
// PDA validation
let (expected_pda, bump) = Pubkey::find_program_address(&[b"state"], program_id);
if state_info.key() != &expected_pda {
return Err(ProgramError::InvalidSeeds);
}
// Create account via CPI
create_account(
authority_info,
state_info,
8 + State::SIZE,
program_id,
system_program,
&[b"state", &[bump]],
)?;
Ok(())
}
State Structs
Anchor:
#[account]
#[derive(InitSpace)]
pub struct State {
pub authority: Pubkey,
pub total: u64,
pub bump: u8,
}
Pinocchio:
#[repr(C)]
pub struct State {
pub authority: [u8; 32],
pub total: u64,
pub bump: u8,
}
impl State {
pub const SIZE: usize = 32 + 8 + 1;
pub fn from_account_info(info: &AccountInfo) -> Result<&Self, ProgramError> {
let data = info.try_borrow_data()?;
if data.len() < 8 + Self::SIZE {
return Err(ProgramError::InvalidAccountData);
}
Ok(unsafe { &*(data[8..].as_ptr() as *const Self) })
}
}
Constraints Mapping
| Anchor Constraint | Pinocchio Equivalent |
|---|---|
#[account(mut)] |
info.is_writable() check |
#[account(signer)] |
info.is_signer() check |
#[account(seeds = [...], bump)] |
Pubkey::find_program_address() |
#[account(constraint = expr @ Error)] |
Manual if !expr { return Err(...) } |
#[account(init, payer, space)] |
create_account() CPI |
#[account(token::mint, token::authority)] |
Token program CPI + validation |
#[account(close = target)] |
Transfer lamports + zero data |
CPI Calls
Anchor:
let cpi_accounts = Transfer {
from: ctx.accounts.from.to_account_info(),
to: ctx.accounts.to.to_account_info(),
authority: ctx.accounts.authority.to_account_info(),
};
token::transfer(CpiContext::new(token_program, cpi_accounts), amount)?;
Pinocchio:
use pinocchio_token::instructions::Transfer;
Transfer {
from: from_info,
to: to_info,
authority: authority_info,
amount,
}.invoke()?;
Limitations
- No IDL generation - Must maintain IDL manually
- Complex constraints - Some runtime constraints need manual review
- Account iteration -
remaining_accountspatterns need manual handling - Dynamic PDA seeds - Runtime seeds need careful handling
License
MIT
🎯 Production Validation
Tested Against Real-World Programs
✅ Official Solana Foundation (4,557+ stars)
- Escrow test program - 0 errors
- Counter examples - 0 errors
✅ Top DeFi Protocols
- Raydium AMM patterns - 0 errors
- Jupiter Exchange patterns - 0 errors
- Marinade Finance staking patterns - 0 errors
✅ NFT & Gaming
- Marketplace patterns (Tensor/Magic Eden-style) - 0 errors
- Lottery with self-referential PDAs - 0 errors
Success Metrics
| Pattern | Success Rate |
|---|---|
| DeFi (AMM, Staking, Vaults) | 100% ✅ |
| NFT (Marketplaces) | 100% ✅ |
| Governance (Voting) | 100% ✅ |
| Gaming (Lottery) | 100% ✅ |
| Overall | 80% (8/10 programs) |
See: PRODUCTION-VALIDATION.md for detailed validation report
🚀 What Works Out-of-the-Box
Fully Supported Patterns ✅
- State Management: init, init_if_needed, Account<'info, T>
- PDAs: Seeds, bumps, self-referential PDAs
- Token Operations: Transfer, Mint, Burn, CPI
- Constraints: has_one, signer, mut, seeds
- Custom Errors: require! macros, error enums
- Advanced Types: String → [u8; N], Option
- Syscalls: Clock, Rent
- Math Operations: Integer square root for AMMs
Examples of Supported Programs
✅ Escrow (token swaps, PDAs, signed invocations)
✅ AMM (liquidity pools, mathematical operations)
✅ Staking (reward calculations, time-based logic)
✅ NFT Marketplace (buy/sell/cancel)
✅ Voting (governance, String fields)
✅ Lottery (self-referential PDAs, Option types)
✅ Token Vaults (deposit/withdraw)
📚 Documentation
- FINAL-RESULTS.md - Complete v0.3.0 test results
- PRODUCTION-VALIDATION.md - Validation against real-world programs
- TESTING-SUMMARY.md - Comprehensive testing methodology
- CLMM-ANALYSIS.md - Raydium CLMM analysis and feasibility assessment
- CLMM-COMPLETE.md - Simplified CLMM demo build results
- CLAUDE.md - Developer guide for contributing
🚀 Example Projects
Real-world programs built with uncpi:
-
Pinray AMM - Constant product AMM (x * y = k)
- 85% smaller than Anchor
- 90% cheaper deployment
- Production-ready patterns
-
Pinray CLMM - Simplified Concentrated Liquidity
- Educational demo
- Q64.64 fixed-point math
- Single tick range implementation
Dependencies
~5–8MB
~150K SLoC