Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ jobs:
- uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
with:
tool: nextest
# Build all 17 guest module wasms ONCE (release/wasm32-wasip2): the single
# Build all 18 guest wasms ONCE (17 modules + the cow adapter,
# release/wasm32-wasip2): the single
# source of truth for guest buildability and the artifacts the integration
# tests load. Replaces the deleted 9-way build-module matrix, which recompiled
# the shared wasm dependency graph ~9x cold. Per-module size report folded in;
Expand All @@ -90,6 +91,11 @@ jobs:
-p balance-tracker -p stop-loss -p http-probe -p echo-venue \
-p echo-client -p echo-keeper -p clock-reader -p flaky-bomb -p flaky-venue \
-p fuel-bomb -p memory-bomb -p panic-bomb -p slow-host
# Separate invocation on purpose: unifying `cow-venue/adapter`
# into the module build would link the adapter's component
# export glue into every keeper module wasm.
cargo build --release --target wasm32-wasip2 --locked \
-p cow-venue --features cow-venue/adapter
{
echo "### module .wasm sizes"
echo "| module | bytes |"
Expand Down
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 13 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# syntax=docker/dockerfile:1.6
#
# Multi-stage build for `shepherd` - the cow composition-root engine
# binary plus the five production WASM modules baked into a single image.
# binary plus the five production WASM modules and the bundled cow
# venue adapter baked into a single image.
#
# Stage 1 (`build`): full Rust toolchain + wasm32-wasip2 target, builds
# the engine in release mode + each module to a Component Model wasm
Expand Down Expand Up @@ -68,7 +69,9 @@ COPY --from=planner /src/recipe.json recipe.json
RUN cargo chef cook --release -p shepherd --recipe-path recipe.json \
&& cargo chef cook --release --target wasm32-wasip2 \
-p twap-monitor -p ethflow-watcher -p price-alert \
-p balance-tracker -p stop-loss --recipe-path recipe.json
-p balance-tracker -p stop-loss --recipe-path recipe.json \
&& cargo chef cook --release --target wasm32-wasip2 \
-p cow-venue --features cow-venue/adapter --recipe-path recipe.json

# Now the workspace sources. `.dockerignore` keeps the context lean
# (no `target/`, no `data/`, no large baseline / backtest fixtures).
Expand All @@ -79,13 +82,15 @@ COPY . .
# is used verbatim so builds are reproducible.
RUN cargo build -p shepherd --release --locked

# Five production modules. The wasm artefacts land under
# Five production modules plus the bundled cow venue adapter. The wasm
# artefacts land under
# `target/wasm32-wasip2/release/<name_with_underscores>.wasm`.
RUN cargo build -p twap-monitor --target wasm32-wasip2 --release --locked \
&& cargo build -p ethflow-watcher --target wasm32-wasip2 --release --locked \
&& cargo build -p price-alert --target wasm32-wasip2 --release --locked \
&& cargo build -p balance-tracker --target wasm32-wasip2 --release --locked \
&& cargo build -p stop-loss --target wasm32-wasip2 --release --locked
&& cargo build -p stop-loss --target wasm32-wasip2 --release --locked \
&& cargo build -p cow-venue --target wasm32-wasip2 --release --locked --features adapter

# ----------------------------------------------------------------- runtime

Expand Down Expand Up @@ -123,6 +128,10 @@ COPY --from=build /src/modules/examples/price-alert/module.toml /opt/shepher
COPY --from=build /src/modules/examples/balance-tracker/module.toml /opt/shepherd/manifests/balance-tracker.toml
COPY --from=build /src/modules/examples/stop-loss/module.toml /opt/shepherd/manifests/stop-loss.toml

# The bundled cow venue adapter's manifest; installed via the
# engine.toml [[adapters]] stanza, never compiled into the engine.
COPY --from=build /src/crates/cow-venue/module.toml /opt/shepherd/manifests/cow-venue.toml

# Drop privileges. The engine never needs root at runtime: it only
# reads /etc/shepherd/engine.toml, writes to /var/lib/shepherd, and
# binds 127.0.0.1:9100 inside the container.
Expand Down
45 changes: 39 additions & 6 deletions crates/cow-venue/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ repository.workspace = true
description = "CoW venue slices, orderbook-only. The default `body` slice carries the venue-neutral order intent body types and their borsh IntentBody codec, linkable by adapters and modules."

[lib]
# Plain library. The default `body` slice is dependency-light so a venue
# adapter component or a strategy module can link the intent body types
# and codec without the host-side CoW machinery.
# The default `body` slice is dependency-light so a venue adapter
# component or a strategy module can link the intent body types and
# codec without the host-side CoW machinery. The cdylib is the
# `adapter` slice's component build (wasm32-wasip2).
crate-type = ["lib", "cdylib"]

[lints]
workspace = true
Expand All @@ -27,6 +29,19 @@ videre-sdk = { path = "../videre-sdk", optional = true }
# `build.rs`, so serde/toml/thiserror are build- and dev-only and never
# reach a guest that links this slice.
nexum-sdk = { path = "../nexum-sdk", optional = true }
# `assembly` slice: the chain-edge order projections and orderbook
# submission bodies. Express-declared (not workspace-inherited) so the
# guest build never inherits the native `http-client` feature.
cowprotocol = { version = "0.2.0", default-features = false, optional = true }
alloy-primitives = { workspace = true, optional = true }
alloy-sol-types = { workspace = true, optional = true }
# `adapter` slice: the orderbook REST speaker over the scoped
# wasi:http transport.
serde = { workspace = true, optional = true }
serde_json = { workspace = true, optional = true }
http = { workspace = true, optional = true }
url = { workspace = true, optional = true }
wit-bindgen = { workspace = true, optional = true }

# `build.rs` parses `data/classification.toml` and emits the static
# lookup table; the same parse is shared with the parity tests below.
Expand All @@ -48,9 +63,27 @@ cowprotocol = { version = "0.2.0", default-features = false }
[features]
# The body-type + codec slice ships by default; the `client` slice layers
# the typed client and the table-driven retry classification on top.
# `--no-default-features` drops both to an empty crate so downstream can
# depend on a future `adapter` slice without pulling the codec or the
# keeper transitively.
# `--no-default-features` drops everything so downstream can depend on a
# single slice without pulling the codec or the keeper transitively.
default = ["body"]
body = ["dep:borsh", "dep:videre-sdk"]
client = ["body", "dep:nexum-sdk"]
# Chain-edge order assembly, shared by the adapter's submit and the
# keeper's legacy submit path. Carries no component glue, so a keeper
# module can link it without exporting the adapter face.
assembly = ["body", "dep:cowprotocol", "dep:alloy-primitives", "dep:alloy-sol-types"]
# The venue-adapter component slice: the `#[videre_sdk::venue]` export
# and the orderbook transport. Only the cdylib wasm build enables it.
adapter = [
"assembly",
"client",
"dep:serde",
"dep:serde_json",
"dep:http",
"dep:url",
"dep:wit-bindgen",
]

[[test]]
name = "conformance"
required-features = ["adapter"]
29 changes: 29 additions & 0 deletions crates/cow-venue/module.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# cow adapter manifest - the CoW venue's `#[videre_sdk::venue]`
# component. The manifest name is the venue id the registry installs
# the adapter under. Outbound orderbook HTTP is the only transport;
# the operator's `[[adapters]].http_allow` grant scopes it at install.

[module]
name = "cow"
version = "0.1.0"
kind = "venue-adapter"
# Placeholder content hash; parsed but not verified in 0.2.
component = "sha256:0000000000000000000000000000000000000000000000000000000000000000"

[capabilities]
required = ["http"]
optional = []

[capabilities.http]
allow = ["api.cow.fi"]

# One adapter instance speaks one chain's orderbook. `orderbook-url`,
# `owner` (enables the pre-sign path), and `http-timeout-ms` are
# optional overrides.
[config]
chain = "1"

# Body-schema versions this adapter decodes: the handshake authority.
# Install asserts the adapter's body-versions export equals it.
[venue]
body_versions = [1]
Loading
Loading