Skip to content

I0 scaffold: crate + manifest + shim, builds to wasip2 #2

Description

@Ansh-699

scaffold — crate, manifest, shim, stubs; builds clean to wasip2

Slice: scaffold. Wave 0 (no blockers). Parent: tracking issue liquidation-guard.
Blocked-by: —.
Check: docs/checks/liquidation-guard/scaffold.md
Report: docs/jobs/liquidation-guard/scaffold-01.md

What to build

Create plugins/liquidation-guard/ — a standalone ZeroClaw wasm tool plugin crate that
compiles clean for host tests AND wasm32-wasip2, mirroring the maintainer's reference
plugin plugins/redact-text/ (read it first: Cargo.toml, manifest.toml,
src/lib.rs). Every source module the later slices fill is created here as a compiling
stub, so src/lib.rs has exactly one owner (this issue) and later slices only rewrite
their own files.

manifest.toml (exact)

name = "liquidation-guard"
version = "0.1.0"
description = "Kamino Lend health guard: tiered liquidation warnings, liquidation-price forecast, ranked remedies, unsigned repay transaction"
author = "Ansh-699"
wasm_path = "liquidation_guard.wasm"
capabilities = ["tool"]
# config_read: host injects this plugin's config section into execute args as `__config`.
# http_client: host wires outbound wasi:http into the component's store.
permissions = ["config_read", "http_client"]

Cargo.toml (exact dependency set — no later issue may touch Cargo.toml/Cargo.lock)

[package]
name = "liquidation-guard"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "ZeroClaw WIT plugin: Kamino Lend health guard with unsigned repay rescue."
publish = false

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
wit-bindgen = "0.46"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
bs58 = "0.5"
sha2 = { version = "0.10", default-features = false }
curve25519-dalek = { version = "4", default-features = false, features = ["alloc"] }

[target.'cfg(target_family = "wasm")'.dependencies]
waki = { version = "0.5.1", features = ["json"] }

[profile.release]
opt-level = "s"
lto = true
strip = true
codegen-units = 1

[workspace]

Commit the generated Cargo.lock. This exact set was verified this run to build on
wasm32-wasip2 in ~31 s with ZERO getrandom in the tree (cargo tree --target wasm32-wasip2 -i getrandom errors with "did not match any packages" — that error IS
the pass condition).

src/lib.rs — the WIT shim (single owner: this issue; no later slice edits it)

Mirror plugins/redact-text/src/lib.rs exactly in mechanics:

  • pub mod args; pub mod config; pub mod guard; pub mod health; pub mod kamino; pub mod net; pub mod remedy; pub mod report; pub mod rescue;
  • #[cfg(target_family = "wasm")] mod component { ... } containing
    wit_bindgen::generate!({ path: "../../wit/v0", world: "tool-plugin", features: ["plugins-wit-v0"] }),
    a PluginInfo impl (name = "liquidation-guard", version = env!("CARGO_PKG_VERSION")),
    a Tool impl, and export!(...) at the end.
  • Tool name() returns "kamino_guard".
  • parameters_schema() returns this JSON (serde_json::json!): object with properties
    action (string, enum ["check","portfolio","rescue"], required), wallet (string,
    base58, optional), market (string, optional), obligation (string, optional),
    repay_ui_amount (number, optional), prev_snapshot (string, optional);
    "required": ["action"], "additionalProperties": false.
  • execute(args) builds a waki-backed transport (see contract below) and returns
    guard::run(&args, &mut transport) mapped into ToolResult { success, output, error }.
    Failures are ToolResult { success: false, .. } — never a trap/panic.
  • The waki adapter implements guard::Transport with
    waki::Client::new() GET/POST, forwarding the response body, status, and the
    date response header. (Field-proven pattern: PR feat(solana): payment suite, three unsigned-only tool plugins on a shared wasip2 core zeroclaw-labs/zeroclaw-plugins#30 in this repo's upstream.)

src/guard.rs — the frozen internal seam (stub now, I6 fills run)

This exact interface contract is what lib.rs and all tests compile against; later
slices cite it and MUST NOT change it:

pub struct HttpRequest {
    pub method: Method,            // enum Method { Get, Post }
    pub url: String,               // absolute https URL
    pub body: Option<String>,      // JSON body for POST
}
pub struct HttpResponse {
    pub status: u16,
    pub body: String,
    pub date_header: Option<String>, // HTTP `Date` response header, verbatim
}
pub trait Transport {
    fn fetch(&mut self, req: &HttpRequest) -> Result<HttpResponse, String>;
}
pub struct ToolOutput { pub success: bool, pub text: String }
pub fn run(raw_args: &str, transport: &mut dyn Transport) -> ToolOutput

Stub run returns ToolOutput { success: false, text: "not implemented".into() }.

Other stubs

src/{config,args,kamino,health,remedy,rescue,net,report}.rs: each a one-line
placeholder (doc comment + empty content is fine) that compiles under
cargo clippy --all-targets -- -D warnings. No #[allow] attributes.

Remaining files

  • .gitignore: /target and *.wasm.
  • LICENSE: dual-license notice (MIT OR Apache-2.0) with both license texts or the
    standard short dual notice.
  • README.md: stub — title, one-paragraph description, "full docs land with the final
    slice". (The readme slice rewrites this file in a later wave.)

Acceptance criteria

  1. cargo build --locked --target wasm32-wasip2 --release succeeds from the plugin
    dir; artifact liquidation_guard.wasm is non-empty.
  2. cargo test --locked passes (zero tests is acceptable at this slice).
  3. cargo clippy --locked --all-targets -- -D warnings and
    cargo clippy --locked --target wasm32-wasip2 -- -D warnings both clean.
  4. cargo fmt --check clean.
  5. cargo tree --target wasm32-wasip2 -i getrandom matches no package (errors).
  6. manifest.toml exactly as above (name == directory name — CI hard requirement).
  7. Cargo.lock committed; guard.rs exposes the contract verbatim.

Boundaries

MAY TOUCH: plugins/liquidation-guard/** (all new files listed above).
MUST NOT TOUCH: anything else — especially wit/, registry.json, tools/,
.github/, other plugins, docs/ (touching .github/ tools/ wit/ registry.json
triggers a full 31-plugin CI sweep and wit-drift/registry failures).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions