Примеры Разработки Solana

Комплексные примеры разработки блокчейна Solana включая умные контракты на Rust с Anchor, высокопроизводительные программы, разработку NFT и развертывание программ

💻 Базовая Программа на Anchor rust

🟡 intermediate ⭐⭐⭐⭐

Введение в разработку Solana с фреймворком Anchor, создание простого умного контракта с базовой функциональностью

⏱️ 35 min 🏷️ anchor, solana, rust, smart-contract
Prerequisites: Rust programming, Solana basics, Anchor framework
// Anchor Framework Basic Program
// Cargo.toml dependencies:
// anchor-lang = "0.29.0"
// anchor-spl = "0.29.0"

use anchor_lang::prelude::*;
use anchor_spl::token::{self, Token, TokenAccount, Mint, Transfer};

declare_id!("11111111111111111111111111111111");

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

    /// Initialize the program
    pub fn initialize(ctx: Context<Initialize>, authority: Pubkey) -> Result<()> {
        let config = &mut ctx.accounts.config;
        config.authority = authority;
        config.counter = 0;
        config.is_initialized = true;

        msg!("Program initialized by authority: {}", authority);
        Ok(())
    }

    /// Increment counter
    pub fn increment_counter(ctx: Context<IncrementCounter>) -> Result<()> {
        let config = &mut ctx.accounts.config;
        config.counter += 1;

        msg!("Counter incremented to: {}", config.counter);
        Ok(())
    }

    /// Create a new token mint
    pub fn create_token_mint(
        ctx: Context<CreateTokenMint>,
        decimals: u8,
        name: String,
        symbol: String,
    ) -> Result<()> {
        let cpi_accounts = token::InitializeMint {
            mint: ctx.accounts.mint.to_account_info(),
            rent: ctx.accounts.rent.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);

        token::initialize_mint(cpi_ctx, decimals, &ctx.accounts.authority.key(), None)?;

        // Store metadata (simplified example)
        let metadata = &mut ctx.accounts.metadata;
        metadata.name = name;
        metadata.symbol = symbol;
        metadata.decimals = decimals;
        metadata.mint = ctx.accounts.mint.key();

        msg!("Token created: {} ({})", metadata.name, metadata.symbol);
        Ok(())
    }

    /// Mint tokens to an account
    pub fn mint_tokens(
        ctx: Context<MintTokens>,
        amount: u64,
    ) -> Result<()> {
        let cpi_accounts = token::MintTo {
            mint: ctx.accounts.mint.to_account_info(),
            to: ctx.accounts.token_account.to_account_info(),
            authority: ctx.accounts.authority.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_ctx = CpiContext::new_with_signer(
            cpi_program,
            cpi_accounts,
            &[&[&ctx.bumps.mint_authority, &[]]],
        );

        token::mint_to(cpi_ctx, amount)?;

        msg!("Minted {} tokens", amount);
        Ok(())
    }

    /// Transfer tokens between accounts
    pub fn transfer_tokens(
        ctx: Context<TransferTokens>,
        amount: u64,
    ) -> Result<()> {
        let cpi_accounts = Transfer {
            from: ctx.accounts.from.to_account_info(),
            to: ctx.accounts.to.to_account_info(),
            authority: ctx.accounts.authority.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);

        token::transfer(cpi_ctx, amount)?;

        msg!("Transferred {} tokens", amount);
        Ok(())
    }
}

// Account structures
#[account]
pub struct Config {
    pub authority: Pubkey,
    pub counter: u64,
    pub is_initialized: bool,
}

#[account]
pub struct TokenMetadata {
    pub name: String,
    pub symbol: String,
    pub decimals: u8,
    pub mint: Pubkey,
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(
        init,
        payer = payer,
        space = 8 + 32 + 8 + 1 // discriminator + authority + counter + is_initialized
    )]
    pub config: Account<'info, Config>,

    #[account(mut)]
    pub payer: Signer<'info>,

    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct IncrementCounter<'info> {
    #[account(mut)]
    pub config: Account<'info, Config>,
    pub authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct CreateTokenMint<'info> {
    #[account(
        init,
        payer = payer,
        mint::decimals = 0,
        mint::authority = mint_authority,
    )]
    pub mint: Account<'info, Mint>,

    #[account(
        init,
        payer = payer,
        space = 8 + 64 + 8 + 8 + 32 // discriminator + name + symbol + decimals + mint
    )]
    pub metadata: Account<'info, TokenMetadata>,

    /// CHECK: This is the mint authority PDA
    #[account(seeds = [b"mint_authority"], bump)]
    pub mint_authority: UncheckedAccount<'info>,

    pub authority: Signer<'info>,
    #[account(mut)]
    pub payer: Signer<'info>,
    pub rent: Sysvar<'info, Rent>,
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, Token>,
}

