NEAR Documentation
  • Basics
  • Develop
  • Stake
  • Integrate
  • Tokens
  • Contribute
  • API
  • Community
  • GitHub

›Creating Contracts

Quickstart

  • Orientation
  • Building Apps
  • Networks

Tutorials

  • Introduction
  • Guided Walkthroughs

    • Figment Tutorials
    • Create Transactions
    • Issue a Token
    • Cross-Contract Calls
    • Simple AssemblyScript tests
    • Simple Rust smart contract

    Helpful References

    • Contract Structure
    • Project Structure

    Videos

    • Accounts & keys
    • Smart Contract Reviews
    • Misc

JavaScript library

  • Introduction
  • Guides
  • Examples

Smart Contracts

  • Introduction
  • Creating Contracts

    • Rust
    • AssemblyScript

    Using Contracts

    • Rust
    • JavaScript
    • API

    Testing Contracts

    • Testing contracts

    Virtual Machine Limits

    • Runtime Limits

Ethereum Compatibility

  • Network status
  • Simple script & NEAR CLI guide
  • Pet Shop example
  • Web3 provider
  • Using Truffle
  • Local setup
  • Proxy RPC Server
  • Testing contracts

Machine Setup

  • Local Development on TestNet
  • Local Development on Local Network
  • Running a node
  • Running a Node on Windows

FAQ

  • Developer FAQ
Edit

near-sdk

near-sdk

Rust library for writing NEAR smart contracts.

Previously known as near-bindgen.

Crates.io version Download Reference Documentation Join the community on Discord Travis Build

Features | Pre-requisites | Writing Rust Contract | Building Rust Contract | Reference Documentation

Example

Wrap a struct in #[near_bindgen] and it generates a smart contract compatible with the NEAR blockchain:

use near_sdk::{near_bindgen, env};

#[near_bindgen]
#[derive(Default, BorshDeserialize, BorshSerialize)]
pub struct StatusMessage {
    records: HashMap<String, String>,
}

#[near_bindgen]
impl StatusMessage {
    pub fn set_status(&mut self, message: String) {
        let account_id = env::signer_account_id();
        self.records.insert(account_id, message);
    }

    pub fn get_status(&self, account_id: String) -> Option<String> {
        self.records.get(&account_id).cloned()
    }
}

Features

  • Unit-testable. Writing unit tests is easy with near-sdk:

    #[test]
    fn set_get_message() {
        let context = get_context(vec![]);
        testing_env!(context);
        let mut contract = StatusMessage::default();
        contract.set_status("hello".to_string());
        assert_eq!("hello".to_string(), contract.get_status("bob_near".to_string()).unwrap());
    }
    

    Run unit test the usual way:

    cargo test --package status-message
    
  • Asynchronous cross-contract calls. Asynchronous cross-contract calls allow parallel execution of multiple contracts in parallel with subsequent aggregation on another contract. env exposes the following methods:

    • promise_create -- schedules an execution of a function on some contract;
    • promise_then -- attaches the callback back to the current contract once the function is executed;
    • promise_and -- combinator, allows waiting on several promises simultaneously, before executing the callback;
    • promise_return -- treats the result of execution of the promise as the result of the current function.

    Follow examples/cross-contract-high-level to see various usages of cross contract calls, including system-level actions done from inside the contract like balance transfer (examples of other system-level actions are: account creation, access key creation/deletion, contract deployment, etc).

  • Initialization methods. We can define an initialization method that can be used to initialize the state of the contract.

    #[near_bindgen]
    impl StatusMessage {
      #[init]
      pub fn new(user: String, status: String) -> Self {
          let mut res = Self::default();
          res.records.insert(user, status);
          res
      }
    }
    

Even if you have initialization method your smart contract is still expected to derive Default trait. If you don't want to disable default initialization then you can prohibit it like this:

impl Default for StatusMessage {
    fn default() -> Self {
        panic!("Contract should be initialized before the usage.")
    }
}
  • Payable methods. We can allow methods to accept token transfer together with the function call. This is done so that contracts can define a fee in tokens that needs to be payed when they are used. By the default the methods are not payable and they will panic if someone will attempt to transfer tokens to them during the invocation. This is done for safety reason, in case someone accidentally transfers tokens during the function call.

To declare a payable method simply use #[payable] decorator:

use near_sdk::payable;

#[payable]
pub fn my_method(&mut self) {
...
}

Pre-requisites

To develop Rust contracts you would need to:

  • Install Rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • Add wasm target to your toolchain:
rustup target add wasm32-unknown-unknown

Writing Rust Contract

You can follow the examples/status-message crate that shows a simple Rust contract.

The general workflow is the following:

  1. Create a crate and configure the Cargo.toml similarly to how it is configured in examples/status-message/Cargo.toml;

  2. Crate needs to have one pub struct that will represent the smart contract itself:

    • The struct needs to implement Default trait which NEAR will use to create the initial state of the contract upon its first usage;
    • The struct also needs to implement BorshSerialize and BorshDeserialize traits which NEAR will use to save/load contract's internal state;

    Here is an example of a smart contract struct:

    use near_sdk::{near_bindgen, env};
    
    #[near_bindgen]
    #[derive(Default, BorshSerialize, BorshDeserialize)]
    pub struct MyContract {
        data: HashMap<u64, u64>
    }
    
  3. Define methods that NEAR will expose as smart contract methods:

    • You are free to define any methods for the struct but only public methods will be exposed as smart contract methods;
    • Methods need to use either &self, &mut self, or self;
    • Decorate the impl section with #[near_bindgen] macro. That is where all the M.A.G.I.C. (Macros-Auto-Generated Injected Code) is happening
    • If you need to use blockchain interface, e.g. to get the current account id then you can access it with env::*;

    Here is an example of smart contract methods:

    #[near_bindgen]
    impl MyContract {
       pub fn insert_data(&mut self, key: u64, value: u64) -> Option<u64> {
           self.data.insert(key)
       }
       pub fn get_data(&self, key: u64) -> Option<u64> {
           self.data.get(&key).cloned()
       }
    }
    

Building Rust Contract

We can build the contract using rustc:

RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release

License

This repository is distributed under the terms of both the MIT license and the Apache License (Version 2.0). See LICENSE and LICENSE-APACHE for details.

Got a question? Ask it on StackOverflow!

Last updated on 1/20/2021 by Josh
← IntroductionAssemblyScript →
  • Example
  • Features
  • Pre-requisites
  • Writing Rust Contract
  • Building Rust Contract
  • License
  • Wallet
  • Explorer
  • Examples
  • Docs
  • Twitter
  • GitHub
  • Discord
  • Telegram
  • WeChat
  • YouTube

Developers

  • Overview
  • Technology
  • Docs
  • GitHub
  • Bounties
  • Developer Program
  • Survey

Ecosystem

  • Events
  • Contributor Program
  • Guild Program
  • Startup Accelerator
  • Bounties
  • Tokens

About

  • Team
  • Careers
  • Backers
  • Press Kit
  • Brand Guidelines
  • Privacy Policy

2020 NEAR Protocol|All rights reserved|hello@near.org|Privacy Policy