RiskEngine is a stateless contract — it stores no user positions. On every call it reads position data from the caller’s SmartAccount and LendingPools, prices everything via Oracle, and returns a boolean. It never modifies state in those contracts; it only reads.
Testnet address: CBL7RCG5H4VIZCNF7BRM2FQFXK7N5KRQKW7ZVEQZJKNXHA6FEU4OXK5I
Guard Functions
These are the three functions that gate every state-changing operation in the protocol. AccountManager calls the appropriate guard before every borrow, withdrawal, or liquidation.is_borrow_allowed
true if borrowing borrow_amt of symbol from the pool would leave the account healthy. Uses the gross-asset model — new borrows count as both an asset (purchased) and a liability simultaneously.
Gross-asset borrow check:
is_withdraw_allowed
true if withdrawing withdraw_amt of symbol collateral would leave the account healthy.
Withdraw check:
is_account_healthy
true if:
BALANCE_TO_BORROW_THRESHOLD = 1.1 × 10¹⁸.
Used internally by is_borrow_allowed, is_withdraw_allowed, and by liquidation callers to check if an account is eligible for liquidation.
Portfolio Query Functions
get_current_total_balance
margin_account, in USD WAD. Iterates every token in SmartAccount.get_all_collateral_tokens() and prices each one.
Collateral valuation by type:
get_current_total_borrows
margin_account, in USD WAD. Queries each LendingPool’s get_borrow_balance() for each symbol in BorrowedTokensList.
Blend b-Token Valuation
When SmartAccount holds Blend b-tokens (received by depositing into Blend pool), the RiskEngine values them using the Blend pool’sb_rate:
b_rate is read directly from Blend’s pool reserve data. It represents the exchange rate from b-tokens to the underlying asset.
Symbol Canonicalization
Before querying Oracle prices, the RiskEngine maps wrapped token symbols to their underlying asset for pricing:
LP tracking tokens (
AQ_XLM_USDC, SS_XLM_USDC, AQ_XLM_AQUA, AQ_XLM_USDT) have no oracle feed and are valued at $0.
Price Caching
Within a singleis_borrow_allowed or get_current_total_balance call, oracle prices are fetched once per symbol and cached in a local Map<Symbol, u128>. This avoids duplicate cross-contract oracle calls when the same symbol appears multiple times (e.g., both as collateral and debt).
Dust Threshold
Debts below10^16 WAD (0.01 token in 18-decimal terms) are ignored during health checks. This prevents rounding-dust positions from blocking otherwise-healthy accounts.
Constants
Error Codes
Cross-Contract Reads
The RiskEngine reads from, but never writes to, other contracts:Related
- Math Reference — complete health factor formula with worked examples
- AccountManager — the only contract that calls RiskEngine guards
- Oracle — price feed source
- Health Factor — user-facing explanation of the 1.1× invariant