#[derive(Accounts)]
pub struct MintTokens<'info> {
    #[account(mut)]
    pub mint: Account<'info, Mint>,

    #[account(
        init_if_needed,
        payer = payer,
        token::mint = mint,
        token::authority = authority,
    )]
    pub token_account: Account<'info, TokenAccount>,

    pub authority: Signer<'info>,
    #[account(mut)]
    pub payer: Signer<'info>,
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, Token>,
    pub rent: Sysvar<'info, Rent>,
}

#[derive(Accounts)]
pub struct TransferTokens<'info> {
    #[account(mut)]
    pub from: Account<'info, TokenAccount>,

    #[account(mut)]
    pub to: Account<'info, TokenAccount>,

    pub authority: Signer<'info>,
    pub token_program: Program<'info, Token>,
}

// Error handling
#[error_code]
pub enum ErrorCode {
    #[msg("Unauthorized access")]
    Unauthorized,
    #[msg("Invalid amount")]
    InvalidAmount,
    #[msg("Account already initialized")]
    AlreadyInitialized,
    #[msg("Account not initialized")]
    NotInitialized,
}

💻 Развертывание и Тестирование Программ Solana bash

🟡 intermediate ⭐⭐⭐

Полное руководство по развертыванию, тестированию и управлению программами Solana с инструментами CLI и скриптами автоматизации

⏱️ 20 min 🏷️ deployment, solana, anchor, automation
Prerequisites: Solana CLI, Anchor framework, Linux/Unix shell
#!/bin/bash
# Solana Program Deployment Script
# Simplified deployment automation for Solana programs

set -e

# Configuration variables
PROGRAM_NAME="my_program"
NETWORK="devnet"  # Options: devnet, testnet, mainnet-beta
KEYPAIR_PATH="./deploy-keypair.json"

# Color output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'

# Simple logging function
log() {
    echo -e "${GREEN}=> $1${NC}"
}

warn() {
    echo -e "${YELLOW}=> WARNING: $1${NC}"
}

error() {
    echo -e "${RED}=> ERROR: $1${NC}"
    exit 1
}

# Check if required tools are installed
check_tools() {
    log "Checking required tools..."

    command -v solana >/dev/null 2>&1 || error "Solana CLI not installed"
    command -v anchor >/dev/null 2>&1 || error "Anchor CLI not installed"
    command -v cargo >/dev/null 2>&1 || error "Rust/Cargo not installed"

    log "All required tools found"
}

# Setup Solana environment
setup_environment() {
    log "Setting up Solana environment..."

    # Set network
    case "${NETWORK}" in
        "devnet")
            solana config set --url devnet
            ;;
        "testnet")
            solana config set --url testnet
            ;;
        "mainnet-beta")
            solana config set --url mainnet-beta
            ;;
    esac

    log "Network set to: ${NETWORK}"
}

# Generate keypair if needed
setup_keypair() {
    if [[ ! -f "${KEYPAIR_PATH}" ]]; then
        log "Generating new keypair..."
        solana-keygen new --outfile "${KEYPAIR_PATH}" --no-bip39-passphrase
    fi

    # Show balance
    local balance=$(solana balance --keypair "${KEYPAIR_PATH}" | grep -o '[0-9.]*' | head -1)
    log "Current balance: ${balance} SOL"

    # Request airdrop on devnet/testnet if needed
    if [[ "${NETWORK}" != "mainnet-beta" ]] && (( $(echo "${balance} < 1" | bc -l) )); then
        log "Requesting airdrop..."
        solana airdrop 2 --keypair "${KEYPAIR_PATH}"
    fi
}

# Build the program
build_program() {
    log "Building ${PROGRAM_NAME}..."

    if [[ ! -f "Anchor.toml" ]]; then
        error "Anchor.toml not found"
    fi

    # Build with Anchor
    anchor build

    if [[ $? -eq 0 ]]; then
        log "Build successful!"

        # Get program ID
        local program_id=$(solana address -k target/deploy/${PROGRAM_NAME}-keypair.json)
        log "Program ID: ${program_id}"

        # Check if program ID needs updating in lib.rs
        if [[ -f "programs/${PROGRAM_NAME}/src/lib.rs" ]]; then
            local current_id=$(grep "declare_id!" "programs/${PROGRAM_NAME}/src/lib.rs" | grep -o '"[^"]*"' | tr -d '"')
            if [[ "${current_id}" != "${program_id}" ]]; then
                log "Updating program ID in lib.rs..."
                sed -i "s/${current_id}/${program_id}/g" "programs/${PROGRAM_NAME}/src/lib.rs"
                anchor build  # Rebuild with correct ID
            fi
        fi
    else
        error "Build failed"
    fi
}

