Skip to content

Commit e053477

Browse files
authored
refactor: move to CMC example (#32)
* remove weather example * other migrations * new eth-price-oracle example with CMC * simplify
1 parent 2075cf4 commit e053477

File tree

19 files changed

+194
-283
lines changed

19 files changed

+194
-283
lines changed

.env.example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
# == project ==
3-
# Get your key from: https://openweathermap.org/ for the example
4-
WAVS_ENV_OPEN_WEATHER_API_KEY="00000000000000000000000000000000"
3+
# TODO: make sure you set any project specific env vars in the service_config's host_envs on deploy
4+
WAVS_ENV_YOURKEYHERE="00000000000000000000000000000000"
55

66
# WAVS
77
WAVS_DATA=~/wavs/data

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ forge test
3939
## Rust
4040

4141
```bash
42-
# Generate new bindings from your contract(s)
42+
# Generate new bindings from your contract(s) alias: `make build`
4343
make bindings
4444

4545
# Run rust tests
@@ -55,7 +55,7 @@ make test
5555
# (cd lib/WAVS; cargo install --path ./packages/cli)
5656
# (cd lib/WAVS; just docker-build)
5757

58-
docker cp $(docker create --name tc ghcr.io/lay3rlabs/wavs:0.3.0-alpha5-amd64):/usr/local/bin/wavs-cli ~/.cargo/bin/wavs-cli && docker rm tc
58+
docker cp $(docker create --name tc ghcr.io/lay3rlabs/wavs:0.3.0-alpha5):/usr/local/bin/wavs-cli ~/.cargo/bin/wavs-cli && docker rm tc
5959
```
6060

6161
### Start Anvil, WAVS, and Deploy Eigenlayer
@@ -64,9 +64,6 @@ docker cp $(docker create --name tc ghcr.io/lay3rlabs/wavs:0.3.0-alpha5-amd64):/
6464
# copy over the .env file
6565
cp .env.example .env
6666

67-
# [!] Get your key from: https://openweathermap.org/
68-
# Update the WAVS_ENV_OPEN_WEATHER_API_KEY in the .env file with your key`
69-
7067
# MacOS Docker:
7168
# Docker Engine -> Settings -> Resources -> Network -> 'Enable Host Networking'
7269
# or
@@ -82,11 +79,11 @@ sudo chmod 0666 .docker/cli/deployments.json
8279
wavs-cli deploy-eigen-service-manager --data ./.docker/cli
8380
export SERVICE_MANAGER=`jq -r '.eigen_service_managers.local | .[-1]' .docker/cli/deployments.json`
8481

85-
# Deploy
82+
# Deploy contracts
8683
export FOUNDRY_ANVIL_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
8784
forge script ./script/Deploy.s.sol ${SERVICE_MANAGER} --sig "run(string)" --rpc-url http://localhost:8545 --broadcast
8885

89-
# Grab deployed service manager from script file output
86+
# Get deployed contracts
9087
export SERVICE_HANDLER_ADDR=`jq -r '.service_handler' "./.docker/cli/script_deploy.json"`
9188
echo "Service Handler Addr: $SERVICE_HANDLER_ADDR"
9289

@@ -102,7 +99,7 @@ make wasi-build
10299

103100
# TODO: currently broken upstream
104101
# Verify execution works as expected without deploying
105-
# wavs-cli exec --component $(pwd)/compiled/eth_trigger_weather.wasm --input Nashville,TN
102+
# wavs-cli exec --component $(pwd)/compiled/eth_price_oracle.wasm --input `cast format-bytes32-string 1`
106103
```
107104

108105
## Deploy Service and Verify
@@ -111,18 +108,16 @@ make wasi-build
111108
# Contract trigger function signature to listen for
112109
trigger_event=$(cast sig-event "NewTrigger(bytes)"); echo "Trigger Event: $trigger_event"
113110

114-
wavs-cli deploy-service --log-level=error --quiet-results=false --data ./.docker/cli --component $(pwd)/compiled/eth_trigger_weather.wasm \
111+
wavs-cli deploy-service --log-level=error --data ./.docker/cli --component $(pwd)/compiled/eth_price_oracle.wasm \
115112
--trigger-event-name ${trigger_event:2} \
116113
--trigger eth-contract-event \
117114
--trigger-address ${TRIGGER_ADDR} \
118115
--submit-address ${SERVICE_HANDLER_ADDR} \
119-
--service-config '{"fuel_limit":100000000,"max_gas":5000000,"host_envs":["WAVS_ENV_OPEN_WEATHER_API_KEY"],"kv":[],"workflow_id":"default","component_id":"default"}'
120-
116+
--service-config '{"fuel_limit":100000000,"max_gas":5000000,"host_envs":[],"kv":[],"workflow_id":"default","component_id":"default"}'
121117

122118
# Submit AVS request -> chain
123-
cast send ${TRIGGER_ADDR} "addTrigger(bytes)" `cast format-bytes32-string Nashville,TN` --rpc-url http://localhost:8545 --private-key $FOUNDRY_ANVIL_PRIVATE_KEY
119+
cast send ${TRIGGER_ADDR} "addTrigger(bytes)" `cast format-bytes32-string 1` --rpc-url http://localhost:8545 --private-key $FOUNDRY_ANVIL_PRIVATE_KEY
124120

125-
# Grab data from the contract directly
126-
hex_bytes=$(cast decode-abi "getData(uint64)(bytes)" `cast call ${SERVICE_HANDLER_ADDR} "getData(uint64)" 1`)
127-
echo `cast --to-ascii $hex_bytes`
121+
ID=`cast call ${TRIGGER_ADDR} "nextTriggerId()" --rpc-url http://localhost:8545`; echo "ID: $ID"
122+
cast --to-ascii $(cast decode-abi "getData(uint64)(bytes)" `cast call ${SERVICE_HANDLER_ADDR} "getData(uint64)" $ID`)
128123
```

app/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ async fn main() -> Result<()> {
2626
let resp = contract.getData(1).call().await?;
2727

2828
let hex = resp.data;
29-
println!("Weather Response Hex: {:?}\n", hex);
29+
println!("Response Hex: {:?}\n", hex);
3030

3131
let ascii = to_ascii(hex.to_string().as_str())?;
32-
println!("Weather Response ASCII: {:?}", ascii);
32+
println!("Response ASCII: {:?}", ascii);
3333

3434
Ok(())
3535
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "eth-trigger-weather"
2+
name = "eth-price-oracle"
33
edition.workspace = true
44
version.workspace = true
55
authors.workspace = true
@@ -32,5 +32,5 @@ strip = true
3232
lto = true
3333

3434
[package.metadata.component]
35-
package = "component:eth-trigger-weather"
35+
package = "component:eth-price-oracle"
3636
target = "wavs:worker/layer-trigger-world@0.3.0-alpha2"
File renamed without changes.
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
mod trigger;
2+
use trigger::{decode_trigger_event, encode_trigger_output};
3+
pub mod bindings;
4+
use crate::bindings::{export, Guest, TriggerAction};
5+
use serde::{Deserialize, Serialize};
6+
use wstd::{
7+
http::{Client, Request},
8+
io::{empty, AsyncRead},
9+
runtime::block_on,
10+
};
11+
12+
struct Component;
13+
export!(Component with_types_in bindings);
14+
15+
impl Guest for Component {
16+
fn run(trigger_action: TriggerAction) -> std::result::Result<Vec<u8>, String> {
17+
let (trigger_id, req) =
18+
decode_trigger_event(trigger_action.data).map_err(|e| e.to_string())?;
19+
20+
// Convert bytes to string and parse first char as u64
21+
let input = std::str::from_utf8(&req).map_err(|e| e.to_string())?;
22+
println!("input id: {}", input);
23+
24+
let id = input.chars().next().ok_or("Empty input")?;
25+
let id = id.to_digit(16).ok_or("Invalid hex digit")? as u64;
26+
27+
let res = block_on(async move {
28+
let resp_data = get_price_feed(id).await;
29+
println!("resp_data: {:?}", resp_data);
30+
31+
match resp_data {
32+
Ok(resp) => {
33+
let output: Vec<u8> = serde_json::to_vec(&resp).unwrap();
34+
Ok(output)
35+
}
36+
Err(e) => Err(e),
37+
}
38+
});
39+
40+
match res {
41+
Ok(data) => Ok(encode_trigger_output(trigger_id, &data)),
42+
Err(e) => Err(e),
43+
}
44+
}
45+
}
46+
47+
async fn get_price_feed(id: u64) -> Result<PriceFeedData, String> {
48+
let url = format!(
49+
"https://api.coinmarketcap.com/data-api/v3/cryptocurrency/detail?id={}&range=1h",
50+
id
51+
);
52+
53+
let current_time = std::time::SystemTime::now().elapsed().unwrap().as_secs();
54+
55+
let req = Request::get(url)
56+
.header("Accept", "application/json")
57+
.header("Content-Type", "application/json")
58+
.header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36")
59+
.header("Cookie", format!("myrandom_cookie={}", current_time))
60+
.body(empty())
61+
.unwrap();
62+
63+
let response = Client::new().send(req).await;
64+
65+
// print out response
66+
println!("response: {:?}", response);
67+
68+
match response {
69+
Ok(mut response) => {
70+
let mut body_buf = Vec::new();
71+
response.body_mut().read_to_end(&mut body_buf).await.unwrap();
72+
73+
let resp = String::from_utf8_lossy(&body_buf);
74+
let json: Root = serde_json::from_str(format!(r#"{}"#, resp).as_str()).unwrap();
75+
76+
return Ok(PriceFeedData {
77+
symbol: json.data.symbol,
78+
price: json.data.statistics.price,
79+
timestamp: json.status.timestamp,
80+
});
81+
}
82+
Err(e) => {
83+
return Err(e.to_string());
84+
}
85+
}
86+
}
87+
88+
#[derive(Debug, Serialize, Deserialize)]
89+
pub struct PriceFeedData {
90+
symbol: String,
91+
timestamp: String,
92+
price: f64,
93+
}
94+
95+
/// -----
96+
/// https://transform.tools/json-to-rust-serde
97+
/// Generated from https://api.coinmarketcap.com/data-api/v3/cryptocurrency/detail?id=1&range=1h
98+
/// -----
99+
///
100+
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
101+
pub struct Root {
102+
pub data: Data,
103+
pub status: Status,
104+
}
105+
106+
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
107+
pub struct Data {
108+
pub id: f64,
109+
pub name: String,
110+
pub symbol: String,
111+
pub statistics: Statistics,
112+
pub description: String,
113+
pub category: String,
114+
pub slug: String,
115+
}
116+
117+
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
118+
pub struct Statistics {
119+
pub price: f64,
120+
#[serde(rename = "totalSupply")]
121+
pub total_supply: f64,
122+
}
123+
124+
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
125+
pub struct CoinBitesVideo {
126+
pub id: String,
127+
pub category: String,
128+
#[serde(rename = "videoUrl")]
129+
pub video_url: String,
130+
pub title: String,
131+
pub description: String,
132+
#[serde(rename = "previewImage")]
133+
pub preview_image: String,
134+
}
135+
136+
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
137+
pub struct Status {
138+
pub timestamp: String,
139+
pub error_code: String,
140+
pub error_message: String,
141+
pub elapsed: String,
142+
pub credit_count: f64,
143+
}
File renamed without changes.

0 commit comments

Comments
 (0)