NEAR Protocol smart contract development in Rust. Use when writing, reviewing, or deploying NEAR smart contracts. Covers contract structure, state management, cross-contract calls, testing, security, and optimization patterns. Based on near-sdk v5.x with modern macro syntax.
Comprehensive guide for developing secure and efficient smart contracts on NEAR Protocol using Rust and the NEAR SDK (v5.x).
Reference these guidelines when:
Install the required tools before starting development:
# Install Rust (if not already installed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add wasm32 target for compiling contracts
rustup target add wasm32-unknown-unknown
# Install cargo-near (build, deploy, and manage contracts)
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/cargo-near/releases/latest/download/cargo-near-installer.sh | sh
# Install near-cli-rs (interact with NEAR network)
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/near-cli-rs/releases/latest/download/near-cli-rs-installer.sh | sh
CRITICAL: ALWAYS run
cargo near newto create new projects. NEVER manually create Cargo.toml, lib.rs, or any project files. The command generates all required files with correct configurations.
# REQUIRED: Create a new contract project using the official template
cargo near new my-contract
# Navigate to project directory
cd my-contract
# Build the contract
cargo near build
# Run tests
cargo test
Why cargo near new is mandatory:
Cargo.toml with proper dependencies and build settingssrc/lib.rs templatetests/ directoryoverflow-checks = trueDO NOT:
Cargo.tomlsrc/lib.rsmy-contract/
├── Cargo.toml # Dependencies and project config
├── src/
│ └── lib.rs # Main contract code
├── tests/ # Integration tests
│ └── test_basics.rs
└── README.md
# Create a testnet account (if needed)
near account create-account sponsor-by-faucet-service my-contract.testnet autogenerate-new-keypair save-to-keychain network-config testnet create
# Build in release mode
cargo near build --release
# Deploy to testnet
cargo near deploy my-contract.testnet without-init-call network-config testnet sign-with-keychain send
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Security & Safety | CRITICAL | security- |
| 2 | Contract Structure | HIGH | structure- |
| 3 | State Management | HIGH | state- |
| 4 | Cross-Contract Calls | MEDIUM-HIGH | xcc- |
| 5 | Contract Upgrades | MEDIUM-HIGH | upgrade- |
| 6 | Chain Signatures | MEDIUM-HIGH | chain- |
| 7 | Gas Optimization | MEDIUM | gas- |
| 8 | Yield & Resume | MEDIUM | yield- |
| 9 | Testing | MEDIUM | testing- |
| 10 | Best Practices | MEDIUM | best- |
security-storage-checks - Always validate storage operations and check depositssecurity-access-control - Implement proper access control using predecessor_account_idsecurity-reentrancy - Protect against reentrancy attacks (update state before external calls)security-overflow - Use overflow-checks = true in Cargo.toml to prevent overflowsecurity-callback-validation - Validate callback results and handle failuressecurity-private-callbacks - Mark callbacks as #[private] to prevent external callssecurity-yoctonear-validation - Validate attached deposits with #[payable] functionssecurity-sybil-resistance - Implement minimum deposit checks to prevent spamstructure-near-bindgen - Use #[near(contract_state)] macro for contract struct (replaces old #[near_bindgen])structure-initialization - Implement proper initialization with #[init] patternsstructure-versioning - Plan for contract upgrades with versioning mechanismsstructure-events - Use env::log_str() and structured event logging (NEP-297)structure-standards - Follow NEAR Enhancement Proposals (NEPs) for standardsstructure-serializers - Use #[near(serializers = [json, borsh])] for data structsstructure-panic-default - Use #[derive(PanicOnDefault)] to require initializationstate-collections - Use SDK collections from near_sdk::store: IterableMap, IterableSet, Vector, LookupMap, LookupSet, UnorderedMap, UnorderedSet, TreeMapstate-serialization - Use Borsh for state, JSON for external interfacesstate-lazy-loading - Use SDK collections for lazy loading to save gas (loaded on-demand, not all at once)state-pagination - Implement pagination with .skip() and .take() for large datasetsstate-migration - Plan state migration strategies using versioningstate-storage-cost - Remember: 1 NEAR ≈ 100kb storage, contracts pay for their storagestate-unique-prefixes - Use unique byte prefixes for all collections (avoid collisions)state-native-vs-sdk - Native collections (Vec, HashMap) load all data; use only for <100 entriesxcc-promise-chaining - Chain promises correctlyxcc-callback-handling - Handle all callback scenarios (success, failure)xcc-gas-management - Allocate appropriate gas for cross-contract callsxcc-error-handling - Implement robust error handlingxcc-result-unwrap - Never unwrap promise results without checksupgrade-migration - Use enums for state versioning and implement migrate method with #[init(ignore_state)]upgrade-self-update - Pattern for contracts that can update themselves programmaticallyupgrade-cleanup-old-state - Always remove old state structures to free storageupgrade-dao-controlled - Use multisig or DAO for production upgrade governancechain-signatures - Derive foreign blockchain addresses, request MPC signatures, and build multichain transactionschain-callback-handling - Handle MPC signature callbacks properlychain-gas-allocation - Allocate sufficient gas for MPC calls (yield/resume pattern)gas-batch-operations - Batch operations to reduce transaction costsgas-minimal-state-reads - Minimize state reads and writes (cache in memory)gas-efficient-collections - Choose appropriate collection types (LookupMap vs IterableMap)gas-view-functions - Mark read-only functions as view (&self in Rust)gas-avoid-cloning - Avoid unnecessary cloning of large data structuresgas-early-validation - Use require! early to save gas on invalid inputsgas-prepaid-gas - Attach appropriate gas for cross-contract calls (recommended: 30 TGas)yield-resume - Create yielded promises, signal resume, handle timeouts, and manage state between yield/resumeyield-gatekeeping - Protect resume methods from unauthorized callerstesting-integration-tests - Use near-sandbox + near-api for integration teststesting-unit-tests - Write comprehensive unit tests with mock contextstesting-sandbox - Test with local sandbox environment before testnet/mainnettesting-edge-cases - Test boundary conditions, overflow, and empty statestesting-gas-profiling - Profile gas usage in integration teststesting-cross-contract - Test cross-contract calls and callbacks thoroughlytesting-failure-scenarios - Test promise failures and timeout scenariostesting-time-travel - Use sandbox.fast_forward() for time-sensitive testsbest-contract-tools - Use near-sdk-contract-tools for NEP standards (FT, NFT, etc.) and NEP-297 structured eventsbest-panic-messages - Provide clear, actionable panic messagesbest-logging - Use env::log_str() for debugging and event emissionbest-documentation - Document public methods, parameters, and complex logicbest-error-types - Define custom error types or use descriptive stringsbest-constants - Use constants for magic numbers and configurationbest-require-macro - Use require! instead of assert! for better error messagesbest-promise-return - Return promises from cross-contract calls for proper trackingbest-sdk-crates - Reuse SDK-exported crates (borsh, serde, base64, etc.)best-account-id-encoding - Encode AccountIds in base32 for 40% storage savingsRead individual rule files for detailed explanations and code examples:
rules/security-storage-checks.md
rules/structure-near-bindgen.md
rules/state-collections.md
rules/xcc-promise-chaining.md
rules/upgrade-migration.md
rules/chain-signatures.md
rules/yield-resume.md
rules/best-contract-tools.md
rules/testing-integration-tests.md
Each rule file contains:
cargo near build, cargo near deploy)near contract call, near contract view)#[near(contract_state)] replaces #[near_bindgen] + derives#[near(serializers = [json, borsh])] for data structsnear_sdk::store::IterableMap, IterableSet, LookupMap, LookupSet, Vector, UnorderedMap, UnorderedSet, TreeMapPromise::new() and .then()#[handle_result] for methods returning Result<T, E> without panicking| Storage | Cost | Notes |
|---|---|---|
| 1 byte | 0.00001 NEAR | ~10kb per 0.1 NEAR |
| 100 KB | ~1 NEAR | Approximate reference |
| AccountId | 64+ bytes | Can save 40% with base32 encoding |
| Contract code | Variable | Paid by contract account |
| Collection | Iterable | Clear | Ordered | Range | Use Case |
|---|---|---|---|---|---|
Vector | Yes | Yes | Yes | Yes | Ordered list with index access |
LookupMap | No | No | No | No | Fast key-value, no iteration needed |
LookupSet | No | No | No | No | Fast membership checks |
IterableMap | Yes | Yes | Yes | No | Key-value with iteration |
IterableSet | Yes | Yes | Yes | No | Set with iteration |
UnorderedMap | Yes | Yes | No | No | Key-value, unordered iteration |
UnorderedSet | Yes | Yes | No | No | Set, unordered iteration |
TreeMap | Yes | Yes | Yes | Yes | Sorted key-value with range queries |