contracts WIT interface and imports only the host capabilities it needs.
Key concepts and tips before starting:
Repository Structure
wit/deps/ define the host ABI your contract links against — vendor the versions your target cluster provides (here, host-interfaces-2.1.0/ and host-tenant-1.0.0/).
Files
world.wit — declare your interface + host imports
Cargo.toml — compile to a WASM component
lib.rs — generate bindings + dispatch to each function
crate::host::* and the exported interface under crate::exports::* — both generated by the macro from wit/.
search.rs — search_offers (synchronous http, no PII)
The http interface is synchronous: the response is available before the call returns. Build a Request with a Verb, headers, and an optional payload.
booking.rs — book_offer (PII via http-with-placeholders)
For calls that carry user PII, use http-with-placeholders. Put {{profile.<field>}} markers in the request body; the host resolves them from the calling user’s profile at dispatch time, so plaintext PII never enters WASM memory.
hwp::call returns a typed HttpError so failures never leak resolved PII — match on it for clear messages:
Reading secrets from the secrets KV map
The API key is read from the tenant’s secrets KV map at runtime. The key is seeded by the tenant SDK before the contract runs — there is no set-credentials host function. kv-store calls take the full z:<tid>:<map> name; build it from tenant-context at runtime (the host enforces the prefix):
Key Design Rules
- Export functions on the
contractsinterface. Each takesgeneric-inputand returnsresult<list<u8>, string>— JSON bytes on success, an error string on failure. There is nodispatchfunction and noContractErrorenum. kv-storecalls take the fullz:<tid>:<map>name. Build it at runtime fromtenant_context::tenant_did()— that value is already the string form, don’t re-encode it. The host enforces the prefix. The map must exist (created and populated by the tenant SDK) before the contract reads or writes it.- Import only the host interfaces you use — they are your contract’s entire capability set. The host refuses to load a contract that imports an interface its tenant world does not provide.
http::callis synchronous; you get the response back before the function returns. Its egress is authorized per-call by the calling user’s grant.- For calls carrying user PII, use
http-with-placeholders: put{{profile.<field>}}markers in the request and the host resolves them inside the enclave, so plaintext PII never enters your contract.