Skip to content

Commit

Permalink
Updated README w/ newest JS CLI calls
Browse files Browse the repository at this point in the history
  • Loading branch information
ChaoticTempest committed May 20, 2022
1 parent 3b09714 commit 76464a5
Showing 1 changed file with 157 additions and 79 deletions.
236 changes: 157 additions & 79 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,50 @@ It is tested on Ubuntu 20.04 and Intel Mac. Other linux and M1 Macs should also
2. `yarn && yarn build` to get <contract>.base64 file (JS smart-contract).
3. Use near-cli to deploy `jsvm.wasm` from the `res` folder to your account.
4. Deploy <contract>.base64 file to `JSVM` account from the previous step.
```sh
near js deploy --accountId <your-account> --base64File <contract-name>.base64 --deposit 0.1 --jsvm <jsvm-account>
```
near call <jsvm-account> deploy_js_contract --accountId <your-account> --args $(cat <contract-name>.base64) --base64 --deposit 0.1
```
<details>
<summary><strong>Or use the raw CLI call instead</strong></summary>
<p>

near call <jsvm-account> deploy_js_contract --accountId <your-account> --args $(cat <contract-name>.base64) --base64 --deposit 0.1

</p>
</details>

5. Interact with your contract using NEAR CLI or `near-api-js`. Encode the parameters and call. If the call cause the state increasement, you also need to attach NEAR to cover the storage deposit for the delta.

```sh
near js call <your-account> <method-name> --args <args> --deposit 0.1 --jsvm <jsvm-account>
```
near call <jsvm-account> call_js_contract --accountId <caller-account> --args <encoded-args> --base64
```
Where `<encoded-args>` can be obtained by:
```
node encode_call.js js_contract_name method_name args
```

<details>
<summary><strong>Or use the raw CLI call instead</strong></summary>
<p>

near call <jsvm-account> call_js_contract --accountId <your-account> --args <encoded-args> --base64

# where `<encoded-args>` can be obtained by:
node encode_call.js <your-account> <method-name> <args>

</p>
</details>

6. If you want to remove the js contract and withdraw the storage deposit, use:

```sh
near js remove --accountId <your-account> --jsvm <jsvm-account>
```
near call <jsvm-account> remove_js_contract --accountId <your-account>
```

<details>
<summary><strong>Or use the raw CLI call instead</strong></summary>
<p>

near call <jsvm-account> remove_js_contract --accountId <your-account>

</p>
</details>

## Demo

Expand All @@ -46,109 +75,158 @@ target/debug/neard run
```

