Protocol Registries
The contract maintains two independent registries using the indexed mapping + soft-delete pattern: one for lending protocols and one for perp protocols.Protocol Types
Lending Protocols
| Constant | Value | Protocol |
|---|---|---|
LENDING_TYPE_AAVE_V3 | 0 | Aave V3 |
IAavePool.getUserAccountData(user) to retrieve the health factor.
Additional types (Compound V3, Radiant) are reserved for future use.Perp Protocols
Health Factor Scanning
The core scanning logic iterates over all active lending protocols for a given account and returns the lowest health factor found:1_000_000_000_000_000_000 (1.0) means the position is at the liquidation
boundary. The default risk threshold is 1_100_000_000_000_000_000 (1.1).Tracked Accounts
The contract maintains an on-chain list of accounts to monitor, capped at 500 addresses. Thescan_tracked_accounts method iterates over this list
and emits AccountAtRisk events for any account whose health factor falls
below the threshold.
Account removal uses swap-and-pop — the last element replaces the removed
element, keeping the operation O(1).
Public Methods
initialize(risk_threshold) -> Result<()>
initialize(risk_threshold) -> Result<()>
add_lending_protocol(pool_address, protocol_type) -> Result<U256>
add_lending_protocol(pool_address, protocol_type) -> Result<U256>
- Rejects zero addresses.
- Returns the new protocol index.
- Emits
LendingProtocolAdded(index, poolAddress, protocolType).
remove_lending_protocol(index) -> Result<()>
remove_lending_protocol(index) -> Result<()>
- Reverts if index is out of bounds or already removed.
- Emits
LendingProtocolRemoved(index, poolAddress).
add_perp_protocol(reader_address, protocol_type) -> Result<U256>
add_perp_protocol(reader_address, protocol_type) -> Result<U256>
- Emits
PerpProtocolAdded(index, readerAddress, protocolType).
remove_perp_protocol(index) -> Result<()>
remove_perp_protocol(index) -> Result<()>
- Emits
PerpProtocolRemoved(index, readerAddress).
get_health_factor(account) -> Result<U256>
get_health_factor(account) -> Result<U256>
scan_accounts(accounts) -> Result<Vec<(Address, U256)>>
scan_accounts(accounts) -> Result<Vec<(Address, U256)>>
(address, healthFactor) tuples.scan_tracked_accounts() -> Result<Vec<(Address, U256)>>
scan_tracked_accounts() -> Result<Vec<(Address, U256)>>
AccountAtRisk events for
each at-risk position found, including a block timestamp.add_account(account) -> Result<()>
add_account(account) -> Result<()>
- Emits
AccountAdded(account).
remove_account(account) -> Result<()>
remove_account(account) -> Result<()>
- Emits
AccountRemoved(account).
set_threshold(new_threshold) -> Result<()>
set_threshold(new_threshold) -> Result<()>
- Emits
ThresholdUpdated(oldThreshold, newThreshold).
tracked_count() -> U256
tracked_count() -> U256
threshold() -> U256
threshold() -> U256
Events
| Event | Indexed Fields | Data Fields |
|---|---|---|
AccountAtRisk | account | healthFactor, timestamp |
AccountAdded | account | — |
AccountRemoved | account | — |
ThresholdUpdated | — | oldThreshold, newThreshold |
LendingProtocolAdded | index | poolAddress, protocolType |
LendingProtocolRemoved | index | poolAddress |
PerpProtocolAdded | index | readerAddress, protocolType |
PerpProtocolRemoved | index | readerAddress |
Off-Chain Integration
The off-chain agent uses this contract in two ways:- On-demand health checks — when a user asks “check my health factor”,
the agent calls
get_health_factorfor their address. - Periodic scanning — a background job calls
scan_tracked_accountsand surfacesAccountAtRiskevents to users via notifications.
Test Coverage
The contract has 43 tests covering:- Initialization (owner set, double-init rejection)
- Access control (owner pass, stranger rejection)
- Account management (add, remove, cap enforcement, swap-and-pop)
- Threshold updates and event emission
- Health factor queries with mocked Aave V3 responses
- Multi-account scanning (at-risk detection, healthy filtering, boundary values)
- Tracked account scanning with event verification
- Lending protocol registry (add, remove, soft-delete, event emission)
- Perp protocol registry (add, remove, access control)
- Multi-protocol health factor (returns lowest across pools)
- Edge cases (no protocols registered, all protocols removed, empty input)