diff --git a/src/content/cre-templates/ai-audit-firewall.mdx b/src/content/cre-templates/ai-audit-firewall.mdx index 6b28b707db0..b8e0e17f6bd 100644 --- a/src/content/cre-templates/ai-audit-firewall.mdx +++ b/src/content/cre-templates/ai-audit-firewall.mdx @@ -15,7 +15,7 @@ githubRepoLinks: - 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-06" +lastModified: "2026-08-17" --- import { Aside } from "@components" @@ -23,128 +23,204 @@ import { Aside } from "@components" -This standalone CRE project implements a confidential pre-execution security firewall for smart contract interactions. +## What this template does -## Description +This CRE workflow implements a confidential pre-execution security firewall for smart contract interactions. Before a proposed transaction is allowed to proceed, the workflow fetches token and protocol contract artifacts from a blockchain scanner, submits them to two independent AI reasoning models, and enforces a security verdict. All scanner and LLM credentials remain protected inside confidential execution throughout the process. -The workflow screens proposed transactions before they are allowed to proceed. It fetches and validates contract -intelligence, runs confidential reasoning to classify risk, and then enforces a firewall decision path. Scanner and -model credentials remain protected inside confidential execution throughout the process. +**Data flow:** -## Target Customer +1. Receive a candidate transaction containing token and protocol contract addresses. +2. Validate scanner credential scopes (`verification:read`, `contracts:read`) before trusting fetched data. +3. Fetch source and ABI artifacts for both contracts through the scanner. +4. Verify that both contracts are on-chain verified. Unverified contracts result in an immediate denial. +5. Submit each contract to independent primary and secondary reasoning models in sequence, using primary analysis results as prior context for the secondary model. +6. Merge risk flags from both models using OR logic and determine the final verdict. +7. Post audit and firewall action records to the database log. +8. Optionally deliver the signed verdict on-chain to a consumer contract. -- Professional retail traders -- Developer shops -- Founders building trading products +## Risk Flags and Verdict Logic -## Structure +### Risk flags -- `project.yaml`: project-level target settings -- `secrets.yaml`: secret ID mappings used by the workflow -- `mock-server.js`: local deterministic API server -- `ai-audit-firewall-ts/`: TypeScript workflow implementation -- `ai-audit-firewall-go/`: Go workflow implementation +Both models independently classify contract behavior into four structured risk signals: -## Private Inputs +| Flag | Description | +| --------------------- | -------------------------------------------------------------- | +| `obfuscatedTax` | Hidden fee or tax mechanism detected in the contract | +| `privilegeEscalation` | Owner or operator can drain funds or alter critical parameters | +| `externalCallRisk` | Calls to external contracts that can alter contract behavior | +| `logicBomb` | Dormant code that activates under a specific condition | -The following inputs are handled as confidential: +Risk flags from both models are merged with OR logic: if either model sets a flag, it is included in the final risk assessment. -- Chain scanner API credentials used for contract metadata retrieval and verification checks. -- LLM reasoning API credentials used for independent audit analysis. +### Verdict logic -## Workflow Notes +| Verdict | Condition | +| --------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `DENY` | Either contract is unverified, or any merged risk flag is `true` | +| `MANUAL_REVIEW` | Either model recommends review, either model has confidence below 0.7, or the two models disagree on their recommendation | +| `ALLOW` | No risk flags detected, both models recommend allow, and both models have confidence ≥ 0.7 | -1. Monitor and ingest the proposed interaction. - The workflow receives candidate transaction context, including token and protocol contract addresses. -2. Fetch and validate contract data confidentially. - It retrieves source and ABI artifacts through the scanner and verifies scanner credential permissions before trusting fetched data. -3. Run smart contract audit analysis. - The workflow submits context to multiple reasoning models and classifies behavior into structured risk signals: - - `obfuscatedTax` - - `privilegeEscalation` - - `externalCallRisk` - - `logicBomb` -4. Enforce firewall action and record outcomes. - Based on aggregate risk, the workflow allows execution, blocks malicious interactions, or routes the attempt for manual review while preserving audit and action logs. +## Prerequisites -Note: Any reasoning stage can be replaced with deterministic rule-based logic if a purely policy-engine implementation is preferred. +- [Bun](https://bun.sh) runtime +- CRE CLI (`cre`) +- A blockchain scanner account with an API key that has `verification:read` and `contracts:read` scopes +- API keys for two LLM reasoning endpoints (primary and secondary) -## Required Environment Variables +## Configuration -Copy `.env.example` to `.env` and provide values for: +The workflow ships with two config files: -- `CRE_ETH_PRIVATE_KEY` (optional for local simulate, required for real chain writes) -- `MOCK_PORT` -- `MOCK_SCANNER_API_KEY` -- `MOCK_PRIMARY_LLM_API_KEY` -- `MOCK_SECONDARY_LLM_API_KEY` +- `ai-audit-firewall-ts/config.staging.json` (TypeScript) and `ai-audit-firewall-go/config.staging.json` (Go): targets mock server endpoints and Ethereum Sepolia testnet +- `ai-audit-firewall-ts/config.production.json` (TypeScript) and `ai-audit-firewall-go/config.production.json` (Go): same structure with empty URLs for you to populate -The local mock server for this project only exposes routes under `/audit-firewall/*`. +Key fields: -**Quick navigation:** +| Field | Description | +| -------------------------------------- | ----------------------------------------------------------------------------------- | +| `schedule` | Cron expression for execution frequency. Default: `0 */5 * * * *` (every 5 minutes) | +| `scanner_url` | Scanner API endpoint for contract metadata and verification | +| `primary_llm_url` | Primary reasoning model endpoint | +| `secondary_llm_url` | Secondary reasoning model endpoint | +| `secrets_ids.scanner_api_key_id` | Secret ID for scanner credentials | +| `secrets_ids.primary_llm_api_key_id` | Secret ID for primary model credentials | +| `secrets_ids.secondary_llm_api_key_id` | Secret ID for secondary model credentials | +| `mock_base_url` | Base URL used for audit log and firewall action posts. Required even in production. | +| `evms[].chain_selector_name` | Target chain for on-chain verdict delivery. Remove the `evms` array to disable. | +| `evms[].consumer_address` | Deployed `AuditFirewallConsumer` contract address | +| `evms[].gas_limit` | Gas limit for on-chain verdict writes | -- [TypeScript Quick Start](#typescript-quick-start) -- [Go Quick Start](#go-quick-start) +## Secrets -## TypeScript Quick Start +Copy `.env.example` to `.env` and populate all values before running locally. + +| Environment variable | Secret ID | Purpose | +| ---------------------------- | ----------------------- | -------------------------------------------------------------------------------- | +| `MOCK_SCANNER_API_KEY` | `scanner_api_key` | Authenticates requests to the blockchain scanner | +| `MOCK_PRIMARY_LLM_API_KEY` | `primary_llm_api_key` | Authenticates requests to the primary reasoning model | +| `MOCK_SECONDARY_LLM_API_KEY` | `secondary_llm_api_key` | Authenticates requests to the secondary reasoning model | +| `CRE_ETH_PRIVATE_KEY` | _(framework-level)_ | Signs transactions for on-chain verdict delivery. Optional for local simulation. | + +Secret IDs are referenced in `secrets.yaml` and mapped to their corresponding secret IDs in `config.staging.json` under `secrets_ids`. For production, register each secret with the CRE secrets manager using those IDs. + +## Quick start + +**TypeScript** + +Run all commands from the `ai-audit-firewall` directory (the project root). 1. Install dependencies -```bash -bun install -``` + ```bash + cd ai-audit-firewall-ts && bun install && cd .. + ``` 2. Create environment file -```bash -cp .env.example .env -``` + ```bash + cp .env.example .env + ``` 3. Start mock server -```bash -bun run mock:server -``` + ```bash + cd ai-audit-firewall-ts && bun run mock:server + ``` + +4. In another terminal, run checks and simulate + + ```bash + cd ai-audit-firewall-ts + bun run typecheck + bun run test + cd .. && cre workflow simulate ./ai-audit-firewall-ts --project-root ./ --target=staging-settings --env ./.env + ``` + +**Go** + +Run all commands from the `ai-audit-firewall` directory (the project root). + +1. Create environment file + + ```bash + cp .env.example .env + ``` + +2. Start the mock server from the TypeScript directory (requires Node or Bun) + + ```bash + cd ai-audit-firewall-ts && bun run mock:server + ``` + +3. In another terminal, run checks and simulate + + ```bash + cd ai-audit-firewall-go + go vet ./... + go test ./... + cd .. && cre workflow simulate ./ai-audit-firewall-go --project-root ./ --target=staging-settings --env ./.env + ``` + +## Production checklist + +- Populate `config.production.json` with real `scanner_url`, `primary_llm_url`, `secondary_llm_url`, and `mock_base_url`. +- Register `scanner_api_key`, `primary_llm_api_key`, and `secondary_llm_api_key` in the CRE secrets manager. +- Confirm the scanner API key has both `verification:read` and `contracts:read` scopes. The workflow validates this at runtime and fails fast if scopes are missing. +- Set `CRE_ETH_PRIVATE_KEY` if on-chain verdict delivery is enabled. +- Deploy `AuditFirewallConsumer.sol` and set its address in `config.production.json` under `evms[].consumer_address`. +- Run `bun run typecheck && bun run test` (TypeScript) or `go vet ./... && go test ./...` (Go) before registering. +- Run `cre workflow simulate` against production endpoints to validate end-to-end behavior before going live. +- Register the workflow: + - TypeScript: `cre workflow register ./ai-audit-firewall-ts --project-root ./ --target=production-settings` + - Go: `cre workflow register ./ai-audit-firewall-go --project-root ./ --target=production-settings` + +## Troubleshooting + +**Scanner credential validation fails** + +The workflow validates scopes before making any scanner calls. If you see a scope-related error, confirm your scanner API key has `verification:read` and `contracts:read` permissions. The error message includes the detected scopes for diagnosis. + +**Verdict is `DENY` for an unverified contract** + +Unverified contracts are denied without running LLM analysis. If you are testing with a contract that is not on-chain verified, use the mock server (which returns mock verification status) or switch to a verified contract address. + +**LLM response cannot be parsed** + +If you see `invalid json response` or a parsing error, the reasoning endpoint returned a malformed body. Confirm that the LLM URL and API key are correct and that the model returns a JSON object with `recommendation`, `confidence`, and `riskFlags` fields. + +**On-chain write fails** -4. In another terminal, run checks +Confirm that `CRE_ETH_PRIVATE_KEY` is set and the consumer contract is deployed on the target chain. The workflow logs `audit-firewall-onchain tx_hash=...` on success. A failed transaction throws an error with the transaction status. -```bash -bun run typecheck -bun run test -``` +**Capability limit errors** -5. Simulate workflow +The workflow enforces a cap of 10 total capability calls per invocation (8 HTTP, 1 Report/consensus, and optionally 1 EVM write when on-chain delivery is enabled). If you extend the workflow with additional HTTP calls, update the pre-hook capability limits accordingly. -```bash -cre workflow simulate ./ai-audit-firewall-ts --target=staging-settings -``` +## Optional on-chain delivery -## Go Quick Start +After each audit, the workflow can write a signed verdict to an on-chain consumer contract. On-chain delivery is controlled by the `evms` array in the config. Remove the array or leave it empty to run the workflow without any on-chain writes. -1. Create environment file (at the shared project root) +**Verdict encoding** -```bash -cp ../.env.example ../.env -``` +Verdicts are ABI-encoded as `(uint8 verdictCode, uint8 riskMask, uint64 chainSelector)`: -2. Start the mock server (requires Node or Bun) +| Field | Value | Meaning | +| ------------- | ----- | ------------- | +| `verdictCode` | `1` | ALLOW | +| `verdictCode` | `2` | DENY | +| `verdictCode` | `3` | MANUAL_REVIEW | -```bash -bun mock-server.js -``` +Risk flags are packed into `riskMask` as a single bitmask byte: bit 0 = `obfuscatedTax`, bit 1 = `privilegeEscalation`, bit 2 = `externalCallRisk`, bit 3 = `logicBomb`. -3. In another terminal, run checks +**Consumer contract** -```bash -go vet ./... -go test ./... -``` +The included `AuditFirewallConsumer.sol` extends `ReceiverTemplate` and exposes the latest verdict, risk mask, and chain selector as public state variables. It emits a `VerdictReceived` event on each report. Deploy this contract and set its address in `config.production.json` under `evms[].consumer_address`. -4. Simulate workflow +**Deployment target** -```bash -cd .. && cre workflow simulate ./ai-audit-firewall-go --target=staging-settings -``` +The staging config targets Ethereum Sepolia (`ethereum-testnet-sepolia`). For mainnet delivery, update `chain_selector_name` to `ethereum-mainnet` and redeploy the consumer contract to that network. diff --git a/src/content/cre-templates/automated-liquidation-protection.mdx b/src/content/cre-templates/automated-liquidation-protection.mdx index c9eb2b18933..41189a5b8f4 100644 --- a/src/content/cre-templates/automated-liquidation-protection.mdx +++ b/src/content/cre-templates/automated-liquidation-protection.mdx @@ -15,7 +15,7 @@ githubRepoLinks: - 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-06" +lastModified: "2026-08-17" --- import { Aside } from "@components" @@ -23,133 +23,206 @@ import { Aside } from "@components" -This standalone CRE project implements a confidential liquidation-defense workflow for DeFi lending positions. +## What this template does -## Description +This CRE workflow implements a confidential liquidation-defense system for DeFi lending positions. It runs on a cron schedule, continuously evaluates a borrower's collateral health, and automatically executes defensive actions before a position reaches the liquidation threshold. Exchange credentials, LLM API keys, risk thresholds, and execution preferences all remain protected inside confidential execution. -The workflow continuously evaluates borrower risk and takes defensive action before a position becomes unsafe. -During periods of high volatility, it can increase collateral, reduce debt, or combine both strategies based on -policy constraints. Sensitive operational data remains protected in confidential execution, including exchange -credentials, model credentials, and user-defined risk thresholds. +**Data flow:** -## Target Customer +1. Fetch current risk state: collateral and debt pricing, health factor, liquidation proximity, LTV, liquidation threshold, and market volatility. +2. Load policy parameters from secrets: reserve deployment caps, minimum reserve balance, health factor targets, collateral and repayment limits, sequencing preference, and preferred venues. +3. Compute a composite risk score from proximity, LTV buffer, health factor, and volatility. +4. Send risk state and policy to an LLM reasoning model to select and sequence defensive actions. +5. Enforce all policy constraints against the proposed action plan before execution. +6. Execute the approved defense plan through the exchange or DeFi API. -- Professional retail traders -- Developer shops -- Founders building trading products +If liquidation proximity is above the warning threshold (the position has sufficient buffer), the workflow exits with `SAFE` and takes no action. -## Structure +## Defensive Actions and Policy Constraints -- `project.yaml`: project-level target settings -- `secrets.yaml`: secret ID mappings used by the workflow -- `mock-server.js`: local deterministic API server -- `automated-liquidation-protection-ts/`: TypeScript workflow implementation -- `automated-liquidation-protection-go/`: Go workflow implementation +### Defensive action types -## Private Inputs +| Action | Description | +| ------------------------------------ | ---------------------------------------------------------------- | +| `add_collateral` | Deposit additional collateral directly into the lending position | +| `bridge_and_add_collateral` | Bridge assets from another chain, then deposit as collateral | +| `swap_reserve_to_collateral` | Swap stablecoin reserves to the collateral asset, then deposit | +| `repay_with_reserves` | Repay outstanding debt using the stablecoin reserve balance | +| `swap_reserve_to_borrowed_and_repay` | Swap reserves to the borrowed asset denomination, then repay | +| `partial_debt_repayment` | Repay a configured percentage of outstanding debt | +| `full_debt_repayment` | Repay the entire outstanding debt balance | -The following inputs are treated as confidential: +### Policy constraints -- Exchange API credentials used to fetch account context such as stablecoin reserves and available cash balance. -- LLM reasoning API credentials and policy parameters used to govern defense behavior, including minimum and target health factors, reserve deployment caps, minimum reserve balance, and collateral allocation limits. -- Execution preferences that define how defense actions should be sequenced. +All policy values are loaded from secrets at runtime. Reserve-based constraints are enforced as hard limits before any execution call. Sequencing and venue preferences guide the LLM action plan. -## Workflow Notes +| Constraint | Description | +| --------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| Reserve deployment cap | Maximum USDC that can be deployed in a single defensive action | +| Reserve floor | Minimum USDC that must remain after any action. Actions that would breach this floor are rejected with an error. | +| Collateral allocation limit | Maximum percentage of available collateral for a single action. Passed to the LLM as a policy parameter. | +| Partial repayment cap | Maximum percentage of outstanding debt that can be repaid in a single action | +| Action sequencing | Order in which defensive moves are prioritized: `collateral-first`, `debt-first`, or `balanced` | +| Preferred venues | Comma-separated list of preferred execution venues (e.g., `binance,onchain,coinbase`) | -1. Observe liquidation risk signals. - The workflow tracks collateral and debt asset pricing, health factor, liquidation proximity, LTV, liquidation threshold, and market volatility. -2. Enforce user policy constraints. - Confidential reasoning evaluates how much capital can be deployed, whether debt reduction should be prioritized, which reserve assets are eligible, and what execution sequence is preferred. -3. Select defense actions. - The workflow builds a response plan that may include collateral-focused moves (deposit, bridge, swap-then-deposit) and debt-focused moves (repay, swap-then-repay, partial payoff, full payoff). -4. Execute the approved defense plan. +### Risk signals monitored -Note: Every reasoning stage can be implemented with deterministic rule-based logic instead of an LLM, if your deployment requires a fully rules-driven policy engine. +| Signal | Description | +| --------------------------- | ---------------------------------------------------------------------------------------- | +| `liquidation_proximity_pct` | Percentage buffer distance from the liquidation threshold (higher = more buffer = safer) | +| `collateral_health_factor` | Ratio of collateral value to outstanding debt | +| `loan_to_value_pct` | Current LTV percentage | +| `liquidation_threshold_pct` | Protocol-defined liquidation threshold | +| `volatility_index` | Market volatility indicator | -## Required Environment Variables +### Risk score -Copy `.env.example` to `.env` and provide values for: +The workflow computes a composite risk score to guide action selection: -- `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` +``` +proximityRisk = max(0, warningThreshold − liquidationProximity) × 5 +ltvBufferRisk = max(0, LTV − (liquidationThreshold − 5)) × 2 +healthRisk = max(0, minHealthFactor − healthFactor) × 100 +volatilityRisk = volatilityIndex × 25 +riskScore = proximityRisk + ltvBufferRisk + healthRisk + volatilityRisk +``` + +## Prerequisites + +- [Bun](https://bun.sh) runtime +- CRE CLI (`cre`) +- A DeFi risk monitoring or exchange API that exposes position health signals +- An LLM API endpoint for reasoning (e.g., an OpenAI-compatible endpoint) + +## Configuration + +The workflow ships with two config files: + +- `automated-liquidation-protection-ts/config.staging.json` (TypeScript) and `automated-liquidation-protection-go/config.staging.json` (Go): targets mock server endpoints +- `automated-liquidation-protection-ts/config.production.json` (TypeScript) and `automated-liquidation-protection-go/config.production.json` (Go): same structure with empty URLs for you to populate + +Key fields: -The local mock server for this project only exposes routes under `/liquidation/*`. +| Field | Description | +| --------------- | ----------------------------------------------------------- | +| `schedule` | Cron expression. Default: `0 */5 * * * *` (every 5 minutes) | +| `mock_base_url` | Base URL for the exchange or risk API | +| `openai_url` | LLM reasoning endpoint | +| `openai_model` | Model identifier (e.g., `gpt-4.1-mini`) | +| `secrets_ids.*` | Secret IDs for API keys and all policy parameters | -**Quick navigation:** +## Secrets -- [TypeScript Quick Start](#typescript-quick-start) -- [Go Quick Start](#go-quick-start) +Copy `.env.example` to `.env` and populate all values before running locally. The workflow enforces a strict limit of exactly 11 secrets per invocation. -## TypeScript Quick Start +| Environment variable | Secret ID | Purpose | +| --------------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------- | +| `MOCK_EXCHANGE_API_KEY` | `exchange_api_key` | Authenticates exchange or risk API requests | +| `MOCK_OPENAI_API_KEY` | `openai_api_key` | Authenticates LLM reasoning API requests | +| `MOCK_LIQUIDATION_WARNING_ACTION_THRESHOLD` | `liquidation_liquidation_warning_action_threshold` | Proximity percentage that triggers defensive actions (e.g., `18`) | +| `MOCK_LIQUIDATION_MINIMUM_HEALTH_FACTOR` | `liquidation_minimum_health_factor` | Minimum acceptable health factor (e.g., `1.25`) | +| `MOCK_LIQUIDATION_TARGET_HEALTH_FACTOR` | `liquidation_target_health_factor` | Target health factor after defense executes (e.g., `1.5`) | +| `MOCK_LIQUIDATION_MAX_STABLECOIN_RESERVE_DEPLOYMENT` | `liquidation_maximum_stablecoin_reserve_deployment` | Maximum USDC that can be deployed per action (e.g., `5000`) | +| `MOCK_LIQUIDATION_MIN_STABLECOIN_RESERVE_BALANCE` | `liquidation_minimum_stablecoin_reserve_balance` | Minimum USDC to keep in reserve (e.g., `2000`) | +| `MOCK_LIQUIDATION_MAX_COLLATERAL_ALLOCATION` | `liquidation_maximum_collateral_allocation` | Maximum collateral percentage per action (e.g., `80`) | +| `MOCK_LIQUIDATION_MAX_PARTIAL_DEBT_REPAYMENT` | `liquidation_maximum_partial_debt_repayment` | Maximum debt repayment percentage per action (e.g., `40`) | +| `MOCK_LIQUIDATION_DEFENSIVE_ACTION_SEQUENCING_PREFERENCE` | `liquidation_defensive_action_sequencing_preference` | `collateral-first`, `debt-first`, or `balanced` | +| `MOCK_LIQUIDATION_PREFERRED_VENUES` | `liquidation_preferred_venues` | Comma-separated venue list (e.g., `binance,onchain,coinbase`) | +| `CRE_ETH_PRIVATE_KEY` | _(framework-level)_ | Optional for local simulation. Required if executing on-chain actions. | + +## Quick start + +**TypeScript** + +Run all commands from the `automated-liquidation-protection` directory (the project root). 1. Install dependencies -```bash -bun install -``` + ```bash + cd automated-liquidation-protection-ts && bun install && cd .. + ``` 2. Create environment file -```bash -cp .env.example .env -``` + ```bash + cp .env.example .env + ``` 3. Start mock server -```bash -bun run mock:server -``` + ```bash + cd automated-liquidation-protection-ts && bun run mock:server + ``` -4. In another terminal, run checks +4. In another terminal, run checks and simulate -```bash -bun run typecheck -bun run test -``` + ```bash + cd automated-liquidation-protection-ts + bun run typecheck + bun run test + cd .. && cre workflow simulate ./automated-liquidation-protection-ts --project-root ./ --target=staging-settings --env ./.env + ``` -5. Simulate workflow +**Go** -```bash -cre workflow simulate ./automated-liquidation-protection-ts --target=staging-settings -``` +Run all commands from the `automated-liquidation-protection` directory (the project root). -## Go Quick Start +1. Create environment file -1. Create environment file (at the shared project root) + ```bash + cp .env.example .env + ``` -```bash -cp ../.env.example ../.env -``` +2. Start the mock server from the TypeScript directory (requires Node or Bun) -2. Start the mock server (requires Node or Bun) + ```bash + cd automated-liquidation-protection-ts && bun run mock:server + ``` -```bash -bun mock-server.js -``` +3. In another terminal, run checks and simulate -3. In another terminal, run checks + ```bash + cd automated-liquidation-protection-go + go vet ./... + go test ./... + cd .. && cre workflow simulate ./automated-liquidation-protection-go --project-root ./ --target=staging-settings --env ./.env + ``` -```bash -go vet ./... -go test ./... -``` +## Production checklist -4. Simulate workflow +- Populate `config.production.json` with real `mock_base_url` and `openai_url`. +- Register all 11 secrets in the CRE secrets manager and verify secret IDs match those defined in `config.production.json` under `secrets_ids`. +- Set `MOCK_LIQUIDATION_MIN_STABLECOIN_RESERVE_BALANCE` to a value that provides a meaningful reserve buffer for your position size. +- Set `CRE_ETH_PRIVATE_KEY` if any defensive action routes through on-chain execution. +- Confirm the exchange API returns the expected risk state schema before deploying. +- Run `bun run typecheck && bun run test` (TypeScript) or `go vet ./... && go test ./...` (Go) before registering. +- Run `cre workflow simulate` against production endpoints to validate end-to-end behavior. +- Register the workflow: + - TypeScript: `cre workflow register ./automated-liquidation-protection-ts --project-root ./ --target=production-settings` + - Go: `cre workflow register ./automated-liquidation-protection-go --project-root ./ --target=production-settings` -```bash -cd .. && cre workflow simulate ./automated-liquidation-protection-go --target=staging-settings -``` +## Troubleshooting + +**Reserve floor breach error** + +If you see `action X breaches reserve floor: projected Y < floor Z`, the proposed action would reduce stablecoin reserves below the configured minimum. Increase `MOCK_LIQUIDATION_MIN_STABLECOIN_RESERVE_BALANCE`, reduce `MOCK_LIQUIDATION_MAX_STABLECOIN_RESERVE_DEPLOYMENT`, or reduce position size. + +**Secrets must be finite numbers** + +If you see `secret X must be a finite number`, one of the numeric policy secrets was set to a non-numeric value. Confirm that all numeric environment variables in `.env` are valid floats or integers (e.g., `1.25`, not `"n/a"`). + +**LLM response format mismatch** + +If the LLM response cannot be parsed, the model must return either an `output_text` field or a nested `output[].content[].text` structure. If neither is present, you will see the error `openai response did not contain output_text`. Check your LLM endpoint logs or mock server configuration to verify the response format. + +**HTTP request failures** + +If you see `request failed status=4XX`, confirm the mock server is running (`bun run mock:server`) and that the API keys in `.env` match the values expected by the mock server. + +**Workflow logs `liquidation-no-action`** + +This is expected behavior when the position is healthy. The log includes `proximity=X threshold=Y reason=Z` to confirm the position state and why no action was taken. diff --git a/src/content/cre-templates/automated-portfolio-rebalancing.mdx b/src/content/cre-templates/automated-portfolio-rebalancing.mdx index 0b3feb789e7..a9b5c781833 100644 --- a/src/content/cre-templates/automated-portfolio-rebalancing.mdx +++ b/src/content/cre-templates/automated-portfolio-rebalancing.mdx @@ -15,7 +15,7 @@ githubRepoLinks: - 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-06" +lastModified: "2026-08-17" --- import { Aside } from "@components" @@ -23,134 +23,195 @@ import { Aside } from "@components" -This standalone CRE project implements a confidential portfolio rebalancing workflow for crypto allocations. +## What this template does -## Description +This CRE workflow implements a confidential portfolio rebalancing system for crypto allocations. It runs on a cron schedule, continuously monitors the drift between current and target asset weights, and automatically executes trades to restore the portfolio when a configurable threshold is exceeded. Exchange credentials, LLM reasoning, target allocations, and all execution preferences remain protected inside confidential execution. -The workflow continuously tracks allocation drift and triggers rebalancing when policy thresholds are exceeded. It -is designed to restore user-defined target weights while protecting sensitive operational inputs, including -exchange credentials, model credentials, policy thresholds, and execution preferences inside confidential execution. +**Data flow:** -## Target Customer +1. Fetch current portfolio state: holdings, asset prices, volatility index, and stablecoin reserve depth. +2. Calculate per-asset allocation drift from configured target weights (BTC, ETH, USDC). +3. If maximum drift across all assets is below the policy threshold, exit with `NOOP` and take no action. +4. Send portfolio state and policy to an LLM reasoning model for trade selection. +5. Reconcile LLM-proposed trades against policy constraints: venue overrides and slippage caps take precedence over LLM suggestions. +6. Reject any trade that would breach the reserve floor. Cap oversized trades and split them into chunks. +7. Separate trades into on-chain and off-chain execution routes and submit the full plan to the execute API. -- Professional retail traders -- Developer shops -- Founders building trading products +## Policy Constraints and Risk Flags -## Structure +### Policy constraints -- `project.yaml`: project-level target settings -- `secrets.yaml`: secret ID mappings used by the workflow -- `mock-server.js`: local deterministic API server -- `automated-portfolio-rebalancing-ts/`: TypeScript workflow implementation -- `automated-portfolio-rebalancing-go/`: Go workflow implementation +All policy values are loaded from secrets at runtime and enforced before any trade is submitted to the execute API. -## Private Inputs +| Constraint | Description | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | +| Target allocations | Target weight for each asset as a decimal (e.g., `0.5` = 50% BTC). All three values must sum to `1.0`. | +| Drift threshold | Minimum drift percentage that triggers a rebalance. The workflow exits with `NOOP` if no asset exceeds this. | +| Maximum trade size | Per-chunk trade size cap in USD. Trades above this are split into equal-sized chunks. | +| Reserve floor | Minimum USDC that must remain after all buy trades. Buy capacity is reduced to protect the floor; trades that breach it are rejected. | +| Slippage limit | Maximum acceptable slippage in basis points. LLM-proposed slippage values are clamped to this ceiling. | +| Trade ordering | Sequence in which trades execute: `sells-first`, `buys-first`, or `model-order` | +| Preferred venues | Comma-separated venue priority list used when the LLM does not specify a venue | -The following inputs are handled as confidential: +### Drift monitoring -- Exchange API credentials used to read holdings, reserve data, and execution context, including stablecoin reserve depth and cash balance. -- LLM reasoning API credentials. -- Portfolio policy settings such as target allocation mix, minimum drift threshold, maximum trade size per execution, and required stablecoin reserve floor. -- Execution preferences such as venue priority, slippage limits, and trade chunking/ordering behavior. +The workflow computes allocation drift for each asset and triggers a rebalance when any asset exceeds the threshold: -## Workflow Notes +``` +currentWeight = assetValueUsd / totalPortfolioValueUsd +drift = |currentWeight − targetWeight| × 100 +``` + +If `maxDrift < driftThresholdPct` across all assets, the workflow exits with `NOOP`. Otherwise, it builds sell orders for overweight assets and buy orders for underweight assets. + +### Trade execution guardrails + +- **Reserve floor**: Buy capacity is computed as `stablecoinReserve − reserveFloor + totalPlannedSellUsd`. Trades that would cause the reserve to drop below the floor are rejected. +- **Slippage**: Each trade's slippage is clamped to `min(llmProposed, maxSlippageBps)`. +- **Trade chunking**: Trades larger than `maxTradeUsd` are split into chunks of up to `maxTradeUsd` each (the final chunk may be smaller), tracked with `chunkIndex` and `chunkCount`. +- **LLM reconciliation**: LLM-proposed trade symbols and directions must align with policy-computed targets. Policy venue and slippage values override LLM suggestions when they conflict. + +## Prerequisites + +- [Bun](https://bun.sh) runtime +- CRE CLI (`cre`) +- An exchange or portfolio API that exposes current holdings, asset prices, and reserve data +- An LLM API endpoint for reasoning (e.g., an OpenAI-compatible endpoint) + +## Configuration -1. Monitor portfolio state. - The workflow gathers market prices, current asset weights, drift from target allocations, reserve health, and volatility signals. -2. Enforce user-defined portfolio constraints. - Confidential reasoning validates weight constraints, drift triggers, rebalance sizing limits, reserve protection requirements, and slippage controls. -3. Build a rebalance action plan. - The plan can include buying underweight assets, selling overweight assets, enforcing reserve floors, capping per-trade notionals, and optimizing execution through chunking and smart venue routing. -4. Execute rebalance actions across venues. - Depending on route selection, the workflow can execute both on-chain operations (such as swaps) and off-chain operations (such as centralized exchange API trades). +The workflow ships with two config files: -Note: Reasoning stages can be implemented with deterministic rule-based logic instead of an LLM when a fully rules-driven execution model is preferred. +- `automated-portfolio-rebalancing-ts/config.staging.json` (TypeScript) and `automated-portfolio-rebalancing-go/config.staging.json` (Go): targets mock server endpoints +- `automated-portfolio-rebalancing-ts/config.production.json` (TypeScript) and `automated-portfolio-rebalancing-go/config.production.json` (Go): same structure with empty URLs for you to populate -## Required Environment Variables +Key fields: -Copy `.env.example` to `.env` and provide values for: +| Field | Description | +| --------------- | ----------------------------------------------------------- | +| `schedule` | Cron expression. Default: `0 */5 * * * *` (every 5 minutes) | +| `mock_base_url` | Base URL for the exchange or portfolio API | +| `openai_url` | LLM reasoning endpoint | +| `openai_model` | Model identifier (e.g., `gpt-4.1-mini`) | +| `secrets_ids.*` | Secret IDs for API keys and all policy parameters | -- `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 -The local mock server for this project only exposes routes under `/rebalancing/*`. +Copy `.env.example` to `.env` and populate all values before running locally. The workflow enforces a strict limit of exactly 11 secrets and 5 HTTP calls per invocation. -**Quick navigation:** +| Environment variable | Secret ID | Purpose | +| --------------------------------------------- | ---------------------------------------- | -------------------------------------------------------------------- | +| `MOCK_EXCHANGE_API_KEY` | `exchange_api_key` | Authenticates exchange API requests | +| `MOCK_OPENAI_API_KEY` | `openai_api_key` | Authenticates LLM reasoning API requests | +| `MOCK_REBALANCING_TARGET_ALLOCATION_BTC_PCT` | `rebalancing_target_allocation_btc_pct` | Target BTC weight as a decimal (e.g., `0.5`) | +| `MOCK_REBALANCING_TARGET_ALLOCATION_ETH_PCT` | `rebalancing_target_allocation_eth_pct` | Target ETH weight as a decimal (e.g., `0.3`) | +| `MOCK_REBALANCING_TARGET_ALLOCATION_USDC_PCT` | `rebalancing_target_allocation_usdc_pct` | Target USDC weight as a decimal (e.g., `0.2`) | +| `MOCK_REBALANCING_DRIFT_THRESHOLD_PCT` | `rebalancing_drift_threshold_pct` | Drift percentage that triggers rebalancing (e.g., `5`) | +| `MOCK_REBALANCING_MAX_TRADE_USD` | `rebalancing_max_trade_usd` | Maximum USD per trade chunk (e.g., `5000`) | +| `MOCK_REBALANCING_RESERVE_FLOOR_USDC` | `rebalancing_reserve_floor_usdc` | Minimum USDC to keep in reserve (e.g., `2000`) | +| `MOCK_REBALANCING_MAX_SLIPPAGE_BPS` | `rebalancing_max_slippage_bps` | Maximum slippage in basis points (e.g., `50`) | +| `MOCK_REBALANCING_PREFERRED_VENUES` | `rebalancing_preferred_venues` | Comma-separated venue list (e.g., `binance,coinbase,onchain`) | +| `MOCK_REBALANCING_ORDER_SEQUENCE_PREFERENCE` | `rebalancing_order_sequence_preference` | `model-order`, `sells-first`, or `buys-first` | +| `CRE_ETH_PRIVATE_KEY` | _(framework-level)_ | Optional for local simulation. Required for on-chain swap execution. | -- [TypeScript Quick Start](#typescript-quick-start) -- [Go Quick Start](#go-quick-start) +## Quick start -## TypeScript Quick Start +**TypeScript** + +Run all commands from the `automated-portfolio-rebalancing` directory (the project root). 1. Install dependencies -```bash -bun install -``` + ```bash + cd automated-portfolio-rebalancing-ts && bun install && cd .. + ``` 2. Create environment file -```bash -cp .env.example .env -``` + ```bash + cp .env.example .env + ``` 3. Start mock server -```bash -bun run mock:server -``` + ```bash + cd automated-portfolio-rebalancing-ts && bun run mock:server + ``` -4. In another terminal, run checks +4. In another terminal, run checks and simulate -```bash -bun run typecheck -bun run test -``` + ```bash + cd automated-portfolio-rebalancing-ts + bun run typecheck + bun run test + cd .. && cre workflow simulate ./automated-portfolio-rebalancing-ts --project-root ./ --target=staging-settings --env ./.env + ``` -5. Simulate workflow +**Go** -```bash -cre workflow simulate ./automated-portfolio-rebalancing-ts --target=staging-settings -``` +Run all commands from the `automated-portfolio-rebalancing` directory (the project root). -## Go Quick Start +1. Create environment file -1. Create environment file (at the shared project root) + ```bash + cp .env.example .env + ``` -```bash -cp ../.env.example ../.env -``` +2. Start the mock server from the TypeScript directory (requires Node or Bun) -2. Start the mock server (requires Node or Bun) + ```bash + cd automated-portfolio-rebalancing-ts && bun run mock:server + ``` -```bash -bun mock-server.js -``` +3. In another terminal, run checks and simulate -3. In another terminal, run checks + ```bash + cd automated-portfolio-rebalancing-go + go vet ./... + go test ./... + cd .. && cre workflow simulate ./automated-portfolio-rebalancing-go --project-root ./ --target=staging-settings --env ./.env + ``` -```bash -go vet ./... -go test ./... -``` +## Production checklist -4. Simulate workflow +- Populate `config.production.json` with real `mock_base_url` and `openai_url`. +- Register all 11 secrets in the CRE secrets manager and verify secret IDs match those defined in `config.production.json` under `secrets_ids`. +- Confirm target allocation secrets sum to `1.0` across BTC, ETH, and USDC before registering. +- Set `MOCK_REBALANCING_RESERVE_FLOOR_USDC` to a value that provides a meaningful liquidity buffer for your portfolio size. +- Set `CRE_ETH_PRIVATE_KEY` if on-chain swap routes are enabled. +- Confirm the exchange API returns the expected portfolio state schema before deploying. +- Run `bun run typecheck && bun run test` (TypeScript) or `go vet ./... && go test ./...` (Go) before registering. +- Run `cre workflow simulate` against production endpoints to validate end-to-end behavior. +- Register the workflow: + - TypeScript: `cre workflow register ./automated-portfolio-rebalancing-ts --project-root ./ --target=production-settings` + - Go: `cre workflow register ./automated-portfolio-rebalancing-go --project-root ./ --target=production-settings` -```bash -cd .. && cre workflow simulate ./automated-portfolio-rebalancing-go --target=staging-settings -``` +## Troubleshooting + +**Workflow exits with NOOP** + +This is expected behavior when allocation drift is below the configured threshold. Check current versus target allocations and compare against `MOCK_REBALANCING_DRIFT_THRESHOLD_PCT`. Lower the threshold value to trigger rebalancing more frequently. + +**Reserve floor breach error** + +If you see `trade X breaches reserve floor: projected Y < floor Z`, a planned buy trade would consume too much of the stablecoin reserve. Decrease `MOCK_REBALANCING_RESERVE_FLOOR_USDC`, reduce `MOCK_REBALANCING_MAX_TRADE_USD`, or reduce the proportion of buy trades. + +**Config validation error** + +If you see `config requires schedule, mock_base_url, openai_url, and openai_model`, one of those fields is missing from the active config file. Verify that all four fields are populated in `config.production.json` (or `config.staging.json`). + +**LLM response format mismatch** + +If the LLM response cannot be parsed, the model must return an `output_text` field containing a JSON object with `shouldRebalance`, `reasoning`, and `trades` fields. Check that your LLM endpoint returns this structure and that the API key is valid. + +**HTTP request failures** + +If you see `request failed status=4XX`, confirm the mock server is running and that `MOCK_EXCHANGE_API_KEY` and `MOCK_OPENAI_API_KEY` in `.env` match the values expected by the mock server. + +**Secrets must be finite numbers** + +If you see `secret X must be a finite number`, one of the numeric policy secrets was set to a non-numeric value. Confirm that all numeric environment variables in `.env` are valid floats or integers. diff --git a/src/content/cre/concepts/confidential-workflows.mdx b/src/content/cre/concepts/confidential-workflows.mdx index 16564a9deb7..43887f073a4 100644 --- a/src/content/cre/concepts/confidential-workflows.mdx +++ b/src/content/cre/concepts/confidential-workflows.mdx @@ -10,7 +10,7 @@ metadata: import { Aside } from "@components" -A **Confidential Workflow** is a CRE [workflow](/cre/key-terms#workflow) that designates part of its logic to run inside a secure [enclave](/cre/key-terms#enclave)—a running instance of a [Trusted Execution Environment (TEE)](/cre/key-terms#tee-trusted-execution-environment), a hardware-isolated environment designed to keep the computation and data it processes confidential from the machine's own operator during execution—instead of on Workflow DON nodes. +A **Confidential Workflow** is a CRE [workflow](/cre/key-terms#workflow) that designates part of its logic to run inside a secure [enclave](/cre/key-terms#enclave)—a running instance of a [Trusted Execution Environment (TEE)](/cre/key-terms#tee-trusted-execution-environment), a hardware-isolated environment designed to keep the computation and data it processes confidential from the machine's own operator during execution—instead of on Workflow DON nodes. Confidential Workflows serve as the confidential compute foundation to unlock Private Smart Contracts, where encrypted transactions are processed through confidential offchain computation and resulting state is committed onchain or other DA layers. Confidential Workflows are fundamentally standard CRE workflows with an explicit confidential execution path added where you need it, composing freely with standard workflow logic in the same application. Secrets fetched inside the enclave, and any computation you mark as confidential, are intended to remain confidential from node operators during execution. You decide what stays inside the enclave and what crosses back out to the Workflow DON for consensus-verified execution, such as generating a report to submit onchain. @@ -18,10 +18,11 @@ For hands-on steps, jump straight to [Making a Workflow Confidential](/cre/guide -## Where this fits in CRE +## Where this Ifits in CRE If you're new to CRE workflows, start with [Getting Started](/cre/getting-started/overview) to build a standard workflow first—one where your handler's logic runs on Workflow DON nodes like any other capability call. Confidential Workflows extends that same model: once you're comfortable with handlers, triggers, and callbacks, this page and the [guide](/cre/guides/workflow/using-confidential-workflows) show you how to carve out a confidential execution path for the parts of a workflow that need it, without changing how the rest of your workflow is built, deployed, or operated. @@ -69,7 +70,8 @@ You remain responsible for not leaking confidential information back out through