Start here · Beginner
NEAR by Example
Learn to write NEAR smart contracts the way you already think — in Solidity. Every concept is shown side by side: the Solidity you know on the left, the NEAR equivalent (Rust) on the right.
Compact and complete: short, real examples you can read top to bottom, each with a note on what changes when you come from the EVM, and a three-question check at the end.
27 lessons~105 min81 quiz questionsFree · no sign-up
What you’ll learn
- Write, initialise and deploy a NEAR contract in Rust
- Model state with near-sdk collections and pay for storage
- Handle accounts, access keys, deposits and transfers
- Make asynchronous cross-contract calls with callbacks
- Implement the NEAR token standards (FT, NFT, multi-token)
- Emit events, manage ownership, upgrade and test contracts
Lessons
1. Getting started
- Your first contractA counter, in both worlds. A NEAR contract is a Rust struct plus an impl block — the fields are storage, the methods are your ABI.
- Primitive typesuint/int become sized Rust integers, address becomes AccountId, bytes/string map to Rust equivalents — and you pick the width yourself.
- If, loops & matchif/else and loops carry over directly. Rust adds match (a superpowered switch) and makes if an expression that returns a value.
2. State & storage
- State, constants & localsWhere values live. Struct fields are storage, module const is a compile-time constant, and a let inside a method is a local — no storage / memory / calldata keywords.
- Structs & enumsstruct maps to a Rust struct; enum becomes a far more powerful Rust enum. Types stored in state or crossing the ABI need serializer derives.
- Collections: mappings & arraysmapping and dynamic arrays become explicit types from near_sdk::store — LookupMap, Vector — each with its own storage prefix.
- Storage stakingOn NEAR, state costs locked NEAR — roughly 1 NEAR per 100 KB — not one-time gas. The contract measures bytes used and makes the caller cover them.
3. Functions & calls
- Functions: view, mutating & payableReads vs writes are the &self vs &mut self receiver. Accepting NEAR needs #[payable]. msg.sender and msg.value become env:: calls.
- Initialization (constructors)When default state is not enough, mark a method #[init]. It runs once, takes arguments, and returns the starting state — the constructor.
- Errors: assert, require & panicGuard clauses roll the whole call back and refund unused gas. require! and env::panic_str are your revert.
- Access control (modifiers)Rust has no modifier keyword. You write a small guard method and call it at the top of each protected method — same effect, plain code.
- GasNEAR meters gas too, but measured in gas units (Tgas), paid by the caller, and attached explicitly to cross-contract calls.
- View vs change callsReads are free RPC queries with no signer and no gas; writes are signed transactions. Calling a read as a transaction costs gas and changes nothing — a classic first surprise.
4. Accounts & keys
- Accounts: who is callingaddress becomes AccountId — a human-readable name. predecessor, signer and current account replace msg.sender, tx.origin and address(this).
- Access keysA NEAR account can hold many keys with different powers. Full-access keys are root; function-call keys are scoped — native account abstraction, no ERC-4337 needed.
5. Money
- Amounts: NEAR, yocto & U128wei becomes yocto-NEAR (10^24). NearToken does the unit math, and amounts cross the ABI as U128 strings to keep their precision.
- Sending NEARTransfer value by creating a Promise. Promise::new(to).transfer(amount) replaces address.call{value:} — and it runs after your method, not during it.
6. Cross-contract calls
7. Token standards
- Fungible tokens (NEP-141)NEP-141 is the ERC-20 of NEAR — but there is no approve/allowance. ft_transfer_call does an atomic transfer-and-call instead.
- NFTs (NEP-171)NEP-171 is the ERC-721 of NEAR. Token ids are strings, transfers use the same transfer-and-call pattern, and NEP-177 metadata fields are stored on-chain (though the media field is usually a URL to off-chain content).
- Multi-token (NEP-245)NEP-245 is the ERC-1155 of NEAR — many token types (fungible and non-fungible) in one contract, with batch transfers.
8. Patterns
- Events (NEP-297)No native event type — you emit a structured JSON log line. Indexers parse the EVENT_JSON standard the way they parse EVM logs.
- OwnershipNo OpenZeppelin Ownable base to inherit — you keep an owner field and a guard, plus a two-word transfer method.
- Upgrading a contractNo proxy, no delegatecall. You deploy new wasm to the same account; the state stays and an optional migrate reshapes it.
- No inheritance: traits & compositionRust has no contract inheritance. Shared behavior comes from traits (with default methods) and shared state from composition.
9. Tooling
- Testingcargo test runs unit tests against the contract as a plain Rust struct. near-workspaces is the sandbox for cross-contract and gas — like forge fork tests.
- Build & deployCompile to wasm, deploy to a named account you control, then call it. A transaction call changes state; a read-only call reads for free.