Skip to content

openSVM/uncpi

Repository files navigation

uncpi

Crates.io CI License: MIT Production Ready Success Rate

"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

  1. No IDL generation - Must maintain IDL manually
  2. Complex constraints - Some runtime constraints need manual review
  3. Account iteration - remaining_accounts patterns need manual handling
  4. 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

πŸš€ 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

About

Transpile Anchor programs to Pinocchio for 85%+ binary size reduction

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages