near-bindgen

Rust library for writing NEAR smart contracts.

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

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

## Example Wrap a struct in `#[near_bindgen]` and it generates a smart contract compatible with the NEAR blockchain: ```rust #[near_bindgen] #[derive(Default, BorshDeserialize, BorshSerialize)] pub struct StatusMessage { records: HashMap, } #[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 { self.records.get(&account_id).cloned() } } ``` ## Features * **Unit-testable.** Writing unit tests is easy with `near-bindgen`: ```rust #[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: ```bash 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](https://github.com/nearprotocol/near-bindgen/tree/master/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. ```rust #[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: ```rust impl Default for StatusMessage { fn default() -> Self { panic!("Contract should be initialized before the usage.") } } ``` ## Pre-requisites To develop Rust contracts you would need to: * Install [Rustup](https://rustup.rs/): ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` * Add wasm target to your toolchain: ```bash rustup target add wasm32-unknown-unknown ``` ## Writing Rust Contract You can follow the [examples/status-message](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](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: ```rust #[near_bindgen] #[derive(Default, BorshSerialize, BorshDeserialize)] pub struct MyContract { data: HashMap } ``` 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: ```rust #[near_bindgen] impl MyContract { pub fn insert_data(&mut self, key: u64, value: u64) -> Option { self.data.insert(key) } pub fn get_data(&self, key: u64) -> Option { self.data.get(&key).cloned() } } ``` ## Building Rust Contract We can build the contract using rustc: ```bash RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release ```