Configuration that is common to all devs is in taskfile/config.yml
Secrets and other configuration that is per-individual is in .env files (copied from .env.example) which are gitignored.
These are the only places where configuration should be stored!
Well, not quite, there's two exceptions:
- backend/wavs-home/wavs.toml - hardcoded WAVS configuration for operators/aggregators and local testing
- backend/chains/start_neutron.sh - local-chain configuration for testing
But really, that's it... if you find yourself adding configuration somewhere else, think again!
- backend - all backend files (html, docker compose, wavs toml, etc.)
- backend/chains - local-chain script for testing
- backend/docker - docker compose files (populated at runtime)
- backend/wavs-home - WAVS home (operator and aggregator)
- backend/oauth-site - Local oauth html file for access token retrieval
- docs/ - documentation
- packages/ - all Rust code packages
- packages/client - client package
- packages/components - WASI components used in services
- packages/contracts - CosmWasm smart contracts
- packages/contracts/api - Not a contract, but rather the API for all contracts
- packages/task-helper - helper binary for taskfile tasks
- packages/tests - on-chain and off-chain tests
- packages/utils - shared utils for other packages (local use only)
- packages/version-pins - workaround for pinning transitive dependencies
- taskfile/ - Taskfile scripts
- wit-definitions/ - WIT files used by WASI components
Additionally, there are important gitignored directories that are generated by building and deploying:
.builds/- built components and contracts.deployments/- deployment artifacts and info
The overall idea is to use Taskfile tasks for all common operations, so that devs don't have to remember complex commands.
Since all the config is loaded from the taskfile/config.yml and .env files, the flow is that it passes these onto docker, binary arguments, etc.
Sometimes the Taskfile syntax isn't expressive enough, in which case we have the task-helper binary, which is strongly typed Rust code that is deeply integrated with the codebase.
There are a few overriding ideas that permeate the codebase:
For example, we point at the shared contract api in the root Cargo.toml, so that types are shared (via the app-contract-api package name) and there's no chance of drift.
This allows catching type-like bugs at compiletime in components, tests, task-helper, etc.
By "contract client" we mean a client that knows the specific methods of a contract (not just execute/query, but things like "query all the emails")
By "everywhere" we mean multitest, real async with tokio, components with wasi, and so on.
This is done by having bit of complexity tucked away in the local client package (e.g. the heavy feature-gating), and then building abstractions on top of that.
It's also empowered by the Rust climb client, which works natively in binaries, WASI, and WASM/browser.
The concept is to make iterating on tests as easy as possible, so that devs can quickly add tests for new features and fix bugs.
That means:
- off-chain tests with multitest for fast iteration
- on-chain tests with tokio for real-world testing
- shared test utils in the tests package for reusability