Wrapped SOL
Wrapped SOL (wSOL) is native SOL held inside an SPL token account. DeFi programs expect SPL token CPIs, so SOL is temporarily wrapped, used, then unwrapped back to native lamports.
Search across all documentation pages
Wrapped SOL (wSOL) is native SOL held inside an SPL token account. DeFi programs expect SPL token CPIs, so SOL is temporarily wrapped, used, then unwrapped back to native lamports.
spl-token wrap 1.5
spl-token unwrap <WSOL_TOKEN_ACCOUNT>use anchor_lang::system_program;
use anchor_spl::token::{self, sync_native, TokenAccount};
// Deposit lamports into WSOL ATA, then sync_nativeWhen to reach for this:
solana balance
spl-token address --token So11111111111111111111111111111111111111112
spl-token wrap 0.5
spl-token balance So11111111111111111111111111111111111111112
spl-token unwrap <WSOL_ATA_ADDRESS>
solana balanceuse anchor_lang::prelude::*;
use anchor_spl::token::{self, Token, TokenAccount, SyncNative};
pub const WSOL_MINT: Pubkey = anchor_spl::token::spl_token::native_mint::ID;
#[derive(Accounts)]
pub struct WrapSol<'info> {
#[account(mut)]
pub payer: Signer<'info>,
#[account(
mut,
constraint = wsol_ata.mint == WSOL_MINT @ ErrorCode::NotWsol,
)]
pub wsol_ata: Account<'info, TokenAccount>,
pub token_program: Program<'info, Token>,
pub system_program: Program<'info, System>,
}
pub fn wrap_sol(ctx: Context<WrapSol>, lamports: u64) -> Result<()> {
system_program::transfer(
CpiContext::new(
ctx.accounts.system_program.to_account_info(),
system_program::Transfer {
from: ctx.accounts.payer.to_account_info(),
to: ctx.accounts.wsol_ata.to_account_info(),
},
),
lamports,
)?;
token::sync_native(CpiContext::new(
ctx.accounts.token_program.to_account_info(),
SyncNative {
account: ctx.accounts.wsol_ata.to_account_info(),
},
))?;
Ok(())
}
#[error_code]
pub enum ErrorCode {
NotWsol,
}import { createSolanaRpc, address } from "@solana/kit";
const WSOL_MINT = address("So11111111111111111111111111111111111111112");
const rpc = createSolanaRpc("https://api.devnet.solana.com");
// Many DEX SDKs auto-wrap SOL; manual flows use syncNative instruction after lamport transferWhat this demonstrates:
sync_native updates SPL balanceSo11111111111111111111111111111111111111112sync_native reconciles SPL amount field| Form | Account type | Used by |
|---|---|---|
| Native SOL | System-owned wallet | Transfers, fees, staking |
| wSOL | SPL token account (same mint) | AMMs, unified token vaults |
// Close WSOL account to unwrap - returns lamports to destination
use anchor_spl::token::CloseAccount;
// Ensure amount is 0 or use withdraw pattern per your SDKsync_native after lamport deposit.native_mint::ID.| Alternative | Use When | Don't Use When |
|---|---|---|
| Native SOL transfer | Simple payments | AMM requires SPL CPI |
Program deposit_sol helper | Protocol abstracts wrap | Custom instruction set |
| wSOL ATA persistent | Frequent trader | One-off payment |
SOL deposited into an SPL token account for the native mint, making it behave like any SPL token in programs.
So11111111111111111111111111111111111111112 on all clusters.
SPL Token program CPIs cannot move native lamports from wallets without wrapping pattern.
9, matching lamports per SOL.
Yes. Lamports move into WSOL token account (plus fees).
Updates token account amount field to match lamports held by the account.
Yes. Standard transfer between WSOL token accounts.
spl-token unwrap or close/drain WSOL ATA per SDK patterns.
Yes for most SOL-input swaps - SDK handles wrap/unwrap in transaction.
Native mint is protocol-defined - not a typical launch mint.
Yes in PDA-owned WSOL ATAs with proper signer seeds on transfer.
WSOL uses classic native mint on Token program, not Token-2022.
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.
Reviewed by Chris St. John·Last updated Jul 19, 2026