From 007dfecd265895b6d53db3ef2a2dde8c8afac628 Mon Sep 17 00:00:00 2001 From: Emmanuel Jacquier Date: Tue, 4 Aug 2026 21:26:30 -0400 Subject: [PATCH 1/3] Added conf workflows templates --- .../cre-templates/ai-audit-firewall.mdx | 229 ++++++++++++++++ .../automated-liquidation-protection.mdx | 189 +++++++++++++ .../automated-portfolio-rebalancing.mdx | 175 ++++++++++++ .../hello-confidential-workflows.mdx | 259 ++++++++++++++++++ 4 files changed, 852 insertions(+) create mode 100644 src/content/cre-templates/ai-audit-firewall.mdx create mode 100644 src/content/cre-templates/automated-liquidation-protection.mdx create mode 100644 src/content/cre-templates/automated-portfolio-rebalancing.mdx create mode 100644 src/content/cre-templates/hello-confidential-workflows.mdx diff --git a/src/content/cre-templates/ai-audit-firewall.mdx b/src/content/cre-templates/ai-audit-firewall.mdx new file mode 100644 index 00000000000..e6f337b2977 --- /dev/null +++ b/src/content/cre-templates/ai-audit-firewall.mdx @@ -0,0 +1,229 @@ +--- +title: "AI Smart Contract Audit Firewall" +description: "Screen proposed token interactions with two independent LLM audits, then merge risk flags into an ALLOW, DENY, or MANUAL_REVIEW verdict." +author: "Chainlink Labs" +excerpt: "Gate transactions with dual-model AI audits inside a TEE and deliver the verdict onchain." +image: "thumbnail.jpg" +tags: + - "confidential" + - "ai" + - "security" +githubUrl: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/ai-audit-firewall" +githubRepoLinks: + - label: "TypeScript" + url: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/ai-audit-firewall" +datePublished: "2026-08-04" +lastModified: "2026-08-04" +--- + +import { Aside, Accordion } from "@components" + +## What This Template Does + +This workflow runs inside a **Trusted Execution Environment (TEE)** and acts as a confidential gate for proposed token interactions. Contract source, transaction details, and model prompts never leave the confidential runtime. + +On every cron execution the workflow: + +1. Fetches a **proposed transaction** +2. Fetches the **token and protocol contract artifacts** from a scanner service +3. Runs **two independent LLM audits** — the second receives the first analysis as prior context +4. Merges the risk flags and decides **ALLOW**, **DENY**, or **MANUAL_REVIEW** +5. Writes an audit log entry and a firewall action +6. Optionally writes the verdict onchain with `EVMClient` + + + +## Risk Flags + +Both models are asked to evaluate the same four checks: + +| Flag | What it detects | +| --------------------- | ------------------------------------------------------------------ | +| `obfuscatedTax` | Hidden or dynamically-adjustable transfer fees | +| `privilegeEscalation` | Owner or admin functions that can seize funds or change core rules | +| `externalCallRisk` | Untrusted external calls and reentrancy surface | +| `logicBomb` | Conditional logic that changes behavior after a trigger is reached | + +## Verdict Logic + +The `determineVerdict` function merges both analyses: + +- **DENY** — any malicious risk flag is set in the merged flag set +- **MANUAL_REVIEW** — either model recommends `review`, either model's confidence is below `0.7`, or the two models disagree +- **ALLOW** — both models agree, both are confident, and no risk flag fired + + + +## Prerequisites + +- **[Bun](https://bun.com/docs/installation)** — the repository is configured as a Bun workspace +- **[Chainlink CRE CLI](https://docs.chain.link/cre/getting-started/cli-installation)** installed and configured +- **Git** for cloning the repository +- **A funded wallet on Ethereum Sepolia** — only if you want to test the optional onchain delivery path + +## Setup + + + +```bash +git clone https://github.com/smartcontractkit/confidential-compute-examples.git +cd confidential-compute-examples +bun install +``` + +`bun install` at the repository root installs dependencies for every workflow because the repo is a Bun workspace. + + + + + +From the repository root: + +```bash +cp .env.example .env +``` + +Set the values you want to use. The mock keys are used by both the workflow and the shared demo server: + +```bash +MOCK_PORT=8787 +MOCK_SCANNER_API_KEY=mock-scanner-key +MOCK_PRIMARY_LLM_API_KEY=mock-primary-llm-key +MOCK_SECONDARY_LLM_API_KEY=mock-secondary-llm-key +``` + +`secrets.yaml` at the repository root maps the logical secret IDs to these environment variables. + + + + + +Open `ai-audit-firewall/config.staging.json`: + +```json +{ + "schedule": "0 */5 * * * *", + "mock_base_url": "http://127.0.0.1:8787/audit-firewall", + "scanner_url": "http://127.0.0.1:8787/audit-firewall/scanner", + "primary_llm_url": "http://127.0.0.1:8787/audit-firewall/v1/analysis/primary", + "secondary_llm_url": "http://127.0.0.1:8787/audit-firewall/v1/analysis/secondary", + "secrets_ids": { + "scanner_api_key_id": "scanner_api_key", + "primary_llm_api_key_id": "primary_llm_api_key", + "secondary_llm_api_key_id": "secondary_llm_api_key" + } +} +``` + +1. Keep the default values if you are using the shared mock server on port `8787` +2. Update `mock_base_url`, `scanner_url`, `primary_llm_url`, and `secondary_llm_url` if you are using a different port or host +3. Keep `secrets_ids` aligned with `secrets.yaml` +4. If you do not want to test onchain delivery yet, remove or clear the `evms` entry + + + + + +```bash +cd ai-audit-firewall +bun run typecheck +bun run test +``` + + + + + +From the repository root: + +```bash +bun run mock:server +``` + +The server listens on `http://127.0.0.1:8787` and serves this workflow's routes under the `/audit-firewall/*` namespace — transaction proposals, contract artifact lookups, the two audit model endpoints, and the logging and action endpoints. + + + + + +In a new terminal, from the repository root: + +```bash +cre workflow simulate ./ai-audit-firewall --target=staging-settings +``` + +The workflow logs each stage (`audit-firewall-onchain-report-start`, `audit-firewall-complete`) and returns a JSON result containing the verdict, reasoning, merged risk flags, both model analyses, the audit log ID, and the firewall action ID. + + + +## Secrets + +`config.staging.json` expects these secret IDs in `secrets_ids`: + +- `scanner_api_key` +- `primary_llm_api_key` +- `secondary_llm_api_key` + +## Optional Onchain Delivery + +The workflow can encode the verdict as a CRE report and write it to a consumer contract. + + + +Deploy `contracts/AuditFirewallConsumer.sol`. It extends `contracts/ReceiverTemplate.sol`, which validates that reports arrive from the Chainlink Forwarder. + +Forwarder mode must match your environment: + +- **Simulation** uses the Mock Forwarder +- **Production** uses the Keystone Forwarder + +Deploy or configure the consumer with the forwarder address that matches the mode you are running. See [Forwarder Addresses](https://docs.chain.link/cre/supported-networks-ts#forwarder-addresses) for the correct address. + + + + + +Set `evms[0]` in your config file: + +```json +"evms": [ + { + "chain_selector_name": "ethereum-testnet-sepolia", + "consumer_address": "0xYourConsumer", + "gas_limit": "500000" + } +] +``` + +1. Set `evms[0].consumer_address` to the deployed consumer address +2. Keep `evms[0].chain_selector_name` aligned with the target network in `project.yaml` +3. Increase `evms[0].gas_limit` if your deployed contract needs more gas + + + + + +## Production Checklist + +1. Replace the example URLs in `config.production.json` with real endpoints +2. Set real secret values for the scanner and both model providers +3. Deploy the consumer contract +4. Update `config.production.json` so `evms[0].consumer_address`, `evms[0].chain_selector_name`, and `evms[0].gas_limit` match the deployed target +5. Confirm the consumer's forwarder address matches your environment + +## Troubleshooting + +- **401 responses from the APIs** usually indicate a secret mismatch between `.env`, `secrets.yaml`, and `secrets_ids` in the config file +- **Simulation failures tied to RPC config** usually come from incorrect `project.yaml` target values +- **Model responses that fail to parse** mean your configured endpoint is not returning the expected JSON payload shape — the workflow expects `riskFlags`, `recommendation`, `confidence`, and `reasoning` +- **Onchain write failures** mean the consumer rejected the report; confirm the forwarder address configured on the contract matches the mode you are simulating or deploying in diff --git a/src/content/cre-templates/automated-liquidation-protection.mdx b/src/content/cre-templates/automated-liquidation-protection.mdx new file mode 100644 index 00000000000..c76beafcef9 --- /dev/null +++ b/src/content/cre-templates/automated-liquidation-protection.mdx @@ -0,0 +1,189 @@ +--- +title: "Automated Liquidation Protection" +description: "Defend a leveraged position inside a TEE — read risk state, generate an LLM defense plan, and enforce policy limits before executing." +author: "Chainlink Labs" +excerpt: "Run policy-constrained liquidation defense confidentially with CRE and TEE execution." +image: "thumbnail.jpg" +tags: + - "confidential" + - "liquidation" + - "defi" +githubUrl: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/automated-liquidation-protection" +githubRepoLinks: + - label: "TypeScript" + url: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/automated-liquidation-protection" +datePublished: "2026-08-04" +lastModified: "2026-08-04" +--- + +import { Aside, Accordion } from "@components" + +## What This Template Does + +This workflow runs inside a **Trusted Execution Environment (TEE)** and generates a policy-constrained defense plan for a leveraged ETH position. Risk data, policy parameters, and model prompts never leave the confidential runtime. + +On every cron execution the workflow: + +1. Fetches the exchange and model API secrets from the CRE secrets store +2. Reads the account **policy** and the current **risk state** (leverage, liquidation proximity, collateral health, reserves) +3. Computes a **risk score** from the risk state and policy thresholds +4. Asks an LLM for a set of **defensive actions** +5. Enforces reserve, slippage, and sequencing constraints on the proposed actions +6. Executes the approved actions through an execution endpoint + +If the position is healthy or no action survives the policy filter, the workflow returns `SAFE` without executing anything. + + + +## Defensive Actions + +The LLM may propose any of the following action types. Each one is validated against the policy before it becomes executable: + +| Action | Description | +| --------------------------- | -------------------------------------------------------- | +| `add_collateral` | Post additional collateral from reserves | +| `bridge_and_add_collateral` | Bridge funds from another chain, then post as collateral | +| `reallocate_collateral` | Move collateral between positions or venues | +| `reduce_position` | Partially deleverage the position | +| `close_position` | Fully exit the position | +| `hedge_short_perp` | Open an offsetting short perpetual | + +## Policy Constraints + +The policy is fetched at runtime and bounds everything the model is allowed to do: + +- `max_reserve_deployment_usdc` — ceiling on capital deployed in a single cycle +- `min_reserve_balance_usdc` — reserve floor that must remain untouched +- `max_acceptable_leverage` — leverage target used in risk scoring +- `incremental_deleveraging_limit_pct` — cap on how much of the position can be reduced per cycle +- `liquidation_warning_action_threshold` — proximity threshold that triggers a defense +- `allow_leverage_reduction` — whether deleveraging actions are permitted at all +- `execution_sequence_preference` — `collateral-first`, `deleverage-first`, or `hedge-first` +- `preferred_venues` — venue allowlist used when routing each action + + + +## Prerequisites + +- **[Bun](https://bun.com/docs/installation)** — the repository is configured as a Bun workspace +- **[Chainlink CRE CLI](https://docs.chain.link/cre/getting-started/cli-installation)** installed and configured +- **Git** for cloning the repository + +## Setup + + + +```bash +git clone https://github.com/smartcontractkit/confidential-compute-examples.git +cd confidential-compute-examples +bun install +``` + +`bun install` at the repository root installs dependencies for every workflow because the repo is a Bun workspace. + + + + + +From the repository root: + +```bash +cp .env.example .env +``` + +Set the values you want to use. The mock keys are used by both the workflow and the shared demo server: + +```bash +MOCK_PORT=8787 +MOCK_EXCHANGE_API_KEY=mock-exchange-key +MOCK_OPENAI_API_KEY=mock-openai-key +``` + +`secrets.yaml` at the repository root maps the logical secret IDs to these environment variables. + + + + + +Open `automated-liquidation-protection/config.staging.json`: + +```json +{ + "schedule": "0 */5 * * * *", + "mock_base_url": "http://127.0.0.1:8787/liquidation", + "openai_url": "http://127.0.0.1:8787/liquidation/v1/responses", + "openai_model": "gpt-4.1-mini", + "secrets_ids": { + "exchange_api_key_id": "exchange_api_key", + "openai_api_key_id": "openai_api_key" + } +} +``` + +1. Keep the default values if you are using the shared mock server on port `8787` +2. Update `mock_base_url` and `openai_url` if you are using a different port or host +3. Keep `secrets_ids` aligned with `secrets.yaml` + + + + + +```bash +cd automated-liquidation-protection +bun run typecheck +bun run test +``` + + + + + +From the repository root: + +```bash +bun run mock:server +``` + +The server listens on `http://127.0.0.1:8787` and serves this workflow's routes under the `/liquidation/*` namespace — policy, risk state, model responses, and the execution endpoint. + + + + + +In a new terminal, from the repository root: + +```bash +cre workflow simulate ./automated-liquidation-protection --target=staging-settings +``` + +The workflow logs each stage (`liquidation-getsecret-ok`, `liquidation-defense-executed`) and returns either `SAFE` or a JSON summary with the status, action count, risk score, and execution ID. + + + +## Secrets + +`config.staging.json` expects these secret IDs in `secrets_ids`: + +- `exchange_api_key` +- `openai_api_key` + +## Production Checklist + +1. Replace `mock_base_url` with your real risk, policy, and execution service URL +2. Use a production model endpoint and model in `openai_url` and `openai_model` +3. Confirm `config.production.json` points to the correct service base URL before deployment +4. Register production secret values for exchange and model access + +## Troubleshooting + +- **401 responses from the APIs** usually indicate a secret mismatch between `.env`, `secrets.yaml`, and `secrets_ids` in the config file +- **Simulation failures tied to RPC config** usually come from incorrect `project.yaml` target values +- **Model responses that fail to parse** mean your configured endpoint is not returning the expected JSON payload shape — the workflow expects `shouldDefend`, `reasoning`, and `actions` diff --git a/src/content/cre-templates/automated-portfolio-rebalancing.mdx b/src/content/cre-templates/automated-portfolio-rebalancing.mdx new file mode 100644 index 00000000000..9d021cf2ecd --- /dev/null +++ b/src/content/cre-templates/automated-portfolio-rebalancing.mdx @@ -0,0 +1,175 @@ +--- +title: "Automated Portfolio Rebalancing" +description: "Detect allocation drift, generate LLM trade proposals, and enforce slippage, reserve, and trade-size limits inside a TEE." +author: "Chainlink Labs" +excerpt: "Rebalance a portfolio confidentially with policy-constrained, LLM-assisted trade execution." +image: "thumbnail.jpg" +tags: + - "confidential" + - "rebalancing" + - "defi" +githubUrl: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/automated-portfolio-rebalancing" +githubRepoLinks: + - label: "TypeScript" + url: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/automated-portfolio-rebalancing" +datePublished: "2026-08-04" +lastModified: "2026-08-04" +--- + +import { Aside, Accordion } from "@components" + +## What This Template Does + +This workflow runs inside a **Trusted Execution Environment (TEE)** and generates policy-constrained rebalance trades when allocation drift exceeds the configured threshold. Holdings, prices, and target allocations never leave the confidential runtime. + +On every cron execution the workflow: + +1. Fetches the exchange and model API secrets from the CRE secrets store +2. Reads **policy**, **holdings**, **prices**, and a **volatility index** +3. Computes per-asset **allocation drift** against the target weights +4. Asks an LLM for **trade proposals** +5. Enforces slippage, reserve-floor, and max-trade-size constraints +6. Chunks oversized trades and routes each chunk to a preferred venue +7. Executes the approved trade plan through an execution endpoint + +If no asset has drifted past the threshold, the workflow returns without trading. + + + +## Policy Constraints + +The policy is fetched at runtime and bounds every trade the model is allowed to propose: + +- `target_allocations` — target weight per symbol +- `drift_threshold_pct` — minimum drift required before rebalancing runs at all +- `max_trade_usd` — maximum notional per trade; larger trades are split into chunks +- `reserve_floor_usdc` — USDC reserve that must remain untouched +- `max_slippage_bps` — slippage ceiling applied to every trade +- `preferred_venues` — venue allowlist used when routing each chunk + + + +## Prerequisites + +- **[Bun](https://bun.com/docs/installation)** — the repository is configured as a Bun workspace +- **[Chainlink CRE CLI](https://docs.chain.link/cre/getting-started/cli-installation)** installed and configured +- **Git** for cloning the repository + +## Setup + + + +```bash +git clone https://github.com/smartcontractkit/confidential-compute-examples.git +cd confidential-compute-examples +bun install +``` + +`bun install` at the repository root installs dependencies for every workflow because the repo is a Bun workspace. + + + + + +From the repository root: + +```bash +cp .env.example .env +``` + +Set the values you want to use. The mock keys are used by both the workflow and the shared demo server: + +```bash +MOCK_PORT=8787 +MOCK_EXCHANGE_API_KEY=mock-exchange-key +MOCK_OPENAI_API_KEY=mock-openai-key +``` + +`secrets.yaml` at the repository root maps the logical secret IDs to these environment variables. + + + + + +Open `automated-portfolio-rebalancing/config.staging.json`: + +```json +{ + "schedule": "0 */5 * * * *", + "mock_base_url": "http://127.0.0.1:8787/rebalancing", + "openai_url": "http://127.0.0.1:8787/rebalancing/v1/responses", + "openai_model": "gpt-4.1-mini", + "secrets_ids": { + "exchange_api_key_id": "exchange_api_key", + "openai_api_key_id": "openai_api_key" + } +} +``` + +1. Keep the default values if you are using the shared mock server on port `8787` +2. Update `mock_base_url` and `openai_url` if you are using a different port or host +3. Keep `secrets_ids` aligned with `secrets.yaml` + + + + + +```bash +cd automated-portfolio-rebalancing +bun run typecheck +bun run test +``` + + + + + +From the repository root: + +```bash +bun run mock:server +``` + +The server listens on `http://127.0.0.1:8787` and serves this workflow's routes under the `/rebalancing/*` namespace — portfolio, prices, volatility, policy, model responses, and the execution endpoint. + + + + + +In a new terminal, from the repository root: + +```bash +cre workflow simulate ./automated-portfolio-rebalancing --target=staging-settings +``` + +The workflow logs each stage (`rebalance-executed`) and returns a JSON summary with the status, trade count, maximum drift percentage, and execution ID. + + + +## Secrets + +`config.staging.json` expects these secret IDs in `secrets_ids`: + +- `exchange_api_key` +- `openai_api_key` + +## Production Checklist + +1. Replace `mock_base_url` with your real policy, market, and execution service URL +2. Use a production model endpoint and model in `openai_url` and `openai_model` +3. Confirm `config.production.json` points to the correct service base URL before deployment +4. Register production secret values for exchange and model access + +## Troubleshooting + +- **401 responses from the APIs** usually indicate a secret mismatch between `.env`, `secrets.yaml`, and `secrets_ids` in the config file +- **Simulation failures tied to RPC config** usually come from incorrect `project.yaml` target values +- **Model responses that fail to parse** mean your configured endpoint is not returning the expected JSON payload shape — the workflow expects `shouldRebalance`, `reasoning`, and `trades` diff --git a/src/content/cre-templates/hello-confidential-workflows.mdx b/src/content/cre-templates/hello-confidential-workflows.mdx new file mode 100644 index 00000000000..0a285e51429 --- /dev/null +++ b/src/content/cre-templates/hello-confidential-workflows.mdx @@ -0,0 +1,259 @@ +--- +title: "Hello Confidential Workflows" +description: "Run a handler inside a TEE — fetch a secret, call an API from the enclave, then cross back to the DON for consensus." +author: "Chainlink Labs" +excerpt: "Learn the minimal end-to-end shape of a CRE Confidential Workflow with TEE execution." +image: "thumbnail.jpg" +cliTemplateIds: + - label: "TypeScript" + id: "hello-confidential-workflows-ts" +tags: + - "confidential" + - "tee" + - "secrets" +githubUrl: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/hello-confidential-workflows" +githubRepoLinks: + - label: "TypeScript" + url: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/hello-confidential-workflows/hello-confidential-workflows-ts" +datePublished: "2026-08-04" +lastModified: "2026-08-04" +--- + +import { Aside, Accordion } from "@components" + + + +## What This Template Does + +By default, a CRE workflow's callback runs on Workflow DON nodes, where node operators can in principle inspect what it is computing. That's fine for most workflows — but some logic is sensitive on its own: a risk threshold, a rebalancing policy, a proprietary scoring model. Leaking the policy can be as damaging as leaking a credential. + +A **[Confidential Workflow](https://docs.chain.link/cre/concepts/confidential-workflows)** moves that part into a hardware-isolated [enclave](https://docs.chain.link/cre/key-terms#enclave). This template is the minimal end-to-end shape of one, in four steps: + +| Step | What it demonstrates | API | +| ---- | ---------------------------------------------------- | ----------------------------------------- | +| 1 | Register a handler that runs inside a TEE | `cre.handlerInTee(trigger, fn, tees)` | +| 2 | Fetch a secret inside the enclave | `runtime.getSecret({ id })` | +| 3 | Make a capability call from inside the enclave | `HTTPClient.sendRequest(teeRuntime, req)` | +| 4 | Cross back to the DON for anything needing consensus | `runtime.usingTheDons()` | + +## Architecture + +```text +┌──────────────┐ +│ CronTrigger │ fires on schedule (runs on the Workflow DON) +└──────┬───────┘ + │ DON hands the triggered request to an enclave + v +╔══════════════════════════════════════════════════════════════╗ +║ ENCLAVE (TEE — hidden from node operators) ║ +║ ║ +║ Step 2: runtime.getSecret({ id: 'API_TOKEN' }) ║ +║ ▲ ║ +║ └──── released by Vault DON, decrypted in-enclave║ +║ ║ +║ Step 3: HTTPClient.sendRequest(runtime, { ... }) ║ +║ Authorization: Bearer ║ +║ ▲ trust from enclave attestation, not consensus ║ +║ ║ +║ Confidential logic: score(response) vs. scoreThreshold ║ +║ -> verdict = APPROVE | REJECT ║ +╚═══════════════════════════╤══════════════════════════════════╝ + │ Step 4: runtime.usingTheDons() + │ ONLY the verdict + score cross out + v +┌──────────────────────────────────────────────────────────────┐ +│ WORKFLOW DON — donRuntime.report({ ... }) │ +│ BFT consensus verifies the enclave attestation, then signs │ +└──────────────────────────────────────────────────────────────┘ +``` + +## How It Works + +`my-workflow/workflow.ts`: + +1. **Registers the cron handler with `cre.handlerInTee`**, constrained to `[{ tee: 'nitro', regions: ['us-west-2'] }]` +2. **Fetches `API_TOKEN`** with `runtime.getSecret()` — the Vault DON releases it only into an attested enclave, and it is decrypted at the moment the call runs +3. **Calls the configured URL** with `HTTPClient.sendRequest(runtime, ...)`, passing the `TeeRuntime` so the request executes from inside the enclave with the secret in the `Authorization` header +4. **Scores the response** against `scoreThreshold` — this stands in for your proprietary logic, and is the part that stays invisible to node operators +5. **Crosses back with `usingTheDons()`** and generates a signed report containing only the verdict and score — never the secret or the raw response + +The default endpoint is `https://postman-echo.com/headers`, which echoes the request headers back — no signup or real API key needed. The workflow uses that to confirm the secret really was injected inside the enclave, reporting it as the boolean `secret reached API: true` rather than by logging the token. It never logs the response body either; the confidentiality boundary is the reason, and it's worth keeping that habit even in simulation. + + + +## Use Cases + +- **Automated liquidation protection** — keep risk thresholds and the defensive strategy off Workflow DON nodes so they can't be predicted and front-run +- **Portfolio rebalancing** — hide the allocation policy and trade-sizing logic so the rebalance isn't anticipated +- **LLM audit firewall** — keep evaluation criteria and third-party API credentials inside the enclave +- **Payment orchestration** — keep routing logic and account details confidential +- **Proprietary scoring** — compute over licensed or sensitive data without exposing the data or the model + +## Prerequisites + +- **[Bun](https://bun.sh/)** runtime installed +- **[Chainlink CRE CLI](https://docs.chain.link/cre/getting-started/cli-installation)** installed and configured +- **Enrollment in the Confidential Workflows private beta** — required to deploy, not to simulate + +## Getting Started + + + +```bash +cd my-workflow && bun install && cd .. +``` + + + + + +```bash +cp .env.example .env +``` + +Set `SECRET_API_TOKEN` in `.env`. `secrets.yaml` maps the workflow-facing secret ID `API_TOKEN` to that environment variable: + +```yaml +secretsNames: + API_TOKEN: + - SECRET_API_TOKEN +``` + +With the default echo endpoint, any non-empty value works. + + + + + +```bash +cd my-workflow && bun test +``` + + + + + +```bash +cre workflow simulate my-workflow --target staging-settings --non-interactive --trigger-index 0 +``` + +Expected output: + +```text +[SIMULATION] Running trigger trigger=cron-trigger@1.0.0 +╭────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Trigger requested TEE Execution your trigger will run in one of the following Tees: │ +│ - AWS Nitro in us-west-2 │ +│ The simulator is not a real TEE, and is meant to debug. │ +│ Do not use it for sensitive information. │ +│ During real execution, user logs for this trigger will not be visible, and will not leave the TEE. │ +│ They are presented in the simulator for debugging only. │ +╰────────────────────────────────────────────────────────────────────────────────────────────────────╯ + +[USER LOG] Enclave computation complete. verdict=REJECT + +✓ Workflow Simulation Result: +"REJECT (score: 371, secret reached API: true)" +``` + +Three things to notice: + +- The simulator confirms the TEE constraint it resolved (`AWS Nitro in us-west-2`) and warns that **it is not a real enclave** — logs are shown for debugging only. In real execution those logs never leave the TEE. +- `secret reached API: true` means the Vault DON secret was fetched inside the enclave and arrived in the outbound request's `Authorization` header. +- The verdict flips between `APPROVE` and `REJECT` from run to run. That's expected: the score is derived from the live response body, and the echo endpoint includes a per-request trace ID. Lower `scoreThreshold` to see `APPROVE` consistently. + + + +## Configuration + +`my-workflow/config.staging.json`: + +| Field | Description | +| ---------------- | ----------------------------------------------------------------------- | +| `schedule` | Cron expression (6 fields, seconds first) | +| `url` | Endpoint called from inside the enclave | +| `secretId` | Secret ID fetched with `runtime.getSecret()`; must match `secrets.yaml` | +| `scoreThreshold` | Threshold the confidential scoring compares against | + +## TEE Constraints + +The third argument to `handlerInTee` declares which enclaves the handler accepts: + +```ts +{ +} // any registered TEE, any region +{ + regions: ["us-west-2"] +} // any TEE, restricted to a region +;[{ tee: "nitro", regions: ["us-west-2"] }] // specific TEE types and regions +``` + +AWS Nitro in `us-west-2` is currently the only registered TEE type and region. This is an actively evolving alpha API — check your installed SDK version if you expect otherwise. + +## Confidentiality Boundary + +Understanding what is and isn't protected matters more here than in a regular workflow. + +| Protected by default | **Not** automatically protected | +| ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| Secrets the Vault DON releases into the enclave | Triggers, chain reads, and chain writes — these always run on Workflow DON nodes | +| Sensitive inputs and intermediate values you don't share outside the enclave | Your workflow's **source code and deployed binary** | +| Capability calls made from inside the enclave | Capability calls not routed through the enclave | +| Enclave execution memory, while your computation runs | Reports, calldata, and any output you deliver outside the enclave | + +Consequences worth internalizing: + +- **Your source and binary are readable.** If the logic itself is the secret, make sure it actually _executes_ inside the enclave — don't rely on the binary being opaque, because it isn't. +- **`usingTheDons()` is a one-way door.** Anything you pass into a capability call on that runtime executes on Workflow DON nodes like any non-confidential call. Cross over only what doesn't need to stay hidden. +- **Don't log from inside the enclave in production.** Logs leave the confidentiality boundary. This template logs only the verdict, and the comment marks it for removal before deploying. +- **Keep enclave logic deterministic.** The enclave result is attested and verified by DON consensus. +- **Enclaves are not tenant-isolated today.** A single enclave can run confidential workflows from multiple customers concurrently, sharing execution memory. Isolation between confidential executions is planned, not part of the current beta. + +## Which Secrets Belong in an Enclave? + +Not every secret needs enclave-level protection. + +**Higher value — consider enclave execution:** wallet and CA private keys; exchange, custody, payment-processor, banking, or LLM-provider credentials; OAuth client secrets, JWT signing keys, KMS keys; payment data, health data, other PII. + +**Lower value — regular DON execution is usually fine:** API keys for publicly available data (weather, explorers, public price feeds, public RPCs); public wallet addresses. + +The common thread: a secret belongs in the enclave if disclosure would expose more than the workflow needs. + +## Customization + +- **Put your real logic in the enclave** — replace `scoreResponse` in `workflow.ts` with the policy, threshold, or model you need to keep private +- **Deliver the report onchain** — pass the report from Step 4 to `evmClient.writeReport(donRuntime, report)`; the RPCs in `project.yaml` are already set up for Sepolia. See the [Keeper Bot](/cre-templates/keeper-bot) or [Event Reactor](/cre-templates/event-reactor) templates for the full write path +- **Change the trigger** — `handlerInTee` accepts any CRE trigger, same as `handler`; swap cron for a log trigger to react to onchain events confidentially +- **Fetch more secrets** — call `runtime.getSecret()` once per secret; the TypeScript `SecretsProvider` has no batch variant + +## Security + +- Never commit `.env` files or secrets — `.gitignore` covers `*.env` +- Remove or gate every `runtime.log()` inside the TEE handler before deploying +- Audit what crosses `usingTheDons()`; that data is no longer confidential + +## Further Reading + +- [Confidential Workflows in CRE](https://docs.chain.link/cre/concepts/confidential-workflows) — concepts and use cases +- [Making a Workflow Confidential](https://docs.chain.link/cre/guides/workflow/using-confidential-workflows) — step-by-step guide +- [Confidential Workflows Client SDK Reference](https://docs.chain.link/cre/reference/sdk/confidential-workflows-client) — full API +- [Confidential HTTP](https://docs.chain.link/cre/capabilities/confidential-http) — for a single outbound request, without a full confidential handler +- [confidential-compute-examples](https://github.com/smartcontractkit/confidential-compute-examples) — production-shaped reference workflows + + From ff2d03d7e7cf364b0f1945f772a5941addc4f74d Mon Sep 17 00:00:00 2001 From: Emmanuel Jacquier Date: Tue, 4 Aug 2026 21:47:41 -0400 Subject: [PATCH 2/3] updated metadatas --- src/content/cre-templates/ai-audit-firewall.mdx | 2 +- src/content/cre-templates/automated-liquidation-protection.mdx | 2 +- src/content/cre-templates/automated-portfolio-rebalancing.mdx | 2 +- src/content/cre-templates/hello-confidential-workflows.mdx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/cre-templates/ai-audit-firewall.mdx b/src/content/cre-templates/ai-audit-firewall.mdx index e6f337b2977..29e1e65ceba 100644 --- a/src/content/cre-templates/ai-audit-firewall.mdx +++ b/src/content/cre-templates/ai-audit-firewall.mdx @@ -1,6 +1,6 @@ --- title: "AI Smart Contract Audit Firewall" -description: "Screen proposed token interactions with two independent LLM audits, then merge risk flags into an ALLOW, DENY, or MANUAL_REVIEW verdict." +description: "Automatically analyze and screen smart contract interactions before execution to detect and block malicious transactions, while preserving the confidentiality of chain scanner and LLM reasoning API credentials." author: "Chainlink Labs" excerpt: "Gate transactions with dual-model AI audits inside a TEE and deliver the verdict onchain." image: "thumbnail.jpg" diff --git a/src/content/cre-templates/automated-liquidation-protection.mdx b/src/content/cre-templates/automated-liquidation-protection.mdx index c76beafcef9..061e5706f7f 100644 --- a/src/content/cre-templates/automated-liquidation-protection.mdx +++ b/src/content/cre-templates/automated-liquidation-protection.mdx @@ -1,6 +1,6 @@ --- title: "Automated Liquidation Protection" -description: "Defend a leveraged position inside a TEE — read risk state, generate an LLM defense plan, and enforce policy limits before executing." +description: "Automatically protect DeFi lending positions by continuously monitoring liquidation risk and executing collateral management, debt repayment, position reduction, or hedging strategies while preserving the confidentiality of centralized exchange as well as LLM API keys, proprietary risk management thresholds, and execution preferences." author: "Chainlink Labs" excerpt: "Run policy-constrained liquidation defense confidentially with CRE and TEE execution." image: "thumbnail.jpg" diff --git a/src/content/cre-templates/automated-portfolio-rebalancing.mdx b/src/content/cre-templates/automated-portfolio-rebalancing.mdx index 9d021cf2ecd..9148db1d693 100644 --- a/src/content/cre-templates/automated-portfolio-rebalancing.mdx +++ b/src/content/cre-templates/automated-portfolio-rebalancing.mdx @@ -1,6 +1,6 @@ --- title: "Automated Portfolio Rebalancing" -description: "Detect allocation drift, generate LLM trade proposals, and enforce slippage, reserve, and trade-size limits inside a TEE." +description: "Automatically rebalance crypto portfolios by continuously monitoring allocation drift and executing portfolio adjustments when predefined thresholds are exceeded, while preserving the confidentiality of exchange API keys, LLM reasoning, portfolio allocation thresholds, and execution preferences." author: "Chainlink Labs" excerpt: "Rebalance a portfolio confidentially with policy-constrained, LLM-assisted trade execution." image: "thumbnail.jpg" diff --git a/src/content/cre-templates/hello-confidential-workflows.mdx b/src/content/cre-templates/hello-confidential-workflows.mdx index 0a285e51429..8146fbd5dc2 100644 --- a/src/content/cre-templates/hello-confidential-workflows.mdx +++ b/src/content/cre-templates/hello-confidential-workflows.mdx @@ -1,6 +1,6 @@ --- title: "Hello Confidential Workflows" -description: "Run a handler inside a TEE — fetch a secret, call an API from the enclave, then cross back to the DON for consensus." +description: "Quickstart confidential workflow that registers a TEE handler, securely fetches a secret inside the enclave, executes a capability call from within the enclave, and returns to the DON for any operations requiring decentralized consensus." author: "Chainlink Labs" excerpt: "Learn the minimal end-to-end shape of a CRE Confidential Workflow with TEE execution." image: "thumbnail.jpg" From c32d55b5095248555147dc444b2c1014bbe7d97c Mon Sep 17 00:00:00 2001 From: Emmanuel Jacquier Date: Thu, 6 Aug 2026 12:17:05 -0400 Subject: [PATCH 3/3] Updated 4 new conf compute metadata based on latest readme.md changes --- .../cre-templates/ai-audit-firewall.mdx | 182 ++++++++++++-- .../automated-liquidation-protection.mdx | 181 +++++++++++--- .../automated-portfolio-rebalancing.mdx | 192 +++++++++++--- .../hello-confidential-workflows.mdx | 234 ++++++++++++------ 4 files changed, 628 insertions(+), 161 deletions(-) diff --git a/src/content/cre-templates/ai-audit-firewall.mdx b/src/content/cre-templates/ai-audit-firewall.mdx index 29e1e65ceba..d2c7abf19f7 100644 --- a/src/content/cre-templates/ai-audit-firewall.mdx +++ b/src/content/cre-templates/ai-audit-firewall.mdx @@ -2,38 +2,62 @@ title: "AI Smart Contract Audit Firewall" description: "Automatically analyze and screen smart contract interactions before execution to detect and block malicious transactions, while preserving the confidentiality of chain scanner and LLM reasoning API credentials." author: "Chainlink Labs" -excerpt: "Gate transactions with dual-model AI audits inside a TEE and deliver the verdict onchain." +excerpt: "Gate transactions with dual-model AI audits inside a TEE and deliver the verdict onchain in TypeScript or Go." image: "thumbnail.jpg" +cliTemplateIds: + - label: "TypeScript" + id: "ai-audit-firewall-ts" + - label: "Go" + id: "ai-audit-firewall-go" tags: - "confidential" - "ai" - "security" -githubUrl: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/ai-audit-firewall" +githubUrl: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/confidential-workflows/ai-audit-firewall" githubRepoLinks: - label: "TypeScript" - url: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/ai-audit-firewall" + url: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/confidential-workflows/ai-audit-firewall/ai-audit-firewall-ts" + - label: "Go" + url: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/confidential-workflows/ai-audit-firewall/ai-audit-firewall-go" datePublished: "2026-08-04" -lastModified: "2026-08-04" +lastModified: "2026-08-06" --- import { Aside, Accordion } from "@components" -## What This Template Does + + +This workflow runs inside a **Trusted Execution Environment (TEE)** and acts as a confidential gate for proposed +token interactions. Contract source, transaction details, and model prompts never leave the confidential runtime. +The TypeScript and Go implementations are behaviorally equivalent - pick whichever language you build in. + +**Quick navigation:** + +- [TypeScript Implementation](#typescript-implementation) +- [Go Implementation](#go-implementation) + +--- -This workflow runs inside a **Trusted Execution Environment (TEE)** and acts as a confidential gate for proposed token interactions. Contract source, transaction details, and model prompts never leave the confidential runtime. +## What This Template Does On every cron execution the workflow: -1. Fetches a **proposed transaction** -2. Fetches the **token and protocol contract artifacts** from a scanner service +1. Fetches a **proposed transaction**, including the token and protocol contract addresses +2. Fetches the **token and protocol contract artifacts** from a scanner service, verifying scanner credential permissions before trusting the fetched data 3. Runs **two independent LLM audits** — the second receives the first analysis as prior context 4. Merges the risk flags and decides **ALLOW**, **DENY**, or **MANUAL_REVIEW** 5. Writes an audit log entry and a firewall action 6. Optionally writes the verdict onchain with `EVMClient` @@ -64,29 +88,30 @@ The `determineVerdict` function merges both analyses: ## Prerequisites -- **[Bun](https://bun.com/docs/installation)** — the repository is configured as a Bun workspace +- **[Bun](https://bun.com/docs/installation)** — used to install dependencies and to run the shared mock server (both languages) +- **[Go](https://go.dev/dl/) 1.25 or later** — only if you are building the Go implementation - **[Chainlink CRE CLI](https://docs.chain.link/cre/getting-started/cli-installation)** installed and configured - **Git** for cloning the repository - **A funded wallet on Ethereum Sepolia** — only if you want to test the optional onchain delivery path -## Setup +`ai-audit-firewall/` is a single CRE project shared by both languages — `project.yaml`, `secrets.yaml`, `.env.example`, and `contracts/` live at the project root, with `ai-audit-firewall-ts/` and `ai-audit-firewall-go/` as sibling workflow directories underneath it. + +## TypeScript Implementation + +### Getting Started with TypeScript ```bash -git clone https://github.com/smartcontractkit/confidential-compute-examples.git -cd confidential-compute-examples +git clone https://github.com/smartcontractkit/cre-templates.git +cd cre-templates/starter-templates/confidential-workflows/ai-audit-firewall bun install ``` -`bun install` at the repository root installs dependencies for every workflow because the repo is a Bun workspace. - -From the repository root: - ```bash cp .env.example .env ``` @@ -100,13 +125,13 @@ MOCK_PRIMARY_LLM_API_KEY=mock-primary-llm-key MOCK_SECONDARY_LLM_API_KEY=mock-secondary-llm-key ``` -`secrets.yaml` at the repository root maps the logical secret IDs to these environment variables. +`secrets.yaml` maps the logical secret IDs to these environment variables. -Open `ai-audit-firewall/config.staging.json`: +Open `ai-audit-firewall-ts/config.staging.json`: ```json { @@ -133,7 +158,6 @@ Open `ai-audit-firewall/config.staging.json`: ```bash -cd ai-audit-firewall bun run typecheck bun run test ``` @@ -142,7 +166,7 @@ bun run test -From the repository root: +From the project root: ```bash bun run mock:server @@ -154,19 +178,92 @@ The server listens on `http://127.0.0.1:8787` and serves this workflow's routes -In a new terminal, from the repository root: +In a new terminal, from the project root: ```bash -cre workflow simulate ./ai-audit-firewall --target=staging-settings +cre workflow simulate ./ai-audit-firewall-ts --target=staging-settings ``` The workflow logs each stage (`audit-firewall-onchain-report-start`, `audit-firewall-complete`) and returns a JSON result containing the verdict, reasoning, merged risk flags, both model analyses, the audit log ID, and the firewall action ID. +## Go Implementation + +### Getting Started with Go + + + +From the shared project root: + +```bash +cp ../.env.example ../.env +``` + +`../secrets.yaml` maps the same logical secret IDs shown above to these environment variables. + + + + + +```bash +cd ai-audit-firewall-go +go vet ./... +go test ./... +``` + + + + + +From the `ai-audit-firewall-go` directory (requires Node or Bun): + +```bash +bun mock-server.js +``` + + + + + +In a new terminal, from the project root: + +```bash +cre workflow simulate ./ai-audit-firewall-go --target=staging-settings +``` + + + +### Confidentiality Boundary (Go) + +The handler is registered with `cre.HandlerInTee`, so it receives a `cre.TeeRuntime` rather than a `cre.Runtime`. Scanner and model credentials are released by the Vault DON directly into the attested enclave and decrypted only when `GetSecret()` runs; HTTP calls go through `client.SendRequestInTee(runtime, ...)`, keeping URLs, headers, contract source, and model reasoning confidential from node operators. The only place that leaves the enclave is `writeVerdictOnChain`, which calls `runtime.UsingTheDons()` — and only the verdict code, the risk-flag bitmask, and the chain selector cross that boundary. The contract source, model reasoning, and scanner credentials never do. + + + +### Restrictions (Go pre-hook) + +The Go implementation registers with `cre.HandlerInTeeWithPreHook`. The pre-hook runs **in the DON, before the enclave executes**, and returns a closed capability set for that execution: + +| Restriction | Value | Why | +| ---------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| Capability set type | `CLOSED` | Any capability call not listed below is rejected outright | +| `maxTotalCalls` | 10 | Overall ceiling across all capabilities | +| `http-actions@1.0.0-alpha` / `SendRequest` | 8 | Steady state is 7 calls (proposal, credential check, 2 contract fetches, 2 model calls, audit log, firewall action); 8 leaves one call of headroom | +| `consensus@1.0.0-alpha` / `Report` | 1 | One signed report per run | +| `evm:ChainSelector:@1.0.0` / `WriteReport` | 1 | One onchain write per run, scoped to the configured chain | +| `maxSecrets` | 3 | Exact-match only, in the `main` namespace | + +The EVM restriction is added only when an EVM target is configured, keeping the onchain leg opt-in. Because the set is closed, adding a capability call to the workflow means raising the matching limit here, or the run gets cut off by its own restrictions. + ## Secrets -`config.staging.json` expects these secret IDs in `secrets_ids`: +Both implementations expect these secret IDs in `secrets_ids`: - `scanner_api_key` - `primary_llm_api_key` @@ -210,9 +307,34 @@ Set `evms[0]` in your config file: +## TEE Constraints + +The third argument to the TEE handler API declares which enclaves the handler accepts: + +```ts +{ +} // any registered TEE, any region +{ + regions: ["us-west-2"] +} // any TEE, restricted to a region +;[{ tee: "nitro", regions: ["us-west-2"] }] // specific TEE types and regions +``` + +```go +cre.AnyTee{} // any registered TEE, any region +cre.AnyTeeInRegions{Regions: []cre.Region{cre.AwsUsWest2}} // any TEE, restricted to a region +cre.OneOfTees{cre.Nitro{Regions: []cre.NitroRegion{cre.NitroUsWest2}}} // specific TEEs and regions +``` + +AWS Nitro in `us-west-2` is currently the only registered TEE type and region. In Go, each TEE binding owns its own +region enum, so passing a region a TEE does not support is a compile-time error. + ## Production Checklist 1. Replace the example URLs in `config.production.json` with real endpoints @@ -227,3 +349,11 @@ Set `evms[0]` in your config file: - **Simulation failures tied to RPC config** usually come from incorrect `project.yaml` target values - **Model responses that fail to parse** mean your configured endpoint is not returning the expected JSON payload shape — the workflow expects `riskFlags`, `recommendation`, `confidence`, and `reasoning` - **Onchain write failures** mean the consumer rejected the report; confirm the forwarder address configured on the contract matches the mode you are simulating or deploying in +- **Go simulation cut off mid-run** usually means a capability call was added without raising the matching limit in the pre-hook's restriction set + +## Further Reading + +- [Confidential Workflows in CRE](https://docs.chain.link/cre/concepts/confidential-workflows) - concepts and use cases +- [Making a Workflow Confidential](https://docs.chain.link/cre/guides/workflow/using-confidential-workflows) - step-by-step guide +- [Confidential Workflows Client SDK Reference](https://docs.chain.link/cre/reference/sdk/confidential-workflows-client) - full API +- [Hello Confidential Workflows](/cre-templates/hello-confidential-workflows) - the minimal version of this pattern diff --git a/src/content/cre-templates/automated-liquidation-protection.mdx b/src/content/cre-templates/automated-liquidation-protection.mdx index 061e5706f7f..782b09bec2f 100644 --- a/src/content/cre-templates/automated-liquidation-protection.mdx +++ b/src/content/cre-templates/automated-liquidation-protection.mdx @@ -2,25 +2,47 @@ title: "Automated Liquidation Protection" description: "Automatically protect DeFi lending positions by continuously monitoring liquidation risk and executing collateral management, debt repayment, position reduction, or hedging strategies while preserving the confidentiality of centralized exchange as well as LLM API keys, proprietary risk management thresholds, and execution preferences." author: "Chainlink Labs" -excerpt: "Run policy-constrained liquidation defense confidentially with CRE and TEE execution." +excerpt: "Run policy-constrained liquidation defense confidentially with CRE and TEE execution in TypeScript or Go." image: "thumbnail.jpg" +cliTemplateIds: + - label: "TypeScript" + id: "automated-liquidation-protection-ts" + - label: "Go" + id: "automated-liquidation-protection-go" tags: - "confidential" - "liquidation" - "defi" -githubUrl: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/automated-liquidation-protection" +githubUrl: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/confidential-workflows/automated-liquidation-protection" githubRepoLinks: - label: "TypeScript" - url: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/automated-liquidation-protection" + url: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/confidential-workflows/automated-liquidation-protection/automated-liquidation-protection-ts" + - label: "Go" + url: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/confidential-workflows/automated-liquidation-protection/automated-liquidation-protection-go" datePublished: "2026-08-04" -lastModified: "2026-08-04" +lastModified: "2026-08-06" --- import { Aside, Accordion } from "@components" -## What This Template Does + + +This workflow runs inside a **Trusted Execution Environment (TEE)** and generates a policy-constrained defense plan +for a leveraged position. Risk data, policy parameters, and model prompts never leave the confidential runtime. The +TypeScript and Go implementations are behaviorally equivalent - pick whichever language you build in. + +**Quick navigation:** + +- [TypeScript Implementation](#typescript-implementation) +- [Go Implementation](#go-implementation) + +--- -This workflow runs inside a **Trusted Execution Environment (TEE)** and generates a policy-constrained defense plan for a leveraged ETH position. Risk data, policy parameters, and model prompts never leave the confidential runtime. +## What This Template Does On every cron execution the workflow: @@ -34,8 +56,10 @@ On every cron execution the workflow: If the position is healthy or no action survives the policy filter, the workflow returns `SAFE` without executing anything. @@ -67,53 +91,56 @@ The policy is fetched at runtime and bounds everything the model is allowed to d - `preferred_venues` — venue allowlist used when routing each action ## Prerequisites -- **[Bun](https://bun.com/docs/installation)** — the repository is configured as a Bun workspace +- **[Bun](https://bun.com/docs/installation)** — used to install dependencies and to run the shared mock server (both languages) +- **[Go](https://go.dev/dl/) 1.25 or later** — only if you are building the Go implementation - **[Chainlink CRE CLI](https://docs.chain.link/cre/getting-started/cli-installation)** installed and configured - **Git** for cloning the repository -## Setup +`automated-liquidation-protection/` is a single CRE project shared by both languages — `project.yaml`, `secrets.yaml`, and `.env.example` live at the project root, with `automated-liquidation-protection-ts/` and `automated-liquidation-protection-go/` as sibling workflow directories underneath it. + +## TypeScript Implementation + +### Getting Started with TypeScript ```bash -git clone https://github.com/smartcontractkit/confidential-compute-examples.git -cd confidential-compute-examples +git clone https://github.com/smartcontractkit/cre-templates.git +cd cre-templates/starter-templates/confidential-workflows/automated-liquidation-protection bun install ``` -`bun install` at the repository root installs dependencies for every workflow because the repo is a Bun workspace. - -From the repository root: - ```bash cp .env.example .env ``` -Set the values you want to use. The mock keys are used by both the workflow and the shared demo server: +Provide values for the required environment variables: -```bash -MOCK_PORT=8787 -MOCK_EXCHANGE_API_KEY=mock-exchange-key -MOCK_OPENAI_API_KEY=mock-openai-key -``` +- `CRE_ETH_PRIVATE_KEY` (optional for local simulate) +- `MOCK_PORT`, `MOCK_EXCHANGE_API_KEY`, `MOCK_OPENAI_API_KEY` +- `MOCK_LIQUIDATION_WARNING_ACTION_THRESHOLD`, `MOCK_LIQUIDATION_MINIMUM_HEALTH_FACTOR`, `MOCK_LIQUIDATION_TARGET_HEALTH_FACTOR` +- `MOCK_LIQUIDATION_MAX_STABLECOIN_RESERVE_DEPLOYMENT`, `MOCK_LIQUIDATION_MIN_STABLECOIN_RESERVE_BALANCE`, `MOCK_LIQUIDATION_MAX_COLLATERAL_ALLOCATION` +- `MOCK_LIQUIDATION_MAX_PARTIAL_DEBT_REPAYMENT`, `MOCK_LIQUIDATION_DEFENSIVE_ACTION_SEQUENCING_PREFERENCE`, `MOCK_LIQUIDATION_PREFERRED_VENUES` -`secrets.yaml` at the repository root maps the logical secret IDs to these environment variables. +`secrets.yaml` maps the exchange and model secret IDs to their environment variables. The local mock server only exposes routes under `/liquidation/*`. -Open `automated-liquidation-protection/config.staging.json`: +Open `automated-liquidation-protection-ts/config.staging.json`: ```json { @@ -137,7 +164,6 @@ Open `automated-liquidation-protection/config.staging.json`: ```bash -cd automated-liquidation-protection bun run typecheck bun run test ``` @@ -146,7 +172,7 @@ bun run test -From the repository root: +From the project root: ```bash bun run mock:server @@ -158,19 +184,105 @@ The server listens on `http://127.0.0.1:8787` and serves this workflow's routes -In a new terminal, from the repository root: +In a new terminal, from the project root: ```bash -cre workflow simulate ./automated-liquidation-protection --target=staging-settings +cre workflow simulate ./automated-liquidation-protection-ts --target=staging-settings ``` The workflow logs each stage (`liquidation-getsecret-ok`, `liquidation-defense-executed`) and returns either `SAFE` or a JSON summary with the status, action count, risk score, and execution ID. +## Go Implementation + +### Getting Started with Go + + + +From the shared project root: + +```bash +cp ../.env.example ../.env +``` + +`../secrets.yaml` maps the same logical secret IDs shown above to these environment variables. + + + + + +```bash +cd automated-liquidation-protection-go +go vet ./... +go test ./... +``` + + + + + +From the `automated-liquidation-protection-go` directory (requires Node or Bun): + +```bash +bun mock-server.js +``` + + + + + +In a new terminal, from the project root: + +```bash +cre workflow simulate ./automated-liquidation-protection-go --target=staging-settings +``` + + + +### Confidentiality Boundary (Go) + +The handler is registered with `cre.HandlerInTee`, so it receives a `cre.TeeRuntime` rather than a `cre.Runtime`. Policy secrets are released by the Vault DON directly into the attested enclave and decrypted only when `GetSecret()` runs; HTTP calls go through `client.SendRequestInTee(runtime, ...)`, keeping URLs, headers, and response bodies confidential from node operators. What is not confidential is the workflow binary itself — the logic is provided to the enclave by the Workflow DON and is revealed. `runtime.UsingTheDons()` is a one-way door: anything passed to a capability call there is no longer confidential. + +This template logs only non-sensitive markers (`liquidation-getsecret-ok`, action counts), and its tests assert that no secret reaches the logs — but remove the log lines entirely before deploying to production. + +## TEE Constraints + +The third argument to the TEE handler API declares which enclaves the handler accepts: + +```ts +{ +} // any registered TEE, any region +{ + regions: ["us-west-2"] +} // any TEE, restricted to a region +;[{ tee: "nitro", regions: ["us-west-2"] }] // specific TEE types and regions +``` + +```go +cre.AnyTee{} // any registered TEE, any region +cre.AnyTeeInRegions{Regions: []cre.Region{cre.AwsUsWest2}} // any TEE, restricted to a region +cre.OneOfTees{cre.Nitro{Regions: []cre.NitroRegion{cre.NitroUsWest2}}} // specific TEEs and regions +``` + +AWS Nitro in `us-west-2` is currently the only registered TEE type and region. In Go, each TEE binding owns its own +region enum, so passing a region a TEE does not support is a compile-time error. + +## Configuration + +`config.staging.json`: + +| Field | Description | +| --------------- | --------------------------------------------------------- | +| `schedule` | Cron expression (6 fields, seconds first) | +| `mock_base_url` | Base URL for the risk-state and execute-defense endpoints | +| `openai_url` | Reasoning endpoint called from inside the enclave | +| `openai_model` | Model name passed to the reasoning endpoint | +| `secrets_ids` | Maps each policy input to a secret ID in `secrets.yaml` | + ## Secrets -`config.staging.json` expects these secret IDs in `secrets_ids`: +Both implementations expect these secret IDs in `secrets_ids`: - `exchange_api_key` - `openai_api_key` @@ -187,3 +299,10 @@ The workflow logs each stage (`liquidation-getsecret-ok`, `liquidation-defense-e - **401 responses from the APIs** usually indicate a secret mismatch between `.env`, `secrets.yaml`, and `secrets_ids` in the config file - **Simulation failures tied to RPC config** usually come from incorrect `project.yaml` target values - **Model responses that fail to parse** mean your configured endpoint is not returning the expected JSON payload shape — the workflow expects `shouldDefend`, `reasoning`, and `actions` + +## Further Reading + +- [Confidential Workflows in CRE](https://docs.chain.link/cre/concepts/confidential-workflows) - concepts and use cases +- [Making a Workflow Confidential](https://docs.chain.link/cre/guides/workflow/using-confidential-workflows) - step-by-step guide +- [Confidential Workflows Client SDK Reference](https://docs.chain.link/cre/reference/sdk/confidential-workflows-client) - full API +- [Hello Confidential Workflows](/cre-templates/hello-confidential-workflows) - the minimal version of this pattern diff --git a/src/content/cre-templates/automated-portfolio-rebalancing.mdx b/src/content/cre-templates/automated-portfolio-rebalancing.mdx index 9148db1d693..5793304a61a 100644 --- a/src/content/cre-templates/automated-portfolio-rebalancing.mdx +++ b/src/content/cre-templates/automated-portfolio-rebalancing.mdx @@ -2,25 +2,48 @@ title: "Automated Portfolio Rebalancing" description: "Automatically rebalance crypto portfolios by continuously monitoring allocation drift and executing portfolio adjustments when predefined thresholds are exceeded, while preserving the confidentiality of exchange API keys, LLM reasoning, portfolio allocation thresholds, and execution preferences." author: "Chainlink Labs" -excerpt: "Rebalance a portfolio confidentially with policy-constrained, LLM-assisted trade execution." +excerpt: "Rebalance a portfolio confidentially with policy-constrained, LLM-assisted trade execution in TypeScript or Go." image: "thumbnail.jpg" +cliTemplateIds: + - label: "TypeScript" + id: "automated-portfolio-rebalancing-ts" + - label: "Go" + id: "automated-portfolio-rebalancing-go" tags: - "confidential" - "rebalancing" - "defi" -githubUrl: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/automated-portfolio-rebalancing" +githubUrl: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/confidential-workflows/automated-portfolio-rebalancing" githubRepoLinks: - label: "TypeScript" - url: "https://github.com/smartcontractkit/confidential-compute-examples/tree/main/automated-portfolio-rebalancing" + url: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/confidential-workflows/automated-portfolio-rebalancing/automated-portfolio-rebalancing-ts" + - label: "Go" + url: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/confidential-workflows/automated-portfolio-rebalancing/automated-portfolio-rebalancing-go" datePublished: "2026-08-04" -lastModified: "2026-08-04" +lastModified: "2026-08-06" --- import { Aside, Accordion } from "@components" -## What This Template Does + + +This workflow runs inside a **Trusted Execution Environment (TEE)** and generates policy-constrained rebalance +trades when allocation drift exceeds the configured threshold. Holdings, prices, and target allocations never +leave the confidential runtime. The TypeScript and Go implementations are behaviorally equivalent - pick whichever +language you build in. + +**Quick navigation:** + +- [TypeScript Implementation](#typescript-implementation) +- [Go Implementation](#go-implementation) + +--- -This workflow runs inside a **Trusted Execution Environment (TEE)** and generates policy-constrained rebalance trades when allocation drift exceeds the configured threshold. Holdings, prices, and target allocations never leave the confidential runtime. +## What This Template Does On every cron execution the workflow: @@ -35,8 +58,10 @@ On every cron execution the workflow: If no asset has drifted past the threshold, the workflow returns without trading. @@ -53,53 +78,58 @@ The policy is fetched at runtime and bounds every trade the model is allowed to - `preferred_venues` — venue allowlist used when routing each chunk ## Prerequisites -- **[Bun](https://bun.com/docs/installation)** — the repository is configured as a Bun workspace +- **[Bun](https://bun.com/docs/installation)** — used to install dependencies and to run the shared mock server (both languages) +- **[Go](https://go.dev/dl/) 1.25 or later** — only if you are building the Go implementation - **[Chainlink CRE CLI](https://docs.chain.link/cre/getting-started/cli-installation)** installed and configured - **Git** for cloning the repository -## Setup +`automated-portfolio-rebalancing/` is a single CRE project shared by both languages — `project.yaml`, `secrets.yaml`, and `.env.example` live at the project root, with `automated-portfolio-rebalancing-ts/` and `automated-portfolio-rebalancing-go/` as sibling workflow directories underneath it. + +## TypeScript Implementation + +### Getting Started with TypeScript ```bash -git clone https://github.com/smartcontractkit/confidential-compute-examples.git -cd confidential-compute-examples +git clone https://github.com/smartcontractkit/cre-templates.git +cd cre-templates/starter-templates/confidential-workflows/automated-portfolio-rebalancing bun install ``` -`bun install` at the repository root installs dependencies for every workflow because the repo is a Bun workspace. - -From the repository root: - ```bash cp .env.example .env ``` -Set the values you want to use. The mock keys are used by both the workflow and the shared demo server: +Provide values for the required environment variables: -```bash -MOCK_PORT=8787 -MOCK_EXCHANGE_API_KEY=mock-exchange-key -MOCK_OPENAI_API_KEY=mock-openai-key -``` +- `CRE_ETH_PRIVATE_KEY` (optional for local simulate) +- `MOCK_PORT`, `MOCK_EXCHANGE_API_KEY`, `MOCK_OPENAI_API_KEY` +- `MOCK_REBALANCING_TARGET_ALLOCATION_BTC_PCT`, `MOCK_REBALANCING_TARGET_ALLOCATION_ETH_PCT`, `MOCK_REBALANCING_TARGET_ALLOCATION_USDC_PCT` +- `MOCK_REBALANCING_DRIFT_THRESHOLD_PCT`, `MOCK_REBALANCING_MAX_TRADE_USD`, `MOCK_REBALANCING_RESERVE_FLOOR_USDC` +- `MOCK_REBALANCING_MAX_SLIPPAGE_BPS`, `MOCK_REBALANCING_PREFERRED_VENUES`, `MOCK_REBALANCING_ORDER_SEQUENCE_PREFERENCE` -`secrets.yaml` at the repository root maps the logical secret IDs to these environment variables. +`secrets.yaml` maps the exchange and model secret IDs to their environment variables. The local mock server only exposes routes under `/rebalancing/*`. -Open `automated-portfolio-rebalancing/config.staging.json`: +Open `automated-portfolio-rebalancing-ts/config.staging.json`: ```json { @@ -123,7 +153,6 @@ Open `automated-portfolio-rebalancing/config.staging.json`: ```bash -cd automated-portfolio-rebalancing bun run typecheck bun run test ``` @@ -132,7 +161,7 @@ bun run test -From the repository root: +From the project root: ```bash bun run mock:server @@ -144,19 +173,113 @@ The server listens on `http://127.0.0.1:8787` and serves this workflow's routes -In a new terminal, from the repository root: +In a new terminal, from the project root: ```bash -cre workflow simulate ./automated-portfolio-rebalancing --target=staging-settings +cre workflow simulate ./automated-portfolio-rebalancing-ts --target=staging-settings ``` The workflow logs each stage (`rebalance-executed`) and returns a JSON summary with the status, trade count, maximum drift percentage, and execution ID. +## Go Implementation + +### Getting Started with Go + + + +From the shared project root: + +```bash +cp ../.env.example ../.env +``` + +`../secrets.yaml` maps the same logical secret IDs shown above to these environment variables. + + + + + +```bash +cd automated-portfolio-rebalancing-go +go vet ./... +go test ./... +``` + + + + + +From the `automated-portfolio-rebalancing-go` directory (requires Node or Bun): + +```bash +bun mock-server.js +``` + + + + + +In a new terminal, from the project root: + +```bash +cre workflow simulate ./automated-portfolio-rebalancing-go --target=staging-settings +``` + + + +### Confidentiality Boundary (Go) + +The handler is registered with `cre.HandlerInTee`, so it receives a `cre.TeeRuntime` rather than a `cre.Runtime`. Policy secrets are released by the Vault DON directly into the attested enclave and decrypted only when `GetSecret()` runs; HTTP calls go through `client.SendRequestInTee(runtime, ...)`, keeping URLs, headers, and response bodies confidential from node operators. What is not confidential is the workflow binary itself — the logic is provided to the enclave by the Workflow DON and is revealed. `runtime.UsingTheDons()` is a one-way door: anything passed to a capability call there is no longer confidential. + +This template logs only non-sensitive markers (`rebalance-getsecret-ok`, trade counts), and its tests assert that no secret reaches the logs — but remove the log lines entirely before deploying to production. + + + +## TEE Constraints + +The third argument to the TEE handler API declares which enclaves the handler accepts: + +```ts +{ +} // any registered TEE, any region +{ + regions: ["us-west-2"] +} // any TEE, restricted to a region +;[{ tee: "nitro", regions: ["us-west-2"] }] // specific TEE types and regions +``` + +```go +cre.AnyTee{} // any registered TEE, any region +cre.AnyTeeInRegions{Regions: []cre.Region{cre.AwsUsWest2}} // any TEE, restricted to a region +cre.OneOfTees{cre.Nitro{Regions: []cre.NitroRegion{cre.NitroUsWest2}}} // specific TEEs and regions +``` + +AWS Nitro in `us-west-2` is currently the only registered TEE type and region. In Go, each TEE binding owns its own +region enum, so passing a region a TEE does not support is a compile-time error. + +## Configuration + +`config.staging.json`: + +| Field | Description | +| --------------- | ----------------------------------------------------------------------- | +| `schedule` | Cron expression (6 fields, seconds first) | +| `mock_base_url` | Base URL for the portfolio, prices, volatility, and execution endpoints | +| `openai_url` | Reasoning endpoint called from inside the enclave | +| `openai_model` | Model name passed to the reasoning endpoint | +| `secrets_ids` | Maps each policy input to a secret ID in `secrets.yaml` | + ## Secrets -`config.staging.json` expects these secret IDs in `secrets_ids`: +Both implementations expect these secret IDs in `secrets_ids`: - `exchange_api_key` - `openai_api_key` @@ -173,3 +296,10 @@ The workflow logs each stage (`rebalance-executed`) and returns a JSON summary w - **401 responses from the APIs** usually indicate a secret mismatch between `.env`, `secrets.yaml`, and `secrets_ids` in the config file - **Simulation failures tied to RPC config** usually come from incorrect `project.yaml` target values - **Model responses that fail to parse** mean your configured endpoint is not returning the expected JSON payload shape — the workflow expects `shouldRebalance`, `reasoning`, and `trades` + +## Further Reading + +- [Confidential Workflows in CRE](https://docs.chain.link/cre/concepts/confidential-workflows) - concepts and use cases +- [Making a Workflow Confidential](https://docs.chain.link/cre/guides/workflow/using-confidential-workflows) - step-by-step guide +- [Confidential Workflows Client SDK Reference](https://docs.chain.link/cre/reference/sdk/confidential-workflows-client) - full API +- [Hello Confidential Workflows](/cre-templates/hello-confidential-workflows) - the minimal version of this pattern diff --git a/src/content/cre-templates/hello-confidential-workflows.mdx b/src/content/cre-templates/hello-confidential-workflows.mdx index 8146fbd5dc2..b68a7ceecbe 100644 --- a/src/content/cre-templates/hello-confidential-workflows.mdx +++ b/src/content/cre-templates/hello-confidential-workflows.mdx @@ -2,11 +2,13 @@ title: "Hello Confidential Workflows" description: "Quickstart confidential workflow that registers a TEE handler, securely fetches a secret inside the enclave, executes a capability call from within the enclave, and returns to the DON for any operations requiring decentralized consensus." author: "Chainlink Labs" -excerpt: "Learn the minimal end-to-end shape of a CRE Confidential Workflow with TEE execution." +excerpt: "Learn the minimal end-to-end shape of a CRE Confidential Workflow in TypeScript or Go." image: "thumbnail.jpg" cliTemplateIds: - label: "TypeScript" id: "hello-confidential-workflows-ts" + - label: "Go" + id: "hello-confidential-workflows-go" tags: - "confidential" - "tee" @@ -15,32 +17,46 @@ githubUrl: "https://github.com/smartcontractkit/cre-templates/tree/main/starter- githubRepoLinks: - label: "TypeScript" url: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/hello-confidential-workflows/hello-confidential-workflows-ts" + - label: "Go" + url: "https://github.com/smartcontractkit/cre-templates/tree/main/starter-templates/hello-confidential-workflows/hello-confidential-workflows-go" datePublished: "2026-08-04" -lastModified: "2026-08-04" +lastModified: "2026-08-06" --- import { Aside, Accordion } from "@components" +This template shows the smallest useful shape of a confidential CRE workflow: register a handler that runs in a TEE, +pull a secret inside the enclave, make a capability call from inside the enclave, then hand only the non-sensitive +result back to the Workflow DON for consensus-backed operations. + +**Quick navigation:** + +- [TypeScript Implementation](#typescript-implementation) +- [Go Implementation](#go-implementation) + +--- + ## What This Template Does -By default, a CRE workflow's callback runs on Workflow DON nodes, where node operators can in principle inspect what it is computing. That's fine for most workflows — but some logic is sensitive on its own: a risk threshold, a rebalancing policy, a proprietary scoring model. Leaking the policy can be as damaging as leaking a credential. +By default, a CRE workflow callback runs on Workflow DON nodes, where node operators can inspect what it is computing. +That is acceptable for many workflows, but not for logic where the policy, model, or threshold itself is sensitive. -A **[Confidential Workflow](https://docs.chain.link/cre/concepts/confidential-workflows)** moves that part into a hardware-isolated [enclave](https://docs.chain.link/cre/key-terms#enclave). This template is the minimal end-to-end shape of one, in four steps: +A **[Confidential Workflow](https://docs.chain.link/cre/concepts/confidential-workflows)** moves that sensitive part +into a hardware-isolated [enclave](https://docs.chain.link/cre/key-terms#enclave). This template demonstrates the +minimal end-to-end shape in four steps: -| Step | What it demonstrates | API | -| ---- | ---------------------------------------------------- | ----------------------------------------- | -| 1 | Register a handler that runs inside a TEE | `cre.handlerInTee(trigger, fn, tees)` | -| 2 | Fetch a secret inside the enclave | `runtime.getSecret({ id })` | -| 3 | Make a capability call from inside the enclave | `HTTPClient.sendRequest(teeRuntime, req)` | -| 4 | Cross back to the DON for anything needing consensus | `runtime.usingTheDons()` | +| Step | What it demonstrates | API | +| ---- | ---------------------------------------------------- | --------------------------------------------------- | +| 1 | Register a handler that runs inside a TEE | `cre.handlerInTee(trigger, fn, tees)` | +| 2 | Fetch a secret inside the enclave | `runtime.getSecret({ id })` / `runtime.GetSecret()` | +| 3 | Make a capability call from inside the enclave | `HTTPClient.sendRequest(runtime, req)` | +| 4 | Cross back to the DON for anything needing consensus | `runtime.usingTheDons()` | ## Architecture @@ -51,7 +67,7 @@ A **[Confidential Workflow](https://docs.chain.link/cre/concepts/confidential-wo │ DON hands the triggered request to an enclave v ╔══════════════════════════════════════════════════════════════╗ -║ ENCLAVE (TEE — hidden from node operators) ║ +║ ENCLAVE (TEE - hidden from node operators) ║ ║ ║ ║ Step 2: runtime.getSecret({ id: 'API_TOKEN' }) ║ ║ ▲ ║ @@ -68,45 +84,31 @@ A **[Confidential Workflow](https://docs.chain.link/cre/concepts/confidential-wo │ ONLY the verdict + score cross out v ┌──────────────────────────────────────────────────────────────┐ -│ WORKFLOW DON — donRuntime.report({ ... }) │ +│ WORKFLOW DON - donRuntime.report({ ... }) │ │ BFT consensus verifies the enclave attestation, then signs │ └──────────────────────────────────────────────────────────────┘ ``` ## How It Works -`my-workflow/workflow.ts`: +`my-workflow/workflow.ts` and `my-workflow/workflow.go` follow the same confidential pattern: -1. **Registers the cron handler with `cre.handlerInTee`**, constrained to `[{ tee: 'nitro', regions: ['us-west-2'] }]` -2. **Fetches `API_TOKEN`** with `runtime.getSecret()` — the Vault DON releases it only into an attested enclave, and it is decrypted at the moment the call runs -3. **Calls the configured URL** with `HTTPClient.sendRequest(runtime, ...)`, passing the `TeeRuntime` so the request executes from inside the enclave with the secret in the `Authorization` header -4. **Scores the response** against `scoreThreshold` — this stands in for your proprietary logic, and is the part that stays invisible to node operators -5. **Crosses back with `usingTheDons()`** and generates a signed report containing only the verdict and score — never the secret or the raw response - -The default endpoint is `https://postman-echo.com/headers`, which echoes the request headers back — no signup or real API key needed. The workflow uses that to confirm the secret really was injected inside the enclave, reporting it as the boolean `secret reached API: true` rather than by logging the token. It never logs the response body either; the confidentiality boundary is the reason, and it's worth keeping that habit even in simulation. +1. **Register the cron handler with `cre.handlerInTee`**, constrained to `[{ tee: 'nitro', regions: ['us-west-2'] }]` +2. **Fetch `API_TOKEN`** inside the enclave - the Vault DON releases it only into an attested enclave +3. **Call the configured URL** from inside the enclave, sending the secret in the `Authorization` header +4. **Score the response** against `scoreThreshold` - this represents the private policy you want to keep hidden +5. **Cross back with `usingTheDons()`** and report only the verdict and score - never the secret or raw response -## Use Cases - -- **Automated liquidation protection** — keep risk thresholds and the defensive strategy off Workflow DON nodes so they can't be predicted and front-run -- **Portfolio rebalancing** — hide the allocation policy and trade-sizing logic so the rebalance isn't anticipated -- **LLM audit firewall** — keep evaluation criteria and third-party API credentials inside the enclave -- **Payment orchestration** — keep routing logic and account details confidential -- **Proprietary scoring** — compute over licensed or sensitive data without exposing the data or the model - -## Prerequisites - -- **[Bun](https://bun.sh/)** runtime installed -- **[Chainlink CRE CLI](https://docs.chain.link/cre/getting-started/cli-installation)** installed and configured -- **Enrollment in the Confidential Workflows private beta** — required to deploy, not to simulate +## TypeScript Implementation -## Getting Started +### Getting Started with TypeScript @@ -122,7 +124,8 @@ cd my-workflow && bun install && cd .. cp .env.example .env ``` -Set `SECRET_API_TOKEN` in `.env`. `secrets.yaml` maps the workflow-facing secret ID `API_TOKEN` to that environment variable: +Set `SECRET_API_TOKEN` in `.env`. `secrets.yaml` maps the workflow-facing secret ID `API_TOKEN` to that environment +variable: ```yaml secretsNames: @@ -169,9 +172,82 @@ Expected output: Three things to notice: -- The simulator confirms the TEE constraint it resolved (`AWS Nitro in us-west-2`) and warns that **it is not a real enclave** — logs are shown for debugging only. In real execution those logs never leave the TEE. -- `secret reached API: true` means the Vault DON secret was fetched inside the enclave and arrived in the outbound request's `Authorization` header. -- The verdict flips between `APPROVE` and `REJECT` from run to run. That's expected: the score is derived from the live response body, and the echo endpoint includes a per-request trace ID. Lower `scoreThreshold` to see `APPROVE` consistently. +- The simulator confirms the TEE constraint it resolved (`AWS Nitro in us-west-2`) and warns that it is not a real + enclave. In real execution those logs never leave the TEE. +- `secret reached API: true` means the Vault DON secret was fetched inside the enclave and arrived in the outbound + request's `Authorization` header. +- The verdict flips between `APPROVE` and `REJECT` from run to run. That is expected: the score is derived from the + live response body, and the echo endpoint includes a per-request trace ID. + + + +## Go Implementation + +### Getting Started with Go + + + +```bash +cd my-workflow && go mod tidy && cd .. +``` + + + + + +```bash +cp .env.example .env +``` + +Set `SECRET_API_TOKEN` in `.env`. `secrets.yaml` maps the workflow-facing secret ID `API_TOKEN` to that environment +variable: + +```yaml +secretsNames: + API_TOKEN: + - SECRET_API_TOKEN +``` + +With the default echo endpoint, any non-empty value works. + + + + + +```bash +cd my-workflow && go test ./... +``` + + + + + +```bash +cre workflow simulate my-workflow --target staging-settings --non-interactive --trigger-index 0 +``` + +Expected output: + +```text +[SIMULATION] Running trigger trigger=cron-trigger@1.0.0 +╭────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Trigger requested TEE Execution your trigger will run in one of the following Tees: │ +│ - AWS Nitro in us-west-2 │ +│ The simulator is not a real TEE, and is meant to debug. │ +│ Do not use it for sensitive information. │ +│ During real execution, user logs for this trigger will not be visible, and will not leave the TEE. │ +│ They are presented in the simulator for debugging only. │ +╰────────────────────────────────────────────────────────────────────────────────────────────────────╯ + +[USER LOG] Enclave computation complete. verdict=REJECT + +✓ Workflow Simulation Result: +"REJECT (score: 371, secret reached API: true)" +``` + +The Go and TypeScript versions share the same confidential workflow shape. The main differences are the language +tooling and the SDK surface: Go uses `runtime.GetSecret()` and the Go `HTTPClient` implementation, while TypeScript +uses `runtime.getSecret()` and the TypeScript SDK. @@ -179,12 +255,12 @@ Three things to notice: `my-workflow/config.staging.json`: -| Field | Description | -| ---------------- | ----------------------------------------------------------------------- | -| `schedule` | Cron expression (6 fields, seconds first) | -| `url` | Endpoint called from inside the enclave | -| `secretId` | Secret ID fetched with `runtime.getSecret()`; must match `secrets.yaml` | -| `scoreThreshold` | Threshold the confidential scoring compares against | +| Field | Description | +| ---------------- | ----------------------------------------------------------------------------------------------- | +| `schedule` | Cron expression (6 fields, seconds first) | +| `url` | Endpoint called from inside the enclave | +| `secretId` | Secret ID fetched with `runtime.getSecret()` / `runtime.GetSecret()`; must match `secrets.yaml` | +| `scoreThreshold` | Threshold the confidential scoring compares against | ## TEE Constraints @@ -199,57 +275,69 @@ The third argument to `handlerInTee` declares which enclaves the handler accepts ;[{ tee: "nitro", regions: ["us-west-2"] }] // specific TEE types and regions ``` -AWS Nitro in `us-west-2` is currently the only registered TEE type and region. This is an actively evolving alpha API — check your installed SDK version if you expect otherwise. +AWS Nitro in `us-west-2` is currently the only registered TEE type and region. ## Confidentiality Boundary -Understanding what is and isn't protected matters more here than in a regular workflow. +Understanding what is and is not protected matters more here than in a regular workflow. -| Protected by default | **Not** automatically protected | -| ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -| Secrets the Vault DON releases into the enclave | Triggers, chain reads, and chain writes — these always run on Workflow DON nodes | -| Sensitive inputs and intermediate values you don't share outside the enclave | Your workflow's **source code and deployed binary** | -| Capability calls made from inside the enclave | Capability calls not routed through the enclave | -| Enclave execution memory, while your computation runs | Reports, calldata, and any output you deliver outside the enclave | +| Protected by default | **Not** automatically protected | +| ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| Secrets the Vault DON releases into the enclave | Triggers, chain reads, and chain writes - these always run on Workflow DON nodes | +| Sensitive inputs and intermediate values you do not share outside the enclave | Your workflow's **source code and deployed binary** | +| Capability calls made from inside the enclave | Capability calls not routed through the enclave | +| Enclave execution memory, while your computation runs | Reports, calldata, and any output you deliver outside the enclave | Consequences worth internalizing: -- **Your source and binary are readable.** If the logic itself is the secret, make sure it actually _executes_ inside the enclave — don't rely on the binary being opaque, because it isn't. -- **`usingTheDons()` is a one-way door.** Anything you pass into a capability call on that runtime executes on Workflow DON nodes like any non-confidential call. Cross over only what doesn't need to stay hidden. -- **Don't log from inside the enclave in production.** Logs leave the confidentiality boundary. This template logs only the verdict, and the comment marks it for removal before deploying. +- **Your source and binary are readable.** If the logic itself is the secret, make sure it actually executes inside + the enclave - do not rely on the binary being opaque, because it is not. +- **`usingTheDons()` is a one-way door.** Anything you pass into a capability call on that runtime executes on + Workflow DON nodes like any non-confidential call. Cross over only what does not need to stay hidden. +- **Do not log from inside the enclave in production.** Logs leave the confidentiality boundary. This template logs + only the verdict, and the comment marks it for removal before deploying. - **Keep enclave logic deterministic.** The enclave result is attested and verified by DON consensus. -- **Enclaves are not tenant-isolated today.** A single enclave can run confidential workflows from multiple customers concurrently, sharing execution memory. Isolation between confidential executions is planned, not part of the current beta. +- **Enclaves are not tenant-isolated today.** A single enclave can run confidential workflows from multiple customers + concurrently, sharing execution memory. Isolation between confidential executions is planned, not part of the + current beta. ## Which Secrets Belong in an Enclave? Not every secret needs enclave-level protection. -**Higher value — consider enclave execution:** wallet and CA private keys; exchange, custody, payment-processor, banking, or LLM-provider credentials; OAuth client secrets, JWT signing keys, KMS keys; payment data, health data, other PII. +**Higher value - consider enclave execution:** wallet and CA private keys; exchange, custody, payment-processor, +banking, or LLM-provider credentials; OAuth client secrets, JWT signing keys, KMS keys; payment data, health data, +other PII. -**Lower value — regular DON execution is usually fine:** API keys for publicly available data (weather, explorers, public price feeds, public RPCs); public wallet addresses. +**Lower value - regular DON execution is usually fine:** API keys for publicly available data (weather, explorers, +public price feeds, public RPCs); public wallet addresses. The common thread: a secret belongs in the enclave if disclosure would expose more than the workflow needs. ## Customization -- **Put your real logic in the enclave** — replace `scoreResponse` in `workflow.ts` with the policy, threshold, or model you need to keep private -- **Deliver the report onchain** — pass the report from Step 4 to `evmClient.writeReport(donRuntime, report)`; the RPCs in `project.yaml` are already set up for Sepolia. See the [Keeper Bot](/cre-templates/keeper-bot) or [Event Reactor](/cre-templates/event-reactor) templates for the full write path -- **Change the trigger** — `handlerInTee` accepts any CRE trigger, same as `handler`; swap cron for a log trigger to react to onchain events confidentially -- **Fetch more secrets** — call `runtime.getSecret()` once per secret; the TypeScript `SecretsProvider` has no batch variant +- **Put your real logic in the enclave** - replace `scoreResponse` in `workflow.ts` or `workflow.go` with the policy, + threshold, or model you need to keep private +- **Deliver the report onchain** - pass the report from Step 4 to `evmClient.writeReport(donRuntime, report)`; the + RPCs in `project.yaml` are already set up for Sepolia. See the [Keeper Bot](/cre-templates/keeper-bot) or [Event + Reactor](/cre-templates/event-reactor) templates for the full write path +- **Change the trigger** - `handlerInTee` accepts any CRE trigger, same as `handler`; swap cron for a log trigger to + react to onchain events confidentially +- **Fetch more secrets** - call `runtime.getSecret()` / `runtime.GetSecret()` once per secret ## Security -- Never commit `.env` files or secrets — `.gitignore` covers `*.env` +- Never commit `.env` files or secrets - `.gitignore` covers `*.env` - Remove or gate every `runtime.log()` inside the TEE handler before deploying - Audit what crosses `usingTheDons()`; that data is no longer confidential ## Further Reading -- [Confidential Workflows in CRE](https://docs.chain.link/cre/concepts/confidential-workflows) — concepts and use cases -- [Making a Workflow Confidential](https://docs.chain.link/cre/guides/workflow/using-confidential-workflows) — step-by-step guide -- [Confidential Workflows Client SDK Reference](https://docs.chain.link/cre/reference/sdk/confidential-workflows-client) — full API -- [Confidential HTTP](https://docs.chain.link/cre/capabilities/confidential-http) — for a single outbound request, without a full confidential handler -- [confidential-compute-examples](https://github.com/smartcontractkit/confidential-compute-examples) — production-shaped reference workflows +- [Confidential Workflows in CRE](https://docs.chain.link/cre/concepts/confidential-workflows) - concepts and use cases +- [Making a Workflow Confidential](https://docs.chain.link/cre/guides/workflow/using-confidential-workflows) - step-by-step guide +- [Confidential Workflows Client SDK Reference](https://docs.chain.link/cre/reference/sdk/confidential-workflows-client) - full API +- [Confidential HTTP](https://docs.chain.link/cre/capabilities/confidential-http) - for a single outbound request, without a full confidential handler +- [confidential-compute-examples](https://github.com/smartcontractkit/confidential-compute-examples) - production-shaped reference workflows