tests: example rust contracts moved from warp-wasm-templates
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -2,6 +2,8 @@
|
||||
|
||||
node_modules/
|
||||
crates/warp-contracts/target
|
||||
crates/pst/contract/definition/bindings/
|
||||
crates/pst/cache/
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
@@ -28,4 +30,6 @@ yalc.lock
|
||||
bundles/
|
||||
|
||||
.secrets
|
||||
logs
|
||||
logs
|
||||
|
||||
target
|
||||
|
||||
3
crates/pst/.eslintignore
Normal file
3
crates/pst/.eslintignore
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
lib
|
||||
src/__tests__/integration/data
|
||||
18
crates/pst/.eslintrc.json
Normal file
18
crates/pst/.eslintrc.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint", "prettier"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": 1, // warning
|
||||
"multiline-ternary": "off",
|
||||
"no-nested-ternary": "off",
|
||||
"no-multiple-empty-lines": "off",
|
||||
"prettier/prettier": 2 // error
|
||||
}
|
||||
}
|
||||
3
crates/pst/.prettierignore
Normal file
3
crates/pst/.prettierignore
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
lib
|
||||
src/__tests__/integration/data
|
||||
6
crates/pst/.prettierrc
Normal file
6
crates/pst/.prettierrc
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"semi": true,
|
||||
"trailingComma": "none",
|
||||
"singleQuote": true,
|
||||
"printWidth": 120
|
||||
}
|
||||
441
crates/pst/Cargo.lock
generated
Normal file
441
crates/pst/Cargo.lock
generated
Normal file
@@ -0,0 +1,441 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.132"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1847b767a3d62d95cbf3d8a9f0e421cf57a0d8aa4f411d4b16525afb0284d4ed"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"schemars_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af4d7e1b012cb3d9129567661a63755ea4b8a7386d339dc945ae187e403c6743"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-wasm-bindgen"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89797afd69d206ccd11fb0ea560a44bbb87731d020670e79416d442919257d42"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-test"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53474327ae5e166530d17f2d956afcb4f8a004de581b3cae10f12006bc8163e3"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
|
||||
|
||||
[[package]]
|
||||
name = "warp-contracts"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"warp-contracts-core",
|
||||
"warp-contracts-macro",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp-contracts-core"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp-contracts-macro"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
"warp-contracts-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp_pst"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tokio-test",
|
||||
"warp-contracts",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
2
crates/pst/Cargo.toml
Normal file
2
crates/pst/Cargo.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[workspace]
|
||||
members = ["contract/definition"]
|
||||
178
crates/pst/README.md
Normal file
178
crates/pst/README.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# 🦀 Warp contracts - Rust template
|
||||
|
||||
Following repository is a template for writing SmartWeave contracts in Rust and building them into WASM binaries which can be then processed by Warp SDK.
|
||||
|
||||
It contains an example implementation of a PST contract - which you can use as a base for implementing your own contract.
|
||||
If you are not familiar with the concept of Profit Sharing Tokens, check out a [tutorial](https://academy.warp.cc/tutorials/pst/introduction/intro) for writing your first PST contract in our Warp Academy.
|
||||
|
||||
- [Installation](#-installation)
|
||||
- [Code structure](#-code-structure)
|
||||
- [Writing contract](#-writing-contract)
|
||||
- [Accessing JavaScript imports](#accessing-javascript-imports)
|
||||
- [Foreign contract read](#foreign-contract-read)
|
||||
- [Foreign contract write](#foreign-contract-write)
|
||||
- [Build](#-build)
|
||||
- [Typescript bindings](#typescript-bindings)
|
||||
- [Tests](#-tests)
|
||||
- [Deploy](#-deploy)
|
||||
- [Using SDK](#-using-sdk)
|
||||
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
You will need:
|
||||
|
||||
- Rust :-) (https://doc.rust-lang.org/cargo/getting-started/installation.html)
|
||||
- [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) (on Apple's M1s you may need Rosetta `softwareupdate --install-rosetta` for wasm-pack to run)
|
||||
- [Node.js](https://nodejs.org/en/download/) version 16.5 or above
|
||||
- [yarn](https://yarnpkg.com/getting-started/install) installed
|
||||
|
||||
To install all Node.js dependencies run the following command:
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
## 🔍 Code structure
|
||||
|
||||
- [deploy/](deploy) - contains deployment scripts for localhost/testnet/mainnet and contract's initial state definition
|
||||
- [contract](contract) - contains definitions and implementation for the contract
|
||||
- [definition/](contract/definition) - contains contract definitions (e.g. actions, errors and state) which define shape of the contract, it also includes tools to generate JSON files from contract definition files
|
||||
- [action.rs](contract/definition/src/action.rs) - contains enums of the `WriteAction`, `ReadAction` and `ReadResponse`, each of it includes structs with specific definitons (e.g. `Balance` struct), it also contains `ActionResult` and `HandlerResult` enums
|
||||
- [error.rs](contract/defintion/src/error.rs) - contains the definition of contract's business errors (e.g. "not enough balance")
|
||||
- [generate_json.rs](contract/definition/src/generate_json.rs) - tool to generate JSON schemas from the definitions
|
||||
- [state.rs](contract/definition/src/state.rs) - contains the definition of contract's state
|
||||
- [implementation](contract/implementation) - contains implementation for the contract definitions, it will be compiled to WASM and used when deploying contract to the blockchain
|
||||
- [pkg/](pkg) - generated by `wasm-pack` during build process - contains compiled wasm binary, js "glue" code, etc.
|
||||
- [src/](src) - contains the source code of the contract implementing contract definitions
|
||||
- [actions/](contract/implementation/src/actions) - the main part of the contract - contains `actions` (functions) that can be called to interact
|
||||
with the contract (and either change its internal state or return a view of the current state).
|
||||
These functions contain all the business logic of the contract
|
||||
- [contract_utils/](contract/implementation/src/contract_utils) - contains low-level code responsible for mapping types, storing state,
|
||||
definition of functions imported from js, etc.
|
||||
🔥Do Not Edit🔥, unless you really know what you're doing :-)
|
||||
- [contract.rs](contract/implementation/src/contract.rs) - entry point (from the contract's developer perspective) to the contract.
|
||||
Contains the `handle` function that calls specific contract's functions based on passed action
|
||||
- [tests/](tests) - contains integration tests written in Jest
|
||||
|
||||
## 🧑💻 Writing contract
|
||||
|
||||
If you want to edit contract's code and create your own implementation you can do it by following these steps:
|
||||
|
||||
1. Edit `init-state.json` by adding the initial state for your contract - [deploy/state/init-state.json](deploy/state/init-state.json)
|
||||
2. Modify the state definition of the contract - [contract/definition/src/state.rs](contract/definition/src/state.rs)
|
||||
3. Edit/add actions which user will be able to call while interacting with the contract - [contract/definiton/src/actions](contract/definition/src/actions) and [contract/implementation/src/actions](contract/implementation/src/actions).
|
||||
We suggest keeping each action in a separate file.
|
||||
4. Add above action functions to the pattern matching in `handle` function in [contract/implementation/src/contract.rs](contract/implementation/src/contract.rs)
|
||||
|
||||
### Accessing JavaScript imports
|
||||
|
||||
An example of how to access imports can be found here: [contract/implementation/src/contract.rs](contract/implementation/src/contract.rs)
|
||||
|
||||
### Foreign contract read
|
||||
|
||||
An example of how to read other contract state can be found here: [contract/implementation/src/actions/foreign_read.rs](contract/implementation/src/actions/foreign_read.rs)
|
||||
|
||||
### Foreign contract write
|
||||
|
||||
An example of how to call other contract function can be found here: [contract/implementation/src/actions/foreign_write.rs](contract/implementation/src/actions/foreign_write.rs)
|
||||
|
||||
Keep in mind that internal contract writes require the flag `internalWrites` to be turned on in the
|
||||
evaluation options (for both calling and callee contracts). See [tests/contract.spec.ts](tests/contract.spec.ts#L111).
|
||||
|
||||
In order to access the calling contract tx id - use `SmartWeave::caller()`.
|
||||
`SmartWeave::caller()` returns:
|
||||
|
||||
1. same value as `Transaction::owner()` - for standard interactions with contract
|
||||
2. transaction id of the calling contract - in case of internal writes
|
||||
|
||||
## 👷 Build
|
||||
|
||||
Compile your contract to WASM binary by running following command:
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
|
||||
## Typescript bindings
|
||||
|
||||
Rust contract definitions can be compiled to Typescript:
|
||||
|
||||
1. Firstly JSON schemas are generated from Rust contract definitions using [schemars](https://github.com/GREsau/schemars).
|
||||
2. Then, JSON schemas are compiled to Typescript using [json-schema-to-typescript](https://github.com/bcherny/json-schema-to-typescript).
|
||||
3. Lastly, a helper class is generated from typescript bindings which allows to easily interact with the contract. Instead of using `writeInteraction` method each time, specific functions can be called within the contract, e.g.:
|
||||
|
||||
```ts
|
||||
async transfer(transfer: Transfer, options?: WriteInteractionOptions): Promise<WriteInteractionResponse | null> {
|
||||
return await this.contract.writeInteraction<BaseInput & Transfer>({ function: 'transfer', ...transfer }, options);
|
||||
}
|
||||
```
|
||||
|
||||
Generate JSON:
|
||||
|
||||
```bash
|
||||
yarn gen-json
|
||||
```
|
||||
|
||||
Compile JSON to Typescript:
|
||||
|
||||
```bash
|
||||
yarn gen-ts
|
||||
```
|
||||
|
||||
Gnerate JSON and compile to Typescript:
|
||||
|
||||
```bash
|
||||
yarn gen-bindings
|
||||
```
|
||||
|
||||
Files will be generated in [contract/definition/bindings](contract/definition/bindings).
|
||||
|
||||
## 🧪 Tests
|
||||
|
||||
Write tests for your contract (we will use Jest library for testing) - you can find a template in the [tests/](tests) folder.
|
||||
Run tests with
|
||||
|
||||
```bash
|
||||
yarn test
|
||||
```
|
||||
|
||||
## 📜 Deploy
|
||||
|
||||
Deploy your contract to one of the networks (mainnet/Warp public testnet/localhost) by running following command (`network`: `mainnet` | `testnet` | `local`)
|
||||
|
||||
Please note that in case of local deployment, you need to have `ArLocal` instance running - `npx arlocal`.
|
||||
|
||||
```bash
|
||||
yarn deploy:[network]
|
||||
```
|
||||
|
||||
💡**NOTE**: If you want to deploy your contract locally you need to run Arlocal by typing following command:
|
||||
|
||||
```bash
|
||||
npx arlocal
|
||||
```
|
||||
|
||||
💡**NOTE**: When using mainnet please put your wallet key in [deploy/mainnet/.secrets/wallet-mainnet.json](deploy/mainnet/.secrets/wallet-mainnet.json). `.secrets` folder has been added to `.gitignore` so your key is kept securely.
|
||||
|
||||
You can view deploy script code [here](deploy/scripts/deploy.js).
|
||||
|
||||
## 🟥 Using SDK
|
||||
|
||||
Optionally - you can run one of the scripts which uses Warp SDK to interact with the contract. Using SDKs' methods works exactly the same as in case of a regular JS contract.
|
||||
|
||||
💡**NOTE** You will need to have a file with the wallet key and a file with the contract id to run these scripts. If you do not have them please run a [deploy](#-deploy) script.
|
||||
|
||||
1. `read` - reads contract state, check out the code in [deploy/scripts/read-contract-state.js](deploy/scripts/read-contract-state.js)
|
||||
|
||||
```bash
|
||||
npm run read:[network]
|
||||
```
|
||||
|
||||
2. `balance` - get balance for a wallet address, check out the code in [deploy/scripts/interact-balance.js](deploy/scripts/interact-balance.js)
|
||||
|
||||
```bash
|
||||
npm run balance:[network]
|
||||
```
|
||||
|
||||
3. `transfer` - transfer specific amount of tokens to the indicated wallet, check out the code in [deploy/scripts/interact-transfer.js](deploy/scripts/interact-transfer.js)
|
||||
517
crates/pst/contract/Cargo.lock
generated
Normal file
517
crates/pst/contract/Cargo.lock
generated
Normal file
@@ -0,0 +1,517 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b015a331cc64ebd1774ba119538573603427eaace0a1950c423ab971f903796"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad445822218ce64be7a341abfb0b1ea43b5c23aa83902542a4542e78309d8e5e"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b84f9ebcc6c1f5b8cb160f6990096a5c127f423fcb6e1ccc46c370cbdfb75dfc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"schemars_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.156"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-wasm-bindgen"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.156"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"pin-project-lite",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-test"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53474327ae5e166530d17f2d956afcb4f8a004de581b3cae10f12006bc8163e3"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||
|
||||
[[package]]
|
||||
name = "warp-contracts"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"warp-contracts-core",
|
||||
"warp-contracts-macro",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp-contracts-core"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp-contracts-macro"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
"warp-contracts-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp_pst"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tokio-test",
|
||||
"warp-contracts",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp_pst_implementation"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
"console_error_panic_hook",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"tokio-test",
|
||||
"warp-contracts",
|
||||
"warp_pst",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
2
crates/pst/contract/Cargo.toml
Normal file
2
crates/pst/contract/Cargo.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[workspace]
|
||||
members = ["definition", "implementation"]
|
||||
15
crates/pst/contract/definition/Cargo.toml
Normal file
15
crates/pst/contract/definition/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "warp_pst"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "Warp PST template"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
warp-contracts = { version = "0.1.2", features = ["debug"], path = "../../../warp-contracts" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tokio-test = "0.4.2"
|
||||
schemars = "0.8.10"
|
||||
strum = "0.24.1"
|
||||
strum_macros = "0.24.3"
|
||||
160
crates/pst/contract/definition/src/action.rs
Normal file
160
crates/pst/contract/definition/src/action.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
mod req {
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Balance {
|
||||
pub target: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KvPut {
|
||||
pub key: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KvGet {
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Transfer {
|
||||
pub qty: u64,
|
||||
pub target: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Evolve {
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ForeignRead {
|
||||
pub contract_tx_id: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ForeignView {
|
||||
pub contract_tx_id: String,
|
||||
pub target: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ForeignWrite {
|
||||
pub contract_tx_id: String,
|
||||
pub qty: u64,
|
||||
pub target: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase", tag = "function")]
|
||||
pub enum Action {
|
||||
Balance(Balance),
|
||||
|
||||
Transfer(Transfer),
|
||||
|
||||
Evolve(Evolve),
|
||||
|
||||
ForeignView(ForeignView),
|
||||
|
||||
ForeignRead(ForeignRead),
|
||||
|
||||
ForeignWrite(ForeignWrite),
|
||||
|
||||
KvGet(KvGet),
|
||||
|
||||
KvPut(KvPut),
|
||||
}
|
||||
}
|
||||
|
||||
pub use req::*;
|
||||
|
||||
mod res {
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
use crate::{error::PstError, state::PstState};
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PstBalanceResult {
|
||||
pub balance: u64,
|
||||
pub ticker: String,
|
||||
pub target: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PstKvGetResult {
|
||||
pub key: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PstForeignViewResult {
|
||||
pub balance: u64,
|
||||
pub ticker: String,
|
||||
pub target: String,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, PartialEq, Debug, Serialize, Deserialize, Hash, Eq, EnumIter)]
|
||||
#[serde(rename_all = "camelCase", tag = "function")]
|
||||
pub enum PstViewResponse {
|
||||
BalanceResult(PstBalanceResult),
|
||||
KvGetResult(PstKvGetResult),
|
||||
ForeignViewResult(PstForeignViewResult),
|
||||
}
|
||||
|
||||
pub type PstViewResult =
|
||||
warp_contracts::handler_result::ViewResult<PstViewResponse, PstError>;
|
||||
pub type PstWriteResult =
|
||||
warp_contracts::handler_result::WriteResult<PstState, PstError>;
|
||||
}
|
||||
|
||||
pub use res::*;
|
||||
|
||||
mod bindings {
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, EnumIter)]
|
||||
#[serde(rename_all = "camelCase", tag = "function")]
|
||||
pub enum View {
|
||||
Balance(Balance),
|
||||
BalanceResult(PstBalanceResult),
|
||||
ForeignView(ForeignView),
|
||||
ForeignViewResult(PstForeignViewResult),
|
||||
KvGet(KvGet),
|
||||
KvGetResult(PstKvGetResult),
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, EnumIter)]
|
||||
#[serde(rename_all = "camelCase", tag = "function")]
|
||||
pub enum WriteAction {
|
||||
Transfer(Transfer),
|
||||
|
||||
Evolve(Evolve),
|
||||
|
||||
ForeignRead(ForeignRead),
|
||||
|
||||
ForeignWrite(ForeignWrite),
|
||||
|
||||
KvPut(KvPut),
|
||||
}
|
||||
}
|
||||
|
||||
pub use bindings::*;
|
||||
13
crates/pst/contract/definition/src/error.rs
Normal file
13
crates/pst/contract/definition/src/error.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(JsonSchema, Serialize, Deserialize, Debug)]
|
||||
#[serde(tag = "kind", content = "data")]
|
||||
pub enum PstError {
|
||||
TransferAmountMustBeHigherThanZero,
|
||||
IDontLikeThisContract,
|
||||
CallerBalanceNotEnough(u64),
|
||||
OnlyOwnerCanEvolve,
|
||||
EvolveNotAllowed,
|
||||
WalletHasNoBalanceDefined(String),
|
||||
}
|
||||
41
crates/pst/contract/definition/src/generate_json.rs
Normal file
41
crates/pst/contract/definition/src/generate_json.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::Path;
|
||||
use std::{env, fs};
|
||||
|
||||
use schemars::JsonSchema;
|
||||
|
||||
use crate::action::{View, WriteAction};
|
||||
use crate::state::ContractState;
|
||||
|
||||
const SCHEMAS_DIR: &str = "./bindings/json";
|
||||
|
||||
fn generate<T: JsonSchema>(name: &str) -> Result<(), std::io::Error> {
|
||||
let schema = schemars::schema_for!(T);
|
||||
let schema_file = Path::new(SCHEMAS_DIR).join(name).with_extension("json");
|
||||
|
||||
fs::create_dir_all(SCHEMAS_DIR)?;
|
||||
fs::write(&schema_file, serde_json::to_string_pretty(&schema)?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_json() -> Result<(), std::io::Error> {
|
||||
let run = if let Ok(run) = env::var("GENERATE_JSON") {
|
||||
run == "true" || run == "1"
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !run {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
generate::<ContractState>("ContractState")?;
|
||||
generate::<WriteAction>("WriteAction")?;
|
||||
generate::<View>("View")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
4
crates/pst/contract/definition/src/lib.rs
Normal file
4
crates/pst/contract/definition/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod action;
|
||||
pub mod error;
|
||||
pub mod generate_json;
|
||||
pub mod state;
|
||||
24
crates/pst/contract/definition/src/state.rs
Normal file
24
crates/pst/contract/definition/src/state.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
#[derive(JsonSchema, Serialize, Deserialize, Clone, Default, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PstState {
|
||||
pub ticker: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub name: Option<String>,
|
||||
pub owner: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub evolve: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub can_evolve: Option<bool>,
|
||||
pub balances: HashMap<String, u64>,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema, Clone, Debug, Serialize, Deserialize, EnumIter)]
|
||||
#[serde(rename_all = "camelCase", tag = "function")]
|
||||
pub enum ContractState {
|
||||
State(PstState),
|
||||
}
|
||||
19
crates/pst/contract/implementation/Cargo.toml
Normal file
19
crates/pst/contract/implementation/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "warp_pst_implementation"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
console_error_panic_hook = "0.1.7"
|
||||
warp_pst = { path = "../definition" }
|
||||
warp-contracts = { version = "0.1.2", features = ["debug"], path = "../../../warp-contracts" }
|
||||
wasm-bindgen = "=0.2.84"
|
||||
wasm-bindgen-futures = "=0.4.34"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde-wasm-bindgen = "=0.5.0"
|
||||
async-recursion = "1.0.0"
|
||||
async-trait = "0.1.56"
|
||||
tokio-test = "0.4.2"
|
||||
20
crates/pst/contract/implementation/src/actions/balance.rs
Normal file
20
crates/pst/contract/implementation/src/actions/balance.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use super::ViewActionable;
|
||||
use warp_pst::{
|
||||
action::{Balance, PstBalanceResult, PstViewResponse::BalanceResult, PstViewResult},
|
||||
error::PstError::*,
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
impl ViewActionable for Balance {
|
||||
fn action(self, _caller: String, state: &PstState) -> PstViewResult {
|
||||
if !state.balances.contains_key(&self.target) {
|
||||
return PstViewResult::ContractError(WalletHasNoBalanceDefined(self.target));
|
||||
}
|
||||
let balance_response = PstBalanceResult {
|
||||
balance: *state.balances.get(&self.target).unwrap(),
|
||||
ticker: state.ticker.clone(),
|
||||
target: self.target,
|
||||
};
|
||||
PstViewResult::Success(BalanceResult(balance_response))
|
||||
}
|
||||
}
|
||||
23
crates/pst/contract/implementation/src/actions/evolve.rs
Normal file
23
crates/pst/contract/implementation/src/actions/evolve.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use super::WriteActionable;
|
||||
use warp_contracts::js_imports::Transaction;
|
||||
use warp_pst::{
|
||||
action::{Evolve, PstWriteResult},
|
||||
error::PstError::*,
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
impl WriteActionable for Evolve {
|
||||
fn action(self, _caller: String, mut state: PstState) -> PstWriteResult {
|
||||
match state.can_evolve {
|
||||
Some(true) => {
|
||||
if state.owner == Transaction::owner() {
|
||||
state.evolve = Option::from(self.value);
|
||||
PstWriteResult::Success(state)
|
||||
} else {
|
||||
PstWriteResult::ContractError(OnlyOwnerCanEvolve)
|
||||
}
|
||||
}
|
||||
_ => PstWriteResult::ContractError(EvolveNotAllowed),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
use super::AsyncWriteActionable;
|
||||
use async_trait::async_trait;
|
||||
use warp_contracts::{foreign_call::read_foreign_contract_state, js_imports::log};
|
||||
use warp_pst::{
|
||||
action::{ForeignRead, PstWriteResult},
|
||||
error::PstError::*,
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl AsyncWriteActionable for ForeignRead {
|
||||
async fn action(self, _caller: String, mut state: PstState) -> PstWriteResult {
|
||||
if self.contract_tx_id == "bad_contract" {
|
||||
return PstWriteResult::ContractError(IDontLikeThisContract);
|
||||
}
|
||||
let foreign_contract_state: PstState =
|
||||
match read_foreign_contract_state(&self.contract_tx_id).await {
|
||||
Ok(s) => s,
|
||||
Err(e) => return PstWriteResult::RuntimeError(e),
|
||||
};
|
||||
// Some dummy logic - just for the sake of the integration test
|
||||
if foreign_contract_state.ticker == "FOREIGN_PST" {
|
||||
log("Adding to tokens");
|
||||
for val in state.balances.values_mut() {
|
||||
*val += 1000;
|
||||
}
|
||||
}
|
||||
|
||||
PstWriteResult::Success(state)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use super::AsyncViewActionable;
|
||||
use async_trait::async_trait;
|
||||
use serde::Serialize;
|
||||
use warp_contracts::{foreign_call::view_foreign_contract_state, handler_result::ViewResult::*};
|
||||
use warp_pst::{
|
||||
action::{
|
||||
ForeignView, PstBalanceResult, PstForeignViewResult, PstViewResponse::*, PstViewResult,
|
||||
},
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct BalanceInput {
|
||||
function: String,
|
||||
target: String,
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl AsyncViewActionable for ForeignView {
|
||||
async fn action(self, _caller: String, _state: &PstState) -> PstViewResult {
|
||||
let foreign_contract_state = view_foreign_contract_state(
|
||||
&self.contract_tx_id,
|
||||
BalanceInput {
|
||||
target: self.target,
|
||||
function: "balance".to_string(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
match foreign_contract_state {
|
||||
Success(PstBalanceResult {
|
||||
balance,
|
||||
ticker,
|
||||
target,
|
||||
}) => Success(ForeignViewResult(PstForeignViewResult {
|
||||
balance,
|
||||
ticker,
|
||||
target,
|
||||
})),
|
||||
ContractError(e) => ContractError(e),
|
||||
RuntimeError(e) => RuntimeError(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
use super::AsyncWriteActionable;
|
||||
use async_trait::async_trait;
|
||||
use serde::Serialize;
|
||||
use warp_contracts::{foreign_call::write_foreign_contract, handler_result::WriteResult::*};
|
||||
use warp_pst::{
|
||||
action::{ForeignWrite, PstWriteResult},
|
||||
error::PstError,
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Input {
|
||||
function: String,
|
||||
qty: u64,
|
||||
target: String,
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl AsyncWriteActionable for ForeignWrite {
|
||||
async fn action(self, _caller: String, state: PstState) -> PstWriteResult {
|
||||
match write_foreign_contract::<Input, PstError>(
|
||||
&self.contract_tx_id,
|
||||
Input {
|
||||
function: "transfer".to_string(),
|
||||
qty: self.qty,
|
||||
target: self.target,
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
Success(_) => Success(state),
|
||||
ContractError(e) => ContractError(e),
|
||||
RuntimeError(e) => RuntimeError(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
28
crates/pst/contract/implementation/src/actions/kv_get.rs
Normal file
28
crates/pst/contract/implementation/src/actions/kv_get.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use super::AsyncViewActionable;
|
||||
use async_trait::async_trait;
|
||||
use warp_contracts::{handler_result::ViewResult::*, kv_operations::kv_get};
|
||||
use warp_pst::{
|
||||
action::{KvGet, PstKvGetResult, PstViewResponse, PstViewResult},
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl AsyncViewActionable for KvGet {
|
||||
async fn action(self, _caller: String, _state: &PstState) -> PstViewResult {
|
||||
match kv_get(&self.key).await {
|
||||
Success(a) => {
|
||||
PstViewResult::Success(PstViewResponse::KvGetResult(PstKvGetResult {
|
||||
key: self.key,
|
||||
value: a,
|
||||
}))
|
||||
}
|
||||
ContractError(_) => {
|
||||
PstViewResult::Success(PstViewResponse::KvGetResult(PstKvGetResult {
|
||||
key: self.key,
|
||||
value: "".to_owned(),
|
||||
}))
|
||||
},
|
||||
RuntimeError(e) => RuntimeError(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
24
crates/pst/contract/implementation/src/actions/kv_put.rs
Normal file
24
crates/pst/contract/implementation/src/actions/kv_put.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use super::AsyncWriteActionable;
|
||||
use async_trait::async_trait;
|
||||
use warp_contracts::{
|
||||
js_imports::{log, Transaction},
|
||||
kv_operations::kv_put,
|
||||
};
|
||||
use warp_pst::{
|
||||
action::{KvPut, PstWriteResult},
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl AsyncWriteActionable for KvPut {
|
||||
async fn action(self, caller: String, state: PstState) -> PstWriteResult {
|
||||
let owner = Transaction::owner();
|
||||
log(&format!("caller {caller}"));
|
||||
log(&format!("Transaction owner {owner}"));
|
||||
|
||||
match kv_put(&self.key, &self.value).await {
|
||||
Err(e) => PstWriteResult::RuntimeError(e),
|
||||
Ok(_) => PstWriteResult::Success(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
36
crates/pst/contract/implementation/src/actions/mod.rs
Normal file
36
crates/pst/contract/implementation/src/actions/mod.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use async_trait::async_trait;
|
||||
use warp_pst::{action::{PstViewResult, PstWriteResult}, state::PstState};
|
||||
|
||||
pub mod balance;
|
||||
pub mod evolve;
|
||||
pub mod foreign_read;
|
||||
pub mod foreign_view;
|
||||
pub mod foreign_write;
|
||||
pub mod kv_get;
|
||||
pub mod kv_put;
|
||||
pub mod transfer;
|
||||
|
||||
pub use balance::*;
|
||||
pub use evolve::*;
|
||||
pub use foreign_read::*;
|
||||
pub use foreign_view::*;
|
||||
pub use foreign_write::*;
|
||||
pub use transfer::*;
|
||||
|
||||
pub trait ViewActionable {
|
||||
fn action(self, caller: String, state: &PstState) -> PstViewResult;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
pub trait AsyncViewActionable {
|
||||
async fn action(self, caller: String, state: &PstState) -> PstViewResult;
|
||||
}
|
||||
|
||||
pub trait WriteActionable {
|
||||
fn action(self, caller: String, state: PstState) -> PstWriteResult;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
pub trait AsyncWriteActionable {
|
||||
async fn action(self, caller: String, state: PstState) -> PstWriteResult;
|
||||
}
|
||||
36
crates/pst/contract/implementation/src/actions/transfer.rs
Normal file
36
crates/pst/contract/implementation/src/actions/transfer.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use super::WriteActionable;
|
||||
use warp_contracts::js_imports::{log, SmartWeave, Transaction};
|
||||
use warp_pst::{
|
||||
action::{PstWriteResult, Transfer},
|
||||
error::PstError::*,
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
impl WriteActionable for Transfer {
|
||||
fn action(self, _caller: String, mut state: PstState) -> PstWriteResult {
|
||||
log(("caller ".to_owned() + &SmartWeave::caller()).as_str());
|
||||
log(("Transaction owner ".to_owned() + &Transaction::owner()).as_str());
|
||||
|
||||
if self.qty == 0 {
|
||||
return PstWriteResult::ContractError(TransferAmountMustBeHigherThanZero);
|
||||
}
|
||||
|
||||
let caller = Transaction::owner();
|
||||
let balances = &mut state.balances;
|
||||
|
||||
// Checking if caller has enough funds
|
||||
let caller_balance = *balances.get(&caller).unwrap_or(&0);
|
||||
if caller_balance < self.qty {
|
||||
return PstWriteResult::ContractError(CallerBalanceNotEnough(caller_balance));
|
||||
}
|
||||
|
||||
// Update caller balance
|
||||
balances.insert(caller, caller_balance - self.qty);
|
||||
|
||||
// Update target balance
|
||||
let target_balance = *balances.get(&self.target).unwrap_or(&0);
|
||||
balances.insert(self.target, target_balance + self.qty);
|
||||
|
||||
PstWriteResult::Success(state)
|
||||
}
|
||||
}
|
||||
55
crates/pst/contract/implementation/src/contract.rs
Normal file
55
crates/pst/contract/implementation/src/contract.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use warp_pst::{
|
||||
action::{Action, PstWriteResult, PstViewResult},
|
||||
state::PstState,
|
||||
};
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
use crate::actions::*;
|
||||
use warp_contracts::{js_imports::*, warp_contract};
|
||||
|
||||
#[warp_contract(write)]
|
||||
pub async fn handle_write(state: PstState, action: Action) -> PstWriteResult {
|
||||
console_error_panic_hook::set_once();
|
||||
let effective_caller = SmartWeave::caller();
|
||||
|
||||
//Example of accessing functions imported from js:
|
||||
log("log from contract");
|
||||
log(&("Transaction::id()".to_owned() + &Transaction::id()));
|
||||
log(&("Transaction::owner()".to_owned() + &Transaction::owner()));
|
||||
log(&("Transaction::target()".to_owned() + &Transaction::target()));
|
||||
|
||||
log(&("Block::height()".to_owned() + &Block::height().to_string()));
|
||||
log(&("Block::indep_hash()".to_owned() + &Block::indep_hash()));
|
||||
log(&("Block::timestamp()".to_owned() + &Block::timestamp().to_string()));
|
||||
|
||||
log(&("Contract::id()".to_owned() + &Contract::id()));
|
||||
log(&("Contract::owner()".to_owned() + &Contract::owner()));
|
||||
|
||||
log(&("SmartWeave::caller()".to_owned() + &SmartWeave::caller()));
|
||||
|
||||
// for vrf-compatible interactions
|
||||
log(&("Vrf::value()".to_owned() + &Vrf::value()));
|
||||
log(&("Vrf::randomInt(7)".to_owned() + &Vrf::randomInt(7).to_string()));
|
||||
|
||||
match action {
|
||||
Action::Transfer(action) => action.action(effective_caller, state),
|
||||
Action::Evolve(action) => action.action(effective_caller, state),
|
||||
Action::ForeignRead(action) => action.action(effective_caller, state).await,
|
||||
Action::ForeignWrite(action) => action.action(effective_caller, state).await,
|
||||
Action::KvPut(action) => action.action(effective_caller, state).await,
|
||||
_ => PstWriteResult::RuntimeError("invalid method for write".to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
#[warp_contract(view)]
|
||||
pub async fn handle_view(state: &PstState, action: Action) -> PstViewResult {
|
||||
console_error_panic_hook::set_once();
|
||||
let effective_caller = SmartWeave::caller();
|
||||
|
||||
match action {
|
||||
Action::Balance(action) => action.action(effective_caller, state),
|
||||
Action::ForeignView(action) => action.action(effective_caller, state).await,
|
||||
Action::KvGet(action) => action.action(effective_caller, state).await,
|
||||
_ => PstViewResult::RuntimeError("invalid method for view".to_owned()),
|
||||
}
|
||||
}
|
||||
2
crates/pst/contract/implementation/src/lib.rs
Normal file
2
crates/pst/contract/implementation/src/lib.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
mod actions;
|
||||
mod contract;
|
||||
9
crates/pst/deploy/local/deploy-local.js
Normal file
9
crates/pst/deploy/local/deploy-local.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { deploy } = require('../scripts/deploy');
|
||||
|
||||
deploy(
|
||||
'localhost',
|
||||
1984,
|
||||
'http',
|
||||
'local',
|
||||
'deploy/local/wallet_local.json'
|
||||
).finally();
|
||||
9
crates/pst/deploy/local/interact-balance-local.js
Normal file
9
crates/pst/deploy/local/interact-balance-local.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { interactBalance } = require('../scripts/interact-balance');
|
||||
|
||||
interactBalance(
|
||||
'localhost',
|
||||
1984,
|
||||
'http',
|
||||
'local',
|
||||
'deploy/local/wallet_local.json'
|
||||
).finally();
|
||||
9
crates/pst/deploy/local/interact-transfer-local.js
Normal file
9
crates/pst/deploy/local/interact-transfer-local.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { interactTransfer } = require('../scripts/interact-transfer');
|
||||
|
||||
interactTransfer(
|
||||
'localhost',
|
||||
1984,
|
||||
'http',
|
||||
'local',
|
||||
'deploy/local/wallet_local.json'
|
||||
).finally();
|
||||
9
crates/pst/deploy/local/read-contract-state-local.js
Normal file
9
crates/pst/deploy/local/read-contract-state-local.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { readContractState } = require('../scripts/read-contract-state');
|
||||
|
||||
readContractState(
|
||||
'localhost',
|
||||
1984,
|
||||
'http',
|
||||
'local',
|
||||
'deploy/local/wallet_local.json'
|
||||
).finally();
|
||||
1
crates/pst/deploy/mainnet/contract-tx-id.txt
Normal file
1
crates/pst/deploy/mainnet/contract-tx-id.txt
Normal file
@@ -0,0 +1 @@
|
||||
tom87dg3RgkUGTfOwIO-eNb5WCvoGkFCS44B7koVW_I
|
||||
9
crates/pst/deploy/mainnet/deploy-mainnet.js
Normal file
9
crates/pst/deploy/mainnet/deploy-mainnet.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { deploy } = require('../scripts/deploy');
|
||||
|
||||
deploy(
|
||||
'arweave.net',
|
||||
443,
|
||||
'https',
|
||||
'mainnet',
|
||||
'deploy/mainnet/wallet_mainnet.json'
|
||||
).finally();
|
||||
9
crates/pst/deploy/mainnet/interact-balance-mainnet.js
Normal file
9
crates/pst/deploy/mainnet/interact-balance-mainnet.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { interactBalance } = require('../scripts/interact-balance');
|
||||
|
||||
interactBalance(
|
||||
'arweave.net',
|
||||
443,
|
||||
'https',
|
||||
'mainnet',
|
||||
'deploy/mainnet/wallet_mainnet.json'
|
||||
).finally();
|
||||
9
crates/pst/deploy/mainnet/interact-transfer-mainnet.js
Normal file
9
crates/pst/deploy/mainnet/interact-transfer-mainnet.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { interactTransfer } = require('../scripts/interact-transfer');
|
||||
|
||||
interactTransfer(
|
||||
'arweave.net',
|
||||
443,
|
||||
'https',
|
||||
'mainnet',
|
||||
'deploy/mainnet/wallet_mainnet.json'
|
||||
).finally();
|
||||
9
crates/pst/deploy/mainnet/read-contract-state-mainnet.js
Normal file
9
crates/pst/deploy/mainnet/read-contract-state-mainnet.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { readContractState } = require('../scripts/read-contract-state');
|
||||
|
||||
readContractState(
|
||||
'arweave.net',
|
||||
443,
|
||||
'https',
|
||||
'mainnet',
|
||||
'deploy/mainnet/wallet_mainnet.json'
|
||||
).finally();
|
||||
56
crates/pst/deploy/scripts/deploy.js
Normal file
56
crates/pst/deploy/scripts/deploy.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { WarpFactory, defaultCacheOptions } = require('warp-contracts');
|
||||
const { mineBlock } = require('./utils/mine-block');
|
||||
const { loadWallet, walletAddress } = require('./utils/load-wallet');
|
||||
const { connectArweave } = require('./utils/connect-arweave');
|
||||
|
||||
module.exports.deploy = async function (host, port, protocol, target, walletJwk) {
|
||||
const arweave = connectArweave(host, port, protocol);
|
||||
const warp = module.exports.getWarpInstance(port, target);
|
||||
const wallet = await loadWallet(arweave, walletJwk, target);
|
||||
const walletAddr = await walletAddress(arweave, wallet);
|
||||
const contractSrc = fs.readFileSync(path.join(__dirname, '../../contract/implementation/pkg/rust-contract_bg.wasm'));
|
||||
const stateFromFile = JSON.parse(fs.readFileSync(path.join(__dirname, '../state/init-state.json'), 'utf-8'));
|
||||
|
||||
const initialState = {
|
||||
...stateFromFile,
|
||||
...{
|
||||
owner: walletAddr,
|
||||
balances: {
|
||||
...stateFromFile.balances,
|
||||
[walletAddr]: 10000000,
|
||||
},
|
||||
},
|
||||
};
|
||||
const {contractTxId} = await warp.createContract.deploy(
|
||||
{
|
||||
wallet,
|
||||
initState: JSON.stringify(initialState),
|
||||
src: contractSrc,
|
||||
wasmSrcCodeDir: path.join(__dirname, '../../contract/implementation/src'),
|
||||
wasmGlueCode: path.join(__dirname, '../../contract/implementation/pkg/rust-contract.js'),
|
||||
}
|
||||
);
|
||||
fs.writeFileSync(path.join(__dirname, `../${target}/contract-tx-id.txt`), contractTxId);
|
||||
|
||||
if (target == 'testnet' || target == 'local') {
|
||||
await mineBlock(arweave);
|
||||
}
|
||||
|
||||
if (target == 'testnet') {
|
||||
console.log(`Check contract at https://sonar.warp.cc/#/app/contract/${contractTxId}?network=testnet`);
|
||||
} else {
|
||||
console.log('Contract tx id', contractTxId);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.getWarpInstance = function (port, target) {
|
||||
if (target == 'local') {
|
||||
return WarpFactory.forLocal(port);
|
||||
} else if (target == 'testnet') {
|
||||
return WarpFactory.forTestnet();
|
||||
} else {
|
||||
return WarpFactory.forMainnet({ ...defaultCacheOptions, inMemory: true });
|
||||
}
|
||||
}
|
||||
23
crates/pst/deploy/scripts/interact-balance.js
Normal file
23
crates/pst/deploy/scripts/interact-balance.js
Normal file
@@ -0,0 +1,23 @@
|
||||
const { loadWallet } = require('./utils/load-wallet');
|
||||
const { connectArweave } = require('./utils/connect-arweave');
|
||||
const { connectPstContract } = require('./utils/connect-pst-contract');
|
||||
const { contractTxId } = require('./utils/contract-tx-id');
|
||||
|
||||
module.exports.interactBalance = async function (
|
||||
host,
|
||||
port,
|
||||
protocol,
|
||||
target,
|
||||
walletJwk
|
||||
) {
|
||||
const arweave = connectArweave(host, port, protocol);
|
||||
const wallet = await loadWallet(arweave, walletJwk, target, true);
|
||||
|
||||
const walletAddress = await arweave.wallets.jwkToAddress(wallet);
|
||||
|
||||
const txId = contractTxId(target);
|
||||
const pst = await connectPstContract(arweave, wallet, txId, target);
|
||||
const balance = await pst.currentBalance(walletAddress);
|
||||
|
||||
console.log(balance);
|
||||
};
|
||||
29
crates/pst/deploy/scripts/interact-transfer.js
Normal file
29
crates/pst/deploy/scripts/interact-transfer.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const { loadWallet } = require('./utils/load-wallet');
|
||||
const { connectArweave } = require('./utils/connect-arweave');
|
||||
const { connectPstContract } = require('./utils/connect-pst-contract');
|
||||
const { contractTxId } = require('./utils/contract-tx-id');
|
||||
const { mineBlock } = require('./utils/mine-block');
|
||||
|
||||
module.exports.interactTransfer = async function (host, port, protocol, target, walletJwk) {
|
||||
const arweave = connectArweave(host, port, protocol);
|
||||
const wallet = await loadWallet(arweave, walletJwk, target, true);
|
||||
const txId = contractTxId(target);
|
||||
const pst = await connectPstContract(arweave, wallet, txId, target);
|
||||
|
||||
const transferId = await pst.transfer({
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M',
|
||||
qty: 555,
|
||||
});
|
||||
|
||||
await mineBlock(arweave);
|
||||
const state = await pst.currentState();
|
||||
|
||||
console.log('Updated state:', state);
|
||||
console.log('Contract tx id', txId);
|
||||
|
||||
if (target == 'testnet') {
|
||||
console.log(`Check transfer interaction at https://sonar.warp.cc/#/app/interaction/${transferId}?network=testnet`);
|
||||
} else {
|
||||
console.log('Transfer tx id', transferId);
|
||||
}
|
||||
};
|
||||
22
crates/pst/deploy/scripts/read-contract-state.js
Normal file
22
crates/pst/deploy/scripts/read-contract-state.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const { loadWallet } = require('./utils/load-wallet');
|
||||
const { connectArweave } = require('./utils/connect-arweave');
|
||||
const { connectContract } = require('./utils/connect-contract');
|
||||
const { contractTxId } = require(`./utils/contract-tx-id`);
|
||||
|
||||
module.exports.readContractState = async function (
|
||||
host,
|
||||
port,
|
||||
protocol,
|
||||
target,
|
||||
walletJwk
|
||||
) {
|
||||
const arweave = connectArweave(host, port, protocol);
|
||||
const wallet = await loadWallet(arweave, walletJwk, target, true);
|
||||
|
||||
const txId = contractTxId(target);
|
||||
const contract = await connectContract(arweave, wallet, txId, target);
|
||||
const { cachedValue } = await contract.readState();
|
||||
|
||||
console.log('Current state:', cachedValue.state);
|
||||
console.log('Contract tx id', txId);
|
||||
};
|
||||
4
crates/pst/deploy/scripts/utils/addFunds.js
Normal file
4
crates/pst/deploy/scripts/utils/addFunds.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports.addFunds = async function (arweave, wallet) {
|
||||
const walletAddress = await arweave.wallets.getAddress(wallet);
|
||||
await arweave.api.get(`/mint/${walletAddress}/1000000000000000`);
|
||||
};
|
||||
9
crates/pst/deploy/scripts/utils/connect-arweave.js
Normal file
9
crates/pst/deploy/scripts/utils/connect-arweave.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const Arweave = require('arweave');
|
||||
|
||||
module.exports.connectArweave = function (host, port, protocol) {
|
||||
return Arweave.init({
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: protocol,
|
||||
});
|
||||
};
|
||||
15
crates/pst/deploy/scripts/utils/connect-contract.js
Normal file
15
crates/pst/deploy/scripts/utils/connect-contract.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const { getWarpInstance } = require("../deploy");
|
||||
|
||||
module.exports.connectContract = async function (
|
||||
arweave,
|
||||
wallet,
|
||||
contractTxId,
|
||||
target
|
||||
) {
|
||||
console.log('Target:', target);
|
||||
|
||||
const warp = getWarpInstance(arweave.api.config.port, target);
|
||||
return warp
|
||||
.contract(contractTxId)
|
||||
.connect(wallet);
|
||||
};
|
||||
14
crates/pst/deploy/scripts/utils/connect-pst-contract.js
Normal file
14
crates/pst/deploy/scripts/utils/connect-pst-contract.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const { getWarpInstance } = require("../deploy");
|
||||
|
||||
module.exports.connectPstContract = async function (
|
||||
arweave,
|
||||
wallet,
|
||||
contractTxId,
|
||||
target
|
||||
) {
|
||||
|
||||
const warp = getWarpInstance(arweave.api.config.port, target);
|
||||
return warp
|
||||
.pst(contractTxId)
|
||||
.connect(wallet);
|
||||
};
|
||||
19
crates/pst/deploy/scripts/utils/contract-tx-id.js
Normal file
19
crates/pst/deploy/scripts/utils/contract-tx-id.js
Normal file
@@ -0,0 +1,19 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
module.exports.contractTxId = function (target) {
|
||||
let txId;
|
||||
try {
|
||||
txId = fs
|
||||
.readFileSync(
|
||||
path.join(__dirname, `../../../deploy/${target}/contract-tx-id.txt`),
|
||||
'utf-8'
|
||||
)
|
||||
.trim();
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
'Contract tx id file not found! Please run deploy script first.'
|
||||
);
|
||||
}
|
||||
|
||||
return txId;
|
||||
};
|
||||
10
crates/pst/deploy/scripts/utils/create-testnet-wallet.js
Normal file
10
crates/pst/deploy/scripts/utils/create-testnet-wallet.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
module.exports.generateWallet = async function (arweave, target) {
|
||||
const wallet = await arweave.wallets.generate();
|
||||
fs.writeFileSync(
|
||||
path.join(__dirname, `../../${target}/wallet_${target}.json`),
|
||||
JSON.stringify(wallet)
|
||||
);
|
||||
};
|
||||
33
crates/pst/deploy/scripts/utils/load-wallet.js
Normal file
33
crates/pst/deploy/scripts/utils/load-wallet.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const fs = require('fs');
|
||||
const { addFunds } = require('./addFunds');
|
||||
const { generateWallet } = require('./create-testnet-wallet');
|
||||
|
||||
const path = require('path');
|
||||
|
||||
module.exports.loadWallet = async function (
|
||||
arweave,
|
||||
walletJwk,
|
||||
target,
|
||||
generated
|
||||
) {
|
||||
let wallet;
|
||||
if (!generated) {
|
||||
await generateWallet(arweave, target);
|
||||
}
|
||||
|
||||
try {
|
||||
wallet = JSON.parse(fs.readFileSync(path.join(walletJwk), 'utf-8'));
|
||||
} catch (e) {
|
||||
throw new Error('Wallet file not found! Please run deploy script first.');
|
||||
}
|
||||
|
||||
if (target == 'testnet' || target == 'local') {
|
||||
await addFunds(arweave, wallet);
|
||||
}
|
||||
|
||||
return wallet;
|
||||
};
|
||||
|
||||
module.exports.walletAddress = async function (arweave, wallet) {
|
||||
return arweave.wallets.getAddress(wallet);
|
||||
};
|
||||
3
crates/pst/deploy/scripts/utils/mine-block.js
Normal file
3
crates/pst/deploy/scripts/utils/mine-block.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports.mineBlock = async function (arweave) {
|
||||
await arweave.api.get('mine');
|
||||
};
|
||||
7
crates/pst/deploy/state/init-state.json
Normal file
7
crates/pst/deploy/state/init-state.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ticker": "PST TMPL RUST",
|
||||
"name": "PST Template Rust",
|
||||
"balances": {},
|
||||
"canEvolve": true,
|
||||
"evolve": null
|
||||
}
|
||||
1
crates/pst/deploy/testnet/contract-tx-id.txt
Normal file
1
crates/pst/deploy/testnet/contract-tx-id.txt
Normal file
@@ -0,0 +1 @@
|
||||
Y8sad_he0w0ryzxKvS7PGEXQbxBl142KX5OTpiPDYV0
|
||||
9
crates/pst/deploy/testnet/deploy-test.js
Normal file
9
crates/pst/deploy/testnet/deploy-test.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { deploy } = require('../scripts/deploy');
|
||||
|
||||
deploy(
|
||||
'arweave.net',
|
||||
443,
|
||||
'https',
|
||||
'testnet',
|
||||
'deploy/testnet/wallet_testnet.json'
|
||||
).finally();
|
||||
9
crates/pst/deploy/testnet/interact-balance-testnet.js
Normal file
9
crates/pst/deploy/testnet/interact-balance-testnet.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { interactBalance } = require('../scripts/interact-balance');
|
||||
|
||||
interactBalance(
|
||||
'testnet.redstone.tools',
|
||||
443,
|
||||
'https',
|
||||
'testnet',
|
||||
'deploy/testnet/wallet_testnet.json'
|
||||
).finally();
|
||||
9
crates/pst/deploy/testnet/interact-transfer-testnet.js
Normal file
9
crates/pst/deploy/testnet/interact-transfer-testnet.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { interactTransfer } = require('../scripts/interact-transfer');
|
||||
|
||||
interactTransfer(
|
||||
'testnet.redstone.tools',
|
||||
443,
|
||||
'https',
|
||||
'testnet',
|
||||
'deploy/testnet/wallet_testnet.json'
|
||||
).finally();
|
||||
9
crates/pst/deploy/testnet/read-contract-state-testnet.js
Normal file
9
crates/pst/deploy/testnet/read-contract-state-testnet.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { readContractState } = require('../scripts/read-contract-state');
|
||||
|
||||
readContractState(
|
||||
'testnet.redstone.tools',
|
||||
443,
|
||||
'https',
|
||||
'testnet',
|
||||
'deploy/testnet/wallet_testnet.json'
|
||||
).finally();
|
||||
1
crates/pst/deploy/testnet/wallet_testnet.json
Normal file
1
crates/pst/deploy/testnet/wallet_testnet.json
Normal file
@@ -0,0 +1 @@
|
||||
{"kty":"RSA","n":"zvtUbqKK76RcA1nKTmOjcZgkqLEOw40mLEmWA_Q_TgBYN4NJcZHPfWehS2Vlbalhf6ZiNu_J0Q-zk3tnk12Fkt-UDpje0uxkkigihwxOGmpB2gi6yTRpQfFg4ccG3QY9nx-R2hEOJaY056dXm9UY4gFVI_dYvqZbPt0_N8FmUgNVq9OgtkUVY07PAZA55kiqh2POWycsbv3FPgPt1D7QDj7jDuqRKBfMdHPqZF9qBiEo5kIyAPm8QCbQ0DY-pIjEMY0ENL4b2yTGRQNz-WH0wIAddGFPo9oGma8RdU5Uk82IJWpXxFF2Z4BOqVQnBBnIxXZNJpAN2WQ6xmGDtwRVBnV0l4nfzzpELEOZ98nlyY1YMBqBPqjnKP2_9M2FjdzsV8pnX5kUQE7_SjH0yAKEhRtYXcsvMF7Hy61rAUjD1RgIxqx-aJeJHGugc9I5IpobocX5dzdoRujSOIg_jTT7LzzP6BE2CK71crq-5cYicGje-DkwBoeRxJaRIZbAkp0AOsg1yQnURm3oGZaRw3qoqmcFp1eku5_HVORZJBvG5u2KSxa8giO6sNC0RN1NyD-RsnNLZ82eedpO8sn4rV_9LlTDqFcHgCuoOjt5A8GDYdJN5v6RljqHAcUWIwPC_rC9b4y80WO1vmND1P6j2uUj2wMKKQbOHVphyq2IZTS3skM","e":"AQAB","d":"ehG50uHj5L9fUM6UxLR4wVbEUATUOzo0iCwB4GUdLKiBXoP8PZGL-F60vp2XOxyJFtqO0-2JbdW_x7wg8sVWMK_RRuabi3PFQHmRG2qDaYq_OZKqbl2NsklkJOPXRWUX1I-u2hfy6vth-jk0LwB3g1rb1rFa0l2UNLgRP5W8_aNf1E2kW7rUiVQCO97OduTmRaD0I8gvqWna-N8iVWmSFMS77qEiaK3Yc9mlI_stsV2_HEVv7ila_86kmhdTzH-ojbyn_V8dWJoQoMUPkcVWrm0gcfGuIWlFOUAJoNBIiz7NC5vzFSIiHZqLScwKkp2OTf6eM58Du_EjxLngD4Drjyr-ev_ziEeWVRVd-HgWzhhBplOuFyW7jViKLuJ87mKmArbuA1TpZvpjuraAMi9DNE_2NRuJJn0cYtQLMeDQhZo7TiYVs55jGjEvel2iPLcMAmL_ac6zvLlX2o5XP2MdYv1nfYGyhBz9XO-6toolVsNtXkNPayEDBeU_bPn2igRrjQuGQuuvpbGQMtcNUVgKtUXzzwkJZxji6wt8GVF2D74COPYRFhBYO3TlBNpr_aVI537sJx7P38BPDqH4Tc0MpV72mINqMgJ56mFsepT75UzBAC8BDw5AKeq1rqIE4XoVFTuEXURmLwdDJJhc4Dl_Syc3h0IRiL-bnEZA7usvddE","p":"6_z2eBPZAhMNJ5edjMYW9Zo-zh0y-BCevTQn-4jhKE7z07nNAbofP_PHtEMZYZifSAmkN8QG6TQnyrn-txWfUTGBfE6CwE-GO-AVAJF_OneBZK-9X4W8hNrbRTsGGXRSfF35cuOmMwmqUkqxq03BTnK5pT0PzIHFv2OEm0d5ukq78eC3cd54f1M9QZ9ZUBtOAdvXB0A-EIQBw24m5KtLctJfGB9rGxRyrjyDrvFLSvgUn-G2kjcRnWn_l2mzTPjSct7Niyf1QXjBA11HwT7T98f13-iUY_U29Klk_0DOyL3ynVUHu-SdcPz5JGszetxx9S_gBKAK-FiIWp8sHKsvmQ","q":"4Iir0P8qYme7wRHmDRiOcSSDz9XjrGwYZU8WYbIQK-ff4XOwcXmJs-wq0N1HfjZhYiMaWFRser5oXyT8Xpkw-6gCjfSHIezZ3m6OCUfSeHQ_94OYfLr_CMCA6gOb4fU7x1Y4cqxzWbb7V1W24Kv4gUa9A30hjfnmh-1pT5EMJiu-_1KECgmSmuH0PZQg3OtWfvldJCbx-FltaE9wxQElRzcfulOLDXS7_AksJUnNmY7jWj9IVoG-nmKRvAAjgf0agXOE26icuHiM1dn9oQVAri2AGTbTkmTHWCdSBoZ4G53qwo36wZQvKD4u4TMAFh5ydmlOomn7Px86xi0ciH3KOw","dp":"KC9zaQ84LPpBizRuR8KTtk8F0uN2AngSD_YJuPOeI9cN_kfteRXQrHs-zpt-fvgWZ5X8uOJQqvWOsR7rGRI9hv3_JsPX0Be6rAeEjAw6tiITjqm-fb2wVI9QN4HNkBgW08bM65uIebhzoH_HsXwUJt-ybUjwn8qZefXgZvDM8cQ4LQAvPNy9eDEchUg1VUbRCc_91eZCq11PT5A6X0YsGuln-BuhiYL55GG5qti8EZAdMvykslFeVofuVkJRnhHhBF6ccc3kHboKZCBGT8n7Hn6WiAJ7AmqHaTJPWIgYrmZqIhCQuJY9mTf61RDMO2e-oBn-88qtE40_6u6f_GHKQQ","dq":"eZIGVVaTAEziH5stUBHnreLza2iHqSet3cyAdc0PbHZThaI5-nav1Dcex4_H0dJnz9bpwMGVKrBFmp5P9nhDST6ig3HOaNPw8roxNV0p3AY1TDJ4MbCdvYNdSVdC44kAIOHSFmTA3-ZvF85VAjiaiIRgeq8Zp-GSrC4jQu1qApDVDTEERNsCAdIth9nYIUVaw80IXTao9KqWzk-U41XHdVOnXh81vsdhsQjWWiono-j1uDtjU1NUfjUoav44O31rCIQffz8_-7Fpr7Aj3zcU2jnQjdZdn3npZRWFF_tetLVAEq8FAiLVlZh1kYEnntJFb099P_raCkdCb2KlfFF_WQ","qi":"sxxizN6dhWM8Ww2Vr7Ti-vDV0YqYGdAN_Fy8gAaLtINbhk2YrzBO-q3M_HAXendE8SHFNM2f9xAnpzTJND9aww27MkSmaslY65VVjoLkoh2YONmaePKV8T0MG2ffEl1lnhvS_nq63aJWNBJm7U_wizv0yYbYTi0QI0R7wJiXaWwlA4qFPsBwbUYgzSnxU2_cesjesShbQ-shVkKdscN6QD4feEvI9io28ZDqrpHRc7TrKIYK_RKSj_8DpI1qAMlZ4VUHF-nEAEFeZ__Z4rC3rL0CvgpaCwmSKw8eHidfZCIpnOV7nFm_8_tWVphOdaodRXVXfEfOY2_8qv1UYgEUSQ"}
|
||||
16
crates/pst/jest.config.js
Normal file
16
crates/pst/jest.config.js
Normal file
@@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
// Automatically clear mock calls and instances between every test
|
||||
clearMocks: true,
|
||||
|
||||
moduleFileExtensions: ['ts', 'js'],
|
||||
|
||||
testPathIgnorePatterns: ['/tests\/data/'],
|
||||
|
||||
testEnvironment: 'node',
|
||||
|
||||
transformIgnorePatterns: ['<rootDir>/node_modules/(?!@assemblyscript/.*)'],
|
||||
|
||||
transform: {
|
||||
'^.+\\.(ts|js)$': 'ts-jest',
|
||||
},
|
||||
};
|
||||
63
crates/pst/package.json
Normal file
63
crates/pst/package.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"name": "warp-rust-template",
|
||||
"version": "0.0.1",
|
||||
"description": "Warp WASM Rust contract template",
|
||||
"main": "index.js",
|
||||
"author": "Redstone Team <dev@redstone.finance>",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "wasm-pack build --target nodejs --release --out-name rust-contract contract/implementation",
|
||||
"build:dev": "wasm-pack build --target nodejs --dev --out-name rust-contract contract/implementation",
|
||||
"gen-bindings": "yarn gen-json && yarn gen-ts",
|
||||
"gen-json": "GENERATE_JSON=1 cargo test generate_json -- --nocapture && yarn format:json-bindings",
|
||||
"gen-ts": "ts-node --transpileOnly ./scripts/generate-ts.ts && yarn format:ts-bindings",
|
||||
"test": "jest ./tests",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"lint:fix": "eslint . --ext .ts --fix",
|
||||
"format:json-bindings": "eslint 'contract/definition/bindings/json/*.json' --fix",
|
||||
"format:ts-bindings": "eslint 'contract/definition/bindings/ts/*.ts' --fix",
|
||||
"prettier:format": "prettier --config .prettierrc '**/**/*.ts' --write",
|
||||
"deploy:local": "yarn build && node deploy/local/deploy-local.js",
|
||||
"deploy:testnet": "yarn build && node deploy/testnet/deploy-test.js",
|
||||
"deploy:mainnet": "yarn build && node deploy/mainnet/deploy-mainnet.js",
|
||||
"read:local": "node deploy/local/read-contract-state-local.js",
|
||||
"read:testnet": "node deploy/testnet/read-contract-state-testnet.js",
|
||||
"read:mainnet": "node deploy/mainnet/read-contract-state-mainnet.js",
|
||||
"transfer:local": "node deploy/local/interact-transfer-local.js",
|
||||
"transfer:testnet": "node deploy/testnet/interact-transfer-testnet.js",
|
||||
"transfer:mainnet": "node deploy/mainnet/interact-transfer-mainnet.js",
|
||||
"balance:local": "node deploy/local/interact-balance-local.js",
|
||||
"balance:testnet": "node deploy/testnet/interact-balance-testnet.js",
|
||||
"balance:mainnet": "node deploy/mainnet/interact-balance-mainnet.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"arlocal": "^1.1.59",
|
||||
"arweave": "1.12.4",
|
||||
"json-schema-to-typescript": "^11.0.1",
|
||||
"typescript": "^4.6.2",
|
||||
"warp-contracts": "1.2.56",
|
||||
"warp-contracts-plugin-deploy": "1.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"arweave": "1.12.4"
|
||||
},
|
||||
"overrides": {
|
||||
"arweave": "1.12.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/node": "^18.6.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.40.0",
|
||||
"@typescript-eslint/parser": "^5.40.0",
|
||||
"eslint": "^8.25.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^3.4.1",
|
||||
"jest": "^28.1.3",
|
||||
"prettier": "^2.3.2",
|
||||
"ts-jest": "^28.0.7",
|
||||
"ts-node": "^10.9.1"
|
||||
}
|
||||
}
|
||||
43
crates/pst/scripts/generate-ts.ts
Normal file
43
crates/pst/scripts/generate-ts.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
// NOTE: It is currently required to use a script file in order to run json2ts instead of using its
|
||||
// CLI because the CLI interprets `--additionalProperties false` as `false` being a string.
|
||||
|
||||
import { parse, join } from 'node:path';
|
||||
import { readdirSync, writeFileSync, mkdirSync, readFileSync } from 'node:fs';
|
||||
|
||||
import { compileFromFile } from 'json-schema-to-typescript';
|
||||
import { writeImplementationFile } from './generation-utils';
|
||||
|
||||
const BINDINGS_ROOT = './contract/definition/bindings';
|
||||
const BINDINGS_JSON = join(BINDINGS_ROOT, 'json');
|
||||
const BINDINGS_TS = join(BINDINGS_ROOT, 'ts');
|
||||
|
||||
mkdirSync(BINDINGS_TS, { recursive: true });
|
||||
|
||||
const getFile = (name: string) => {
|
||||
const filePath = join(BINDINGS_JSON, name);
|
||||
return JSON.parse(readFileSync(filePath, 'utf-8'));
|
||||
};
|
||||
|
||||
for (const fileName of readdirSync(BINDINGS_JSON)) {
|
||||
const jsonPath = join(BINDINGS_JSON, fileName);
|
||||
const tsPath = join(BINDINGS_TS, parse(fileName).name + '.ts');
|
||||
const file = getFile(fileName);
|
||||
delete file['$schema'];
|
||||
file.oneOf.forEach((f) => {
|
||||
f['$schema'] = 'http://json-schema.org/draft-07/schema#';
|
||||
f.title = f.properties.function.enum[0];
|
||||
delete f.properties.function;
|
||||
});
|
||||
writeFileSync(join(BINDINGS_JSON, fileName), JSON.stringify(file));
|
||||
|
||||
compileFromFile(jsonPath, {
|
||||
additionalProperties: false
|
||||
}).then((tsContent) => writeFileSync(tsPath, tsContent));
|
||||
}
|
||||
|
||||
writeImplementationFile(BINDINGS_TS, [
|
||||
getFile('View.json'),
|
||||
getFile('WriteAction.json'),
|
||||
getFile('ContractState.json')
|
||||
// eslint-disable-next-line
|
||||
]).catch((e) => console.log(e));
|
||||
114
crates/pst/scripts/generation-utils.ts
Normal file
114
crates/pst/scripts/generation-utils.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import path from 'path';
|
||||
|
||||
// eslint-disable-next-line
|
||||
export const writeImplementationFile = async (bindings: any, actions: any[]) => {
|
||||
let resImpl = ``;
|
||||
const actionsView = getActionsName(actions[0]);
|
||||
const actionsWrite = getActionsName(actions[1]);
|
||||
|
||||
resImpl = `
|
||||
/**
|
||||
* This file was automatically generated. Do not modify it, if you encounter any problems \n- please raise an issue: https://github.com/warp-contracts/warp-wasm-templates/issues.
|
||||
*/\n\n
|
||||
import { WriteInteractionOptions, WriteInteractionResponse, Contract, Warp, ArWallet, ContractError, EvaluationOptions } from 'warp-contracts';\nimport { ${actionsView} } from './View';\nimport { ${actionsWrite} } from './WriteAction';\nimport { State } from './ContractState';\n\n`;
|
||||
resImpl += `
|
||||
export interface BaseInput {
|
||||
function: string;
|
||||
}
|
||||
|
||||
export class ${makeFirstCharUpper(implName)}Contract {
|
||||
readonly contract: Contract<State>;
|
||||
|
||||
constructor(contractId: string, warp: Warp) {
|
||||
this.contract = warp.contract<State>(contractId);
|
||||
}
|
||||
|
||||
connect(wallet: ArWallet) {
|
||||
this.contract.connect(wallet);
|
||||
return this;
|
||||
}
|
||||
|
||||
setEvaluationOptions(evaluationOptions: Partial<EvaluationOptions>) {
|
||||
this.contract.setEvaluationOptions(evaluationOptions);
|
||||
return this;
|
||||
}
|
||||
|
||||
async currentState(): Promise<State> {
|
||||
const { cachedValue } = await this.contract.readState();
|
||||
return cachedValue.state;
|
||||
}
|
||||
|
||||
\n`;
|
||||
for (const readObj of actions[0].oneOf) {
|
||||
resImpl += generateInteractions(readObj, true);
|
||||
}
|
||||
for (const writeObj of actions[1].oneOf) {
|
||||
resImpl += generateInteractions(writeObj, false);
|
||||
}
|
||||
resImpl += `}`;
|
||||
writeFileSync(join(bindings, `${makeFirstCharUpper(implName)}Contract.ts`), resImpl);
|
||||
};
|
||||
|
||||
const generateInteractions = (functionObj, read: boolean) => {
|
||||
const interactionName = functionObj.title;
|
||||
const interactionNameUpper = makeFirstCharUpper(interactionName);
|
||||
if (read) {
|
||||
if (functionObj.title.includes('Result')) {
|
||||
return '';
|
||||
} else {
|
||||
return `async ${interactionName}(${interactionName}: ${interactionNameUpper}): Promise<${interactionNameUpper}Result> {
|
||||
const interactionResult = await this.contract.viewState<BaseInput & ${makeFirstCharUpper(
|
||||
interactionNameUpper
|
||||
)}, ${interactionNameUpper}Result>({ function: '${interactionName}', ...${interactionName} });
|
||||
if (interactionResult.type == 'error') {
|
||||
throw new ContractError(interactionResult.error);
|
||||
} else if (interactionResult.type == 'exception') {
|
||||
throw Error(interactionResult.errorMessage);
|
||||
}
|
||||
return interactionResult.result;
|
||||
}\n\n`;
|
||||
}
|
||||
} else {
|
||||
return `async ${interactionName}(
|
||||
${interactionName}: ${interactionNameUpper},
|
||||
options?: WriteInteractionOptions
|
||||
): Promise<WriteInteractionResponse | null> {
|
||||
return await this.contract.writeInteraction<BaseInput & ${interactionNameUpper}>(
|
||||
{ function: '${interactionName}', ...${interactionName} },
|
||||
options
|
||||
);
|
||||
}\n\n`;
|
||||
}
|
||||
};
|
||||
|
||||
export const interfaceString = (interfaceName: string, properties: string) => {
|
||||
return `export interface ${interfaceName}{ ${properties}}\n`;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line
|
||||
const getFunctionNames = (list: any[]) => {
|
||||
const functionNames = [];
|
||||
for (const typeObj of list) {
|
||||
const functionName = typeObj.title;
|
||||
functionName != 'function' && functionNames.push(functionName.charAt(0).toUpperCase() + functionName.slice(1));
|
||||
}
|
||||
return functionNames;
|
||||
};
|
||||
|
||||
const getActionsName = (action) => {
|
||||
let actionsName = ``;
|
||||
let actionsFunctions = [];
|
||||
actionsFunctions = [...actionsFunctions, ...getFunctionNames(action.oneOf || action.anyOf)];
|
||||
actionsFunctions.forEach((a) => {
|
||||
actionsFunctions.indexOf(a) == actionsFunctions.length - 1 ? (actionsName += a) : (actionsName += `${a}, `);
|
||||
});
|
||||
return actionsName;
|
||||
};
|
||||
|
||||
const implName = path.basename(process.cwd());
|
||||
|
||||
const makeFirstCharUpper = (s: string) => {
|
||||
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||
};
|
||||
377
crates/pst/tests/contract.spec.ts
Normal file
377
crates/pst/tests/contract.spec.ts
Normal file
@@ -0,0 +1,377 @@
|
||||
import fs from 'fs';
|
||||
|
||||
import ArLocal from 'arlocal';
|
||||
import Arweave from 'arweave';
|
||||
import { JWKInterface } from 'arweave/node/lib/wallet';
|
||||
import {
|
||||
InteractionResult,
|
||||
LoggerFactory,
|
||||
PstState,
|
||||
Warp,
|
||||
SmartWeaveTags,
|
||||
WarpFactory,
|
||||
TagsParser,
|
||||
ArweaveWrapper,
|
||||
WasmSrc
|
||||
} from 'warp-contracts';
|
||||
import { DeployPlugin } from 'warp-contracts-plugin-deploy';
|
||||
import path from 'path';
|
||||
import { PstContract } from '../contract/definition/bindings/ts/PstContract';
|
||||
import { State } from '../contract/definition/bindings/ts/ContractState';
|
||||
|
||||
jest.setTimeout(30000);
|
||||
|
||||
describe('Testing the Rust WASM Profit Sharing Token', () => {
|
||||
let contractSrc: Buffer;
|
||||
let contractGlueCodeFile: string;
|
||||
|
||||
let wallet: JWKInterface;
|
||||
let walletAddress: string;
|
||||
|
||||
let initialState: State;
|
||||
|
||||
let arweave: Arweave;
|
||||
let arlocal: ArLocal;
|
||||
let warp: Warp;
|
||||
let pst: PstContract;
|
||||
let pst2: PstContract;
|
||||
let pst3: PstContract;
|
||||
|
||||
let contractTxId: string;
|
||||
|
||||
let properForeignContractTxId: string;
|
||||
let wrongForeignContractTxId: string;
|
||||
|
||||
let arweaveWrapper: ArweaveWrapper;
|
||||
let tagsParser: TagsParser;
|
||||
|
||||
beforeAll(async () => {
|
||||
// note: each tests suit (i.e. file with tests that Jest is running concurrently
|
||||
// with another files has to have ArLocal set to a different port!)
|
||||
arlocal = new ArLocal(1820, false);
|
||||
await arlocal.start();
|
||||
|
||||
tagsParser = new TagsParser();
|
||||
|
||||
LoggerFactory.INST.logLevel('error');
|
||||
LoggerFactory.INST.logLevel('debug', 'WASM:Rust');
|
||||
//LoggerFactory.INST.logLevel('debug', 'WasmContractHandlerApi');
|
||||
|
||||
warp = WarpFactory.forLocal(1820).use(new DeployPlugin());
|
||||
({ arweave } = warp);
|
||||
arweaveWrapper = new ArweaveWrapper(arweave);
|
||||
|
||||
({ jwk: wallet, address: walletAddress } = await warp.generateWallet());
|
||||
|
||||
contractSrc = fs.readFileSync(path.join(__dirname, '../contract/implementation/pkg/rust-contract_bg.wasm'));
|
||||
const contractSrcCodeDir: string = path.join(__dirname, '../contract/implementation/src');
|
||||
contractGlueCodeFile = path.join(__dirname, '../contract/implementation/pkg/rust-contract.js');
|
||||
const stateFromFile: PstState = JSON.parse(fs.readFileSync(path.join(__dirname, './data/token-pst.json'), 'utf8'));
|
||||
|
||||
initialState = {
|
||||
...stateFromFile,
|
||||
...{
|
||||
owner: walletAddress,
|
||||
balances: {
|
||||
...stateFromFile.balances,
|
||||
[walletAddress]: 555669
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// deploying contract using the new SDK.
|
||||
({ contractTxId } = await warp.deploy({
|
||||
wallet,
|
||||
initState: JSON.stringify(initialState),
|
||||
src: contractSrc,
|
||||
wasmSrcCodeDir: contractSrcCodeDir,
|
||||
wasmGlueCode: contractGlueCodeFile
|
||||
}));
|
||||
|
||||
({ contractTxId: properForeignContractTxId } = await warp.deploy({
|
||||
wallet,
|
||||
initState: JSON.stringify({
|
||||
...initialState,
|
||||
...{
|
||||
ticker: 'FOREIGN_PST',
|
||||
name: 'foreign contract'
|
||||
}
|
||||
}),
|
||||
src: contractSrc,
|
||||
wasmSrcCodeDir: contractSrcCodeDir,
|
||||
wasmGlueCode: contractGlueCodeFile
|
||||
}));
|
||||
|
||||
({ contractTxId: wrongForeignContractTxId } = await warp.deploy({
|
||||
wallet,
|
||||
initState: JSON.stringify({
|
||||
...initialState,
|
||||
...{
|
||||
ticker: 'FOREIGN_PST_2',
|
||||
name: 'foreign contract 2'
|
||||
}
|
||||
}),
|
||||
src: contractSrc,
|
||||
wasmSrcCodeDir: contractSrcCodeDir,
|
||||
wasmGlueCode: contractGlueCodeFile
|
||||
}));
|
||||
|
||||
pst = new PstContract(contractTxId, warp);
|
||||
pst2 = new PstContract(properForeignContractTxId, warp);
|
||||
pst3 = new PstContract(wrongForeignContractTxId, warp);
|
||||
|
||||
// connecting wallet to the PST contract
|
||||
pst.connect(wallet).setEvaluationOptions({ internalWrites: true });
|
||||
pst2.connect(wallet).setEvaluationOptions({ internalWrites: true });
|
||||
pst3.connect(wallet).setEvaluationOptions({ useKVStorage: true });
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await arlocal.stop();
|
||||
});
|
||||
|
||||
it('should properly deploy contract', async () => {
|
||||
const contractTx = await arweave.transactions.get(contractTxId);
|
||||
expect(contractTx).not.toBeNull();
|
||||
|
||||
const contractSrcTxId = tagsParser.getTag(contractTx, SmartWeaveTags.CONTRACT_SRC_TX_ID);
|
||||
const contractSrcTx = await arweave.transactions.get(contractSrcTxId);
|
||||
expect(tagsParser.getTag(contractSrcTx, SmartWeaveTags.CONTENT_TYPE)).toEqual('application/wasm');
|
||||
expect(tagsParser.getTag(contractSrcTx, SmartWeaveTags.WASM_LANG)).toEqual('rust');
|
||||
expect(tagsParser.getTag(contractSrcTx, SmartWeaveTags.WASM_META)).toBeTruthy();
|
||||
|
||||
const srcTxData = await arweaveWrapper.txData(contractSrcTxId);
|
||||
const wasmSrc = new WasmSrc(srcTxData);
|
||||
expect(wasmSrc.wasmBinary()).not.toBeNull();
|
||||
expect(wasmSrc.additionalCode()).toEqual(fs.readFileSync(contractGlueCodeFile, 'utf-8'));
|
||||
expect((await wasmSrc.sourceCode()).size).toEqual(11);
|
||||
});
|
||||
|
||||
it('should read pst state and balance data', async () => {
|
||||
expect(await pst.currentState()).toEqual(initialState);
|
||||
expect((await pst.balance({ target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M' })).balance).toEqual(10000000);
|
||||
expect((await pst.balance({ target: '33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA' })).balance).toEqual(23111222);
|
||||
expect((await pst.balance({ target: walletAddress })).balance).toEqual(555669);
|
||||
});
|
||||
|
||||
it('should properly transfer tokens', async () => {
|
||||
await pst.transfer(
|
||||
{
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M',
|
||||
qty: 555
|
||||
},
|
||||
{ vrf: true }
|
||||
);
|
||||
|
||||
expect((await pst.currentState()).balances[walletAddress]).toEqual(555669 - 555);
|
||||
expect((await pst.currentState()).balances['uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M']).toEqual(10000000 + 555);
|
||||
});
|
||||
|
||||
it('should properly use KV', async () => {
|
||||
await pst3.kvPut(
|
||||
{
|
||||
key: 'key1',
|
||||
value: 'value1'
|
||||
},
|
||||
{ vrf: true }
|
||||
);
|
||||
const ok = await pst3.kvGet({ key: 'key1' });
|
||||
expect(ok.key).toEqual('key1');
|
||||
expect(ok.value).toEqual('value1');
|
||||
const nok = await pst3.kvGet({ key: 'non-existent' });
|
||||
expect(nok.key).toEqual('non-existent');
|
||||
expect(nok.value).toEqual('');
|
||||
});
|
||||
|
||||
it('should properly view contract state', async () => {
|
||||
const result = await pst.balance({ target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M' });
|
||||
expect(result.balance).toEqual(10000000 + 555);
|
||||
expect(result.ticker).toEqual('EXAMPLE_PST_TOKEN');
|
||||
expect(result.target).toEqual('uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M');
|
||||
});
|
||||
|
||||
// note: the dummy logic on the test contract should add 1000 tokens
|
||||
// to each address, if the foreign contract state 'ticker' field = 'FOREIGN_PST'
|
||||
it('should properly read foreign contract state', async () => {
|
||||
await pst.foreignRead(
|
||||
{
|
||||
contractTxId: wrongForeignContractTxId
|
||||
},
|
||||
{ vrf: true }
|
||||
);
|
||||
expect((await pst.currentState()).balances[walletAddress]).toEqual(555669 - 555);
|
||||
expect((await pst.currentState()).balances['uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M']).toEqual(10000000 + 555);
|
||||
await pst.foreignRead(
|
||||
{
|
||||
contractTxId: properForeignContractTxId
|
||||
},
|
||||
{ vrf: true }
|
||||
);
|
||||
expect((await pst.currentState()).balances[walletAddress]).toEqual(555669 - 555 + 1000);
|
||||
expect((await pst.currentState()).balances['uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M']).toEqual(
|
||||
10000000 + 555 + 1000
|
||||
);
|
||||
});
|
||||
|
||||
it('should properly view foreign contract state', async () => {
|
||||
const res = await pst.foreignView({
|
||||
contractTxId: properForeignContractTxId,
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M'
|
||||
});
|
||||
expect(res.ticker).toEqual('FOREIGN_PST');
|
||||
expect(res.target).toEqual('uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M');
|
||||
expect(res.balance).toEqual(10_000_000);
|
||||
});
|
||||
|
||||
it('should propagate error from view foreign contract state', async () => {
|
||||
let exc;
|
||||
try {
|
||||
await pst.foreignView({
|
||||
contractTxId: properForeignContractTxId,
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M-Invalid'
|
||||
});
|
||||
} catch (e) {
|
||||
exc = e;
|
||||
}
|
||||
expect(exc).toHaveProperty('error.kind', 'WalletHasNoBalanceDefined');
|
||||
expect(exc).toHaveProperty('error.data', 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M-Invalid');
|
||||
});
|
||||
|
||||
it('should properly perform internal write', async () => {
|
||||
const balance = (await pst2.balance({ target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M' })).balance;
|
||||
|
||||
await pst.foreignWrite(
|
||||
{
|
||||
contractTxId: properForeignContractTxId,
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M',
|
||||
qty: 555
|
||||
},
|
||||
{ vrf: true }
|
||||
);
|
||||
|
||||
expect((await pst2.balance({ target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M' })).balance).toEqual(
|
||||
balance + 555
|
||||
);
|
||||
expect((await pst2.balance({ target: walletAddress })).balance).toEqual(555669 - 555);
|
||||
});
|
||||
|
||||
it('should properly perform dry write with overwritten caller', async () => {
|
||||
const { address: overwrittenCaller } = await warp.generateWallet();
|
||||
|
||||
await pst.transfer(
|
||||
{
|
||||
target: overwrittenCaller,
|
||||
qty: 1000
|
||||
},
|
||||
{ vrf: true }
|
||||
);
|
||||
|
||||
// note: transfer should be done from the "overwrittenCaller" address, not the "walletAddress"
|
||||
const result: InteractionResult<State, unknown> = await pst.contract.dryWrite(
|
||||
{
|
||||
function: 'transfer',
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M',
|
||||
qty: 333
|
||||
},
|
||||
overwrittenCaller,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
expect(result.state.balances[walletAddress]).toEqual(555114 - 1000 + 1000);
|
||||
expect(result.state.balances['uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M']).toEqual(10000000 + 1000 + 555 + 333);
|
||||
expect(result.state.balances[overwrittenCaller]).toEqual(1000 - 333);
|
||||
});
|
||||
|
||||
it('should properly handle runtime errors', async () => {
|
||||
const result = await pst.contract.dryWrite(
|
||||
{
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M',
|
||||
qty: 555
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
expect(result.type).toEqual('exception');
|
||||
expect(result).toHaveProperty('errorMessage');
|
||||
});
|
||||
|
||||
it('should properly handle contract errors', async () => {
|
||||
const result = await pst.contract.dryWrite(
|
||||
{
|
||||
function: 'transfer',
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M',
|
||||
qty: 0
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
expect(result.type).toEqual('error');
|
||||
expect(result.error).toHaveProperty('kind', 'TransferAmountMustBeHigherThanZero');
|
||||
});
|
||||
|
||||
xit('should return stable gas results', async () => {
|
||||
const results = [];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const result = await pst.contract.dryWrite(
|
||||
{
|
||||
function: 'transfer',
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M',
|
||||
qty: 555
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
results.push(result);
|
||||
}
|
||||
|
||||
results.forEach((result) => {
|
||||
expect(result.gasUsed).toEqual(9388933);
|
||||
});
|
||||
});
|
||||
|
||||
xit('should honor gas limits', async () => {
|
||||
pst.setEvaluationOptions({
|
||||
gasLimit: 5000000
|
||||
});
|
||||
|
||||
const result = await pst.contract.dryWrite(
|
||||
{
|
||||
function: 'transfer',
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M',
|
||||
qty: 555
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
expect(result.type).toEqual('exception');
|
||||
expect(result.errorMessage.startsWith('[RE:OOG] Out of gas!')).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should properly evolve contract's source code", async () => {
|
||||
const balance = (await pst.currentState()).balances[walletAddress];
|
||||
|
||||
const newSource = fs.readFileSync(path.join(__dirname, './data/token-evolve.js'), 'utf8');
|
||||
|
||||
const srcTx = await warp.createSource({ src: newSource }, wallet);
|
||||
const newSrcTxId = await warp.saveSource(srcTx);
|
||||
|
||||
await pst.evolve({ value: newSrcTxId }, { vrf: true });
|
||||
|
||||
// note: the evolved balance always adds 555 to the result
|
||||
expect((await pst.balance({ target: walletAddress })).balance).toEqual(balance + 555);
|
||||
});
|
||||
});
|
||||
70
crates/pst/tests/data/token-evolve.js
Normal file
70
crates/pst/tests/data/token-evolve.js
Normal file
@@ -0,0 +1,70 @@
|
||||
export function handle(state, action) {
|
||||
const balances = state.balances;
|
||||
const canEvolve = state.canEvolve;
|
||||
const input = action.input;
|
||||
const caller = action.caller;
|
||||
|
||||
if (input.function === 'transfer') {
|
||||
const target = input.target;
|
||||
const qty = input.qty;
|
||||
|
||||
if (!Number.isInteger(qty)) {
|
||||
throw new ContractError('Invalid value for "qty". Must be an integer');
|
||||
}
|
||||
|
||||
if (!target) {
|
||||
throw new ContractError('No target specified');
|
||||
}
|
||||
|
||||
if (qty <= 0 || caller === target) {
|
||||
throw new ContractError('Invalid token transfer');
|
||||
}
|
||||
|
||||
if (balances[caller] < qty) {
|
||||
throw new ContractError(
|
||||
`Caller balance not high enough to send ${qty} token(s)!`
|
||||
);
|
||||
}
|
||||
|
||||
// Lower the token balance of the caller
|
||||
balances[caller] -= qty;
|
||||
if (target in balances) {
|
||||
// Wallet already exists in state, add new tokens
|
||||
balances[target] += qty;
|
||||
} else {
|
||||
// Wallet is new, set starting balance
|
||||
balances[target] = qty;
|
||||
}
|
||||
|
||||
return { state };
|
||||
}
|
||||
|
||||
if (input.function === 'balance') {
|
||||
const target = input.target;
|
||||
const ticker = state.ticker;
|
||||
|
||||
if (typeof target !== 'string') {
|
||||
throw new ContractError('Must specify target to get balance for');
|
||||
}
|
||||
|
||||
if (typeof balances[target] !== 'number') {
|
||||
throw new ContractError('Cannot get balance, target does not exist');
|
||||
}
|
||||
|
||||
return { result: { target, ticker, balance: balances[target] + 555 } };
|
||||
}
|
||||
|
||||
if (input.function === 'evolve' && canEvolve) {
|
||||
if (state.owner !== caller) {
|
||||
throw new ContractError('Only the owner can evolve a contract.');
|
||||
}
|
||||
|
||||
state.evolve = input.value;
|
||||
|
||||
return { state };
|
||||
}
|
||||
|
||||
throw new ContractError(
|
||||
`No function supplied or function not recognised: "${input.function}"`
|
||||
);
|
||||
}
|
||||
9
crates/pst/tests/data/token-pst.json
Normal file
9
crates/pst/tests/data/token-pst.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ticker": "EXAMPLE_PST_TOKEN",
|
||||
"owner": "uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M",
|
||||
"canEvolve": true,
|
||||
"balances": {
|
||||
"uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M": 10000000,
|
||||
"33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA": 23111222
|
||||
}
|
||||
}
|
||||
10
crates/pst/tsconfig.json
Normal file
10
crates/pst/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "Node",
|
||||
"target": "ES2018",
|
||||
"lib": ["dom"],
|
||||
"esModuleInterop": true,
|
||||
"downlevelIteration": true
|
||||
},
|
||||
"exclude": ["node_modules", "tools", "contract/implementation/pkg"]
|
||||
}
|
||||
7326
crates/pst/yarn.lock
Normal file
7326
crates/pst/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
225
crates/toy-contract/Cargo.lock
generated
Normal file
225
crates/toy-contract/Cargo.lock
generated
Normal file
@@ -0,0 +1,225 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-wasm-bindgen"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toy-contract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"warp-contracts",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "warp-contracts"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"warp-contracts-core",
|
||||
"warp-contracts-macro",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp-contracts-core"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp-contracts-macro"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
"warp-contracts-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
18
crates/toy-contract/Cargo.toml
Normal file
18
crates/toy-contract/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "toy-contract"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "test"
|
||||
repository = "not applicable"
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
warp-contracts = { version = "0.1.2", path = "../warp-contracts" }
|
||||
wasm-bindgen = "=0.2.84"
|
||||
wasm-bindgen-futures = { version = "0.4.34" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde-wasm-bindgen = "0.5"
|
||||
js-sys = "0.3.61"
|
||||
0
crates/toy-contract/LICENSE
Normal file
0
crates/toy-contract/LICENSE
Normal file
0
crates/toy-contract/README.md
Normal file
0
crates/toy-contract/README.md
Normal file
16
crates/toy-contract/jest.config.js
Normal file
16
crates/toy-contract/jest.config.js
Normal file
@@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
// Automatically clear mock calls and instances between every test
|
||||
clearMocks: true,
|
||||
|
||||
moduleFileExtensions: ['ts', 'js'],
|
||||
|
||||
testPathIgnorePatterns: ['/tests\/data/'],
|
||||
|
||||
testEnvironment: 'node',
|
||||
|
||||
transformIgnorePatterns: ['<rootDir>/node_modules/(?!@assemblyscript/.*)'],
|
||||
|
||||
transform: {
|
||||
'^.+\\.(ts|js)$': 'ts-jest',
|
||||
},
|
||||
};
|
||||
64
crates/toy-contract/package.json
Normal file
64
crates/toy-contract/package.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "warp-rust-template",
|
||||
"version": "0.0.1",
|
||||
"description": "Warp WASM Rust contract template",
|
||||
"main": "index.js",
|
||||
"author": "Redstone Team <dev@redstone.finance>",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "wasm-pack build --target nodejs --release --out-name rust-contract .",
|
||||
"build:dev": "wasm-pack build --target nodejs --dev --out-name rust-contract .",
|
||||
"build:profiling": "wasm-pack build --target nodejs --profiling --out-name rust-contract .",
|
||||
"gen-bindings": "yarn gen-json && yarn gen-ts",
|
||||
"gen-json": "GENERATE_JSON=1 cargo test generate_json -- --nocapture && yarn format:json-bindings",
|
||||
"gen-ts": "ts-node --transpileOnly ./scripts/generate-ts.ts && yarn format:ts-bindings",
|
||||
"test": "jest ./tests",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"lint:fix": "eslint . --ext .ts --fix",
|
||||
"format:json-bindings": "eslint 'contract/definition/bindings/json/*.json' --fix",
|
||||
"format:ts-bindings": "eslint 'contract/definition/bindings/ts/*.ts' --fix",
|
||||
"prettier:format": "prettier --config .prettierrc '**/**/*.ts' --write",
|
||||
"deploy:local": "yarn build && node deploy/local/deploy-local.js",
|
||||
"deploy:testnet": "yarn build && node deploy/testnet/deploy-test.js",
|
||||
"deploy:mainnet": "yarn build && node deploy/mainnet/deploy-mainnet.js",
|
||||
"read:local": "node deploy/local/read-contract-state-local.js",
|
||||
"read:testnet": "node deploy/testnet/read-contract-state-testnet.js",
|
||||
"read:mainnet": "node deploy/mainnet/read-contract-state-mainnet.js",
|
||||
"transfer:local": "node deploy/local/interact-transfer-local.js",
|
||||
"transfer:testnet": "node deploy/testnet/interact-transfer-testnet.js",
|
||||
"transfer:mainnet": "node deploy/mainnet/interact-transfer-mainnet.js",
|
||||
"balance:local": "node deploy/local/interact-balance-local.js",
|
||||
"balance:testnet": "node deploy/testnet/interact-balance-testnet.js",
|
||||
"balance:mainnet": "node deploy/mainnet/interact-balance-mainnet.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"arlocal": "^1.1.59",
|
||||
"arweave": "1.12.4",
|
||||
"json-schema-to-typescript": "^11.0.1",
|
||||
"typescript": "^4.6.2",
|
||||
"warp-contracts": "1.2.56",
|
||||
"warp-contracts-plugin-deploy": "^1.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"arweave": "1.12.4"
|
||||
},
|
||||
"overrides": {
|
||||
"arweave": "1.12.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/node": "^18.6.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.40.0",
|
||||
"@typescript-eslint/parser": "^5.40.0",
|
||||
"eslint": "^8.25.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^3.4.1",
|
||||
"jest": "^28.1.3",
|
||||
"prettier": "^2.3.2",
|
||||
"ts-jest": "^28.0.7",
|
||||
"ts-node": "^10.9.1"
|
||||
}
|
||||
}
|
||||
28
crates/toy-contract/src/lib.rs
Normal file
28
crates/toy-contract/src/lib.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use warp_contracts::{warp_contract, handler_result::{WriteResult, ViewResult}};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct State {
|
||||
x: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Action {
|
||||
x: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct View {
|
||||
x: u8,
|
||||
}
|
||||
|
||||
#[warp_contract(write)]
|
||||
pub fn handle(mut state: State, action: Action) -> WriteResult<State, ()> {
|
||||
state.x = action.x;
|
||||
WriteResult::Success(state)
|
||||
}
|
||||
|
||||
#[warp_contract(view)]
|
||||
pub fn view(state: &State, _action: Action) -> ViewResult<View, ()> {
|
||||
ViewResult::Success(View { x: state.x })
|
||||
}
|
||||
116
crates/toy-contract/tests/contract.spec.ts
Normal file
116
crates/toy-contract/tests/contract.spec.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import fs from 'fs';
|
||||
|
||||
import ArLocal from 'arlocal';
|
||||
import Arweave from 'arweave';
|
||||
import { JWKInterface } from 'arweave/node/lib/wallet';
|
||||
import {
|
||||
LoggerFactory,
|
||||
Warp,
|
||||
SmartWeaveTags,
|
||||
WarpFactory,
|
||||
TagsParser,
|
||||
ArweaveWrapper,
|
||||
WasmSrc,
|
||||
Contract
|
||||
} from 'warp-contracts';
|
||||
import { DeployPlugin } from 'warp-contracts-plugin-deploy';
|
||||
import path from 'path';
|
||||
|
||||
jest.setTimeout(30000);
|
||||
|
||||
class State {
|
||||
constructor(public x: number) {}
|
||||
}
|
||||
|
||||
class View {
|
||||
constructor(public x: number) {}
|
||||
}
|
||||
|
||||
class Action {
|
||||
constructor(public x: number) {}
|
||||
}
|
||||
|
||||
describe('Testing the Rust WASM Profit Sharing Token', () => {
|
||||
let contractSrc: Buffer;
|
||||
let contractGlueCodeFile: string;
|
||||
|
||||
let wallet: JWKInterface;
|
||||
|
||||
const initialState = new State(0);
|
||||
|
||||
let arweave: Arweave;
|
||||
let arlocal: ArLocal;
|
||||
let warp: Warp;
|
||||
let toyContract: Contract<State>;
|
||||
|
||||
let contractTxId: string;
|
||||
|
||||
let arweaveWrapper: ArweaveWrapper;
|
||||
let tagsParser: TagsParser;
|
||||
|
||||
beforeAll(async () => {
|
||||
arlocal = new ArLocal(1820, false);
|
||||
await arlocal.start();
|
||||
|
||||
tagsParser = new TagsParser();
|
||||
LoggerFactory.INST.logLevel('debug');
|
||||
LoggerFactory.INST.logLevel('debug', 'WASM:Rust');
|
||||
//LoggerFactory.INST.logLevel('debug', 'WasmContractHandlerApi');
|
||||
|
||||
warp = WarpFactory.forLocal(1820).use(new DeployPlugin());
|
||||
({ arweave } = warp);
|
||||
arweaveWrapper = new ArweaveWrapper(arweave);
|
||||
|
||||
({ jwk: wallet } = await warp.generateWallet());
|
||||
|
||||
contractSrc = fs.readFileSync(path.join(__dirname, '../pkg/rust-contract_bg.wasm'));
|
||||
const contractSrcCodeDir: string = path.join(__dirname, '../src');
|
||||
contractGlueCodeFile = path.join(__dirname, '../pkg/rust-contract.js');
|
||||
|
||||
// deploying contract using the new SDK.
|
||||
({ contractTxId } = await warp.deploy({
|
||||
wallet,
|
||||
initState: JSON.stringify(initialState),
|
||||
src: contractSrc,
|
||||
wasmSrcCodeDir: contractSrcCodeDir,
|
||||
wasmGlueCode: contractGlueCodeFile
|
||||
}));
|
||||
|
||||
toyContract = warp.contract<State>(contractTxId);
|
||||
|
||||
// connecting wallet to the PST contract
|
||||
toyContract.connect(wallet);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await arlocal.stop();
|
||||
});
|
||||
|
||||
it('should properly deploy contract', async () => {
|
||||
const contractTx = await arweave.transactions.get(contractTxId);
|
||||
expect(contractTx).not.toBeNull();
|
||||
|
||||
const contractSrcTxId = tagsParser.getTag(contractTx, SmartWeaveTags.CONTRACT_SRC_TX_ID);
|
||||
const contractSrcTx = await arweave.transactions.get(contractSrcTxId);
|
||||
expect(tagsParser.getTag(contractSrcTx, SmartWeaveTags.CONTENT_TYPE)).toEqual('application/wasm');
|
||||
expect(tagsParser.getTag(contractSrcTx, SmartWeaveTags.WASM_LANG)).toEqual('rust');
|
||||
expect(tagsParser.getTag(contractSrcTx, SmartWeaveTags.WASM_META)).toBeTruthy();
|
||||
|
||||
const srcTxData = await arweaveWrapper.txData(contractSrcTxId);
|
||||
const wasmSrc = new WasmSrc(srcTxData);
|
||||
expect(wasmSrc.wasmBinary()).not.toBeNull();
|
||||
expect(wasmSrc.additionalCode()).toEqual(fs.readFileSync(contractGlueCodeFile, 'utf-8'));
|
||||
expect((await wasmSrc.sourceCode()).size).toEqual(1);
|
||||
});
|
||||
|
||||
it('should read state', async () => {
|
||||
const { cachedValue } = await toyContract.readState();
|
||||
expect(cachedValue.state).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should write/view state', async () => {
|
||||
await toyContract.writeInteraction<Action>(new Action(4));
|
||||
const interactionResult = await toyContract.viewState<Action, View>(new Action(17));
|
||||
expect(interactionResult.result.x).toEqual(4);
|
||||
});
|
||||
});
|
||||
10
crates/toy-contract/tsconfig.json
Normal file
10
crates/toy-contract/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "Node",
|
||||
"target": "ES2018",
|
||||
"lib": ["dom"],
|
||||
"esModuleInterop": true,
|
||||
"downlevelIteration": true
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
7348
crates/toy-contract/yarn.lock
Normal file
7348
crates/toy-contract/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user