3. Go back to `near-sdk-js`. Have `near-cli` installed. Deploy the jsvm contract. Example session:
```
```sh
near-sdk-js (master) export NEAR_ENV=local
near-sdk-js (master) near deploy test.near jsvm.wasm
Loaded master account test.near key from /home/bo/.near/validator_key.json with public key = ed25519:XXqxAHP1ZRcwCwBTr1MbdF9NM7UVynuTnxhZfFeE5UJ
Starting deployment. Account id: test.near, node: http://localhost:3030, helper: http://localhost:3000, file: jsvm.wasm
Transaction Id EGVd29tthMp7fqkDgP8frftgZhhb3FVazaFhvXpYXNhw
To see the transaction in the transaction explorer, please open this url in your browser
http://localhost:9001/transactions/EGVd29tthMp7fqkDgP8frftgZhhb3FVazaFhvXpYXNhw
Done deploying to test.near
near-sdk-js (master) near deploy test.near jsvm.wasm
```

<details>
<summary><strong>Example output</strong></summary>
<p>

Loaded master account test.near key from /home/bo/.near/validator_key.json with public key = ed25519:XXqxAHP1ZRcwCwBTr1MbdF9NM7UVynuTnxhZfFeE5UJ
Starting deployment. Account id: test.near, node: http://localhost:3030, helper: http://localhost:3000, file: jsvm.wasm
Transaction Id EGVd29tthMp7fqkDgP8frftgZhhb3FVazaFhvXpYXNhw
To see the transaction in the transaction explorer, please open this url in your browser
http://localhost:9001/transactions/EGVd29tthMp7fqkDgP8frftgZhhb3FVazaFhvXpYXNhw
Done deploying to test.near

</p>
</details>

4. Build, deploy hello contract to jsvm contract, and call hello. Example session:
```
near-sdk-js (master) ./builder.sh examples/low-level/hello_near.js
```sh
near-sdk-js (master) ./builder.sh examples/low-level/hello_near.js
near-sdk-js (master) near call test.near deploy_js_contract --accountId test.near --base64 --args $(cat hello_near.base64) --deposit 0.1
Scheduling a call: test.near.deploy_js_contract(AgYsZXhhbXBsZXMvaGVsbG9fbmVhci5qcwpoZWxsbwxoZWxsbzIGZW52BmxvZxRIZWxsbyBOZWFyD7wDAAIAAL4DAAHAAwAADgAGAaABAAAAAQICCwC+AwABwAMBAQjqCMAA4cAB4ikpvAMBBAEACg4OQwYBvgMAAAADAAATADjhAAAAQuIAAAAE4wAAACQBACm8AwECA10OQwYBwAMAAAADAAEQADjhAAAAQuIAAAC/ACQBACm8AwUCA04HCDIyMjI=) with attached 0.1 NEAR
Loaded master account test.near key from /home/bo/.near/validator_key.json with public key = ed25519:XXqxAHP1ZRcwCwBTr1MbdF9NM7UVynuTnxhZfFeE5UJ
Doing account.functionCall()
Transaction Id Df7txPSFWwaBLTz61pSxoVrPPu6qY7fUTJ31xuQtXDBf
To see the transaction in the transaction explorer, please open this url in your browser
http://localhost:9001/transactions/Df7txPSFWwaBLTz61pSxoVrPPu6qY7fUTJ31xuQtXDBf
''
near-sdk-js (master) near call test.near call_js_contract --accountId test.near --base64 --args $(node encode_call.js test.near hello '')
Scheduling a call: test.near.call_js_contract(anN2bXRlc3Rlci50ZXN0bmV0AGhlbGxvAA==)
Loaded master account test.near key from /home/bo/.near/validator_key.json with public key = ed25519:XXqxAHP1ZRcwCwBTr1MbdF9NM7UVynuTnxhZfFeE5UJ
Doing account.functionCall()
Receipt: AcRRGeR16FYg5AEMZ163v5Av1NanZtRHocDUvmGTvoYN
Log [test.near]: Hello Near
Transaction Id GkitU1Cm5bdQJWe6bzkYganiS9tfetuY4buqGFypvQWL
To see the transaction in the transaction explorer, please open this url in your browser
http://localhost:9001/transactions/GkitU1Cm5bdQJWe6bzkYganiS9tfetuY4buqGFypvQWL
''
```
<details>
<summary><strong>Example output</strong></summary>
<p>

Scheduling a call: test.near.deploy_js_contract(AgYsZXhhbXBsZXMvaGVsbG9fbmVhci5qcwpoZWxsbwxoZWxsbzIGZW52BmxvZxRIZWxsbyBOZWFyD7wDAAIAAL4DAAHAAwAADgAGAaABAAAAAQICCwC+AwABwAMBAQjqCMAA4cAB4ikpvAMBBAEACg4OQwYBvgMAAAADAAATADjhAAAAQuIAAAAE4wAAACQBACm8AwECA10OQwYBwAMAAAADAAEQADjhAAAAQuIAAAC/ACQBACm8AwUCA04HCDIyMjI=) with attached 0.1 NEAR
Loaded master account test.near key from /home/bo/.near/validator_key.json with public key = ed25519:XXqxAHP1ZRcwCwBTr1MbdF9NM7UVynuTnxhZfFeE5UJ
Doing account.functionCall()
Transaction Id Df7txPSFWwaBLTz61pSxoVrPPu6qY7fUTJ31xuQtXDBf
To see the transaction in the transaction explorer, please open this url in your browser
http://localhost:9001/transactions/Df7txPSFWwaBLTz61pSxoVrPPu6qY7fUTJ31xuQtXDBf
''
near-sdk-js (master) near call test.near call_js_contract --accountId test.near --base64 --args $(node encode_call.js test.near hello '')
Scheduling a call: test.near.call_js_contract(anN2bXRlc3Rlci50ZXN0bmV0AGhlbGxvAA==)
Loaded master account test.near key from /home/bo/.near/validator_key.json with public key = ed25519:XXqxAHP1ZRcwCwBTr1MbdF9NM7UVynuTnxhZfFeE5UJ
Doing account.functionCall()
Receipt: AcRRGeR16FYg5AEMZ163v5Av1NanZtRHocDUvmGTvoYN
Log [test.near]: Hello Near
Transaction Id GkitU1Cm5bdQJWe6bzkYganiS9tfetuY4buqGFypvQWL
To see the transaction in the transaction explorer, please open this url in your browser
http://localhost:9001/transactions/GkitU1Cm5bdQJWe6bzkYganiS9tfetuY4buqGFypvQWL
''

