Skip to main content

How Solana Differs from EVM

If you’re coming from Ethereum/Solidity, Solana’s programming model is fundamentally different:
ConceptEVM (Ethereum)Solana
Smart contractsContracts store their own statePrograms are stateless; data lives in separate accounts
LanguageSolidityRust (via Anchor framework)
ExecutionSequentialParallel (accounts declared upfront)
FeesGas (variable, can be expensive)Fixed low fees (~$0.00025 per tx)
Finality~12 seconds (Ethereum L1)~400ms
Token standardERC-20SPL Token
Local devAnvil / Hardhatsolana-test-validator
The key mental shift: on Solana, programs don’t own data. Every piece of state is an “account” that programs read from and write to. You declare which accounts each instruction needs upfront, which is how Solana achieves parallel execution.

Anchor Framework

Anchor is to Solana what Hardhat/Foundry is to Ethereum — a higher-level framework that handles the boilerplate. Most production Solana apps use Anchor. Anchor gives you:
  • Automatic account serialization/deserialization
  • Declarative account validation (constraints)
  • IDL generation (like ABI for Solana)
  • TypeScript client generation
  • Built-in testing framework

Project Structure

An Anchor project looks like this:
my-solana-project/
├── Anchor.toml           # Project config
├── Cargo.toml            # Rust workspace config
├── programs/
│   └── my_program/
│       ├── Cargo.toml    # Program dependencies
│       └── src/
│           └── lib.rs    # Program code
├── tests/                # TypeScript tests
│   └── my_program.ts
└── target/
    └── deploy/
        └── my_program.so # Compiled binary
Create a project:
"Create a Solana program that stores a counter with increment and decrement"

Setting Up the Toolchain

First time only — install Rust, Solana CLI, and Anchor:
"Install the Anchor toolchain"
This takes 5-10 minutes. It installs:
  • Rust (stable toolchain)
  • Solana CLI v2.3.0
  • Anchor v0.32.0
You only need to do this once per machine.

Writing an Anchor Program

Here’s a minimal counter program:
use anchor_lang::prelude::*;

declare_id!("11111111111111111111111111111111");

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

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        counter.count = 0;
        Ok(())
    }

    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        counter.count += 1;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 8 + 8)]
    pub counter: Account<'info, Counter>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut)]
    pub counter: Account<'info, Counter>,
}

#[account]
pub struct Counter {
    pub count: u64,
}
Key concepts:
  • #[program] — defines your instruction handlers
  • #[derive(Accounts)] — declares which accounts each instruction needs
  • #[account] — defines the data schema for an account
  • Context<T> — provides access to the validated accounts

Important Version Constraints

Always use these exact versions in your Cargo.toml:
[dependencies]
anchor-lang = "0.32.0"
anchor-spl = "0.32.0"  # if you need SPL token support
solana-program = "2.1"  # never use 2.2+

[features]
idl-build = ["anchor-lang/idl-build"]
Use edition = "2021" in your Cargo.toml (not 2024 — Solana’s platform tools don’t support it yet).

Compiling

"Compile my Anchor program"
This produces:
  • .so binary — the compiled program for deployment
  • IDL file — describes your program’s interface (like an ABI)
  • TypeScript types — generated from the IDL for client code
If compilation fails, the AI shows Rust compiler errors and suggests fixes. Common issues:
  • Type mismatches
  • Missing trait implementations
  • Account constraint violations
  • Wrong dependency versions

Local Development

Start a Local Validator

"Start a local Solana node"
This runs solana-test-validator at http://127.0.0.1:8899. You get:
  • Instant transaction finality
  • Unlimited SOL airdrops
  • Clean state (resets when stopped)
  • No rate limits

Fund Your Wallet

"Fund my wallet with 1000 SOL on local"
On local, there are no airdrop limits. On public devnet/testnet, airdrops are rate-limited to 1-2 SOL at a time.

Deploying Programs

To Local

"Deploy my Solana program to local"
The AI takes the compiled .so file and deploys it. You get back the program ID (the on-chain address of your program).

To Devnet/Testnet

"Switch to Solana testnet and deploy"
Make sure you have SOL on that network. Use airdrops on devnet/testnet:
"Airdrop 2 SOL on testnet"

To Mainnet

"Deploy to Solana mainnet"
Mainnet deployment costs real SOL. The amount depends on your program’s compiled size (rent for storage). Verify everything on devnet first.

Program Upgrades

By default, the deployer retains upgrade authority — you can deploy new versions to the same program address. You can:
  • Upgrade the program later with new code
  • Transfer upgrade authority to a multisig
  • Revoke upgrade authority to make it immutable

SPL Token Operations

SPL tokens are Solana’s equivalent of ERC-20. Manage them through chat:

Create a Token

"Create a new SPL token"

Mint Tokens

"Mint 1000 tokens to my address"

Transfer Tokens

"Transfer 50 tokens to [address]"

Check Balance

"Check my SPL token balance for mint [address]"
SPL tokens require “associated token accounts” — these are created automatically when needed.

Program Derived Addresses (PDAs)

PDAs are deterministic addresses derived from a program ID and seeds. They’re fundamental to Solana development:
#[derive(Accounts)]
pub struct CreateVault<'info> {
    #[account(
        init,
        payer = user,
        space = 8 + 32 + 8,
        seeds = [b"vault", user.key().as_ref()],
        bump
    )]
    pub vault: Account<'info, Vault>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}
Common uses:
  • Program-controlled token accounts (programs can “sign” for PDAs)
  • Deterministic data accounts (predictable addresses based on user + seed)
  • Cross-program invocation authority

Solidity on Solana (Solang)

If you prefer Solidity over Rust, you can compile Solidity for Solana using Solang:
"Compile this Solidity contract for Solana"
Key differences from EVM Solidity:
  • Account management requires explicit annotations
  • Storage works differently (data lives in accounts, not contract storage)
  • Not all Solidity features are available
  • Different gas/compute model
This is useful for EVM developers transitioning to Solana, but Anchor/Rust is the standard for production Solana apps.

Workflow Summary

1

Install Toolchain (Once)

"Install the Anchor toolchain"
2

Create Project

"Create a Solana program that does X"
3

Write Program Logic

Define instructions, accounts, and data structures in Rust.
4

Compile

"Compile my Anchor program"
5

Start Local Validator

"Start a local Solana node"
6

Fund Wallet

"Fund my wallet with 1000 SOL"
7

Deploy

"Deploy my program"
8

Interact

"Call the increment instruction"
9

Deploy to Testnet/Mainnet

"Switch to testnet and deploy"

Troubleshooting

Use edition = "2021" in Cargo.toml and solana-program = "2.1" (not 2.2+). Solana’s platform tools don’t support Rust edition 2024 yet.
Check: wallet connected, sufficient SOL for rent, correct network selected, .so file exists in target/deploy/.
On public devnet/testnet, wait a few minutes between requests. Request 1-2 SOL at a time. On local, there are no limits.
Use exactly: anchor-lang = "0.32.0", solana-program = "2.1", edition = "2021". Don’t add unnecessary solana-* crates.