near-sdk-gr

NEAR Smart Contract SDK for Grain

This project allows you to author smart contracts on the NEAR blockchain using the Grain programming language.

SDK documentation

View the individual pages for each SDK library:

Prerequsites

You’ll need a v0.5.x version of the Grain compiler on your machine and general knowledge of the language. For more information about the language and how to install it, visit grain-lang.org.

Setting up your project

Create a directory for your project. For this example, we’ll call it example-contract.

mkdir example-contract && cd example-contract
git init

Next, add near-sdk-gr to your project.

git submodule add https://github.com/grain-lang/near-sdk-gr.git

Writing your first contract

We’ll create a simple counter. Create a file called counter.gr with the following contents:

import Option from "option"
import Storage from "near/storage"

let key = "counter"

export let setCounter = val => {
  // Write the value to memory.
  Storage.setInt32(key, val)
}

export let loadCounter = () => {
  // Check if key is in storage
  if (!(Storage.hasKey(key))) {
    // Initialize to zero.
    setCounter(0l)
  }

  Option.expect("key should be set", Storage.getInt32(key))
}

Option is Grain’s standard library for working with the Option type and Storage is the SDK for working with storage on the blockchain.

key is the name we’ll use for the key-value pair in storage—in our case, it’s called "counter".

The setCounter function stores a counter value and loadCounter retrieves a counter value.

Next, we’ll create the core of our contract in a file called index.gr:

import { add as (+), sub as (-) } from "int32"
import Utils from "near/utils"
import { setCounter, loadCounter } from "./counter"

export let increment = () => {
  setCounter(loadCounter() + 1l)
}

export let decrement = () => {
  setCounter(loadCounter() - 1l)
}

export let getCounter = () => {
  let value = toString(loadCounter())
  Utils.valueReturnString(value)
}

This is the interface of our contract. Our contract has two methods to change the contract state, increment and decrement, and one method to view the state of the contract, getCounter. getCounter utilizes Utils.valueReturnString to return the counter value as a string back to the caller.

Compiling the contract

There are a number of flags we’ll need to pass to the compiler.

All together, that’s

grain compile -I near-sdk-gr --wasi-polyfill near-sdk-gr/wasi.gr --no-bulk-memory --use-start-section --no-gc --release index.gr

This can be made into a script to make compiling the contract easier.

Testing the contract

Contracts can be tested before deploying them using near-workspaces. For an example, see the counter contract tests.

Configuring VSCode

If you use VSCode to develop your contract, you can tell the language server where the NEAR SDK is by setting the grain.cliFlags setting for your workspace to include -I near-sdk-gr. To prevent recompilation of all of the wasm modules in the tree, configure the full set of flags, -I near-sdk-gr --wasi-polyfill near-sdk-gr/wasi.gr --no-bulk-memory --use-start-section --no-gc --release.