# Deploy program to network
deploy_program() {
    log "Deploying to ${NETWORK}..."

    # Check program size
    local size_bytes=$(stat -c%s "target/deploy/${PROGRAM_NAME}.so" 2>/dev/null || echo "0")
    local max_size=1232832

    if [[ "${size_bytes}" -gt "${max_size}" ]]; then
        warn "Program size (${size_bytes} bytes) exceeds recommended maximum"
    fi

    # Confirm mainnet deployment
    if [[ "${NETWORK}" == "mainnet-beta" ]]; then
        echo "You are about to deploy to mainnet-beta. Continue? [y/N]"
        read -r confirm
        if [[ "${confirm}" != "y" && "${confirm}" != "Y" ]]; then
            log "Deployment cancelled"
            exit 0
        fi
    fi

    # Deploy
    anchor deploy --provider.cluster "${NETWORK}"

    if [[ $? -eq 0 ]]; then
        local program_id=$(solana address -k target/deploy/${PROGRAM_NAME}-keypair.json)
        log "Successfully deployed: ${program_id}"
    else
        error "Deployment failed"
    fi
}

# Test program on devnet
test_program() {
    if [[ "${NETWORK}" != "devnet" ]]; then
        warn "Testing is only available on devnet"
        return
    fi

    log "Testing program..."

    # Run Anchor tests
    anchor test --skip-local-validator

    if [[ $? -eq 0 ]]; then
        log "All tests passed!"
    else
        warn "Some tests failed"
    fi
}

# Show program information
show_info() {
    log "Program Information:"
    echo "Name: ${PROGRAM_NAME}"
    echo "Network: ${NETWORK}"
    echo "KeyPair: ${KEYPAIR_PATH}"

    if [[ -f "target/deploy/${PROGRAM_NAME}-keypair.json" ]]; then
        local program_id=$(solana address -k target/deploy/${PROGRAM_NAME}-keypair.json)
        echo "Program ID: ${program_id}"

        # Check if deployed
        if solana program show "${program_id}" >/dev/null 2>&1; then
            echo "Status: Deployed"
        else
            echo "Status: Not deployed"
        fi
    fi
}

# Main function
main() {
    echo "Solana Program Deployment Script"
    echo "================================"
    echo ""

    case "${1:-deploy}" in
        "setup")
            check_tools
            setup_environment
            setup_keypair
            ;;
        "build")
            build_program
            ;;
        "deploy")
            check_tools
            setup_environment
            setup_keypair
            build_program
            deploy_program
            ;;
        "test")
            test_program
            ;;
        "info")
            show_info
            ;;
        "all")
            check_tools
            setup_environment
            setup_keypair
            build_program
            deploy_program
            test_program
            ;;
        "help"|"-h"|"--help")
            echo "Usage: $0 [COMMAND]"
            echo ""
            echo "Commands:"
            echo "  setup   - Check tools and setup environment"
            echo "  build   - Build the program"
            echo "  deploy  - Deploy to network"
            echo "  test    - Run tests (devnet only)"
            echo "  info    - Show program information"
            echo "  all     - Run setup, build, deploy, and test"
            echo "  help    - Show this help"
            echo ""
            echo "Environment variables:"
            echo "  NETWORK    - Solana network (devnet, testnet, mainnet-beta)"
            echo "  PROGRAM_NAME - Program directory name"
            ;;
        *)
            error "Unknown command: ${1}"
            ;;
    esac
}

# Run main function with all arguments
main "$@

💻 Программа NFT Solana с Metaplex rust

🔴 complex ⭐⭐⭐⭐⭐

Полная реализация NFT на Solana используя стандарт Metaplex, включая обработку метаданных и управление роялти

⏱️ 45 min 🏷️ nft, solana, metaplex, digital-collectibles
Prerequisites: Rust, Anchor framework, Metaplex standard, Solana programming
// Solana NFT Program with Metaplex Standard
// Cargo.toml dependencies:
// anchor-lang = "0.29.0"
// anchor-spl = "0.29.0"
// mpl-token-metadata = "3.0.0"

use anchor_lang::prelude::*;
use anchor_spl::{
    token::{self, Mint, Token, TokenAccount, Transfer, InitializeMint},
    associated_token::AssociatedToken,
};
use mpl_token_metadata::{
    instruction::{
        create_master_edition_v3,
        create_metadata_accounts_v3,
        mint_new_edition_from_master_edition_via_token,
    },
    state::{Metadata, MasterEditionV2, CollectionDetails, Key},
};

