Solana programs Cheat Sheet

Solana programs Cheat Sheet

This cheat sheet is your go-to guide for building Solana programs with Anchor. It covers the essentials, explains why things work, and shares practical tips for real-world projects like voting systems, token airdrops, or NFT minting.


Set Up Your Project

bash

anchor init my_project
cd my_project
anchor build
anchor test
  • anchor init: Creates a new project with all the files you need.
  • anchor build: Turns your Rust code into Solana-compatible bytecode.
  • anchor test: Runs tests to make sure your program works.

Why use this? It’s the fastest way to start a Solana project with Anchor’s tools.


Here’s what’s inside your project folder:

Folder/FileWhat It Does
programs/Your Rust smart contract code lives here.
tests/JavaScript tests to check your program.
migrations/Scripts to deploy your program.
target/Where compiled code goes.
Anchor.tomlConfig file for your project settings.
Cargo.tomlManages Rust dependencies.

Tip: Keep Anchor.toml updated with your wallet and Solana network (e.g., devnet).


Program Basics

rust

#[program]
pub mod my_program {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
        let my_account = &mut ctx.accounts.my_account;
        my_account.data = data;
        Ok(())
    }
}
  • #[program]: Tells Anchor this is your main smart contract.
  • ctx.accounts: Anchor passes in the accounts you’ll work with.
  • Result<()>: Anchor’s way of handling errors (like “success” or “fail”).

Why? This is the core of your program where you define what it does.


Define an Account

rust

#[account]
pub struct MyAccount {
    pub data: u64,
}

Set Up Account Access

rust

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 8 + 8)]
    pub my_account: Account<'info, MyAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}
  • #[account]: Defines what data your account holds (like a database table).
  • #[derive(Accounts)]: Ensures the right accounts are passed to your function.
  • init: Creates a new account.
  • payer: Who pays for the account’s storage on Solana.
  • space: How much storage the account needs (8 bytes for Anchor’s metadata + your data).
  • mut: Marks an account as editable.
  • Signer: Checks if the account signed the transaction.

How to calculate space? Add 8 bytes (Anchor’s metadata) + the size of your fields (e.g., u64 = 8 bytes).

Use case: Store user info, voting records, or token balances.


To read or update an account:

rust

let account = &mut ctx.accounts.my_account;
account.data = 123;
  • Use &mut to change account data.
  • Anchor makes saving data to Solana easy.

Why? This is how you store and update info on the blockchain.


rust

#[error_code]
pub enum ErrorCode {
    #[msg("You’re not allowed to do that!")]
    Unauthorized,
}

rust

if !condition {
    return Err(error!(ErrorCode::Unauthorized));
}
  • Define custom errors with #[error_code].
  • Use them to stop execution and explain what went wrong.

Why? Clear errors make debugging easier for you and your users.


Here’s what you can store in accounts:

TypeWhat It’s For
u8, u64Numbers (small or large)
boolTrue or false
StringText (with a length prefix)
PubkeySolana addresses (like wallets)
Vec<T>Lists (e.g., list of voters)
BTreeSet<T>Sorted lists (great for unique IDs)

Tip: For lists, calculate space dynamically or set a max size to avoid issues.


Anchor uses Borsh to automatically save and load your account data. Just add #[account], and you’re good—no manual work needed!


rust

let clock = Clock::get()?;
let now = clock.unix_timestamp;
  • Use Clock::get() to get the current timestamp.
  • Add pub clock: Sysvar<‘info, Clock> to your context.

Use case: Perfect for voting deadlines, event timers, or expiration dates.


Restrict Access (e.g., Only Owner)

rust

if ctx.accounts.user.key() != ctx.accounts.my_account.owner {
    return Err(error!(ErrorCode::Unauthorized));
}
  • Compare public keys to ensure only the right person can act.

Why? Prevents random users from messing with your data.


To interact with another Solana program (like the Token program):

rust

let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_accounts = Transfer { ... };
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
token::transfer(cpi_ctx, amount)?;

Use case: Send tokens, mint NFTs, or interact with other Solana programs.


Write tests in JavaScript:

js

const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.MyProgram;
  • Use Anchor’s testing tools to simulate Solana and test your program.
  • Set up accounts, call functions, and check results.

Why? Catch bugs before deploying to the blockchain.


bash

anchor build
anchor deploy

Update Anchor.toml with your network and wallet:

toml

[provider]
cluster = "https://api.devnet.solana.com"
wallet = "~/.config/solana/id.json"

Tip: Test on devnet before going to mainnet—it’s free!


MacroWhat It Does
#[account]Defines data for accounts
#[program]Defines your program’s logic
#[derive(Accounts)]Checks accounts passed to functions
#[error_code]Creates custom error messages

  • Use Anchor: It simplifies Solana development.
  • Calculate space: Always know how much storage your accounts need.
  • Add clear errors: Helps you and users understand issues.
  • Break up logic: Use small, focused functions for clarity.
  • Use lists smartly: Vec<Pubkey> for whitelists or user lists.
  • Track time: Use timestamps for time-based features.

Solana front end in TypeScript

Hey there! I’m gonna walk you through setting up a Solana front end in TypeScript with wallet connection support for stuff like Phantom and Solflare. It’s a fun project, and I’ll keep it chill and straightforward with code and explanations. We’re using React with TypeScript, @solana/web3.js for Solana blockchain stuff, and @solana/wallet-adapter to handle wallet connections. Let’s dive in!

1. Get Your Tools Ready

First, you’ll need to install some packages to make this work. Run this in your terminal:

