Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions rules-new/rust.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
description: Rust best practices for Solana smart contract development using Anchor framework and Solana SDK
globs: programs/**/*.rs, src/**/*.rs, tests/**/*.ts
---

# Rust + Solana (Anchor) Best Practices

## Program Structure
- Structure Solana programs using `Anchor` framework standards
- Place program entrypoint logic in `lib.rs`, not `main.rs`
- Organize handlers into modules (e.g., `initialize`, `update`, `close`)
- Separate state definitions, errors, instructions, and utils
- Group reusable logic under a `utils` module (e.g., account validation)
- Use `declare_id!()` to define program ID

## Anchor Framework
- Use `#[derive(Accounts)]` for all instruction contexts
- Validate accounts strictly using constraint macros (e.g., `#[account(mut)]`, `seeds`, `bump]`)
- Define all state structs with `#[account]` and `#[derive(AnchorSerialize, AnchorDeserialize)]`
- Prefer `Init`, `Close`, `Realloc`, `Mut`, and constraint macros to avoid manual deserialization
- Use `ctx.accounts` to access validated context accounts
- Handle CPI (Cross-Program Invocation) calls via Anchor’s CPI helpers

## Serialization
- Use **Borsh** or Anchor's custom serializer (not Serde) for on-chain data
- Always include `#[account(zero_copy)]` or `#[repr(C)]` for packed structures
- Avoid floating point types — use `u64`, `u128`, or fixed-point math
- Zero out or close unused accounts to reduce rent costs

## Testing
- Write tests in TypeScript using Anchor’s Mocha + Chai setup (`tests/*.ts`)
- Use `anchor.workspace.MyProgram` to load deployed contracts
- Use `provider.simulate()` to inspect failed txs
- Spin up a local validator (`anchor test`) and reset between tests
- Airdrop SOL to wallets with `provider.connection.requestAirdrop(...)`
- Validate program logs using `tx.confirmation.logMessages`

## Solana SDK (Manual)
- Use `solana_program` crate when not using Anchor (bare-metal programs)
- Carefully deserialize accounts using `AccountInfo`, `try_from_slice_unchecked`
- Use `solana_program::msg!` for lightweight debugging logs
- Verify accounts via `is_signer`, `is_writable`, `key == expected`
- Never panic! Use `ProgramError::Custom(u32)` or `ErrorCode` enums

## Security Patterns
- Always validate `msg.sender`/signer with `account_info.is_signer`
- Prevent replay attacks via `seeds`, `bump`, and unique PDAs
- Use strict size checks before reallocating or deserializing
- Avoid unsafe unchecked casting; prefer Anchor deserialization
- For CPIs, validate `target_program` against expected program ID
- When using randomness, never rely on timestamps — use oracles or off-chain VRFs

## Performance
- Prefer zero-copy deserialization when accounts are large
- Minimize compute usage; avoid loops and recursion
- Avoid memory reallocations mid-instruction
- Use `#[account(zero_copy)]` and `#[repr(packed)]` for tight layout
- Profile compute units with `solana logs` and `anchor run`

## Dev Workflow
- Use `anchor init` to scaffold projects
- Add Anchor IDL support for front-end usage (JSON ABI)
- Use `anchor build`, `anchor deploy`, `anchor test` consistently
- Use separate `Anchor.toml` environments for devnet/mainnet/localnet
- Format all Rust code with `cargo fmt`, lint with `cargo clippy`
- Keep `Cargo.lock` checked into `programs/` but not root

## Documentation
- Use `///` Rust doc comments for all instructions and accounts
- Include doc examples for each instruction
- Document PDA derivation logic and bump seed expectations
- Maintain up-to-date `README.md` with test commands and deployment steps

## Wallet & Network Handling
- Use `anchorProvider.wallet.publicKey` for signer verification in tests
- Do not hardcode keypairs — use env-based loading (`process.env.ANCHOR_WALLET`)
- Deploy with clear `cluster` targets (`localnet`, `devnet`, `mainnet`)
- Use `anchor keys sync` to propagate program ID changes
- Commit `target/idl/` and `target/types/` to share with front end

## CI/CD & Deploy
- Use GitHub Actions with `solana-cli`, `anchor-cli`, and `node` installed
- Run `anchor test` in CI for every PR
- Use `solana program deploy` with explicit `--program-id` on production deploys
- Upload IDLs to a central registry (e.g., GitHub, IPFS, or `anchor.cloud`)