Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Case Study 2: Automated Liquidation Protection Overview

Template source: cre-templates/starter-templates/confidential-workflows/automated-liquidation-protection

The template is available in TypeScript and Go; the two implementations are behaviorally equivalent. In this bootcamp we are using TypeScript.

The Use Case: Confidential Automated Defense Before Liquidation

This workflow provides continuous risk monitoring and automated defense for a DeFi lending position:

  1. Periodically fetches the position’s risk snapshot: collateral/debt prices, health factor, liquidation proximity, LTV, market volatility, plus your available capital (stablecoin reserves, cash balance)
  2. Inside a confidential environment, computes a risk score using your private policy parameters, and asks an LLM policy engine for a defense decision
  3. Validates the decision against hard policy constraints (deployment caps, reserve floors, …)
  4. Executes defensive actions in your preferred order: add collateral, repay debt, or a combination of both

Everything happens before liquidation arrives — automatically pulling the health factor back into the safe zone during high volatility.

Why This Use Case Must Run Confidentially

This is the signature use case in the Confidential Workflows documentation, and it protects even more than Case Study 1:

Confidential assetImpact of leakage
🔑 Exchange API credentialsCredentials that can query your account balances and reserves get stolen
🔑 LLM API credentialsKeys with spending limits get stolen
🎯 Risk thresholds (warning line, min/target health factor)Predicted → front-run, deliberately pushed toward the liquidation line
💰 Capital parameters (reserve deployment cap, minimum reserve balance, collateral allocation cap)Adversaries calculate the exact boundary of your defensive capacity
🔀 Preferred venuesYour defensive moves get traded against in advance

Notice an interesting design choice: the policy parameters are themselves secrets. This workflow has 10 secrets, 8 of which are not “credentials” in the traditional sense but thresholds and strategy — all released by the Vault DON into the enclave. Node operators have no way to learn “how much you can deploy.” (The one exception is the collateral-first / debt-first / balanced sequencing choice — that’s read from public workflow config, not the Vault DON, so only which venues you act through stays confidential, not the order you act in.)

Workflow Flow

                    ┌──────────────────────────────────────────────┐
                    │              CRON Trigger fires              │
                    │      (evaluates the position every 5 min)    │
                    └──────────────────────┬───────────────────────┘
                                           │
                                           ▼
┌────────────────────────────────────────────────────────────────────────┐
│ Stage 0: Fetch 10 secrets inside the enclave (1 getSecrets call)       │
│ Exchange credential + LLM credential + 8 policy-parameter secrets      │
│ (thresholds / caps / preferred venues; sequencing is public config)    │
└──────────────────────────────────────┬─────────────────────────────────┘
                                       │
                                       ▼
┌────────────────────────────────────────────────────────────────────────┐
│ Stage 1: Observe risk signals (collectRiskSnapshot)                    │
│ GET /risk-state → collateral/debt prices, health factor, liquidation   │
│ proximity, LTV, liquidation threshold, volatility, USDC reserve, cash  │
└──────────────────────────────────────┬─────────────────────────────────┘
                                       │
                                       ▼
┌────────────────────────────────────────────────────────────────────────┐
│ Stage 2: Confidential policy reasoning                                 │
│ ① computeRiskScore: deterministic risk score                           │
│    = proximity risk + LTV buffer risk + health risk + volatility risk  │
│ ② Package risk + riskScore + policy into the prompt                    │
│ ③ POST /v1/responses → the LLM policy engine returns a decision:       │
│    shouldDefend + reasoning + actions[]                                │
└──────────────────────────────────────┬─────────────────────────────────┘
                                       │
                                       ▼
┌────────────────────────────────────────────────────────────────────────┐
│ Stage 3: Hard policy checks (enforcePolicy)                            │
│ · per-execution spend ≤ max_reserve_deployment                         │
│ · post-action reserve ≥ min_reserve_balance (breach → throw)           │
│ · partial repayment % ≤ max_partial_debt_repayment_pct                 │
│ · order actions per execution_sequence_preference                      │
└──────────────────────────────────────┬─────────────────────────────────┘
                                       │
                                       ▼