bash

npm install @solana/web3.js @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-wallets @solana/wallet-adapter-react-ui @solana/wallet-adapter-phantom @solana/wallet-adapter-solflare @solana/wallet-adapter-bitkeep @solana/wallet-adapter-tokenpocket

If you want a sleek UI, you can also add Tailwind CSS (totally optional, but it makes things look nice).


2. Set Up the Wallet Context

You need a way to connect your app to Solana and handle wallets like Phantom or Solflare. Create a file called WalletContextProvider.tsx to set this up.

tsx

// src/contexts/WalletContextProvider.tsx
import React, { FC, ReactNode, useMemo } from "react";
import {
  ConnectionProvider,
  WalletProvider,
} from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import {
  PhantomWalletAdapter,
  SolflareWalletAdapter,
  BitKeepWalletAdapter,
  TokenPocketWalletAdapter,
} from "@solana/wallet-adapter-wallets";
import { clusterApiUrl } from "@solana/web3.js";

// Default wallet modal styles (you can customize these later)
require("@solana/wallet-adapter-react-ui/styles.css");

interface Props {
  children: ReactNode;
}

const WalletContextProvider: FC<Props> = ({ children }) => {
  // Choose your Solana network: "devnet", "testnet", or "mainnet-beta"
  const network = "devnet";
  const endpoint = useMemo(() => clusterApiUrl(network), [network]);

  // Add the wallets you want to support
  const wallets = useMemo(
    () => [
      new PhantomWalletAdapter(),
      new SolflareWalletAdapter(),
      new BitKeepWalletAdapter(),
      new TokenPocketWalletAdapter(),
    ],
    []
  );

  return (
    <ConnectionProvider endpoint={endpoint}>
      <WalletProvider wallets={wallets} autoConnect>
        <WalletModalProvider>{children}</WalletModalProvider>
      </WalletProvider>
    </ConnectionProvider>
  );
};

export default WalletContextProvider;

This file sets up the connection to Solana and lets users pick their wallet.


3. Wrap Your App

Now, wrap your main app with the WalletContextProvider so it knows about the Solana connection and wallets. Update your main.tsx (or index.tsx).

tsx

// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import WalletContextProvider from "./contexts/WalletContextProvider";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <WalletContextProvider>
      <App />
    </WalletContextProvider>
  </React.StrictMode>
);

This makes sure your app is ready to talk to Solana and handle wallet stuff.


4. Build the Wallet Connection UI

Let’s create the main app component to let users connect their wallet and do something cool, like request a devnet airdrop. Here’s the code for App.tsx:

tsx

// src/App.tsx
import React from "react";
import { useWallet, useConnection } from "@solana/wallet-adapter-react";
import { WalletMultiButton } from "@solana/wallet-adapter-react-ui";
import { PublicKey } from "@solana/web3.js";

const App: React.FC = () => {
  const { connection } = useConnection();
  const { publicKey, sendTransaction } = useWallet();

  // Function to request a 1 SOL airdrop on devnet
  const handleAirdrop = async () => {
    if (!publicKey) return;
    try {
      const sig = await connection.requestAirdrop(publicKey, 1e9); // 1 SOL = 1 billion lamports
      await connection.confirmTransaction(sig, "confirmed");
      alert("Airdrop worked! You got 1 SOL!");
    } catch (e) {
      console.error("Airdrop failed:", e);
      alert("Oops, something went wrong with the airdrop.");
    }
  };

  return (
    <div className="min-h-screen flex flex-col items-center justify-center gap-4 bg-gray-900 text-white">
      <h1 className="text-3xl font-bold">Solana Wallet Connect (TypeScript)</h1>
      <WalletMultiButton />
      {publicKey && (
        <div>
          <p>Wallet Address: {publicKey.toBase58()}</p>
          <button
            className="mt-4 px-4 py-2 bg-blue-600 rounded"
            onClick={handleAirdrop}
          >
            Airdrop 1 SOL
          </button>
        </div>
      )}
    </div>
  );
};

export default App;

This creates a simple page with a “Connect Wallet” button and, once connected, shows the wallet address and a button to request a 1 SOL airdrop (works only on devnet).


Here’s the breakdown of the key pieces:

  • WalletContextProvider: This sets up the connection to Solana and lets you use wallets like Phantom or Solflare.
  • ConnectionProvider: Hooks your app up to a Solana network (like devnet or mainnet).
  • WalletProvider: Manages the wallets you want to support.
  • WalletMultiButton: A handy button that lets users connect or disconnect their wallet.
  • useWallet: Gives you access to the wallet’s details, like the public key.
  • useConnection: Lets you interact with the Solana blockchain, like requesting airdrops.

You can support a bunch of wallets with @solana/wallet-adapter-wallets. Some popular ones are:

  • Phantom
  • Solflare
  • BitKeep
  • TokenPocket
  • Glow
  • Backpack

Just import the wallet adapters you want and add them to the wallets array in WalletContextProvider.


On devnet, you can get free SOL for testing using requestAirdrop. This won’t work on mainnet, where you’d need to buy SOL or use a faucet. Perfect for playing around while developing!


If you’re using TypeScript, make sure you’ve got the right types for React:

bash

npm install -D @types/react @types/react-dom

That’s it! You’ve got a Solana front end with wallet support ready to go. Fire it up, connect your wallet, and try the airdrop button on devnet

Comments

No comments yet. Why don’t you start the discussion?

    Leave a Reply

    Your email address will not be published. Required fields are marked *