declare_id!("YOUR_PROGRAM_ID_HERE");

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

    /// Create a new NFT collection
    pub fn create_collection(
        ctx: Context<CreateCollection>,
        name: String,
        symbol: String,
        uri: String,
    ) -> Result<()> {
        let metadata_infos = vec![
            ctx.accounts.metadata.to_account_info(),
            ctx.accounts.mint.to_account_info(),
            ctx.accounts.authority.to_account_info(),
            ctx.accounts.authority.to_account_info(),
            ctx.accounts.payer.to_account_info(),
            ctx.accounts.token_metadata_program.to_account_info(),
            ctx.accounts.token_program.to_account_info(),
            ctx.accounts.system_program.to_account_info(),
            ctx.accounts.rent.to_account_info(),
        ];

        let collection_details = Some(CollectionDetails::V1 { size: 0 });

        create_metadata_accounts_v3(
            CpiContext::new(
                ctx.accounts.token_metadata_program.to_account_info(),
                CreateMetadataAccountsV3 {
                    metadata: ctx.accounts.metadata.to_account_info(),
                    mint: ctx.accounts.mint.to_account_info(),
                    mint_authority: ctx.accounts.authority.to_account_info(),
                    update_authority: ctx.accounts.authority.to_account_info(),
                    payer: ctx.accounts.payer.to_account_info(),
                    system_program: ctx.accounts.system_program.to_account_info(),
                    rent: ctx.accounts.rent.to_account_info(),
                },
            ),
            name,
            symbol,
            uri,
            None,
            0,
            true,
            collection_details,
            None,
        )?;

        let master_edition_infos = vec![
            ctx.accounts.master_edition.to_account_info(),
            ctx.accounts.mint.to_account_info(),
            ctx.accounts.authority.to_account_info(),
            ctx.accounts.authority.to_account_info(),
            ctx.accounts.authority.to_account_info(),
            ctx.accounts.payer.to_account_info(),
            ctx.accounts.token_metadata_program.to_account_info(),
            ctx.accounts.system_program.to_account_info(),
            ctx.accounts.rent.to_account_info(),
        ];

        create_master_edition_v3(
            CpiContext::new(
                ctx.accounts.token_metadata_program.to_account_info(),
                CreateMasterEditionV3 {
                    edition: ctx.accounts.master_edition.to_account_info(),
                    mint: ctx.accounts.mint.to_account_info(),
                    update_authority: ctx.accounts.authority.to_account_info(),
                    mint_authority: ctx.accounts.authority.to_account_info(),
                    payer: ctx.accounts.payer.to_account_info(),
                    system_program: ctx.accounts.system_program.to_account_info(),
                    token_program: ctx.accounts.token_program.to_account_info(),
                    rent: ctx.accounts.rent.to_account_info(),
                },
            ),
            Some(0), // Max supply
        )?;

        // Store collection info in program account
        let collection = &mut ctx.accounts.collection;
        collection.name = name;
        collection.symbol = symbol;
        collection.uri = uri;
        collection.mint = ctx.accounts.mint.key();
        collection.authority = ctx.accounts.authority.key();
        collection.item_count = 0;
        collection.created_at = Clock::get()?.unix_timestamp;

        msg!("Collection created: {} ({})", collection.name, collection.symbol);
        Ok(())
    }

    /// Mint a new NFT into a collection
    pub fn mint_nft(
        ctx: Context<MintNft>,
        name: String,
        symbol: String,
        uri: String,
        seller_fee_basis_points: u16,
    ) -> Result<()> {
        // Create metadata
        let metadata_infos = vec![
            ctx.accounts.metadata.to_account_info(),
            ctx.accounts.mint.to_account_info(),
            ctx.accounts.authority.to_account_info(),
            ctx.accounts.authority.to_account_info(),
            ctx.accounts.payer.to_account_info(),
            ctx.accounts.token_metadata_program.to_account_info(),
            ctx.accounts.token_program.to_account_info(),
            ctx.accounts.system_program.to_account_info(),
            ctx.accounts.rent.to_account_info(),
        ];

        create_metadata_accounts_v3(
            CpiContext::new(
                ctx.accounts.token_metadata_program.to_account_info(),
                CreateMetadataAccountsV3 {
                    metadata: ctx.accounts.metadata.to_account_info(),
                    mint: ctx.accounts.mint.to_account_info(),
                    mint_authority: ctx.accounts.authority.to_account_info(),
                    update_authority: ctx.accounts.authority.to_account_info(),
                    payer: ctx.accounts.payer.to_account_info(),
                    system_program: ctx.accounts.system_program.to_account_info(),
                    rent: ctx.accounts.rent.to_account_info(),
                },
            ),
            name,
            symbol,
            uri,
            Some(ctx.accounts.authority.key()),
            seller_fee_basis_points,
            true,
            None,
            Some(Collection {
                key: Key::CollectionV1,
                verified: true,
            }),
        )?;

        // Create master edition
        let master_edition_infos = vec![
            ctx.accounts.master_edition.to_account_info(),
            ctx.accounts.mint.to_account_info(),
            ctx.accounts.authority.to_account_info(),
            ctx.accounts.authority.to_account_info(),
            ctx.accounts.payer.to_account_info(),
            ctx.accounts.token_metadata_program.to_account_info(),
            ctx.accounts.system_program.to_account_info(),
            ctx.accounts.rent.to_account_info(),
        ];

        create_master_edition_v3(
            CpiContext::new(
                ctx.accounts.token_metadata_program.to_account_info(),
                CreateMasterEditionV3 {
                    edition: ctx.accounts.master_edition.to_account_info(),
                    mint: ctx.accounts.mint.to_account_info(),
                    update_authority: ctx.accounts.authority.to_account_info(),
                    mint_authority: ctx.accounts.authority.to_account_info(),
                    payer: ctx.accounts.payer.to_account_info(),
                    system_program: ctx.accounts.system_program.to_account_info(),
                    token_program: ctx.accounts.token_program.to_account_info(),
                    rent: ctx.accounts.rent.to_account_info(),
                },
            ),
            Some(0), // One of a kind
        )?;

        // Mint one token to the holder
        let cpi_accounts = token::MintTo {
            mint: ctx.accounts.mint.to_account_info(),
            to: ctx.accounts.token_account.to_account_info(),
            authority: ctx.accounts.authority.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_ctx = CpiContext::new_with_signer(
            cpi_program,
            cpi_accounts,
            &[&[&ctx.bumps.mint_authority]],
        );
        token::mint_to(cpi_ctx, 1)?;

        // Update collection item count
        let collection = &mut ctx.accounts.collection;
        collection.item_count += 1;

        // Store NFT info
        let nft_info = &mut ctx.accounts.nft_info;
        nft_info.mint = ctx.accounts.mint.key();
        nft_info.owner = ctx.accounts.owner.key();
        nft_info.collection_mint = collection.mint;
        nft_info.name = name;
        nft_info.uri = uri;
        nft_info.seller_fee_basis_points = seller_fee_basis_points;
        nft_info.created_at = Clock::get()?.unix_timestamp;

        msg!("NFT minted: {}", name);
        Ok(())
    }

    /// Transfer NFT to new owner
    pub fn transfer_nft(
        ctx: Context<TransferNft>,
        amount: u64,
    ) -> Result<()> {
        let cpi_accounts = Transfer {
            from: ctx.accounts.source_token_account.to_account_info(),
            to: ctx.accounts.destination_token_account.to_account_info(),
            authority: ctx.accounts.source_authority.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);

        token::transfer(cpi_ctx, amount)?;

        // Update NFT ownership
        let nft_info = &mut ctx.accounts.nft_info;
        nft_info.owner = ctx.accounts.destination_authority.key();

        msg!("NFT transferred to new owner");
        Ok(())
    }
}