</p>
</details>

### On Testnet
Latest master version of near-sdk-js enclave has been deployed on `jsvm.testnet`. You can use it or deploy your own copy of jsvm, which is simiar to the steps for deploy on local node. The following is the step to deploy and call your contract on `jsvm.testnet`.

1. Build the contract
```
near-sdk-js (master) ./builder.sh examples/low-level/hello_near.js
near-sdk-js (master) ./builder.sh examples/low-level/hello_near.js
```

2. Create an account on testnet wallet. Login it with near-cli:
```
```sh
near-sdk-js (master) export NEAR_ENV=testnet
near-sdk-js (master) near login
```

Please authorize NEAR CLI on at least one of your accounts.
<details>
<summary><strong>Example output</strong></summary>
<p>

If your browser doesn't automatically open, please visit this URL
https://wallet.testnet.near.org/login/?referrer=NEAR+CLI&public_key=ed25519%3A6eNw1uLsVbvHJhPrcN9Rj9wefqfzxJ2tz7VqxY8m3F88&success_url=http%3A%2F%2F127.0.0.1%3A5000
Please authorize at least one account at the URL above.
Please authorize NEAR CLI on at least one of your accounts.

Which account did you authorize for use with NEAR CLI?
Enter it here (if not redirected automatically):
Logged in as [ jsvmtester.testnet ] with public key [ ed25519:6eNw1u... ] successfully
```
If your browser doesn't automatically open, please visit this URL
https://wallet.testnet.near.org/login/?referrer=NEAR+CLI&public_key=ed25519%3A6eNw1uLsVbvHJhPrcN9Rj9wefqfzxJ2tz7VqxY8m3F88&success_url=http%3A%2F%2F127.0.0.1%3A5000
Please authorize at least one account at the URL above.

Which account did you authorize for use with NEAR CLI?
Enter it here (if not redirected automatically):
Logged in as [ jsvmtester.testnet ] with public key [ ed25519:6eNw1u... ] successfully

</p>
</details>

3. Deploy the JS contract:
```
```sh
near-sdk-js (master) export JSVM_ACCOUNT=jsvm.testnet
near-sdk-js (master) near call $JSVM_ACCOUNT deploy_js_contract --accountId jsvmtester.testnet --base64 --args $(cat hello_near.base64) --deposit 0.1
Scheduling a call: jsvm.testnet.deploy_js_contract(AgYsZXhhbXBsZXMvaGVsbG9fbmVhci5qcwpoZWxsbwxoZWxsbzIGZW52BmxvZxRIZWxsbyBOZWFyD7wDAAIAAL4DAAHAAwAADgAGAaABAAAAAQICCwC+AwABwAMBAQjqCMAA4cAB4ikpvAMBBAEACg4OQwYBvgMAAAADAAATADjhAAAAQuIAAAAE4wAAACQBACm8AwECA10OQwYBwAMAAAADAAEQADjhAAAAQuIAAAC/ACQBACm8AwUCA04HCDIyMjI=) with attached 0.1 NEAR
Doing account.functionCall()
Transaction Id 46vC327SWs7JNV7G3XMHkRzETyc6WuxwkdwLhV6Go2kp
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/46vC327SWs7JNV7G3XMHkRzETyc6WuxwkdwLhV6Go2kp
''
```

<details>
<summary><strong>Example output</strong></summary>
<p>

Scheduling a call: jsvm.testnet.deploy_js_contract(AgYsZXhhbXBsZXMvaGVsbG9fbmVhci5qcwpoZWxsbwxoZWxsbzIGZW52BmxvZxRIZWxsbyBOZWFyD7wDAAIAAL4DAAHAAwAADgAGAaABAAAAAQICCwC+AwABwAMBAQjqCMAA4cAB4ikpvAMBBAEACg4OQwYBvgMAAAADAAATADjhAAAAQuIAAAAE4wAAACQBACm8AwECA10OQwYBwAMAAAADAAEQADjhAAAAQuIAAAC/ACQBACm8AwUCA04HCDIyMjI=) with attached 0.1 NEAR
Doing account.functionCall()
Transaction Id 46vC327SWs7JNV7G3XMHkRzETyc6WuxwkdwLhV6Go2kp
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/46vC327SWs7JNV7G3XMHkRzETyc6WuxwkdwLhV6Go2kp
''

</p>
</details>

Note that, in order to deploy the contract, the deployer need to deposit sufficient amount of NEAR to cover storage deposit. It's roughly 0.01 NEAR for 1KB of contract. If you deposit more than required, the additional part will be refunded. If no adequate deposit is attached, the deploy will failed with a panic. If future deployment increase or decrease in size, the difference will need to be paid or refunded, respectively.

4. Call the JS contract:
```
```sh
near-sdk-js (master) near call $JSVM_ACCOUNT call_js_contract --accountId jsvmtester.testnet --args $(node encode_call.js jsvmtester.near hello '') --base64
Scheduling a call: jsvm.testnet.call_js_contract(anN2bXRlc3Rlci50ZXN0bmV0AGhlbGxvAA==)
Doing account.functionCall()
Receipt: 4Mn5d3Kc4n67MxQkcEmi4gxKbrrKXvJE9Rin3q3fdCsQ
Log [jsvm.testnet]: Hello Near
Transaction Id 43K5sjgVeWCYzuDJ3S6j5XHxQnRY8w1TQ84MiDxdtHp1
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/43K5sjgVeWCYzuDJ3S6j5XHxQnRY8w1TQ84MiDxdtHp1
''
```


