### Install Rust + WASM Toolchain Source: https://docs.terminal3.io/developers/adk/get-started/prerequisites/set-up-dev-env Install the WASI Preview 2 build target and optionally the wasm-tools for inspecting WASM binaries. ```bash rustup target add wasm32-wasip2 # WASI Preview 2 build target cargo install wasm-tools # optional — inspect/verify the component ``` -------------------------------- ### Install wasm-tools Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/build-contract Installs the `wasm-tools` utility, which is used to inspect WebAssembly components. ```bash cargo install wasm-tools ``` -------------------------------- ### Tenant-Owned Namespace Example Source: https://docs.terminal3.io/t3n/how-t3n-works/z-namespace Provides a concrete example of a canonical tenant-owned namespace, showing a specific tenant DID suffix and a map name. ```text z:8f3a0123456789abcdef0123456789abcdefc91d:secrets ``` -------------------------------- ### Install the T3N SDK Source: https://docs.terminal3.io/developers/adk/get-started/prerequisites/set-up-dev-env Install the Terminal3 SDK package using npm. Node.js version 18 or higher is required. ```bash npm install @terminal3/t3n-sdk ``` -------------------------------- ### Verifiable Credential (VC) JSON-LD Example Source: https://docs.terminal3.io/intro/components/vc An example of a Verifiable Credential formatted in JSON-LD, including context, issuer, issuance date, and credential subject. ```json { "@context": [ "https://www.w3.org/2018/credentials/v1" ], "id": "https://app.terminal3.io/credentials/58473", "type": ["VerifiableCredential", "UniversityDegreeCredential"], "issuer": "did:key:terminal3", "issuanceDate": "2023-01-01T00:00:00Z", "credentialSubject": { "id": "did:ethr:0xebfeb1f712ebc6f1c276e12ec21", "degree": { "type": "BachelorDegree", "name": "Bachelor of Science and Arts" } }, "proof": { ... } } ``` -------------------------------- ### DID Document Example Source: https://docs.terminal3.io/intro/components/did This JSON object represents a DID document, which contains information associated with a DID, such as cryptographic authentication methods. It includes the DID context, the DID itself, and authentication details. ```json { "@context": [ "https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1" ] "id": "did:example:123456789abcdefghi", "authentication": [{ "id": "did:example:123456789abcdefghi#keys-1", "type": "Ed25519VerificationKey2020", "controller": "did:example:123456789abcdefghi", "publicKeyMultibase": "zH3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" }] } ``` -------------------------------- ### Add WASI Preview 2 Target and Build Release Artifact Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/build-contract Installs the `wasm32-wasip2` target and builds the Rust contract as a release artifact. Ensure you have `crate-type = ["cdylib", "lib"]` in your `Cargo.toml`. ```bash rustup target add wasm32-wasip2 cargo build --target wasm32-wasip2 --release ``` -------------------------------- ### Authenticate to T3N Testnet and Get Tenant DID Source: https://docs.terminal3.io/developers/adk/get-started/prerequisites/set-up-dev-env Authenticate to the T3N testnet using the T3nClient and retrieve the tenant DID from the authenticated session. This DID must match the one admitted as a tenant. ```typescript await t3n.handshake(); const did = await t3n.authenticate(createEthAuthInput(address)); const tenantDid = did.value; // did:t3n: — your onboarding DID ``` -------------------------------- ### Set up T3nClient Source: https://docs.terminal3.io/developers/adk/get-started/prerequisites/set-up-dev-env Initialize a T3nClient instance, setting the environment, loading the WASM component, and providing the EthSign handler for authentication. ```typescript import { T3nClient, TenantClient, setEnvironment, loadWasmComponent, eth_get_address, metamask_sign, createEthAuthInput, getNodeUrl, } from "@terminal3/t3n-sdk"; setEnvironment("testnet"); // "testnet" | "production" — the SDK resolves the node URL for every client const T3N_API_KEY = process.env.T3N_API_KEY!; // your developer key from the claim page const wasmComponent = await loadWasmComponent(); // all crypto runs inside the WASM component const address = eth_get_address(T3N_API_KEY); const t3n = new T3nClient({ wasmComponent, // no baseUrl — resolved from the active environment // EthSign is the only handler you provide — it signs the login challenge with // your key. The client adds the MlKemPublicKey and Random handlers itself. handlers: { EthSign: metamask_sign(address, undefined, T3N_API_KEY), }, }); ``` -------------------------------- ### Importing Host Interfaces in world.wit Source: https://docs.terminal3.io/developers/adk/tips/capabilities-from-wit-import This WIT code demonstrates importing host interfaces like kv-store, logging, tenant-context, and http-iface. Importing `http-iface` enables outbound HTTP requests for your contract. ```wit world your-contract { import t3n:host/kv-store@0.1.0; import t3n:host/logging@0.1.0; import t3n:host/tenant-context@0.1.0; import t3n:host/http-iface@0.1.0; // ← opting into outbound HTTP } ``` -------------------------------- ### Rust Contract Entry Point (lib.rs) Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/write-contract Implements the `Guest` trait for the contract's dispatch function. It routes incoming calls to specific functions like 'search-offers' or 'book-offer' based on the input. ```rust wit_bindgen::generate!({ world: "contract", path: "wit" }); use exports::t3n::contract::dispatch::{Guest, ContractInput, ContractOutput, ContractError}; struct Component; impl Guest for Component { fn dispatch(input: ContractInput) -> Result { match input.function.as_str() { "search-offers" => search::search_offers(input), // no PII — plain http "book-offer" => booking::book_offer(input), // PII via http-with-placeholders other => Err(ContractError::UnknownFunction { name: other.to_string() }), } } } export!(Component); ``` -------------------------------- ### Build TenantClient Source: https://docs.terminal3.io/developers/adk/get-started/prerequisites/set-up-dev-env Construct a TenantClient instance using the authenticated T3nClient, the active node URL, and the tenant DID. The TenantClient is used for managing your own deployment. ```typescript const tenant = new TenantClient({ t3n, baseUrl: getNodeUrl(), // the active node from setEnvironment(); Call `setEnvironment("testnet")` (or `"production"`) — the SDK resolves the cluster URL for every client, so you never hardcode a node URL. tenantDid, }); ``` -------------------------------- ### Print Component WIT Interface Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/build-contract Uses `wasm-tools` to display the WebAssembly component's WIT interface, showing imported host interfaces and the contract entry point. ```bash wasm-tools component wit target/wasm32-wasip2/release/your_contract.wasm ``` -------------------------------- ### Rust Contract Using http-with-placeholders Source: https://docs.terminal3.io/developers/adk/tips/placeholders-outbound-calls This Rust code demonstrates how to construct a JSON body with profile placeholders and make an outbound HTTP POST request using the `http-with-placeholders` host interface. The host resolves `{{profile.}}` markers from the calling user's profile before the request is sent. ```rust use crate::bindings::t3n::host::http_with_placeholders as hwp; // The {{profile.}} markers are resolved host-side from the calling // user's profile — this contract never sees the plaintext values. let body = serde_json::json!({ "data": { "type": "instant", "selected_offers": [req.offer_id], "passengers": [{ "id": "passenger_0", "given_name": "{{profile.first_name}}", "family_name": "{{profile.last_name}}", "born_on": "{{profile.date_of_birth}}", "email": "{{profile.verified_contacts.email.value}}", }] } }); let resp = hwp::call(&hwp::Request { method: "POST".to_string(), url: "https://api.duffel.com/air/orders".to_string(), headers: vec![ ("Authorization".to_string(), format!("Bearer {api_key}")), ("Duffel-Version".to_string(), "v2".to_string()), ("Content-Type".to_string(), "application/json".to_string()), ], body: Some(serde_json::to_vec(&body)?), })?; // resp.body — Duffel's response (booking id + PNR). The passport/name/DOB // were substituted by the host; your WASM never held them. ``` -------------------------------- ### Rust Search Offers Function (search.rs) Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/write-contract Handles 'search-offers' requests using synchronous HTTP calls to an external API. This function is designed to not handle PII directly, making it suitable for plain HTTP requests. ```rust use crate::bindings::t3n::host::{http_iface, logging}; pub fn search_offers(input: ContractInput) -> Result { let req: SearchOffersRequest = serde_json::from_slice(&input.payload) .map_err(|e| ContractError::InvalidInput { detail: e.to_string() })?; let api_key = duffel_api_key()?; // Synchronous HTTP — the response is available in the same call (no PII in flight). let resp = http_iface::call(&http_iface::Request { method: "POST".to_string(), url: "https://api.duffel.com/air/offer_requests?return_offers=false".to_string(), headers: vec![ ("Authorization".to_string(), format!("Bearer {api_key}")), ("Duffel-Version".to_string(), "v2".to_string()), ], body: Some(serde_json::to_vec(&req)?), })?; logging::info("searched offers"); Ok(ContractOutput { payload: resp.body }) } ``` -------------------------------- ### Invoke TEE Contract Functions with T3nClient Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/invoke-contract This snippet demonstrates how an agent uses the `T3nClient` to authenticate and invoke functions on a TEE contract. It includes searching for offers and booking a selected offer, highlighting how PII is handled server-side via `http-with-placeholders`. ```typescript import { T3nClient, loadWasmComponent, createEthAuthInput, eth_get_address, metamask_sign, getScriptVersion, getNodeUrl, } from "@terminal3/t3n-sdk"; const agentKey = process.env.AGENT_KEY!; const agentAddress = eth_get_address(agentKey); const agentClient = new T3nClient({ wasmComponent, // node URL resolved from setEnvironment() — see set-up-dev-env handlers: { EthSign: metamask_sign(agentAddress, undefined, agentKey), }, }); await agentClient.handshake(); await agentClient.authenticate(createEthAuthInput(agentAddress)); const TENANT_SCRIPT = `z:${tenantDid.slice("did:t3n:".length)}:travel/contracts`; const scriptVersion = await getScriptVersion(getNodeUrl(), TENANT_SCRIPT); // 1. Search for offers (no PII) const search = await agentClient.executeAndDecode({ script_name: TENANT_SCRIPT, script_version: scriptVersion, function_name: "search-offers", input: { origin: "LHR", destination: "JFK", departure_date: "2026-07-15", cabin_class: "economy", adult_count: 1 }, }); const offer = search.offers[0]; // 2. Book the chosen offer. No PII in the input — name, DOB and email are // resolved host-side from the user's profile via http-with-placeholders, // and only when the user's grant authorizes this agent (see the grant above). const booking = await agentClient.executeAndDecode({ script_name: TENANT_SCRIPT, script_version: scriptVersion, function_name: "book-offer", input: { offer_id: offer.id, passenger_id: offer.passenger_ids[0], // opaque Duffel id from search — not PII total_amount: offer.total_amount, total_currency: offer.total_currency, }, }); // booking.pnr → the flight booking reference. The passenger's name never left the enclave. ``` -------------------------------- ### TEE Node Execution Flow Sequence Diagram Source: https://docs.terminal3.io/t3n/how-t3n-works/tees Illustrates the sequence of operations for executing a TEE contract on a T3N node, from client request to encrypted response, including data fetching and decryption steps. ```mermaid sequenceDiagram participant C as Client participant TEE as TEE Node participant CAS as CAS (External Storage) participant KV as KV Store C->>TEE: action.execute(encrypted request) TEE->>TEE: Decrypt request TEE->>KV: Get user profile ValueRef by DID KV-->>TEE: ValueRef (CID, storage location) TEE->>CAS: Fetch encrypted profile blob by CID CAS-->>TEE: Encrypted profile blob TEE->>TEE: Decrypt profile (AES-256-GCM with cluster CEK) TEE->>KV: Resolve TEE contract ValueRef from registry KV-->>TEE: TEE Contract ValueRef TEE->>CAS: Fetch TEE contract by CID CAS-->>TEE: TEE contract TEE->>TEE: Execute TEE contract (profile, input) in sandbox TEE-->>C: Encrypted response ``` -------------------------------- ### Public Tenant Map Configuration Source: https://docs.terminal3.io/t3n/how-t3n-works/z-namespace Shows the required configuration for a tenant-owned map to be considered public, involving a specific naming convention and visibility setting. ```text z::public: visibility = Public ``` -------------------------------- ### Verify Contract File Name Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/build-contract Confirms the existence and details of the compiled WASM component. The file name may differ if your package name contains hyphens, which are converted to underscores. ```bash ls -lh target/wasm32-wasip2/release/*.wasm ``` -------------------------------- ### Register WASM Contract Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/register-contract Uploads a compiled WASM contract and registers it with a specified tail and version. Ensure you have an authenticated TenantClient, the WASM file path, and your tenant DID. The resulting contract ID is crucial for creating map ACLs. ```typescript import { readFile } from "fs/promises"; const WASM_PATH = "target/wasm32-wasip2/release/your_contract.wasm"; const CONTRACT_TAIL = "travel/contracts"; const CONTRACT_VERSION = "0.1.0"; const wasmBytes = await readFile(WASM_PATH); const result = await tenant.contracts.register({ tail: CONTRACT_TAIL, version: CONTRACT_VERSION, wasm: wasmBytes, }); // This numeric ID is required in the next setup step when you create map ACLs. const contractId = result.contract_id; const tenantId = tenantDid.slice("did:t3n:".length); const scriptName = `z:${tenantId}:${CONTRACT_TAIL}`; console.log(`registered ${scriptName} as contract id ${contractId}`); ``` -------------------------------- ### T3N Token Metering Flow Source: https://docs.terminal3.io/t3n/how-t3n-works/tokens Illustrates the flow of how a DID's token balance pays for metered contract execution, including compute fuel, host-function calls, and storage. ```text Your DID balance | | pays for v Metered contract execution - WASM compute fuel - host-function calls such as kv.put or cas.write - storage deposit and storage rent - contract registration when the admin request bills your DID ``` -------------------------------- ### WIT Definition for Contract World Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/write-contract Declares the host interfaces that your contract can import and use. The host links your contract against a matching tenant world. ```wit package acme:travel-contract@0.1.0; world contract { import t3n:host/kv-store@0.1.0; import t3n:host/logging@0.1.0; import t3n:host/tenant-context@0.1.0; import t3n:host/http-iface@0.1.0; // synchronous HTTP — call a third-party API // PII-safe variant: the host substitutes {{profile.*}} markers from the // caller's profile so plaintext PII never enters the contract. import t3n:host/http-with-placeholders@0.1.0; export t3n:contract/dispatch@0.1.0; } ``` -------------------------------- ### Retrieve Duffel API Key Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/write-contract This Rust function retrieves the Duffel API key from the host's secrets store. It uses `kv_store::get` to fetch the key and handles potential errors like missing credentials or invalid encoding. ```rust use crate::bindings::t3n::host::kv_store; fn duffel_api_key() -> Result { let bytes = kv_store::get("secrets", "duffel_api_key")? .ok_or(ContractError::CredentialsNotConfigured)?; String::from_utf8(bytes) .map_err(|_| ContractError::InternalError { detail: "invalid api key encoding".into() }) } ``` -------------------------------- ### Canonical Tenant-Owned Namespace Format Source: https://docs.terminal3.io/t3n/how-t3n-works/z-namespace Illustrates the structure of a tenant-owned resource name in T3N, which includes the 'z:' prefix, tenant DID suffix, and a tenant-local name. ```text z:: ``` -------------------------------- ### Cargo.toml for WASM Component Compilation Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/write-contract Configures the Rust project to compile into a WASM component. It specifies dependencies like wit-bindgen and serde for efficient compilation and smaller artifact size. ```toml [package] name = "your-contract" version = "0.1.0" edition = "2021" # crate-type cdylib is what makes the wasm32-wasip2 target emit a # WASM *component* (not a bare module). Keep "lib" too so the # business logic stays unit-testable natively. [lib] crate-type = ["cdylib", "lib"] [dependencies] # wit-bindgen's macro generates the bindings from wit/world.wit at # compile time — no separate codegen step. wit-bindgen = { version = "0.49", default-features = false, features = ["macros", "realloc"] } serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } # Small, self-contained artifact — keeps registration under the size cap. [profile.release] opt-level = "s" lto = true codegen-units = 1 strip = true ``` -------------------------------- ### Seed API Key using map-entry-set Source: https://docs.terminal3.io/developers/adk/tips/seed-api-key Use this snippet to write an API key into the secrets map. The key is stored in `process.env.DUFFEL_API_KEY` and is written to the map under the key `duffel_api_key`. This operation bypasses ACLs and is only visible within the TEE. ```typescript await tenant.executeControl("map-entry-set", { map_name: tenant.canonicalName("secrets"), key: "duffel_api_key", value: process.env.DUFFEL_API_KEY!, }); console.log("API key sealed in z::secrets — not visible outside the TEE"); ``` -------------------------------- ### T3N Multi-Region Architecture Diagram Source: https://docs.terminal3.io/t3n/how-t3n-works/architecture Visual representation of the T3N network topology, illustrating two distinct regions with TEE clusters and regional storage. Shows cross-region communication for key sharing and in-region/remote access for storage. ```text +------------------------------------------------+ | REGION 1 | | (local data processing & residency required) | | | | +----------------------------------+ | | | TEE Cluster 1 | | | | [Node 1] <--> [Node 2] |<--------->| +-----------------------------------+ | +----------------+-----------------+ | | REGION 2 | | ^ | | (no data residency) | | | | | | | v | | +-----------------------------+ | | +----------------+-----------------+ | | | TEE Cluster 2 | | | | Regional Storages |<--------->|------| | [Node 3] <--> [Node 4] | | | | [Content Addressable Storage] | | | +---------------+-------------+ | | | [Regulatory Vault] | | | ^ | | +----------------------------------+ | | | | | | | | | +------------------------------------------------+ +-----------------------------------+ Connections ----------- Cluster 1 <--> Cluster 2 (cross-region threshold key sharing) Cluster 1 <--> Regional Storages (in-region storage) Cluster 2 <--> Regional Storages (remote access to Region 1 storages) ``` -------------------------------- ### Book Offer WASM Contract Source: https://docs.terminal3.io/developers/adk/get-started/walkthrough/write-contract This Rust code defines a WASM function to book an offer. It constructs a JSON payload for the booking request, including passenger details and payment information. PII fields are marked with placeholders for privacy. ```rust fn book_offer_wasm(req: BookOfferReq) -> Result { use serde_json::json; let api_key = get_api_key()?; let order_body = json!({ "data": { "type": "instant", "selected_offers": [req.offer_id], "passengers": [{ "id": req.passenger_id, // Resolved from the user's profile (privacy-preserving path): "given_name": "{{profile.first_name}}", "family_name": "{{profile.last_name}}", "born_on": "{{profile.date_of_birth}}", "gender": "{{profile.gender}}", "email": "{{profile.verified_contacts.email.value}}", // Demo-hardcoded (no profile source): "title": "mr", "passport_number": "X12345678", "passport_country_code": "GB", "passport_expiry_date": "2030-01-01", "phone_number": "+442071234567", }], "payments": [{ "type": "balance", "amount": req.total_amount, "currency": req.total_currency, }] } }); ```