What this template does
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.
Data flow:
- Fetch current risk state: collateral and debt pricing, health factor, liquidation proximity, LTV, liquidation threshold, and market volatility.
- Load policy parameters from secrets: reserve deployment caps, minimum reserve balance, health factor targets, collateral and repayment limits, sequencing preference, and preferred venues.
- Compute a composite risk score from proximity, LTV buffer, health factor, and volatility.
- Send risk state and policy to an LLM reasoning model to select and sequence defensive actions.
- Enforce all policy constraints against the proposed action plan before execution.
- Execute the approved defense plan through the exchange or DeFi API.
If liquidation proximity is above the warning threshold (the position has sufficient buffer), the workflow exits with SAFE and takes no action.
Defensive Actions and Policy Constraints
Defensive action types
| 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 |
Policy constraints
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.
| 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) |
Risk signals monitored
| 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 |
Risk score
The workflow computes a composite risk score to guide action selection:
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 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) andautomated-liquidation-protection-go/config.staging.json(Go): targets mock server endpointsautomated-liquidation-protection-ts/config.production.json(TypeScript) andautomated-liquidation-protection-go/config.production.json(Go): same structure with empty URLs for you to populate
Key fields:
| 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 |
Secrets
Copy .env.example to .env and populate all values before running locally. The workflow enforces a strict limit of exactly 11 secrets per invocation.
| 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).
-
Install dependencies
cd automated-liquidation-protection-ts && bun install && cd .. -
Create environment file
cp .env.example .env -
Start mock server
cd automated-liquidation-protection-ts && bun run mock:server -
In another terminal, run checks and simulate
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
Go
Run all commands from the automated-liquidation-protection directory (the project root).
-
Create environment file
cp .env.example .env -
Start the mock server from the TypeScript directory (requires Node or Bun)
cd automated-liquidation-protection-ts && bun run mock:server -
In another terminal, run checks and simulate
cd automated-liquidation-protection-go go vet ./... go test ./... cd .. && cre workflow simulate ./automated-liquidation-protection-go --project-root ./ --target=staging-settings --env ./.env
Production checklist
- Populate
config.production.jsonwith realmock_base_urlandopenai_url. - Register all 11 secrets in the CRE secrets manager and verify secret IDs match those defined in
config.production.jsonundersecrets_ids. - Set
MOCK_LIQUIDATION_MIN_STABLECOIN_RESERVE_BALANCEto a value that provides a meaningful reserve buffer for your position size. - Set
CRE_ETH_PRIVATE_KEYif 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) orgo vet ./... && go test ./...(Go) before registering. - Run
cre workflow simulateagainst 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
- TypeScript:
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.
CREATED BY CHAINLINK LABS