Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add project setup information and docs site #4

Merged
merged 6 commits into from
Dec 29, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

This project provides bindings to the [NEAR](https://near.org) SDK in order to enable easy writing of NEAR smart contracts in Grain.

## Generating the Documentation
You can find information on how to use this SDK at https://grain-lang.github.io/near-sdk-gr/.

## Developing

### Generating the Documentation

```bash
$ grain doc src -o docs --current-version=0.0.0
```

# Building the Tests
### Building the Tests

Due to an [NPM Bug](https://github.com/npm/cli/issues/4774), this project requires `[email protected]` to build.

Expand Down
120 changes: 120 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# 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:

- [Context](./near/context)
- [Economics](./near/economics)
- [Math](./near/math)
- [Promise](./near/promise)
- [Register](./near/register)
- [Storage](./near/storage)
- [Utils](./near/utils)
- [Validator](./near/validator)
- [Wasi](./near/wasi)

## 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](https://grain-lang.org).

## Setting up your project

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

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

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

```sh
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:

```grain
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`:

```grain
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.

- `-I near-sdk-gr` to tell the compiler where the SDK is;
- `--wasi-polyfill near-sdk-gr/src/near/wasi.gr` to stub out WASI functionality;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like that this is in src/

Can we bring these down a directory?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow what you mean here!

- `--no-bulk-memory` to disable bulk memory operations until NEAR supports them;
- `--use-start-section` to ensure the NEAR blockchain loads all contract setup;
- `--no-gc` to save on gas and storage fees;
- `--elide-type-info` to save a bit more on storage fees;
- `--release` to ensure we have the smallest and most efficient contract to deploy

All together, that's

```sh
grain compile -I near-sdk-gr --wasi-polyfill near-sdk-gr/src/near/wasi.gr --no-bulk-memory --use-start-section --no-gc --elide-type-info --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](https://github.com/grain-lang/near-sdk-gr/blob/4eaeeb90a91e700a7a64fd83cad97946e19d99d3/test-suite/example-contracts/counter/tests/counter.test.js).

## 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 to include `-I near-sdk-gr`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you need all the flags passed to the LSP so that recompiles don't happen, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, though we don't currently advertise people do that (like for compiling for release)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add a note about putting the whole thing though

2 changes: 1 addition & 1 deletion test-suite/example-contracts/counter/src/counter.gr
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export let loadCounter = () => {
// Check if key is in storage
if (!(Storage.hasKey(key))) {
// Initialize to zero.
ignore(setCounter(0l))
setCounter(0l)
}

Option.expect("key should be set", Storage.getInt32(key))
Expand Down
4 changes: 2 additions & 2 deletions test-suite/example-contracts/counter/src/index.gr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import Utils from "near/utils"
import { setCounter, loadCounter } from "./counter"

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

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

export let getCounter = () => {
Expand Down