This document outlines the validation checks performed by the validate_component.sh script on WAVS components. Each check is described along with what issues it's designed to detect and prevent.
- What it checks: Searches for uses of
String::from_utf8on ABI-encoded data - What it catches: Prevents runtime errors from trying to interpret binary ABI data as UTF-8 text
- Common error pattern:
String::from_utf8(abi_encoded_data) - Fix: Use proper ABI decoding methods like
functionCall::abi_decode()orString::abi_decode()
- What it checks: Verifies that components handling ABI-encoded inputs use proper decoding methods
- What it catches: Prevents runtime errors from improper decoding of function calls or parameters
- Fix: Implement appropriate ABI decoding using
FunctionCall::abi_decode,String::abi_decode, etc.
- What it checks: Ensures components receiving function calls define Solidity function signatures
- What it catches: Prevents missing function definitions needed for proper ABI decoding
- Fix: Define Solidity functions using the
sol!macro
- What it checks: Verifies that API response structs derive the
Clonetrait - What it catches: Prevents ownership issues when reusing data from API responses
- Common error pattern:
#[derive(Deserialize)]withoutClone - Fix: Add
Cloneto derive macros for structs:#[derive(Deserialize, Clone)]
- What it checks: Detects
&data.clone()patterns that create immediately dropped values - What it catches: Prevents subtle ownership bugs where cloned values are dropped immediately
- Common error pattern:
let result = process(&data.clone()); - Fix: Create a variable to hold the cloned data:
let data_clone = data.clone(); let result = process(&data_clone);
- What it checks: Finds code that accesses fields from collection elements without cloning
- What it catches: Prevents ownership errors when accessing fields from collections
- Common error pattern:
let field = collection[0].field; - Fix: Clone the field to avoid moving it out:
let field = collection[0].field.clone();
- What it checks: Finds
map_errused onOptiontypes (especiallyget_eth_chain_config) - What it catches: Prevents type errors from using
Resultmethods onOptiontypes - Common error pattern:
get_eth_chain_config("mainnet").map_err(...)? - Fix: Use
ok_or_elseto convertOptiontoResult:get_eth_chain_config("mainnet").ok_or_else(|| "Error message")?
- What it checks: Verifies that commonly used traits like
FromStrare properly imported - What it catches: Prevents compile errors from missing trait imports
- Fix: Add appropriate imports like
use std::str::FromStr;
- What it checks: Ensures
std::cmp::minis imported when theminfunction is used - What it catches: Prevents compile errors from missing the min function import
- Fix: Add
use std::cmp::min;to imports
- What it checks: Detects incorrect import paths for
TxKind(a common blockchain type) - What it catches: Prevents critical compilation errors from incorrect import paths
- Common error pattern:
alloy_rpc_types::eth::TxKind(incorrect) - Fix: Use
alloy_primitives::TxKindinstead
- What it checks: Ensures
block_onfunction is properly imported when used - What it catches: Prevents compile errors from missing async runtime imports
- Fix: Add
use wstd::runtime::block_on;to imports
- What it checks: Verifies that HTTP-related functions are properly imported
- What it catches: Prevents compile errors from missing HTTP function imports
- Fix: Add
use wavs_wasi_chain::http::{fetch_json, http_request_get};
- What it checks: Ensures the
SolCalltrait is imported when usingabi_encodeon function calls - What it catches: Prevents compile errors when encoding function calls
- Fix: Add
use alloy_sol_types::{SolCall, SolValue};to imports
- What it checks: Verifies that the component uses the
export!macro - What it catches: Prevents missing component exports required for WASM compatibility
- Fix: Add
export!(YourComponent with_types_in bindings);to the component
- What it checks: Ensures the correct syntax for the
export!macro - What it catches: Prevents errors from incorrect export macro syntax
- Common error pattern:
export!(YourComponent);(incorrect) - Fix: Use
export!(YourComponent with_types_in bindings);
- What it checks: Detects incorrect field access on the
TriggerActionstruct - What it catches: Prevents runtime errors from accessing non-existent fields
- Common error pattern:
trigger.trigger_data(incorrect) - Fix: Use
trigger.datainstead
- What it checks: Verifies that
trigger.datais not treated as anOption - What it catches: Prevents incorrect matching patterns on non-optional fields
- Common error pattern:
match trigger.data { Some(data) => {}, None => {} } - Fix: Treat as direct value:
match trigger.data { TriggerData::Raw => {}, ... }
- What it checks: Ensures the component implements the
Guesttrait - What it catches: Prevents missing required trait implementations
- Fix: Implement
Guesttrait:impl Guest for YourComponent { fn run(...) {...} }
- What it checks: Verifies the
runfunction has the correct return type signature - What it catches: Prevents incompatible function signatures
- Fix: Use correct signature:
fn run(trigger: TriggerAction) -> Result<Option<Vec<u8>>, String>
- What it checks: Searches for potential hardcoded API keys in the component
- What it catches: Prevents security issues from committing API keys to source control
- Fix: Use environment variables:
std::env::var("WAVS_ENV_YOUR_API_KEY")
- What it checks: Looks for other hardcoded secrets like tokens or passwords
- What it catches: Prevents security vulnerabilities from exposed credentials
- Fix: Use environment variables for all sensitive data
- What it checks: Ensures dependencies use
workspace = trueinstead of explicit versions - What it catches: Prevents version conflicts and ensures consistent dependency management
- Common error pattern:
some-crate = "0.1.0"(incorrect) - Fix: Use
some-crate = { workspace = true }
- What it checks: Runs
cargo checkto find compile errors and warnings - What it catches: Detects general Rust compilation issues early
- Fix: Resolve specific compiler errors and warnings
- What it checks: Ensures the
sol!macro is properly imported when used - What it catches: Prevents compile errors from missing macro imports
- Fix: Add
use alloy_sol_types::sol;oruse alloy_sol_macro::sol;
- What it checks: Verifies that components using Solidity types define a proper
soliditymodule - What it catches: Prevents structural issues with Solidity type definitions
- Fix: Create a proper module structure:
mod solidity { use alloy_sol_macro::sol; sol! { /* your solidity types */ } }
- What it checks: Finds string literals assigned directly to
Stringtype fields - What it catches: Prevents type mismatch errors between
&strandString - Common error pattern:
field: "literal string",(when field isStringtype) - Fix: Add explicit conversion:
field: "literal string".to_string(),
- What it checks: Detects potentially unbounded
string.repeat()operations - What it catches: Prevents capacity overflow errors from excessive string repetition
- Common error pattern:
.repeat(variable)with unbounded variable - Fix: Add bounds:
.repeat(std::cmp::min(variable, 100))
- What it checks: Ensures async functions are properly wrapped with
block_on - What it catches: Prevents runtime issues with async function execution
- Fix: Wrap async calls:
block_on(async { make_request().await })
These validation checks help ensure WAVS components:
- Use proper ABI encoding/decoding techniques
- Handle data ownership correctly
- Import all required traits and functions
- Follow the correct component structure
- Handle errors properly
- Maintain security best practices
- Use workspace dependencies correctly
- Avoid common string manipulation errors
- Structure Solidity types correctly
- Handle async operations properly
By validating components against these checks, developers can avoid common pitfalls and ensure their components will build and run correctly in the WAVS environment.