Skip to content

Commit 6b829da

Browse files
authored
Add terra example contract (#31)
* Add terra example contract
1 parent a82ded9 commit 6b829da

22 files changed

+3485
-2
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Pyth SDK Example Terra Contract
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
13+
jobs:
14+
test:
15+
name: Build
16+
runs-on: ubuntu-latest
17+
defaults:
18+
run:
19+
working-directory: ./examples/terra-contract
20+
steps:
21+
- name: Checkout sources
22+
uses: actions/checkout@v2
23+
24+
- name: Install stable toolchain
25+
uses: actions-rs/toolchain@v1
26+
with:
27+
profile: minimal
28+
toolchain: 1.58.1
29+
target: wasm32-unknown-unknown
30+
override: true
31+
32+
- name: Compile WASM contract
33+
run: cargo build --release --target wasm32-unknown-unknown
34+
env:
35+
RUSTFLAGS: "-C link-arg=-s"
36+
37+
lints:
38+
name: Lints
39+
runs-on: ubuntu-latest
40+
defaults:
41+
run:
42+
working-directory: ./examples/terra-contract
43+
steps:
44+
- name: Checkout sources
45+
uses: actions/checkout@v2
46+
47+
- name: Install stable toolchain
48+
uses: actions-rs/toolchain@v1
49+
with:
50+
profile: minimal
51+
toolchain: 1.58.1
52+
override: true
53+
components: clippy
54+
55+
- name: Generate Schema
56+
run: cargo run --example schema
57+
58+
- name: Schema Changes
59+
# fails if any changes not committed
60+
run: git diff --exit-code schema

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
debug
33
target
44
Cargo.lock
5+
artifacts/
56

67
# IntelliJ temp files
78
.idea
8-
*.iml
9+
*.iml

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ members = [
55
"pyth-sdk-solana",
66
"pyth-sdk-solana/test-contract",
77
"pyth-sdk-terra",
8+
"examples/terra-contract",
89
]

examples/terra-contract/Cargo.toml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
[package]
2+
name = "example-terra-contract"
3+
version = "0.1.0"
4+
authors = ["Ali Behjati <[email protected]>"]
5+
edition = "2018"
6+
7+
exclude = [
8+
# Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication.
9+
"contract.wasm",
10+
"hash.txt",
11+
]
12+
13+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
14+
15+
[lib]
16+
crate-type = ["cdylib", "rlib"]
17+
18+
[features]
19+
# for more explicit tests, cargo test --features=backtraces
20+
backtraces = ["cosmwasm-std/backtraces"]
21+
# use library feature to disable all instantiate/execute/query exports
22+
library = []
23+
24+
[package.metadata.scripts]
25+
optimize = """docker run --rm -v "$(pwd)":/code \
26+
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
27+
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
28+
cosmwasm/rust-optimizer:0.12.5
29+
"""
30+
31+
[dependencies]
32+
cosmwasm-std = { version = "0.16.2" }
33+
cosmwasm-storage = { version = "0.16.0" }
34+
cw-storage-plus = "0.8.0"
35+
schemars = "0.8"
36+
serde = { version = "1.0", default-features = false, features = ["derive"] }
37+
pyth-sdk-terra = { version = "0.1.0", path = "../../pyth-sdk-terra" } # Remove path and use version only when you use this example on your own.
38+
39+
[dev-dependencies]
40+
cosmwasm-schema = { version = "0.16.0" }

examples/terra-contract/Developing.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Developing
2+
3+
This document contains guidance regarding building, testing and preparing your contracts for production.
4+
5+
## Prerequisites
6+
7+
Before starting, make sure you have [rustup](https://rustup.rs/) along with a
8+
recent `rustc` and `cargo` version installed. Rust version 1.58.1 or above is required.
9+
10+
And you need to have the `wasm32-unknown-unknown` target installed as well.
11+
12+
You can check that via:
13+
14+
```sh
15+
rustc --version
16+
cargo --version
17+
rustup target list --installed
18+
# if wasm32 is not listed above, run this
19+
rustup target add wasm32-unknown-unknown
20+
```
21+
22+
## Compiling
23+
24+
After changing the contract, make sure you can compile and run it before
25+
making any changes. Go into the repository and do:
26+
27+
```sh
28+
# this will produce a wasm build in ./target/wasm32-unknown-unknown/release/exxamle_terra_contract.wasm
29+
cargo build --release --target wasm32-unknown-unknown
30+
```
31+
## Generating JSON Schema
32+
33+
While the Wasm calls (`instantiate`, `execute`, `query`) accept JSON, this is not enough
34+
information to use it. You need to expose the schema for the expected messages to the
35+
clients. You can generate this schema by calling `cargo run --example schema`, which will output
36+
4 files in `./schema`, corresponding to the 3 message types the contract accepts,
37+
as well as the internal `State`.
38+
39+
These files are in standard json-schema format, which should be usable by various
40+
client side tools, either to auto-generate codecs, or just to validate incoming
41+
json wrt. the defined schema.
42+
43+
## Preparing the Wasm bytecode for production
44+
45+
Before you upload it to a chain, you need to ensure the smallest output size possible,
46+
as this will be included in the body of a transaction. You also want to have a
47+
reproducible build process, so third parties can verify that the uploaded Wasm
48+
code did indeed come from the claimed rust code.
49+
50+
To solve both these issues, CosmWasm have produced `rust-optimizer`, a docker image to
51+
produce an extremely small build output in a consistent manner. The suggested way
52+
to run it is this:
53+
54+
```sh
55+
docker run --rm -v "$(pwd)":/code \
56+
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
57+
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
58+
cosmwasm/rust-optimizer:0.12.4
59+
```
60+
61+
Or, If you're on an arm64 machine, you should use a docker image built with arm64.
62+
```sh
63+
docker run --rm -v "$(pwd)":/code \
64+
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
65+
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
66+
cosmwasm/rust-optimizer-arm64:0.12.4
67+
```
68+
69+
You must mount the contract code to `/code`. You can use a absolute path instead
70+
of `$(pwd)` if you don't want to `cd` to the directory first. The other two
71+
volumes are nice for speedup. Mounting `/code/target` in particular is useful
72+
to avoid docker overwriting your local dev files with root permissions.
73+
Note the `/code/target` cache is unique for each contract being compiled to limit
74+
interference, while the registry cache is global.
75+
76+
This is rather slow compared to local compilations, especially the first compile
77+
of a given contract. The use of the two volume caches is very useful to speed up
78+
following compiles of the same contract.
79+
80+
This produces an `artifacts` directory with a `PROJECT_NAME.wasm`, as well as
81+
`checksums.txt`, containing the Sha256 hash of the wasm file.
82+
The wasm file is compiled deterministically (anyone else running the same
83+
docker on the same git commit should get the identical file with the same Sha256 hash).
84+
It is also stripped and minimized for upload to a blockchain (it is also compressed using
85+
gzip in the uploading process to make it even smaller).

examples/terra-contract/README.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Pyth SDK Example contract for Terra
2+
3+
This is an example contract that demonstrates reading the Pyth price from the Pyth on-chain contract. It is created using
4+
[cw-template](https://github.com/InterWasm/cw-template) which is a standard template for developing Terra contracts.
5+
6+
## Development
7+
8+
Visit [Developing](./Developing.md) to learn more on how to compile and develop the contract.
9+
10+
## Deploy and Query
11+
The javascript package in `tools` directory contains scripts for querying and deploying the example contract.
12+
13+
If this is the first time running the code, run the below command to install required packages in the `tools` directory:
14+
15+
```
16+
npm install
17+
```
18+
19+
### Testnet Demo
20+
In order to query the contract you can call:
21+
22+
```sh
23+
npm run query -- --network testnet --contract terra1fm4ssxq39m355pdv2wzxggf5uxs2ase4vga9qs
24+
```
25+
26+
If successful the output should look like:
27+
```
28+
{
29+
current_price: { price: 8704350000, conf: 3150000, expo: -8 },
30+
ema_price: { price: 8665158600, conf: 2965370, expo: -8 }
31+
}
32+
```
33+
34+
If the price is not available you will get:
35+
```
36+
rpc error: code = Unknown desc = Generic error: Current price is not available: contract query failed
37+
```
38+
39+
`terra1fm4ssxq39m355pdv2wzxggf5uxs2ase4vga9qs` is a live deployment of the example contract in testnet network. This contract
40+
is configured to return price of `Crypto.LUNA/USD` if it is available. If you have deployed your contract you can replace the
41+
address with your contract address.
42+
### Deployment
43+
44+
Deploying a contract in terra consists of two steps:
45+
1. Uploading the code. This step will give you a code id.
46+
2. Optionally create a new contract or migrate an existing one:
47+
1. Creating a new contract which has an address with a code id as its program.
48+
2. Migrating an existing contract code id to the new code id.
49+
50+
This script can do both steps at the same time. Read below for the details.
51+
52+
#### Uploading the code
53+
54+
First build the contracts as mentioned in [Developing](../Developing.md).
55+
56+
This command will builds and saves all the contracts in the `artifact` directory.
57+
58+
Then, for example, to deploy `example_terra_contract.wasm`, run in the `tools` directory:
59+
60+
``` sh
61+
npm run deploy -- --network testnet --artifact ../artifacts/example_terra_contract.wasm --mnemonic "..."
62+
```
63+
64+
which will print something along the lines of:
65+
66+
``` sh
67+
Storing WASM: ../artifacts/example_terra_contract.wasm (367689 bytes)
68+
Deploy fee: 88446uluna
69+
Code ID: 2435
70+
```
71+
72+
If you do not pass any additional arguments to the script it will only upload the code and returns the code id. If you want to create a
73+
new contract or upgrade an existing contract you should pass more arguments that are described below.
74+
75+
#### Instantiating a new contract
76+
If you want instantiate a new contract after your deployment pass `--instantiate` argument to the above command.
77+
It will upload the code and with the resulting code id instantiates a new example contract:
78+
79+
``` sh
80+
npm run deploy -- --network testnet --artifact ../artifacts/example_terra_contract.wasm --mnemonic "..." --instantiate
81+
```
82+
83+
If successful, the output should look like:
84+
```
85+
Storing WASM: ../artifacts/example_terra_contract.wasm (183749 bytes)
86+
Deploy fee: 44682uluna
87+
Code ID: 53199
88+
Instantiating a contract
89+
Sleeping for 10 seconds for store transaction to finalize.
90+
Instantiated Pyth Example at terra123456789yelw23uh22nadqlyjvtl7s5527er97 (0x0000000000000000000000001234567896267ee5479752a7d683e49317ff4294)
91+
Deployed pyth example contract at terra123456789yelw23uh22nadqlyjvtl7s5527er97
92+
```
93+
94+
This scripts currently set the example contract price to `Crypto.LUNA/USD` but you can change it within `deploy.js`.
95+
96+
#### Migrating an existing contract
97+
If you want to upgrade an existing contract pass `--migrate --contract terra123456xyzqwe..` arguments to the above command.
98+
It will upload the code and with the resulting code id migrates the existing contract to the new one:
99+
100+
``` sh
101+
npm run deploy -- --network testnet --artifact ../artifacts/example_terra_contract.wasm --mnemonic "..." --migrate --contract "terra123..."
102+
```
103+
104+
If successful, the output should look like:
105+
```
106+
Storing WASM: ../artifacts/example_terra_contract.wasm (183749 bytes)
107+
Deploy fee: 44682uluna
108+
Code ID: 53227
109+
Sleeping for 10 seconds for store transaction to finalize.
110+
Migrating contract terra1rhjej5gkyelw23uh22nadqlyjvtl7s5527er97 to 53227
111+
Contract terra1rhjej5gkyelw23uh22nadqlyjvtl7s5527er97 code_id successfully updated to 53227
112+
```
113+
114+
#### Notes
115+
116+
You might encounter gateway timeout or account sequence mismatch in errors. In is good to double check with terra finder as sometimes
117+
transactions succeed despite being timed out.
118+
119+
If that happens in the middle of an instantiation or migration. You can avoid re-uploading the code and use the resulting Code Id
120+
by passing `--code-id <codeId>` instead of `--artifact` and it will only do the instantiation/migration part.
121+
122+
An example is:
123+
124+
``` sh
125+
npm run deploy -- --network testnet --code-id 50123 --mnemonic "..." --migrate --contract "terra123..."
126+
```
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::env::current_dir;
2+
use std::fs::create_dir_all;
3+
4+
use cosmwasm_schema::{
5+
export_schema,
6+
remove_schemas,
7+
schema_for,
8+
};
9+
10+
use example_terra_contract::msg::{
11+
ExecuteMsg,
12+
FetchPriceResponse,
13+
InstantiateMsg,
14+
QueryMsg,
15+
};
16+
use example_terra_contract::state::State;
17+
18+
fn main() {
19+
let mut out_dir = current_dir().unwrap();
20+
out_dir.push("schema");
21+
create_dir_all(&out_dir).unwrap();
22+
remove_schemas(&out_dir).unwrap();
23+
24+
export_schema(&schema_for!(InstantiateMsg), &out_dir);
25+
export_schema(&schema_for!(ExecuteMsg), &out_dir);
26+
export_schema(&schema_for!(QueryMsg), &out_dir);
27+
export_schema(&schema_for!(State), &out_dir);
28+
export_schema(&schema_for!(FetchPriceResponse), &out_dir);
29+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "ExecuteMsg",
4+
"type": "string",
5+
"enum": []
6+
}

0 commit comments

Comments
 (0)