Skip to content

Commit e7eb30f

Browse files
authored
refactor: weather example (#2)
* wip * working -> chain * use bindings in weather + decode * cleanup of docs + fmt * readme slim down * from scratch findings, good to go!
1 parent 5d22590 commit e7eb30f

File tree

20 files changed

+627
-158
lines changed

20 files changed

+627
-158
lines changed

.docker/cli/.gitkeep

Whitespace-only changes.

.env.example

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
# == project ==
3+
# Get your key from: https://openweathermap.org/ for the example
4+
WAVS_ENV_OPEN_WEATHER_API_KEY="00000000000000000000000000000000"
5+
6+
# == ./packages/aggregator/.env ==
7+
WAVS_AGGREGATOR_MNEMONIC="test test test test test test test test test test test junk"
8+
WAVS_AGGREGATOR_DATA=~/wavs/aggregator
9+
10+
# == ./packages/cli/.env ==
11+
WAVS_CLI_ETH_MNEMONIC="test test test test test test test test test test test junk"
12+
WAVS_CLI_DATA=~/wavs/cli
13+
WAVS_CLI_LOG_LEVEL="info, wavs_cli=debug"
14+
15+
# == ./packages/wavs/.env ==
16+
WAVS_DATA=~/wavs/data
17+
WAVS_LOG_LEVEL="info, wavs[{subsys=TriggerManager}]=debug"
18+
WAVS_SUBMISSION_MNEMONIC="test test test test test test test test test test test junk"
19+
WAVS_COSMOS_SUBMISSION_MNEMONIC="cosmos mnemonic here"
20+
WAVS_E2E_COSMOS_MNEMONIC="e2e test cosmos mnemonic here"
21+
WAVS_E2E_COSMOS_TASK_QUEUE_ADDRESS="e2e test cosmos task queue address here"

.github/workflows/contracts.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@ jobs:
4747
run: forge build --sizes
4848

4949
- name: Check bindings are correct
50-
run: forge bind --bindings-path ./crates/bindings --root ./contracts --crate-name bindings --skip-cargo-toml --alloy
50+
run: forge bind --bindings-path ./crates/bindings --crate-name bindings --skip-cargo-toml --alloy

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ cache/
44
Cargo.lock
55
broadcast/
66
compiled/*.wasm
7-
.docker
8-
wavs-cli.toml
7+
.docker/cli/*.json
8+
.env

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"crates/bindings",
55
"components/*",
66
]
7+
resolver = "2"
78

89
[workspace.package]
910
edition = "2021"
@@ -16,6 +17,9 @@ rust-version = "1.80.0"
1617

1718
[workspace.dependencies]
1819
bindings = { path = "crates/bindings" }
19-
# must match the bindings Cargo
20+
# alloy must match the bindings Cargo.toml version, git, and features
2021
alloy = { git = "https://github.com/alloy-rs/alloy", rev = "v0.9.2", features = ["sol-types", "contract"] }
2122
wit-bindgen-rt = { version = "0.32.0", features = ["bitflags"] }
23+
serde = { version = "1.0.211", features = ["derive"] }
24+
serde_json = "1.0.127"
25+
layer-wasi = { git = "https://github.com/Lay3rLabs/avs-toolkit", tag = "v0.2.1" }

Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ bindings:
1616
build: bindings
1717
@$(CARGO) build
1818

19+
## wasi-build: building the WAVS wasi component(s)
20+
wasi-build:
21+
@for component in $(shell ls ./components); do \
22+
echo "Building component: $$component"; \
23+
(cd components/$$component; cargo component build --release); \
24+
done
25+
@mkdir -p ./compiled
26+
@cp ./target/wasm32-wasip1/release/*.wasm ./compiled/
27+
1928
## build-release: building the project in release mode
2029
build-release: bindings
2130
@$(CARGO) build --release

README.md

Lines changed: 46 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,11 @@
1010

1111
**Template for quickly getting started with developing WAVS Rust applications**
1212

13-
Continuous Integration is already set up to test both your Rust and Solidity
14-
code, as well as ensure formatting and that your Rust bindings match the
15-
Solidity build artifacts.
13+
A comprehensive template for developing WAVS (WebAssembly AVS) applications using Rust and Solidity. This template provides a pre-configured development environment with integrated testing frameworks for both Rust and Solidity components.
1614

17-
<!-- ## Directory Structure
15+
## Installation
1816

19-
The project is structured as a mixed Rust workspace with a Foundry project under
20-
`contracts/` and typesafe auto-generated bindings to the contracts under
21-
`crates/bindings/`.
22-
23-
```
24-
├── Cargo.toml
25-
├── app // <-- Your Rust application logic
26-
├── crates
27-
└── bindings // <-- Generated bindings to the smart contracts' abis (like Typechain)
28-
``` -->
29-
30-
## Install
17+
Create a new project using this template:
3118

3219
```bash
3320
forge init --template https://github.com/Lay3rLabs/wavs-foundry-template my-wavs
@@ -38,19 +25,21 @@ forge init --template https://github.com/Lay3rLabs/wavs-foundry-template my-wavs
3825
Given the repository contains both Solidity and Rust code, there's 2 different
3926
workflows.
4027

41-
### Solidity
42-
43-
Forge is using submodules to manage dependencies. Initialize the dependencies:
28+
### Setting up the Environment
4429

45-
If you are in the root directory of the project, run:
30+
Initialize the submodule dependencies:
4631

4732
```bash
4833
forge install
4934
```
5035

51-
Then, run the tests:
36+
Build the contracts:
37+
38+
```bash
39+
forge build
40+
```
5241

53-
If you are in the root directory of the project, run:
42+
Run the tests:
5443

5544
```bash
5645
forge test
@@ -61,12 +50,7 @@ forge test
6150
Rust bindings to the contracts can be generated via `forge bind`, which requires
6251
first building your contracts:
6352

64-
<!-- Any follow-on calls to `forge bind` will check that the generated bindings match
65-
the ones under the build files. If you want to re-generate your bindings, pass
66-
the `--overwrite` flag to your `forge bind` command. -->
67-
6853
```bash
69-
forge build
7054
make bindings
7155
```
7256

@@ -76,77 +60,65 @@ Then, you can run the tests:
7660
cargo test
7761
```
7862

79-
## WAVS Operations
63+
## WAVS
64+
65+
Build the latest solidity:
8066

8167
```bash
8268
forge build
8369
```
8470

85-
Run the following in the WAVS repo (separate terminal)
71+
Install the WAVS CLI:
72+
8673
```bash
87-
# this is based on ebf8cf6bc001d8292696ef6883d55d749c41bdd9 in the WAVS repo
88-
docker compose up # <- in the WAVS repository
74+
(cd lib/WAVS; cargo install --path ./packages/cli)
8975
```
9076

91-
Upload ServiceManager from this repo
92-
9377
```bash
94-
export CLI_EIGEN_CORE_DELEGATION_MANAGER=`docker exec -it wavs bash -c 'jq -r .eigen_core.local.delegation_manager ~/wavs/cli/deployments.json' | tr -d '\r'`
95-
export CLI_EIGEN_CORE_REWARDS_COORDINATOR=`docker exec -it wavs bash -c 'jq -r .eigen_core.local.rewards_coordinator ~/wavs/cli/deployments.json' | tr -d '\r'`
96-
export CLI_EIGEN_CORE_AVS_DIRECTORY=`docker exec -it wavs bash -c 'jq -r .eigen_core.local.avs_directory ~/wavs/cli/deployments.json' | tr -d '\r'`
97-
export FOUNDRY_ANVIL_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
78+
cp .env.example .env
9879

99-
forge script ./script/WavsServiceManager.s.sol --rpc-url http://localhost:8545 --broadcast
100-
```
101-
102-
Build WAVS WASI component
80+
# [!] Get your key from: https://openweathermap.org/
81+
# Update the WAVS_ENV_OPEN_WEATHER_API_KEY in the .env file with your key`
10382

104-
```bash
105-
(cd components/eth-trigger-echo; cargo component build --release)
83+
cp ./lib/WAVS/packages/wavs/wavs.toml .
84+
cp ./lib/WAVS/packages/cli/wavs-cli.toml .
10685

107-
mkdir -p ./compiled && cp ./target/wasm32-wasip1/release/*.wasm ./compiled/
86+
# start the WAVS network
87+
docker compose up
10888
```
10989

110-
Verify
90+
Deploy Eigenlayer and upload your WAVS Service contract
11191

11292
```bash
113-
# install wavs-cli
114-
# https://github.com/Lay3rLabs/WAVS/issues/277
115-
# - right now `E0308` is super annoying @ packages/wavs/src/submission/core.rs:426:13 ^ have to do a `result: result.into(),` for now.
116-
(cd lib/WAVS; cargo install --path ./packages/cli)
117-
118-
cp ./lib/WAVS/packages/cli/wavs-cli.toml .
93+
docker_cmd="docker exec -it wavs bash -c"
94+
export CLI_EIGEN_CORE_DELEGATION_MANAGER=`${docker_cmd} 'jq -r .eigen_core.local.delegation_manager ~/wavs/cli/deployments.json' | tr -d '\r'`
95+
export CLI_EIGEN_CORE_REWARDS_COORDINATOR=`${docker_cmd} 'jq -r .eigen_core.local.rewards_coordinator ~/wavs/cli/deployments.json' | tr -d '\r'`
96+
export CLI_EIGEN_CORE_AVS_DIRECTORY=`${docker_cmd} 'jq -r .eigen_core.local.avs_directory ~/wavs/cli/deployments.json' | tr -d '\r'`
97+
export FOUNDRY_ANVIL_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
11998

120-
# Local Exec
121-
# ./compiled/eth_trigger_echo.wasm does not work because it's relative in `read_component(path: impl AsRef<Path>) -> Vec<u8> ... Path::new("../../")`
122-
wavs-cli exec --component $(pwd)/compiled/eth_trigger_echo.wasm --input testing
99+
forge script ./script/WavsServiceManager.s.sol --rpc-url http://localhost:8545 --broadcast
100+
```
123101

124-
# use the Eigenlayer deployed contracts
125-
mkdir -p .docker; docker cp wavs:/root/wavs/cli/deployments.json .docker/deployments.json
102+
Build WAVS WASI component(s)
126103

127-
# Actual deploy
128-
# - Service manager is from the script/WavsServiceManager.s.sol broadcast logs
129-
export WAVS_CLI_ETH_MNEMONIC="test test test test test test test test test test test junk"
130-
wavs-cli deploy-service --component $(pwd)/compiled/eth_trigger_echo.wasm --service-manager 0x851356ae760d987E095750cCeb3bC6014560891C --data ./.docker
104+
```bash
105+
# build all components/*
106+
make wasi-build
131107

132-
wavs-cli add-task --input "hello testing!" --data ./.docker --service-id <Service-ID>
108+
# Verify execution works as expected without deploying
109+
wavs-cli exec --component $(pwd)/compiled/eth_trigger_weather.wasm --input Nashville,TN
133110
```
134111

112+
Deploy service and verify with adding a task
135113

136-
## Installing Foundry
137-
138-
First run the command below to get `foundryup`, the Foundry toolchain installer:
114+
```bash
115+
source .env
139116

140-
```sh
141-
curl -L https://foundry.paradigm.xyz | bash
142-
```
117+
sudo chmod 0666 .docker/cli/deployments.json
143118

144-
Then, in a new terminal session or after reloading your `PATH`, run it to get
145-
the latest `forge` and `cast` binaries:
119+
wavs-cli deploy-service --data ./.docker/cli --component $(pwd)/compiled/eth_trigger_weather.wasm \
120+
--service-manager 0x851356ae760d987E095750cCeb3bC6014560891C \
121+
--service-config '{"fuelLimit":100000000,"maxGas":5000000,"hostEnvs":["WAVS_ENV_OPEN_WEATHER_API_KEY"],"kv":[]}'
146122

147-
```sh
148-
foundryup
123+
wavs-cli add-task --input "Nashville,TN" --data ./.docker/cli --service-id <Service-ID>
149124
```
150-
151-
For more, see the official
152-
[docs](https://github.com/gakonst/foundry#installation).

app/src/main.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
use alloy::{
2-
primitives::Address,
3-
providers::{Provider, ProviderBuilder},
2+
hex, primitives::Address, providers::{Provider, ProviderBuilder}
43
};
54
use bindings::wavsservicemanager::WavsServiceManager;
65
use eyre::Result;
76

87
#[tokio::main]
98
async fn main() -> Result<()> {
10-
let provider = ProviderBuilder::new().on_builtin("http://127.0.0.1:8545").await?;
9+
let url = "http://127.0.0.1:8545";
10+
let provider = ProviderBuilder::new().on_builtin(url).await?;
1111

12-
let address = "0x0000000000000000000000000000000000000000".parse::<Address>()?;
12+
if provider.get_block_number().await? == 0 {
13+
println!("No blocks / interactions on {url} yet.");
14+
return Ok(());
15+
}
1316

14-
let _contract = WavsServiceManager::new(address, provider.clone());
17+
// update me before running
18+
let contract_address = "0x851356ae760d987e095750cceb3bc6014560891c".parse::<Address>()?;
19+
let contract = WavsServiceManager::new(contract_address, provider.clone());
20+
21+
let resp = contract.signedDataByTriggerId(1).call().await?;
22+
23+
let hex = resp.data;
24+
println!("Weather Response Hex: {:?}\n", hex);
25+
26+
let ascii = to_ascii(hex.to_string().as_str())?;
27+
println!("Weather Response ASCII: {:?}", ascii);
1528

16-
let blk = provider.get_block_number().await?;
17-
println!("Hello, world! {}", blk);
1829
Ok(())
1930
}
31+
32+
pub fn to_ascii(hex: &str) -> Result<String> {
33+
let bytes = hex::decode(hex)?;
34+
if !bytes.iter().all(u8::is_ascii) {
35+
return Err(eyre::eyre!("Invalid ASCII bytes"));
36+
}
37+
Ok(String::from_utf8(bytes).unwrap())
38+
}

components/eth-trigger-echo/src/lib.rs

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "eth-trigger-echo"
2+
name = "eth-trigger-weather"
33
edition.workspace = true
44
version.workspace = true
55
authors.workspace = true
@@ -8,6 +8,10 @@ repository.workspace = true
88

99
[dependencies]
1010
wit-bindgen-rt = { workspace = true }
11+
layer-wasi = { workspace = true }
12+
serde = { workspace = true, features = ["derive"] }
13+
serde_json = {workspace = true}
14+
reqwest = {version = "0.12.12"}
1115

1216
[lib]
1317
crate-type = ["cdylib"]
@@ -20,7 +24,7 @@ strip = true
2024
lto = true
2125

2226
[package.metadata.component]
23-
package = "component:eth-trigger-echo"
27+
package = "component:eth-trigger-weather"
2428

2529
[package.metadata.component.target]
2630
path = "../../lib/WAVS/wit"

0 commit comments

Comments
 (0)