// Account structures
#[account]
pub struct Collection {
    pub name: String,
    pub symbol: String,
    pub uri: String,
    pub mint: Pubkey,
    pub authority: Pubkey,
    pub item_count: u64,
    pub created_at: i64,
}

#[account]
pub struct NftInfo {
    pub mint: Pubkey,
    pub owner: Pubkey,
    pub collection_mint: Pubkey,
    pub name: String,
    pub uri: String,
    pub seller_fee_basis_points: u16,
    pub created_at: i64,
}

#[derive(Accounts)]
pub struct CreateCollection<'info> {
    #[account(
        init,
        payer = payer,
        space = 8 + 32 + 32 + 64 + 32 + 8 + 8 // discriminator + name + symbol + uri + mint + authority + item_count + created_at
    )]
    pub collection: Account<'info, Collection>,

    #[account(mut)]
    pub metadata: UncheckedAccount<'info>,
    #[account(mut)]
    pub master_edition: UncheckedAccount<'info>,
    #[account(mut)]
    pub mint: Signer<'info>,
    pub authority: Signer<'info>,
    #[account(mut)]
    pub payer: Signer<'info>,

    pub token_metadata_program: UncheckedAccount<'info>,
    pub token_program: Program<'info, Token>,
    pub system_program: Program<'info, System>,
    pub rent: Sysvar<'info, Rent>,
}