<details>
<summary><strong>Example output</strong></summary>
<p>

Scheduling a call: jsvm.testnet.call_js_contract(anN2bXRlc3Rlci50ZXN0bmV0AGhlbGxvAA==)
Doing account.functionCall()
Receipt: 4Mn5d3Kc4n67MxQkcEmi4gxKbrrKXvJE9Rin3q3fdCsQ
Log [jsvm.testnet]: Hello Near
Transaction Id 43K5sjgVeWCYzuDJ3S6j5XHxQnRY8w1TQ84MiDxdtHp1
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/43K5sjgVeWCYzuDJ3S6j5XHxQnRY8w1TQ84MiDxdtHp1
''

</p>
</details>

```
near-sdk-js (master) near call $JSVM_ACCOUNT call_js_contract --accountId jsvmtester2.testnet --args $(node encode_call.js jsvmtester.near hello '') --base64
Scheduling a call: jsvm.testnet.call_js_contract(anN2bXRlc3Rlci50ZXN0bmV0AGhlbGxvAA==)
Doing account.functionCall()
Receipt: DzysE3ZNG8fBY4djq1KDYyDLs53jga2Lxpou2kjm3HzC
Log [jsvm.testnet]: Hello Near
Transaction Id AGRHcCCBCFex2hiXQh5BhFDoq7bN1eVoULhSyL4zgMRA
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/AGRHcCCBCFex2hiXQh5BhFDoq7bN1eVoULhSyL4zgMRA
''
```

<details>
<summary><strong>Example output</strong></summary>
<p>

Scheduling a call: jsvm.testnet.call_js_contract(anN2bXRlc3Rlci50ZXN0bmV0AGhlbGxvAA==)
Doing account.functionCall()
Receipt: DzysE3ZNG8fBY4djq1KDYyDLs53jga2Lxpou2kjm3HzC
Log [jsvm.testnet]: Hello Near
Transaction Id AGRHcCCBCFex2hiXQh5BhFDoq7bN1eVoULhSyL4zgMRA
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/AGRHcCCBCFex2hiXQh5BhFDoq7bN1eVoULhSyL4zgMRA
''

</p>
</details>

Note that, The second call shows this method can be call by anyone (`jsvmtester2.testnet` in above example, make sure you login the account with `near login`), not just the one who deployed this JS contract (`jsvmtester.testnet`).

## NEAR-SDK-JS Low Level API Reference

Use `env.func_name(args)` to call low level APIs in JavaScript contracts. `env` is already imported before contract start. For example, `env.read_register(0)`.
To use nightly host functions, such as `alt_bn128_g1_sum`, the enclave contract need to be built with `NEAR_NIGHTLY=1 ./build.sh` and deployed to a nearcore node that has nightly enabled.

### About Type
### About Type

