Example
Wrap a struct in #[near_bindgen] and it generates a smart contract compatible with the NEAR blockchain:
Features
-
Unit-testable. Writing unit tests is easy with
near-bindgen:To run unit tests include
env_testfeature: -
Asynchronous cross-contract calls. Asynchronous cross-contract calls allow parallel execution of multiple contracts in parallel with subsequent aggregation on another contract.
envexposes 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.
Pre-requisites
To develop Rust contracts you would need have:
- Rustup installed and switched to
nightlyRust compiler:
|
- WASM pack installed:
|
Writing Rust Contract
You can follow the test-contract crate that shows a simple Rust contract.
The general workflow is the following:
-
Create a crate and configure the
Cargo.tomlsimilarly to how it is configured in examples/status-message/Cargo.toml; -
Crate needs to have one
pubstruct that will represent the smart contract itself:- The struct needs to implement
Defaulttrait which NEAR will use to create the initial state of the contract upon its first usage; - The struct also needs to implement
BorshSerializeandBorshDeserializetraits which NEAR will use to save/load contract's internal state;
Here is an example of a smart contract struct:
- The struct needs to implement
-
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, orself; - Decorate the
implsection 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:
Building Rust Contract
We can build the contract using rustc:
But then we would want to compress it using wasm-opt and wasm-gc tools that we installed with wasm-pack, see examples/status-message/build.sh.
Limitations and Future Work
The current implementation of wasm_bindgen has the following limitations:
- The smart contract struct should be serializable with borsh which is true for most of the structs;
- The method arguments and the return type should be json-serializable, which is true for most of the types, with some exceptions. For instance,
a
HashMap<MyEnum, SomeValue>whereMyEnumis a non-trivial tagged-union with field-structs in variants will not serialize into json, you would need to convert it toVec<(MyEnum, SomeValue)>first. Require arguments and the return type to be json-serializable for compatiblity with contracts written in other languages, like TypeScript; - Smart contract can use
stdbut cannot use wasm-incompatible OS-level features, like threads, file system, network, etc. In the future we will support the file system too; - Smart contracts should be deterministic and time-independent, e.g. we cannot use
Instant::now. In the future we will exposeInstant::now;
We also have the following temporary inefficiencies:
- Current smart contracts do not utilize the trie and do not use state storage efficiently. It is okay for small collections,
but in the future we will provide an alternative
near::collections::{HashMap, HashSet, Vec}that will be using storage in an efficient way; - The current smart contract size is around typically ~80-180Kb, which happens because we compile-in the
bincodeandserde-jsonlibraries. In the future, we will cherry-pick only the necessary components from these libraries. For now you can usewasm-optto slightly shrink the size:
See Binaryen for the installation instructions.