A Complete Guide to Wrapping, Transferring, and Unwrapping SOL on Solana

·

Wrapped SOL (wSOL) plays a crucial role in the Solana ecosystem by bridging native SOL with SPL token-based applications. This guide walks you through the complete lifecycle of wSOL—wrapping SOL into an SPL token, transferring it across wallets, and unwrapping it back into native SOL—using three major development tools: Solana Web3.js, the Solana CLI, and the Solana Rust SDK.

Whether you're building decentralized exchanges, liquidity pools, or DeFi protocols, understanding how to manage wrapped SOL is essential. We’ll cover each step with practical code examples and clear explanations to ensure you can confidently integrate wSOL into your Solana projects.

What Is Wrapped SOL?

Wrapped SOL (wSOL) is an SPL token that represents native SOL in a tokenized format. While SOL is Solana’s native cryptocurrency used for gas fees and staking, many decentralized applications (dApps) require assets in SPL token form to enable features like liquidity provision, token swaps, and smart contract interactions.

By wrapping SOL into wSOL, users can seamlessly interact with DeFi platforms such as Raydium or Orca, where liquidity pools only accept SPL tokens. Technically, wrapping involves sending SOL to an associated token account (ATA) tied to the native mint (So11111111111111111111111111111111111111112) and calling the syncNative instruction. This updates the token account balance to reflect the wrapped amount.

Unwrapping reverses this process by closing the ATA and reclaiming the underlying SOL.

👉 Learn how to securely manage wSOL transactions with advanced tools


Core Operations with Solana Web3.js

Setting Up Your Project

To begin, create a new TypeScript project:

mkdir wrapped-sol-demo && cd wrapped-sol-demo
echo > app.ts
npm init -y
npm install @solana/web3.js @solana/spl-token typescript ts-node

Ensure you have Node.js v16.15+ and ts-node installed for smooth execution.

Import Required Dependencies

In app.ts, import necessary modules:

import {
  NATIVE_MINT,
  createAssociatedTokenAccountInstruction,
  getAssociatedTokenAddress,
  createSyncNativeInstruction,
  getAccount,
  createTransferInstruction,
  createCloseAccountInstruction,
} from "@solana/spl-token";
import {
  Connection,
  Keypair,
  LAMPORTS_PER_SOL,
  SystemProgram,
  Transaction,
  sendAndConfirmTransaction,
  PublicKey,
} from "@solana/web3.js";

These imports provide access to core blockchain interactions and SPL token utilities.

Main Workflow Function

Define the main function orchestrating all operations:

async function main() {
  const connection = new Connection("http://127.0.0.1:8899", "confirmed");
  const wallet1 = Keypair.generate();
  const wallet2 = Keypair.generate();

  await requestAirdrop(connection, wallet1);
  const tokenAccount1 = await wrapSol(connection, wallet1);
  const tokenAccount2 = await transferWrappedSol(connection, wallet1, wallet2, tokenAccount1);
  await unwrapSol(connection, wallet1, tokenAccount1);
  await printBalances(connection, wallet1, wallet2, tokenAccount2);
}

This script uses a local validator. For production use on devnet or mainnet, replace the endpoint URL with your RPC provider.

Step-by-Step Functions

Request Airdrop

Fetch test SOL for development:

async function requestAirdrop(connection: Connection, wallet: Keypair): Promise<void> {
  const airdropSignature = await connection.requestAirdrop(wallet.publicKey, 2 * LAMPORTS_PER_SOL);
  await connection.confirmTransaction(airdropSignature);
  console.log("✅ - Step 1: Airdrop completed");
}

Wrap SOL

Convert native SOL into wSOL:

async function wrapSol(connection: Connection, wallet: Keypair): Promise<PublicKey> {
  const ata = await getAssociatedTokenAddress(NATIVE_MINT, wallet.publicKey);

  const tx = new Transaction().add(
    createAssociatedTokenAccountInstruction(wallet.publicKey, ata, wallet.publicKey, NATIVE_MINT),
    SystemProgram.transfer({
      fromPubkey: wallet.publicKey,
      toPubkey: ata,
      lamports: LAMPORTS_PER_SOL,
    }),
    createSyncNativeInstruction(ata)
  );

  await sendAndConfirmTransaction(connection, tx, [wallet]);
  console.log("✅ - Step 2: SOL wrapped");
  return ata;
}

Transfer Wrapped SOL

Send wSOL to another wallet:

async function transferWrappedSol(
  connection: Connection,
  fromWallet: Keypair,
  toWallet: Keypair,
  fromTokenAccount: PublicKey
): Promise<PublicKey> {
  const toAta = await getAssociatedTokenAddress(NATIVE_MINT, toWallet.publicKey);

  const tx = new Transaction().add(
    createAssociatedTokenAccountInstruction(fromWallet.publicKey, toAta, toWallet.publicKey, NATIVE_MINT),
    createTransferInstruction(fromTokenAccount, toAta, fromWallet.publicKey, LAMPORTS_PER_SOL / 2)
  );

  await sendAndConfirmTransaction(connection, tx, [fromWallet]);
  console.log("✅ - Step 3: Transferred wrapped SOL");
  return toAta;
}