#[derive(Accounts)]
pub struct MintNft<'info> {
    #[account(mut)]
    pub collection: Account<'info, Collection>,

    #[account(
        init,
        payer = payer,
        space = 8 + 32 + 32 + 32 + 64 + 64 + 2 + 8 // discriminator + mint + owner + collection_mint + name + uri + seller_fee + created_at
    )]
    pub nft_info: Account<'info, NftInfo>,

    #[account(mut)]
    pub metadata: UncheckedAccount<'info>,
    #[account(mut)]
    pub master_edition: UncheckedAccount<'info>,
    #[account(mut)]
    pub mint: Signer<'info>,

    /// CHECK: This is the mint authority PDA
    #[account(seeds = [b"mint_authority"], bump)]
    pub mint_authority: UncheckedAccount<'info>,

    #[account(
        init_if_needed,
        payer = payer,
        token::mint = mint,
        token::authority = mint_authority,
    )]
    pub token_account: Account<'info, TokenAccount>,

    pub owner: Signer<'info>,
    pub authority: Signer<'info>,
    #[account(mut)]
    pub payer: Signer<'info>,

    pub token_metadata_program: UncheckedAccount<'info>,
    pub token_program: Program<'info, Token>,
    associated_token_program: Program<'info, AssociatedToken>,
    pub system_program: Program<'info, System>,
    pub rent: Sysvar<'info, Rent>,
}

#[derive(Accounts)]
pub struct TransferNft<'info> {
    #[account(mut)]
    pub nft_info: Account<'info, NftInfo>,

    #[account(mut)]
    pub source_token_account: Account<'info, TokenAccount>,
    #[account(mut)]
    pub destination_token_account: Account<'info, TokenAccount>,

    pub source_authority: Signer<'info>,
    pub destination_authority: SystemAccount<'info>,

    pub token_program: Program<'info, Token>,
}

// Error handling
#[error_code]
pub enum NftErrorCode {
    #[msg("Invalid collection")]
    InvalidCollection,
    #[msg("NFT already minted")]
    NftAlreadyMinted,
    #[msg("Invalid royalty percentage")]
    InvalidRoyalty,
    #[msg("Unauthorized transfer")]
    UnauthorizedTransfer,
}

💻 Высокопроизводительная Программа Solana rust

🔴 complex ⭐⭐⭐⭐⭐

Оптимизированная программа Solana для приложений с высокой пропускной способностью с эффективными структурами данных и пакетными операциями

⏱️ 50 min 🏷️ performance, optimization, solana, high-throughput
Prerequisites: Advanced Rust, Solana optimization, Blockchain performance
// High-Performance Solana Program
// Optimized for throughput and efficiency
// Cargo.toml dependencies:
// anchor-lang = "0.29.0"
// anchor-spl = "0.29.0"
// solana-program = "1.16.0"

use anchor_lang::prelude::*;
use anchor_spl::token::{Token, TokenAccount};
use std::collections::BTreeMap;
use std::mem::size_of;

