Skip to main content
Welcome! NEAR accounts can store small apps known as smart contracts. In this quick tutorial, we will guide you in creating your first contract on the NEAR testnet! Join us in creating a friendly auction contract, which allows users to place bids, track the highest bidder and claim tokens at the end of the auction.
Which language should I use?We recommend using Rust for production apps due to its mature tooling. However, if you are just prototyping or learning, feel free to use JavaScript!
Prefer an online IDE?Check out NEAR Playground for an easy-to-use online IDE with pre-configured templates.

Prerequisites

Before starting, make sure to set up your development environment.
# Install Rust: https://www.rust-lang.org/tools/install
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Contracts will be compiled to wasm, so we need to add the wasm target
rustup target add wasm32-unknown-unknown

# Install NEAR CLI-RS to deploy and interact with the contract
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/near-cli-rs/releases/latest/download/near-cli-rs-installer.sh | sh

# Install cargo near to help building the contract
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/cargo-near/releases/latest/download/cargo-near-installer.sh | sh

Creating the Contract

Create a smart contract by using one of the scaffolding tools:
cargo near
This command will guide you through creating a new NEAR project with an interactive CLI.
For this tutorial we chose to name the project auction, but feel free to use any name you prefer.

Anatomy of the Contract

The auction smart contract allows users to place bids, track the highest bidder and claim tokens at the end of the auction. Let’s explore the different components:

Contract State & Initialization

The contract stores the highest bid, auction end time, auctioneer address, and a flag to track if proceeds have been claimed. An init function is provided to initialize the contract state.
use near_sdk::{near, env, Promise, NearToken};

#[near(contract_state)]
#[derive(PanicOnDefault)]
pub struct Contract {
    highest_bid: Bid,
    auction_end_time: u64,
    auctioneer: AccountId,
    claimed: bool,
}

#[near]
impl Contract {
    #[init]
    #[private]
    pub fn init(end_time: U64, auctioneer: AccountId) -> Self {
        Self {
            highest_bid: Bid { bidder: "none".parse().unwrap(), bid: NearToken::from_near(0) },
            auction_end_time: end_time.into(),
            auctioneer,
            claimed: false,
        }
    }
}

Placing Bids

Users call the bid function while attaching a deposit representing their bid amount. The function validates that the auction is ongoing, and if the bid is higher than the current highest, it records the new bid and refunds the previous bidder.
#[payable]
pub fn bid(&mut self) {
    let bidder = env::predecessor_account_id();
    let bid = env::attached_deposit();
    let now = env::block_timestamp();

    assert!(now < self.auction_end_time, "Auction has ended");
    assert!(bid > self.highest_bid.bid, "Bid is too low");

    // Refund previous bidder
    if self.highest_bid.bidder != "none" {
        Promise::new(self.highest_bid.bidder.clone())
            .transfer(self.highest_bid.bid);
    }

    // Store new highest bid
    self.highest_bid = Bid { bidder, bid };
}

Claiming Proceeds

Once the auction ends, any user can call claim to transfer the winning bid to the auctioneer:
pub fn claim(&mut self) {
    assert!(env::block_timestamp() >= self.auction_end_time, "Auction ongoing");
    assert!(!self.claimed, "Already claimed");

    self.claimed = true;
    Promise::new(self.auctioneer.clone())
        .transfer(self.highest_bid.bid);
}

View Methods

Users can query the current state of the auction by calling view methods:
pub fn get_highest_bid(&self) -> &Bid {
    &self.highest_bid
}

pub fn get_auction_end_time(&self) -> U64 {
    self.auction_end_time.into()
}

Test the Contract

Let’s make sure the contract works by running its tests:
cargo test

Build & Deploy

Now let’s deploy the contract to testnet!

Build the Contract

cargo near build non-reproducible-wasm

Create an Account

# Replace <contract-acc.testnet> with a name for your contract account
near create-account <contract-acc.testnet> --useFaucet
If you already have a testnet account, you can log in with near login.

Deploy

near deploy <contract-acc.testnet> ./target/near/auction.wasm

Interacting with the Contract

Initialize the Contract

# Get a timestamp for 5 minutes from now (in nanoseconds)
FIVE_MINUTES_FROM_NOW=$(( $(date +%s%N) + 5 * 60 * 1000000000 ))

# Initialize the auction
near call <contract-acc.testnet> init "{\"end_time\": \"$FIVE_MINUTES_FROM_NOW\", \"auctioneer\": \"influencer.testnet\"}" --useAccount <contract-acc.testnet>

Place a Bid

# Create a new account to place the bid
near create-account <bidder-account.testnet> --useFaucet

# Place a bid of 0.01 NEAR
near call <contract-acc.testnet> bid '{}' --deposit 0.01 --useAccount <bidder-account.testnet>

Get Highest Bid

near view <contract-acc.testnet> get_highest_bid '{}'

Claim Proceeds

After the auction ends:
near call <contract-acc.testnet> claim '{}' --useAccount <contract-acc.testnet>

Next Steps

Contract Anatomy

Learn more about contract structure and components

Testing

Deep dive into contract testing strategies

Security

Best practices for secure smart contracts

Cross-Contract Calls

Learn how contracts interact with each other

Build docs developers (and LLMs) love