Unwrap SOL

Reclaim native SOL from wSOL:

async function unwrapSol(
  connection: Connection,
  wallet: Keypair,
  tokenAccount: PublicKey
): Promise<void> {
  const tx = new Transaction().add(
    createCloseAccountInstruction(tokenAccount, wallet.publicKey, wallet.publicKey)
  );
  await sendAndConfirmTransaction(connection, tx, [wallet]);
  console.log("✅ - Step 4: SOL unwrapped");
}

Print Final Balances

Verify outcomes:

async function printBalances(
  connection: Connection,
  wallet1: Keypair,
  wallet2: Keypair,
  tokenAccount2: PublicKey
): Promise<void> {
  const [w1Bal, w2Bal, w2wSol] = await Promise.all([
    connection.getBalance(wallet1.publicKey),
    connection.getBalance(wallet2.publicKey),
    connection.getTokenAccountBalance(tokenAccount2),
  ]);

  console.log(` - Wallet 1 SOL balance: ${w1Bal / LAMPORTS_PER_SOL}`);
  console.log(` - Wallet 2 SOL balance: ${w2Bal / LAMPORTS_PER_SOL}`);
  console.log(` - Wallet 2 wrapped SOL: ${Number(w2wSol.value.amount) / LAMPORTS_PER_SOL}`);
}

Run with ts-node app.ts. Expected output:

✅ - Step 1: Airdrop completed
✅ - Step 2: SOL wrapped
✅ - Step 3: Transferred wrapped SOL
✅ - Step 4: SOL unwrapped
 - Wallet 1 SOL balance: ~1.497
 - Wallet 2 SOL balance: 0
 - Wallet 2 wrapped SOL: 0.5

Using Solana CLI for wSOL Management

The Solana Command Line Interface offers a quick way to handle wSOL without writing code.

Setup and Airdrop

Configure localnet and generate keypairs:

solana config set --url http://localhost:8899
solana-keygen new --no-bip39-passphrase -o wallet1.json
solana-keygen new --no-bip39-passphrase -o wallet2.json
solana airdrop -k wallet1.json 2

Wrap and Transfer

Wrap 1 SOL:

spl-token wrap 1 wallet1.json

Create recipient ATA:

spl-token create-account So11111111111111111111111111111111111111112 --owner wallet2.json --fee-payer wallet1.json

Transfer half:

spl-token transfer So111...2 0.5 [RECIPIENT_ATA] --owner wallet1.json --fee-payer wallet1.json

Unwrap remaining:

spl-token unwrap --owner wallet1.json

Check balances using solana balance and spl-token balance.

👉 Discover powerful tools to test and deploy your wSOL workflows


Implementing wSOL in Rust

For performance-critical applications, Rust provides low-level control.

Add dependencies to Cargo.toml:

[dependencies]
solana-client = "2.0.3"
solana-sdk = "2.0.3"
spl-token = "6.0.0"
spl-associated-token-account = "4.0.0"

Implement logic similar to JavaScript version using RpcClient, Keypair, and SPL instructions. Full code follows same flow: airdrop → wrap → transfer → unwrap → verify.

Run with cargo run after starting a local validator.


Frequently Asked Questions

Q: What is the difference between SOL and wSOL?
A: SOL is Solana’s native coin used for fees and staking. wSOL is an SPL token representing wrapped SOL, enabling use in DeFi protocols that require tokenized assets.

Q: Can I lose funds when wrapping/unwrapping?
A: Not if done correctly. However, always test on devnet first. Closing an ATA without syncing may lead to loss of funds.

Q: Is wrapping reversible?
A: Yes. Unwrapping closes the associated token account and returns lamports (SOL) to the owner.

Q: Do I pay fees when wrapping?
A: Yes. Each transaction—creating ATA, transferring SOL, syncing—incurs standard network fees.

Q: Can I wrap fractional amounts of SOL?
A: Yes. You can wrap any amount down to lamports (0.000000001 SOL).

Q: Why use multiple methods (JS/CLI/Rust)?
A: JS is ideal for web apps, CLI for quick testing, and Rust for high-performance backends or on-chain programs.


Final Thoughts

Mastering wSOL operations unlocks full participation in Solana’s DeFi landscape. Whether you're developing dApps or managing liquidity positions, knowing how to wrap, transfer, and unwrap SOL using Web3.js, CLI, or Rust gives you flexibility and control.

Always test on localnet or devnet before deploying to mainnet. When ready for real-world usage, ensure reliable connectivity with a high-performance RPC provider.

👉 Access enterprise-grade Solana infrastructure to scale your applications