β˜€οΈSVM (Solana)

This guide shows how to claim onchain token rewards from the Fuul protocol on Solana using the @fuul/sdk-solana package. The flow is: get claim checks from the API, initialize the Solana SDK, build claim instructions, and submit the transaction.

circle-info

Before following this guide, make sure you've fetched your claim checks using @fuul/sdk.

Prerequisites

Requirement
Version
Notes

Node.js

>= 18

Required for native crypto support

TypeScript

>= 5.0

Strict mode recommended

@solana/web3.js

^1.95.0

Peer dependency

@coral-xyz/anchor

^0.30.0

Peer dependency

Wallet adapter

Any

@solana/wallet-adapter-react recommended

npm install @fuul/sdk-solana @solana/web3.js @coral-xyz/anchor

1. Configure bundler (Next.js)

The SDK uses Node.js Buffer API. Configure webpack to provide it in the browser.

// next.config.ts
import type { NextConfig } from 'next';
const webpack = require('webpack');

const nextConfig: NextConfig = {
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.resolve.fallback = {
        ...config.resolve.fallback,
        fs: false,
        net: false,
        tls: false,
        buffer: require.resolve('buffer/'),
      };
      config.plugins.push(
        new webpack.ProvidePlugin({
          Buffer: ['buffer', 'Buffer'],
        })
      );
    }
    return config;
  },
};

export default nextConfig;
circle-info

You also need to install the buffer package: npm install buffer.

2. Initialize the SDK

circle-exclamation

3. Fetch on-chain data

Before building a claim, fetch the project nonce and authorized signer from the chain:

4. Build claim instructions

Construct the claim message from the API response and get transaction instructions from the SDK:

circle-info

The SDK resolves Associated Token Accounts (ATAs), PDA addresses, compute budget, and account metas internally. Do not create ATAs manually β€” this causes IllegalOwner errors.

5. Execute the transaction

6. Complete Next.js example

Key types

What the SDK handles internally

Do not pass these manually β€” the SDK derives them:

What
How the SDK derives it

Program ID

From Network enum via internal IDL mapping

Associated Token Accounts

Created inside sdk.claim() if needed

PDA addresses

Derived from seeds (project, config, etc.)

Global config address

Derived from program ID

Compute budget

Determined by SDK

Account metas

Built from instruction requirements

Troubleshooting

Symptom
Cause
Fix

Buffer is not defined

Missing polyfill in browser

Add webpack ProvidePlugin for Buffer

IllegalOwner

Manual ATA creation when SDK handles it

Remove manual createAssociatedTokenAccountInstruction

Account does not exist

Network mismatch (devnet vs mainnet)

Ensure Network enum matches your RPC endpoint

Invalid program id

Hardcoded program ID

Use sdk.getProgram().programId

Signature verification failed

Wrong signer or corrupted signature bytes

Use signer from sdk.getGlobalConfig(), verify signature encoding

window is not defined

Importing SDK in server component

Add 'use client' directive or dynamic import with ssr: false

Blockhash not found

Wrong commitment level

Use 'confirmed' for both connection and transaction

ConstraintSeeds

Wrong PDA derivation

Let SDK derive PDAs β€” don't calculate manually

circle-exclamation

Last updated