Smart contracts

I found it quite useful to explore the partially interactive Anatomy of a Contract

Introduction Official Near Introduction

Install dependencies

# 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 the NEAR CLI 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

Create a smart contract default skeleton:

cargo near new hello-near

After ensuring you have an account you may build the smart contract:

cargo near build

Your wasm will be generated which will them be deployable for example to the test-net:

near contract deploy <created-account> use-file ./target/near/hello_near.wasm without-init-call network-config testnet sign-with-keychain send

Sample output:

near contract deploy vfp.testnet use-file ./target/near/hello_near.wasm without-init-call network-config testnet sign-with-keychain send

Unsigned transaction:

signer_id:    vfp.testnet
receiver_id:  vfp.testnet
actions:
   -- deploy contract 3v7ievz4W6UKBwWubLvyJbSmsSEHnrnXJhRPqJNBQNaK          

▹▸▹▹▹ Signing the transaction with a key saved in the secure keychain ...                                             
Your transaction was signed successfully.
Public key: ed25519:2nh8uWoxsHDj9hzUKfkabtL7YDSTBNPSTDPsaz8ELQoX
Signature: ed25519:48m8ZqdQ3xjFkAogqQoameH6zgVC64kcKkh56PjidBe1B2AW6UUF8cND3QkvZu1SXqE18KzPYyYYxczih5ZjXZdD
▹▹▸▹▹ Sending transaction ...                                                                                         
--- Logs ---------------------------
Logs [vfp.testnet]:   No logs
--- Result -------------------------
Empty result
------------------------------------

Contract code has been successfully deployed.

Gas burned: 7.4 Tgas
Transaction fee: 0.0007339617339116 NEAR
Transaction ID: C8anQCbcTMwsHyneBQhmTnrLeR4EcNuqkXt8YaDo9nGP
To see the transaction in the transaction explorer, please open this url in your browser:
https://explorer.testnet.near.org/transactions/C8anQCbcTMwsHyneBQhmTnrLeR4EcNuqkXt8YaDo9nGP

Here is your console command if you need to script it or re-run:
    near contract deploy vfp.testnet use-file ./target/near/hello_near.wasm without-init-call network-config testnet sign-with-keychain send

Interacting with smart contracts

From the CLI

Querying the states:

near view <created-account> <function-name>

Updating status:

near call <created-account> set_greeting '{"greeting": "hola"}' -accountId <created-account>

// Instantiate a contract object let contract = Contract::new(account_id, contract_id, signer); // Call a method on the contract contract.call_method("method_name", json!({ "param": "value" })); // Get contract state let state: ContractState = contract.view_method("get_state", json!({}));

Handling tokens

// Transfer tokens from one account to another let sender = near.get_account("sender_account"); let recipient = near.get_account("recipient_account"); sender.transfer(&recipient, 100); // Check token balance let balance = recipient.get_balance();

Storage

In the context of smart contracts it is always a good idea to keep the storage requirements low. In that case you are invited to use the Native collections provided by the programming language, these will be serialized into a single value and stored together. If you do not have other alternative than storing big amount of data, then you better take a look at the SDK Collections provided by the NEAR SDk.

There is a very useful table in the Near documentation with the complexity for the typical operations of each of the provided structures. https://docs.near.org/build/smart-contracts/anatomy/collections#complexity

Vector.

Dynamic arrays

#![allow(unused)]
fn main() {
// Declare a vector of u64 elements
let mut my_vector: Vec<u64> = Vec::new();
// Add elements to the vector
my_vector.push(10);
my_vector.push(20);
my_vector.push(30);
// Access elements in the vector
let second_element = my_vector[1];
}

LookupSet

An unordered collection of unique elements. Efficient membership checks

#![allow(unused)]
fn main() {
// Declare a LookupSet of string elements
let mut my_lookupset: LookupSet<String> = LookupSet::new();
// Add elements to the LookupSet
my_lookupset.insert("apple".to_string());
my_lookupset.insert("banana".to_string());
// Check membership
let contains_apple = my_lookupset.contains("apple".to_string());
}

UnorderedMap

A key-value data structure that does not guarantee any specific order of elements.

#![allow(unused)]
fn main() {
// Declare an UnorderedMap with u32 keys and string values
let mut my_unorderedmap: UnorderedMap<u32, String> = UnorderedMap::new();
// Add key-value pairs to the UnorderedMap
my_unorderedmap.insert(1, "value1".to_string());
my_unorderedmap.insert(2, "value2".to_string());
// Iterate over the key-value pairs
for (key, value) in my_unorderedmap.iter() {
   // Process each key-value pair
}

## UnorderedSets

// Declare an UnorderedSet of u32 elements
let mut my_unorderedset: UnorderedSet<u32> = UnorderedSet::new();
// Add elements to the UnorderedSet
my_unorderedset.insert(1);
my_unorderedset.insert(2);// Iterate over the elements
for element in my_unorderedset.iter() {
	// Process each element
}

## LookupMap

// Declare a LookupMap with string keys and u64 values
let mut my_lookupmap: LookupMap<String, u64> = LookupMap::new();
// Add key-value pairs to the LookupMap
my_lookupmap.insert("key1".to_string(), 10);
my_lookupmap.insert("key2".to_string(), 20);
// Access values based on keys
let value = my_lookupmap.get("key1".to_string());

## TreeMap

// Declare a TreeMap with u64 keys and string values
let mut my_treemap: TreeMap<u64, String> = TreeMap::new();
// Add key-value pairs to the TreeMap
my_treemap.insert(3, "value3".to_string());
my_treemap.insert(1, "value1".to_string());
my_treemap.insert(2, "value2".to_string());
// Iterate over the key-value pairs in sorted order
for (key, value) in my_treemap.iter() {
	// Process each key-value pair
}
}