- In arguments, `Uint64: Number | BigInt`. In return, `Uint64: BigInt`. Because JavaScript Number cannot hold all Uint64 without losing precision. But as arguments, interger number is also allowed for convinience. Same for `Uint128`.
- `String` in both arguments and return is a byte buffer encoded as a JavaScript String. Which means:
Expand Down Expand Up @@ -227,7 +305,7 @@ function log(msg: String);
function log_utf8(msg: String);
function log_utf16(msg: String);
// Name confliction with WASI. Can be re-exported with a different name on NEAR side with a protocol upgrade
// Or, this is actually not a primitive, can be implement with log and panic host functions in C side or JS side.
// Or, this is actually not a primitive, can be implement with log and panic host functions in C side or JS side.
// function abort(msg_ptr: Uint32, filename_ptr: Uint32, u32: Uint32, col: Uint32);
```

Expand Down Expand Up @@ -322,7 +400,7 @@ function jsvm_storage_has_key(key: String): Uint64;

These are equivalent to `storage_*` but access limit to the substate of current JS contract. The `jsvm_storage_write` and `jsvm_storage_remove` require and refund deposit to cover the storage delta. `jsvm_storage_*` access the substate of current JS contract by prefix the key of current JS contract name (deployer's account id). You can use `storage_read` and `storage_has_key` to get code and state of other JS contracts. More specifically: code of `contractA` is stored under the key `contractA/code`. state of `contractA` is stored under `contractA/state/` concat with developer specifid key. And:
```
jsvm_storage_read(k, register_id)
jsvm_storage_read(k, register_id)
// equvalent to
storage_read(jsvm_js_contract_name + '/state/' + k)
```
Expand All @@ -333,7 +411,7 @@ function jsvm_value_return(value: String);
function jsvm_call(contract_name: String, method: String, args: String, register_id: Uint64);
```

The `jsvm_value_return` is the version of `value_return` that should be used in all JavaScript contracts. It play well with `jsvm_call`.
The `jsvm_value_return` is the version of `value_return` that should be used in all JavaScript contracts. It play well with `jsvm_call`.

The `jsvm_call` invoke a synchronous cross contract call, to the given JavaScript `contract_name`, `method` with `args`. And capture the value returned from the call and stored in `register_id`.

Expand All @@ -350,8 +428,8 @@ The `jsvm_call` invoke a synchronous cross contract call, to the given JavaScrip

### The error reporting capability of a wasm contract
Smart contract can only use `panic` or `panic_utf8` to abort from execution. That is of error kind `GuestPanic {msg}`. It displays in RPC as `"Smart contract panicked: {msg}"`
And only `panic_utf8` can set that message.
Other than this, if calls a host function, it can returns error provided by that host function. For example, any host function can return a `GasExceeded`. `log_utf8` can return `BadUTF8`. This behavior is part of protocol and we cannot control or trigger in JavaScript (without calling `env.*`).
And only `panic_utf8` can set that message.
Other than this, if calls a host function, it can returns error provided by that host function. For example, any host function can return a `GasExceeded`. `log_utf8` can return `BadUTF8`. This behavior is part of protocol and we cannot control or trigger in JavaScript (without calling `env.*`).

### Use errors
You can throw an error in JavaScript. Our quickjs runtime will detect and automatically invoke `panic_utf8` with `"{error.message}\n:{error.stack}"`. As a result, transaction will fail with `"Smart contract panicked: {error.message}\n{error.stack}"` error message.
Expand All @@ -365,6 +443,6 @@ User can use verror this way:
Under the hood, our quickjs runtime would take the final throwed error, and invoke panic_utf8("{error.message}\n{error.stack}")

## Debug and Test
To get more debug utilities, such as debug print (`debug.log`) and logging stacktrace, you can build JSVM with sandbox flag: `NEAR_SANDBOX=1 ./build.sh`. A `jsvm_sandbox.wasm` will be build in current directory. You can then deploy sandbox versioned jsvm to a local [near-sandbox](https://github.com/near/sandbox). near-sandbox can be launched either manually or via the official testing framework [near-workspaces](https://github.com/near/workspaces-js). We recommend to use near-workspaces to write tests for your smart contracts. An example of use near-workspaces in a JS contract project can be found in `examples/project/`.
To get more debug utilities, such as debug print (`debug.log`) and logging stacktrace, you can build JSVM with sandbox flag: `NEAR_SANDBOX=1 ./build.sh`. A `jsvm_sandbox.wasm` will be build in current directory. You can then deploy sandbox versioned jsvm to a local [near-sandbox](https://github.com/near/sandbox). near-sandbox can be launched either manually or via the official testing framework [near-workspaces](https://github.com/near/workspaces-js). We recommend to use near-workspaces to write tests for your smart contracts. An example of use near-workspaces in a JS contract project can be found in `examples/project/`.

Note that, `jsvm.wasm` can be used for sandbox/near-workspaces as well. But to debug print, you need to use `jsvm_sandbox.wasm` instead.

0 comments on commit 76464a5

Please sign in to comment.