Introduction
Solana stands out as one of the fastest blockchain networks, capable of processing 65,000 transactions per second. Its unique proof-of-history consensus mechanism enables incredible speed while maintaining decentralization.
This comprehensive guide teaches you Solana development from scratch. You’ll learn to build smart contracts with Rust, create dApps, and deploy to Solana’s mainnet.
Why Solana?
Advantages
| Feature | Solana | Ethereum |
|---|---|---|
| TPS | 65,000 | 15-30 |
| Block Time | 400ms | 12-14s |
| Avg Cost | $0.001 | $1-50 |
| Finality | ~400ms | ~15min |
Use Cases
- DeFi protocols
- NFT marketplaces
- Gaming dApps
- Payment systems
- Decentralized exchanges
Setting Up Development
Installation
# Install Solana CLI
sh -c "$(curl -sSfL https://release.solana.com/v1.18.0/install)"
# Add to PATH
export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH"
# Verify installation
solana --version
# Configure devnet
solana config set --url devnet
Development Environment
# Install Anchor (Solana framework)
cargo install --git https://github.com/coral-xyz/anchor avm --locked
avm install latest
avm use latest
# Initialize project
anchor init my-solana-project
cd my-solana-project
Rust for Solana
Basic Program Structure
use anchor_lang::prelude::*;
declare_id!("YourProgramIDHere");
#[program]
pub mod my_program {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let account = &mut ctx.accounts.my_account;
account.data = 0;
msg!("Initialized with data: {}", account.data);
Ok(())
}
pub fn update(ctx: Context<Update>, new_data: u64) -> Result<()> {
let account = &mut ctx.accounts.my_account;
account.data = new_data;
msg!("Updated to: {}", new_data);
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = user, space = 8 + MyAccount::INIT_SPACE)]
pub my_account: Account<'info, MyAccount>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Update<'info> {
#[account(mut)]
pub my_account: Account<'info, MyAccount>,
}
#[account]
#[derive(InitSpace)]
pub struct MyAccount {
pub data: u64,
}
Common Instructions
// Initialize account
#[account(init, payer = user, space = 8 + 32)]
pub new_account: Account<'info, NewAccount>,
// Mutable account
#[account(mut)]
pub account: Account<'info, MyAccount>,
// Seeds for PDA
#[account(
seeds = [b"seed", user.key().as_ref()],
bump
)]
pub pda: Account<'info, PDA>,
// Token account
#[account(
mint::token_id = mint.key(),
authority = user.key()
)]
pub token_account: Account<'info, TokenAccount>,
Anchor Framework
Project Structure
my-project/
โโโ programs/
โ โโโ my-program/
โ โโโ src/
โ โ โโโ lib.rs
โ โโโ Cargo.toml
โโโ tests/
โ โโโ my-program.ts
โโโ Anchor.toml
โโโ package.json
Writing Tests
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { MyProgram } from "../target/types/my_program";
import { assert } from "assert";
describe("my-program", () => {
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.MyProgram as Program<MyProgram>;
it("Initializes account", async () => {
const [pda] = anchor.web3.PublicKey.findProgramAddressSync(
[Buffer.from("seed")],
program.programId
);
await program.methods
.initialize()
.accounts({
myAccount: pda,
user: provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
})
.rpc();
const account = await program.account.myAccount.fetch(pda);
assert.equal(account.data.toNumber(), 0);
});
it("Updates account", async () => {
const [pda] = anchor.web3.PublicKey.findProgramAddressSync(
[Buffer.from("seed")],
program.programId
);
await program.methods
.update(new anchor.BN(42))
.accounts({
myAccount: pda,
})
.rpc();
const account = await program.account.myAccount.fetch(pda);
assert.equal(account.data.toNumber(), 42);
});
});
Building dApps
Frontend Integration
import { Connection, PublicKey, Program, Provider } from "@coral-xyz/anchor";
import { useAnchorWallet } from "@solana/wallet-adapter-react";
// Connect to program
const connection = new Connection("https://api.devnet.solana.com");
const programId = new PublicKey("YourProgramID");
// Create program instance
const program = new Program(idl, programId, provider);
// Fetch account data
const [pda] = PublicKey.findProgramAddressSync(
[Buffer.from("seed")],
program.programId
);
const account = await program.account.myAccount.fetch(pda);
console.log("Data:", account.data.toNumber());
// Send transaction
await program.methods
.update(new anchor.BN(100))
.accounts({
myAccount: pda,
})
.rpc();
Wallet Connection
import { WalletMultiButton } from "@solana/wallet-adapter-react-ui";
import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react";
import { PhantomWalletAdapter } from "@solana/wallet-adapter-phantom";
function App() {
const wallets = [new PhantomWalletAdapter()];
return (
<ConnectionProvider endpoint="https://api.devnet.solana.com">
<WalletProvider wallets={wallets}>
<WalletMultiButton />
<YourApp />
</WalletProvider>
</ConnectionProvider>
);
}
NFT Development
Minting NFTs
use anchor_lang::prelude::*;
use anchor_spl::token::{self, Mint, TokenAccount, Token};
use mpl_token_metadata::state::DataV2;
#[program]
pub mod nft_minting {
pub fn mint_nft(
ctx: Context<MintNFT>,
creator_key: Pubkey,
uri: String,
title: String,
symbol: String,
) -> Result<()> {
// Create mint account
let cpi_ctx = CpiContext::new(
ctx.accounts.token_program.to_account_info(),
token::InitializeMint {
mint: ctx.accounts.mint.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
},
);
token::initialize_mint(
cpi_ctx,
0,
&ctx.accounts.mint.key(),
Some(&ctx.accounts.mint.key()),
)?;
// Create metadata
let metadata_seeds = &[
b"metadata",
ctx.accounts.metadata_program.as_ref(),
ctx.accounts.mint.as_ref().key.as_ref(),
];
let (metadata, _) = Pubkey::find_program_address(
metadata_seeds,
&ctx.accounts.metadata_program.key(),
);
// Create master edition
// ... (additional instructions)
Ok(())
}
}
DeFi Development
Token Swap
// Simple token swap program
#[program]
pub mod token_swap {
pub fn swap(
ctx: Context<Swap>,
amount_in: u64,
min_amount_out: u64,
) -> Result<()> {
// Get exchange rate from oracle
let rate = ctx.accounts.oracle.get_price();
let amount_out = (amount_in as f64 * rate) as u64;
require!(amount_out >= min_amount_out, SwapError::SlippageExceeded);
// Transfer input tokens
token::transfer(
CpiContext::new(
ctx.accounts.token_program.clone(),
token::Transfer {
from: ctx.accounts.from_token_account.to_account_info(),
to: ctx.accounts.swap_token_account.to_account_info(),
authority: ctx.accounts.user.to_account_info(),
},
),
amount_in,
)?;
// Transfer output tokens
// ...
Ok(())
}
}
Best Practices
Security
// Always validate accounts
#[derive(Accounts)]
pub struct SecureInstruction<'info> {
#[account(address = expected_program::ID)]
pub expected_program: Program<'info, ExpectedProgram>,
#[account(
seeds = [b"authority", user.key().as_ref()],
bump = expected_bump
)]
pub authority: Account<'info, Authority>,
// Check token ownership
#[account(
constraint = token_account.owner == user.key() @ ErrorCode::Unauthorized
)]
pub token_account: Account<'info, TokenAccount>,
}
// Use require! for validation
require!(amount > 0, ErrorCode::InvalidAmount);
require!(clock.unix_timestamp() > sale_end, ErrorCode::SaleNotEnded);
Optimization
// Use zero-copy for large data
#[account(zero_copy)]
pub struct LargeData {
pub items: [Item; 1000],
}
// Batch multiple instructions
let tx = new Transaction()
.add(instruction1)
.add(instruction2)
.add(instruction3);
Deployment
Build and Deploy
# Build program
anchor build
# Deploy to devnet
anchor deploy --provider.cluster devnet
# Deploy to mainnet
anchor deploy --provider.cluster mainnet
Verify Deployment
# Verify program on Solana Explorer
solana program show <PROGRAM_ID>
# Check program size
solana program show <PROGRAM_ID> --programs
External Resources
Documentation
Tools
Communities
Conclusion
Solana offers incredible performance for building high-throughput dApps. With Anchor framework, developing smart contracts is more accessible than ever.
Key takeaways:
- Start with Anchor - Simplifies development significantly
- Learn Rust - Essential for Solana development
- Use devnet first - Test extensively before mainnet
- Follow security best practices - Smart contract security is critical
- Join the community - Solana has active developers
Comments