Back to Videos

Raydium program library: your go-to tool for De-Fi use cases

Wednesday, June 4, 2025

Welcome to Week 5 of the Neon Dev Bootcamp!

This week, we're diving into Solana’s Raydium protocol and learning how to interact with it directly from your Solidity contracts using Neon EVM’s composability libraries. If you’re familiar with Uniswap on Ethereum, you’ll find some conceptual similarities but also important architectural differences that you’ll learn to navigate.

Raydium vs. Uniswap: Key Differences

Feature Uniswap (EVM) Raydium (Solana)
Architecture EVM-based smart contracts Stateless Solana programs
Token Accounts Mostly handled automatically Manual setup required
Pool Creation 3–5 contracts per pool 20+ dynamically derived accounts
Interaction Solidity + MetaMask Solidity (via Neon EVM) + Solana accounts

Both offer:

  • AMMs (Automated Market Makers)
  • Swap logic with slippage control
  • Liquidity management & pool creation
  • LP token issuance and fee collection

Raydium’s native Solana logic can be triggered directly from Solidity using the Raydium composability library.

Here’s what you can do:

  • Create CPMM (concentrated liquidity) pools
  • Add/remove liquidity
  • Lock LP positions as NFTs
  • Collect swap fees
  • Trigger swaps

Let’s break down how to call these Raydium program instructions from Solidity.

Library Instructions Overview

Here are the 7 main methods in the library:

Instruction Name Description
createPoolInstruction Creates a CPMM pool with the specified token pair
addLiquidityInstruction Adds liquidity to the specified pool
withdrawLiquidityInstruction Withdraws liquidity from the pool
lockLiquidityInstruction Locks LP tokens and returns metadata/NFT
collectFeesInstruction Collects fees from a locked LP position
swapInputInstruction Swaps an exact amount of token A for token B
swapOutputInstruction Swaps token A for an exact amount of token B

1️⃣ Create Pool

To create a pool:

  • Select Token A and Token B
  • Mint initial liquidity tokens
  • Define a pool start time
  • Define premade ATAs to optimize execution

function createPoolInstruction(
       bytes32 tokenA,
       bytes32 tokenB,
       uint64 mintAAmount,
       uint64 mintBAmount,
       uint64 startTime,
       uint16 configIndex,
       bool returnData,
       bytes32[] memory premadeAccounts

Pool ID is returned from index 3 of the resulting accounts array. Then you can use the getCpmmPdaPoolId() method in the LibRaydiumData library to get the pool ID.

We’re using premade accounts to optimize to optimize performance. Specifically, we need associated token accounts (ATAs) to transfer tokens from the user. The Raydium program also requires these same ATAs. To avoid recalculating them and paying for additional external calls, the library includes an array of precomputed Solana accounts.

2️⃣ Add Liquidity

This lets any user provide liquidity to an existing pool.

Parameters:

  • Pool ID
  • Amounts of Token A and B
  • Base token for LP calculation
  • Slippage (recommended: 1–5%)

function addLiquidityInstruction(
       bytes32 poolId,
       uint64 inputAmount,
       bool baseIn,
       uint16 slippage,
       bool returnData,
       bytes32[] memory premadeAccounts

3️⃣ Withdraw Liquidity

When withdrawing liquidity:

  • Always specify arbitrary token accounts (msg.sender) so the tokens go directly to the user - and not to the contract (they won’t be lost if they go the contract but it adds an extra step)
  • Use returnData = true for success

function withdrawLiquidityInstruction(
       bytes32 poolId,
       uint64 lpAmount,
       uint16 slippage,
       bool returnData,
       bytes32[] memory premadeAccounts

4️⃣ Lock Liquidity

This converts LP tokens into an NFT position. You can add metadata for resale.

function lockLiquidityInstruction(
       bytes32 poolId,
       uint64 lpAmount,
       bool withMetadata,
       bytes32 salt,
       bool returnData,
       bytes32[] memory premadeAccounts

5️⃣ Collect Fees

Can only be called after there’s been some traffic inside the pool, such as swaps.

function collectFeesInstruction(
       bytes32 poolId,
       uint64 lpFeeAmount,
       bytes32 salt,
       bool returnData,
       bytes32[] memory premadeAccounts

6️⃣ Swap Input / Output

Use swapInputInstruction for fixed input, swapOutputInstruction for fixed output:

function buildSwapInputData(uint64 amountIn, uint64 amounOutMin) internal pure returns (bytes memory) {
       require(amountIn > 0, LibRaydiumErrors.InsufficientInputAmount());
       return abi.encodePacked(
           hex"8fbe5adac41e33de", // swapBaseInput: [143, 190, 90, 218, 196, 30, 51, 222]
           amountIn.readLittleEndianUnsigned64(),
           amounOutMin.readLittleEndianUnsigned64()
       );

or

function swapOutputInstruction(
       bytes32 poolId,
       bytes32 inputToken,
       uint64 amountOut,
       uint16 slippage,
       bool returnData,
       bytes32[] memory premadeAccounts

Both internally map to the same swap logic.

Practice Exercise

Your task this week is not just to follow along — but to come up with your own use case for the Raydium composability library. It’ll most likely be a DeFi use case, but feel free to get creative.

Here’s how to approach it based on your experience level:

Beginners

  • Run the test script to see how a Raydium pool is created and used
  • Then, think of a potential DeFi use case for this functionality
  • In your README.md, describe your idea clearly — what the dApp would do and how it would use the Raydium instructions

You don’t need to write custom logic yet — just show that you understand what’s possible.

Advanced

  • Come up with a DeFi use case that leverages one or more Raydium instructions
  • Write your own smart contract(s) implementing this idea
  • If you have time, feel free to add a simple UI — but this is optional
  • You can showcase your work by:
    • Writing and running test scripts
    • Including deployment links
    • Explaining your logic and user flow clearly in the README.md

Resources

Raydium Program Library

Back to Videos