┌────────────────────────────────────────────────────────────────────────┐
│ Stage 4: Execute the defense plan                                      │
│ · proximity ≤ warning threshold and actions exist                      │
│   → POST /execute-defense → "DEFENDED"                                 │
│ · otherwise → log the reason and return "SAFE"                         │
└────────────────────────────────────────────────────────────────────────┘

Visualize the Workflow

Want to explore this workflow yourself? The complete workflow definition is available as a JSON file. You can import it into https://cre.solange.dev/ — a visual GUI tool for CRE workflows — to inspect and interact with the flow step by step.

The Seven Defensive Actions

Recapping the two broad approaches from the previous section, the workflow’s full action set:

TypeActionCategory
add_collateralAdd collateral directly with reservesCollateral side
bridge_and_add_collateralBridge assets cross-chain, then addCollateral side
swap_reserve_to_collateralSwap reserves into the collateral asset, then depositCollateral side
repay_with_reservesRepay debt directly with reservesDebt side
swap_reserve_to_borrowed_and_repaySwap reserves into the borrowed asset, then repayDebt side
partial_debt_repaymentRepay a percentage of the debtDebt side
full_debt_repaymentRepay the debt in fullDebt side

Project Structure

automated-liquidation-protection/         ← CRE project root
├── project.yaml                          ← Project-level config (RPC endpoints)
├── secrets.yaml                          ← 10 secret ID → env var mappings
├── .env.example                          ← Env var template (with all policy defaults)
└── automated-liquidation-protection-ts/  ← TypeScript workflow
    ├── main.ts                           ← The workflow code ⭐
    ├── workflow.yaml                     ← Workflow settings
    ├── config.staging.json               ← Simulation config (URLs, secret ID mappings)
    └── mock-server.js                    ← Local deterministic mock API server

The Ten Secrets

Secret IDTypePurpose
exchange_api_keyCredentialAccess account data (risk snapshot, execute defense)
openai_api_keyCredentialCall the LLM policy engine
liquidation_liquidation_warning_action_thresholdPolicyLiquidation proximity warning line (default 18%)
liquidation_minimum_health_factorPolicyMinimum health factor (default 1.25)
liquidation_target_health_factorPolicyTarget health factor (default 1.5)
liquidation_maximum_stablecoin_reserve_deploymentPolicyMax reserve deployment per execution, $ (default 5000)
liquidation_minimum_stablecoin_reserve_balancePolicyMinimum reserve balance, $ (default 2000)
liquidation_maximum_collateral_allocationPolicyCollateral allocation cap, % (default 80)
liquidation_maximum_partial_debt_repaymentPolicyPartial repayment cap, % (default 40)
liquidation_preferred_venuesPolicyPreferred venue list (default binance,onchain,coinbase)

The sequencing preference (default collateral-first) is not in this table — it’s supplied via public workflow config, not the Vault DON.

The Mock Server

Same pattern as Case Study 1: an Express mock server simulates the external dependencies locally, exposing only /liquidation/* routes:

Mock endpointSimulated role
GET /liquidation/risk-stateExchange/account data source (risk snapshot)
POST /liquidation/v1/responsesOpenAI-style LLM policy engine
POST /liquidation/execute-defenseDefense action execution endpoint

The built-in default risk snapshot is a position already in the danger zone:

  • Collateral: ETH $45,000
  • Debt: $32,000 USDC
  • Health factor: 1.14
  • Liquidation proximity: 12% (warning line: 18%)
  • LTV: 71% / threshold 78%
  • Volatility: 0.37
  • USDC reserve: $10,000
  • Cash: $12,500

→ Liquidation proximity of 12% has already breached the 18% warning line, so the workflow should spring into action.

What’s Next

Let’s open main.ts and see how most of the policy parameters are injected as secrets (one — the sequencing preference — comes from public config instead), and how deterministic constraints “backstop” the LLM’s decisions.