declare_id!("HIGH_PERF_PROGRAM_ID");

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

    /// Initialize high-performance storage
    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let storage = &mut ctx.accounts.storage;
        storage.authority = ctx.accounts.authority.key();
        storage.item_count = 0;
        storage.total_volume = 0;
        storage.last_update = Clock::get()?.unix_timestamp;

        // Initialize batch processing state
        storage.batch_processing = false;
        storage.pending_operations = 0;

        msg!("High-performance storage initialized");
        Ok(())
    }

    /// Batch process multiple operations for efficiency
    pub fn batch_process_operations(
        ctx: Context<BatchProcessOperations>,
        operations: Vec<Operation>,
    ) -> Result<()> {
        require!(operations.len() <= 100, ErrorCode::BatchTooLarge);

        let storage = &mut ctx.accounts.storage;
        storage.batch_processing = true;
        storage.pending_operations = operations.len() as u32;

        // Pre-allocate result array
        let mut results: Vec<OperationResult> = Vec::with_capacity(operations.len());

        // Process operations in chunks for better performance
        for chunk in operations.chunks(10) {
            for operation in chunk {
                let result = match operation.operation_type {
                    0 => process_create_user(&mut ctx.accounts.user_storage, &operation.data),
                    1 => process_update_balance(&mut ctx.accounts.balance_storage, &operation.data),
                    2 => process_transfer(&mut ctx.accounts.balance_storage, &operation.data),
                    _ => return Err(ErrorCode::InvalidOperationType.into()),
                };

                results.push(result);
            }

            // Yield CPU every 10 operations to avoid hitting compute limits
            solana_program::program::invoke(
                &solana_program::system_instruction::transfer(
                    &ctx.accounts.authority.key(),
                    &ctx.accounts.authority.key(),
                    0,
                ),
                &[
                    ctx.accounts.authority.to_account_info(),
                    ctx.accounts.authority.to_account_info(),
                ],
            )?;
        }

        // Update statistics
        storage.item_count += operations.len() as u64;
        storage.total_volume += calculate_total_volume(&results);
        storage.last_update = Clock::get()?.unix_timestamp;
        storage.batch_processing = false;
        storage.pending_operations = 0;

        emit!(BatchProcessed {
            operation_count: operations.len() as u64,
            success_count: results.iter().filter(|r| r.success).count() as u64,
            total_volume: calculate_total_volume(&results),
        });

        msg!("Processed {} operations successfully", operations.len());
        Ok(())
    }

    /// Create optimized user account with compressed storage
    pub fn create_user_optimized(
        ctx: Context<CreateUserOptimized>,
        user_id: [u8; 32],
        username: String,
        metadata: UserMetadata,
    ) -> Result<()> {
        require!(username.len() <= 32, ErrorCode::UsernameTooLong);

        let user_data = &mut ctx.accounts.user_data;
        user_data.user_id = user_id;
        user_data.username = username;
        user_data.metadata = metadata;
        user_data.balance = 0;
        user_data.nonce = 0;
        user_data.created_at = Clock::get()?.unix_timestamp;
        user_data.last_active = Clock::get()?.unix_timestamp;

        // Use bit flags for efficient boolean storage
        user_data.flags = 0;
        if metadata.is_verified {
            user_data.flags |= 1 << 0;
        }
        if metadata.is_premium {
            user_data.flags |= 1 << 1;
        }

        emit!(UserCreated {
            user_id,
            username: user_data.username.clone(),
        });

        msg!("User created efficiently: {}", user_data.username);
        Ok(())
    }

    /// High-frequency trading operations
    pub fn execute_trade(
        ctx: Context<ExecuteTrade>,
        trade_data: TradeData,
    ) -> Result<()> {
        let clock = Clock::get()?;
        let current_slot = clock.slot;

        // Validate trade window (reduced compute cost)
        require!(
            current_slot <= trade_data.expiry_slot,
            ErrorCode::TradeExpired
        );

        let order_book = &mut ctx.accounts.order_book;
        let trade_history = &mut ctx.accounts.trade_history;

        // Find matching order efficiently using binary search
        let match_result = find_matching_order(order_book, &trade_data)?;

        if let Some(matching_order) = match_result {
            // Execute trade
            let trade = execute_trade_logic(
                &trade_data,
                &matching_order,
                current_slot,
            )?;

            // Store trade in circular buffer for efficiency
            let index = (trade_history.count % MAX_TRADES) as usize;
            trade_history.trades[index] = trade;
            trade_history.count += 1;

            // Update order book
            remove_order(order_book, matching_order.order_id)?;

            // Update statistics
            let storage = &mut ctx.accounts.storage;
            storage.total_volume += trade.volume;

            emit!(TradeExecuted {
                order_id: trade_data.order_id,
                matched_order_id: matching_order.order_id,
                volume: trade.volume,
                price: trade.price,
            });
        }

        Ok(())
    }
}

// Optimized data structures
#[account]
pub struct HighPerformanceStorage {
    pub authority: Pubkey,
    pub item_count: u64,
    pub total_volume: u128,
    pub last_update: i64,
    pub batch_processing: bool,
    pub pending_operations: u32,
}

