Skip to content

Commit 07e479c

Browse files
committed
Initial implementation of quickstart tutorial for js enclave
1 parent 21d2489 commit 07e479c

File tree

2 files changed

+297
-6
lines changed

2 files changed

+297
-6
lines changed
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
---
2+
id: enclave-quickstart
3+
title: Javascript Enclave
4+
sidebar_label: Enclave Quickstart
5+
---
6+
7+
The NEAR platform has historically supported writing contracts in Rust and AssemblyScript. This document aims to introduce developers to a new way of writing smart contracts by using Javascript.
8+
9+
Javascript is a widely used programming language that is most well known for its Webpage scripting usages. See the [official Javascript docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript) for more details.
10+
11+
<blockquote class="warning">
12+
<strong>heads up</strong><br /><br />
13+
14+
Javascript smart contract development is not recommended for financial use cases as it is still very new to the NEAR ecosystem.
15+
16+
</blockquote>
17+
18+
## Overview {#overview}
19+
20+
The Javascript Enclave, or jsvm for short, provides an isolated environment where users can learn the basics of how to write smart contracts on NEAR. This isolated environment is run on a virtual machine, similar to how [aurora](https://doc.aurora.dev/getting-started/aurora-engine) operates. Standard smart contracts that are built using Rust or AssemblyScript compile to [WebAssembly](https://webassembly.org/) or simply WASM. With the jsvm, contracts are encoded to base64 and are deployed to a virtual machine.
21+
22+
There are several pros and cons when comparing the enclave approach to the regular WASM approach. The key differences are outlined below.
23+
24+
| Areas | WebAssembly | Enclave |
25+
|---------------------------|--------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
26+
| Can interact with any smart contract on NEAR |||
27+
| Synchronous Cross-Contract Calls |||
28+
| Standards Support |||
29+
| Function Call Access Key Support |||
30+
31+
The Javascript Enclave is a very powerful tool to help you kickstart your smart contract programming journey. Writing contracts in javascript is much easier than learning Rust and the ability for cross-contract calls to be synchronous can greatly help with people's understanding of how contracts can work.
32+
33+
## Quickstart {#quickstart}
34+
35+
In this quickstart guide, you'll learn the basics of setting up a new Javascript smart contract on the enclave that stores and retrieves a greeting message. You'll then go through and create a simple web-based frontend that displays the greeting and allows you to change it.
36+
37+
### Prerequisites
38+
39+
In order to successfully complete this quickstart guide, you'll need to have a few things installed:
40+
- [Node.js](https://nodejs.org/en/about/) and [npm](https://www.npmjs.com/):
41+
```bash
42+
curl -sL https://deb.nodesource.com/setup_17.x | sudo -E bash -
43+
sudo apt install build-essential nodejs
44+
PATH="$PATH"
45+
```
46+
Ensure that they are both installed by running a version check:
47+
```
48+
node -v
49+
npm -v
50+
```
51+
52+
It's important to have the **newest** version of the NEAR-CLI installed such that you can make use of the javascript features. To install or update, run:
53+
54+
```
55+
npm install -g near-cli
56+
```
57+
58+
### Creating a project
59+
60+
Now that you have Node and npm installed, create a new directory to initialize the project in.
61+
62+
```bash
63+
mkdir javascript-enclave-quickstart && cd javascript-enclave-quickstart
64+
```
65+
66+
Once you're in the directory, initialize a new default npm project.
67+
68+
```bash
69+
npm init -y
70+
```
71+
72+
This will create a `package.json` file with contents similar to:
73+
74+
```js
75+
{
76+
"name": "javascript-enclave-quickstart",
77+
"version": "1.0.0",
78+
"description": "",
79+
"main": "index.js",
80+
"scripts": {
81+
"test": "echo \"Error: no test specified\" && exit 1"
82+
},
83+
"keywords": [],
84+
"author": "",
85+
"license": "ISC"
86+
}
87+
```
88+
89+
The next step is to install the `near-sdk-js` package and add it as a dependency for your project. This will allow for convenient ways of building and interacting with your smart contract.
90+
91+
```bash
92+
npm install --save near-sdk-js
93+
```
94+
95+
Once the package has successfully been installed, you can create a convenient script in your `package.json` for building your contract. Add the following line to your `package.json` under the `scripts` section:
96+
97+
```diff
98+
{
99+
"name": "javascript-enclave-quickstart",
100+
"version": "1.0.0",
101+
"description": "",
102+
"main": "index.js",
103+
"scripts": {
104+
+ "build": "near-sdk build",
105+
"test": "echo \"Error: no test specified\" && exit 1"
106+
},
107+
"keywords": [],
108+
"author": "",
109+
"license": "ISC",
110+
"dependencies": {
111+
"near-sdk-js": "^0.1.1"
112+
}
113+
}
114+
```
115+
116+
> **Note:** This is optional and you can simply run `near-sdk build` instead.
117+
118+
You'll now want to create the `src` directory and initialize a new javascript file `index.js` where your contract logic will live.
119+
120+
```bash
121+
mkdir src && cd src && touch index.js && cd ..
122+
```
123+
124+
The last step is to create a new file called `babel.config.json` which allows you to configure how the contract is built. In the project root, create a new file and add the following content.
125+
126+
```bash
127+
touch babel.config.json
128+
```
129+
```js
130+
{
131+
"plugins": [
132+
"near-sdk-js/src/build-tools/near-bindgen-exporter",
133+
["@babel/plugin-proposal-decorators", {"version": "legacy"}]
134+
]
135+
}
136+
```
137+
138+
At this point, you just need to install all the packages and you will be ready to build your smart contract!
139+
140+
```bash
141+
npm install
142+
```
143+
144+
Your file structure should now look as follows:
145+
146+
```
147+
javascript-enclave-quickstart
148+
├── node_modules
149+
├── package-lock.json
150+
├── babel.config.json
151+
├── package.json
152+
└── src
153+
└── index.js
154+
```
155+
156+
### Writing your first contract
157+
158+
Now that you have the basic structure outlined for your project, it's time to start writing your first contract. You'll create a simple contract for setting and getting a greeting message on-chain.
159+
160+
The contract presents 2 methods: set_greeting and get_greeting. The first one stores a String in the contract's parameter message, while the second one retrieves it. By default, the contract returns the message "Hello".
161+
162+
Start by opening the `src/index.js` file as this is where your logic will go. You'll then want to add some imports that will help when writing the contract:
163+
164+
```js
165+
import {NearContract, NearBindgen, call, view, near} from 'near-sdk-js'
166+
```
167+
Let's break down these imports to help you understand why they're necessary.
168+
- `NearContract`: allows our contract to inherit important functionalities for changing and reading the contract's state.
169+
- `NearBindgen`: allows your contract to compile down to something that is NEAR compatible.
170+
- `call, view`: allows your methods to be view functions or change functions.
171+
- `near`: allows you to access important information within your functions such as the signer, predecessor, attached deposit etc..
172+
173+
Now that you've imported everything from the sdk, create a new class that extends the `NearContract`. This class will contain the core logic of your smart contract. You can also use this opportunity to create a default message variable:
174+
175+
```js
176+
// Define the default message
177+
const DEFAULT_MESSAGE = "Hello";
178+
179+
@NearBindgen
180+
class StatusMessage extends NearContract {
181+
// Define the constructor, which initializes the contract with a default message
182+
constructor() {
183+
// Used to give access to methods and properties of the parent or sibling class
184+
super()
185+
// Default the status records to
186+
this.message = DEFAULT_MESSAGE
187+
}
188+
}
189+
```
190+
Running the constructor will default the contract's `message` state variable with the `DEFAULT_MESSAGE`. There's no way to get the current greeting, however. Within the class, add the following function.
191+
192+
```js
193+
// Public method - returns the greeting saved, defaulting to DEFAULT_MESSAGE
194+
@view
195+
get_greeting() {
196+
env.log(`current greeting is ${this.message}`)
197+
return this.message
198+
}
199+
```
200+
You now have a way to initialize the contract and get the current greeting. The next step is to create a setter which will take a message as a parameter and set the contract's `message` variable equal to the passed in string.
201+
202+
```js
203+
// Public method - accepts a greeting, such as "howdy", and records it
204+
@call
205+
set_greeting(message) {
206+
let account_id = near.signerAccountId()
207+
env.log(`Saving greeting ${message}`)
208+
this.message = message
209+
}
210+
```
211+
212+
At this point, your contract is finished and should look as follows:
213+
214+
```js
215+
import {NearContract, NearBindgen, call, view, near} from 'near-sdk-js'
216+
217+
// Define the default message
218+
const DEFAULT_MESSAGE = "Hello";
219+
220+
@NearBindgen
221+
class StatusMessage extends NearContract {
222+
// Define the constructor, which initializes the contract with a default message
223+
constructor() {
224+
// Used to give access to methods and properties of the parent or sibling class
225+
super()
226+
// Default the status records to
227+
this.message = DEFAULT_MESSAGE
228+
}
229+
230+
// Public method - returns the greeting saved, defaulting to DEFAULT_MESSAGE
231+
@view
232+
get_greeting() {
233+
env.log(`current greeting is ${this.message}`)
234+
return this.message
235+
}
236+
237+
// Public method - accepts a greeting, such as "howdy", and records it
238+
@call
239+
set_greeting(message) {
240+
let account_id = near.signerAccountId()
241+
env.log(`Saving greeting ${message}`)
242+
this.message = message
243+
}
244+
}
245+
```
246+
247+
### Building
248+
249+
Now that your contract is finished, it's time to build and deploy it. Run the following command to build your JS code and get the `build/contact.base64` contract file.
250+
251+
```
252+
yarn build
253+
```
254+
255+
You can now deploy the contract and start interacting with it!
256+
257+
### Deploying
258+
259+
Start by deploying the contract using the following command. This will create a [dev account](/docs/concepts/account#dev-accounts) and deploy the contract to it.
260+
261+
```
262+
near js dev-deploy --base64File <build/contract.base64> --deposit 0.1
263+
```
264+
Alternatively, if you have an account already, you can specify the account you want to deploy to:
265+
266+
```
267+
near js deploy --accountId <YOUR_ACCOUNT_ID> --base64File <build/contract.base64> --deposit 0.1
268+
```
269+
270+
> **Note**: When deploying the smart contract using the enclave approach, it will live on top of a virtual machine smart contract that is deployed to `jsvm.testnet`. This will act as a "middleman" and to interact with your contract, you'll need to go through the `jsvm` contract.
271+
272+
### Interacting
273+
274+
Now that your contract is deployed,
275+
276+
277+
278+
279+
280+
281+
> Got a question?
282+
> <a href="https://stackoverflow.com/questions/tagged/nearprotocol"> > <h8>Ask it on StackOverflow!</h8></a>

website/sidebars.json

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@
8080
"develop/contracts/rust/near-sdk-rs",
8181
"develop/contracts/rust/testing-rust-contracts"
8282
]
83+
},
84+
{
85+
"type": "category",
86+
"label": "Javascript",
87+
"items": [
88+
"develop/contracts/js/enclave-quickstart"
89+
]
8390
}
8491
],
8592
"Front-end": [
@@ -89,11 +96,13 @@
8996
"api/naj-cookbook",
9097
"faq/naj-faq"
9198
],
92-
"Run a Node": [{
93-
"type": "link",
94-
"label": "Node Documentation",
95-
"href": "https://near-nodes.io/"
96-
}],
99+
"Run a Node": [
100+
{
101+
"type": "link",
102+
"label": "Node Documentation",
103+
"href": "https://near-nodes.io/"
104+
}
105+
],
97106
"NEAR <> ETH": [
98107
"develop/eth/evm",
99108
"develop/eth/rainbow-bridge"
@@ -259,4 +268,4 @@
259268
"community/contribute/contribute-faq"
260269
]
261270
}
262-
}
271+
}

0 commit comments

Comments
 (0)