#[account]
pub struct UserDataOptimized {
    pub user_id: [u8; 32],
    // Use fixed-size arrays for better performance
    pub username: [u8; 32], // Truncated/encoded username
    pub balance: u64,
    pub nonce: u64,
    pub created_at: i64,
    pub last_active: i64,
    pub flags: u8, // Bit flags for boolean values
    pub metadata_bytes: [u8; 64], // Compressed metadata
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct UserMetadata {
    pub is_verified: bool,
    pub is_premium: bool,
    pub level: u8,
    pub experience: u32,
}

#[account]
pub struct OrderBook {
    pub orders: Vec<Order>, // Consider using custom serialization for better efficiency
    pub count: u64,
    pub last_updated: i64,
}

#[account]
pub struct TradeHistory {
    pub trades: [Trade; MAX_TRADES], // Circular buffer
    pub count: u64,
    pub head: u64,
}

// Struct definitions
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct Operation {
    pub operation_type: u8,
    pub data: Vec<u8>,
    pub priority: u8,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct OperationResult {
    pub success: bool,
    pub error_code: Option<u32>,
    pub gas_used: u64,
    pub result_data: Vec<u8>,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct Order {
    pub order_id: [u8; 32],
    pub user_id: [u8; 32],
    pub order_type: u8, // 0 = bid, 1 = ask
    pub amount: u64,
    pub price: u64,
    pub expiry_slot: u64,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct TradeData {
    pub order_id: [u8; 32],
    pub user_id: [u8; 32],
    pub order_type: u8,
    pub amount: u64,
    pub price: u64,
    pub expiry_slot: u64,
    pub slippage_tolerance: u16, // basis points
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct Trade {
    pub trade_id: [u8; 32],
    pub order_id: [u8; 32],
    pub matched_order_id: [u8; 32],
    pub amount: u64,
    pub price: u64,
    pub volume: u128,
    pub slot: u64,
    pub timestamp: i64,
}

// Constants
const MAX_TRADES: usize = 1000;

// Helper functions
fn process_create_user(
    user_storage: &mut Account<UserDataOptimized>,
    data: &[u8],
) -> OperationResult {
    // Efficient user creation logic
    OperationResult {
        success: true,
        error_code: None,
        gas_used: 1000,
        result_data: vec![],
    }
}

fn process_update_balance(
    balance_storage: &mut Account<UserDataOptimized>,
    data: &[u8],
) -> OperationResult {
    // Efficient balance update
    OperationResult {
        success: true,
        error_code: None,
        gas_used: 500,
        result_data: vec![],
    }
}

fn process_transfer(
    balance_storage: &mut Account<UserDataOptimized>,
    data: &[u8],
) -> OperationResult {
    // Efficient transfer logic
    OperationResult {
        success: true,
        error_code: None,
        gas_used: 1500,
        result_data: vec![],
    }
}

fn find_matching_order(
    order_book: &OrderBook,
    trade_data: &TradeData,
) -> Result<Option<Order>> {
    // Binary search implementation for efficiency
    Ok(None) // Placeholder
}

fn execute_trade_logic(
    trade: &TradeData,
    matching_order: &Order,
    current_slot: u64,
) -> Result<Trade> {
    let volume = (trade.amount as u128).saturating_mul(matching_order.price as u128);

    Ok(Trade {
        trade_id: [0u8; 32], // Generate unique ID
        order_id: trade.order_id,
        matched_order_id: matching_order.order_id,
        amount: trade.amount,
        price: trade.price,
        volume,
        slot: current_slot,
        timestamp: Clock::get()?.unix_timestamp,
    })
}

fn remove_order(order_book: &mut OrderBook, order_id: [u8; 32]) -> Result<()> {
    // Efficient order removal
    Ok(())
}

fn calculate_total_volume(results: &[OperationResult]) -> u128 {
    // Calculate total volume from results
    0
}

// Context definitions
#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(
        init,
        payer = authority,
        space = 8 + 32 + 8 + 16 + 8 + 1 + 4 // discriminator + authority + item_count + total_volume + last_update + batch_processing + pending_operations
    )]
    pub storage: Account<'info, HighPerformanceStorage>,

    #[account(mut)]
    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct BatchProcessOperations<'info> {
    #[account(mut)]
    pub storage: Account<'info, HighPerformanceStorage>,

    #[account(mut)]
    pub user_storage: Account<'info, UserDataOptimized>,

    #[account(mut)]
    pub balance_storage: Account<'info, UserDataOptimized>,

    pub authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct CreateUserOptimized<'info> {
    #[account(
        init,
        payer = authority,
        space = 8 + 32 + 32 + 8 + 8 + 8 + 8 + 1 + 64 // discriminator + optimized structure
    )]
    pub user_data: Account<'info, UserDataOptimized>,

    #[account(mut)]
    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct ExecuteTrade<'info> {
    #[account(mut)]
    pub storage: Account<'info, HighPerformanceStorage>,

    #[account(mut)]
    pub order_book: Account<'info, OrderBook>,

    #[account(mut)]
    pub trade_history: Account<'info, TradeHistory>,

    pub authority: Signer<'info>,
}

// Event definitions
#[event]
pub struct BatchProcessed {
    pub operation_count: u64,
    pub success_count: u64,
    pub total_volume: u128,
}

#[event]
pub struct UserCreated {
    pub user_id: [u8; 32],
    pub username: String,
}

#[event]
pub struct TradeExecuted {
    pub order_id: [u8; 32],
    pub matched_order_id: [u8; 32],
    pub volume: u128,
    pub price: u64,
}

// Error handling
#[error_code]
pub enum ErrorCode {
    #[msg("Batch size too large")]
    BatchTooLarge,
    #[msg("Invalid operation type")]
    InvalidOperationType,
    #[msg("Username too long")]
    UsernameTooLong,
    #[msg("Trade expired")]
    TradeExpired,
    #[msg("Insufficient balance")]
    InsufficientBalance,
    #[msg("Order not found")]
    OrderNotFound,
    #[msg("Invalid price")]
    InvalidPrice,
}