렌딩 핵심: Health Factor와 담보 위험
도입
DeFi lending에서 사용자는 "얼마까지 빌릴 수 있는가"를 먼저 묻지만, 운영자는 "언제 청산될 수 있는가"를 먼저 본다. 이 둘은 비슷해 보이지만 같은 값이 아니다. LTV는 차입 한도를 말하고, liquidation threshold는 담보 가치가 어느 수준까지 떨어졌을 때 position이 liquidation 대상이 되는지를 말한다.
Health factor는 이 차이를 하나의 숫자로 압축한다. 담보 가치에 liquidation threshold를 반영한 값이 부채 가치보다 충분히 크면 position은 여유가 있다. 반대로 1에 가까워질수록 작은 가격 변화, oracle 지연, gas spike, keeper 부족이 실제 손실로 이어질 수 있다.
학습 목표
- LTV, liquidation threshold, health factor를 구분한다.
- multi-collateral position에서 가격 충격이 liquidation risk로 바뀌는 과정을 계산한다.
- 사용자 UI와 risk dashboard에 필요한 담보 buffer를 정의한다.
개념 설명
1 아래로 떨어지면 liquidation 대상
자산별 liquidation threshold를 반영
stable debt도 depeg과 oracle freshness 확인
상관관계가 높은 담보는 eMode와 별도 경고
| 개념 | 의미 | 사용자 문구 | 운영 문구 |
|---|---|---|---|
| LTV | 현재 담보로 빌릴 수 있는 최대 비율 | 최대 차입 한도 | onboarding limit |
| Liquidation threshold | 청산 기준에 쓰는 담보 인정 비율 | 청산 위험 기준 | solvency threshold |
| Health factor | threshold-adjusted collateral / debt | 청산 여유 | liquidation queue priority |
| Liquidation bonus | liquidator가 받는 할인 또는 보상 | 청산 시 손실 가능성 | keeper incentive |
코드로 확인하기
type Collateral = { symbol: string; amount: number; priceUsd: number; liquidationThreshold: number };type Debt = { symbol: string; amount: number; priceUsd: number };export function healthFactor(collaterals: Collateral[], debts: Debt[]) { const thresholdValue = collaterals.reduce( (sum, item) => sum + item.amount * item.priceUsd * item.liquidationThreshold, 0 ); const debtValue = debts.reduce((sum, item) => sum + item.amount * item.priceUsd, 0); return debtValue === 0 ? Number.POSITIVE_INFINITY : thresholdValue / debtValue;}select user_id, sum(collateral_usd * liquidation_threshold) / nullif(sum(debt_usd), 0) as health_factor, case when sum(collateral_usd * liquidation_threshold) / nullif(sum(debt_usd), 0) < 1 then 'liquidatable' when sum(collateral_usd * liquidation_threshold) / nullif(sum(debt_usd), 0) < 1.1 then 'urgent' else 'watch' end as risk_bucketfrom lending_account_snapshotsgroup by user_id;계산식은 간단하지만 governance parameter, oracle price, collateral enablement가 섞이면 실수하기 쉽다. 특히 LTV를 liquidation threshold 대신 쓰면 사용자의 위험을 과소평가하거나 과대평가한다.
강의 포인트
| 관점 | 확인할 질문 | 증거로 남길 것 |
|---|---|---|
| Parameter | LTV와 threshold가 분리되어 있는가 | market config snapshot |
| Price | 어떤 oracle 가격을 쓰는가 | feed, timestamp, deviation |
| User action | 사용자가 무엇을 하면 HF가 올라가는가 | repay, add collateral, close |
| Liquidation | keeper가 실제로 처리 가능한가 | queue size, gas, bonus |
실무 예시
백엔드[CLIENT] 차입 화면에서 "아직 500 USDC 더 빌릴 수 있음"만 보여주면 사용자가 위험을 오해한다. 가격 변동성이 큰 담보라면 추가 차입 후 health factor가 얼마나 낮아지는지, 5% 가격 충격에서 어떤 상태가 되는지 같이 보여야 한다.
인덱서risk dashboard는 전체 사용자의 health factor 분포를 본다. 평균 health factor는 의미가 약하다. 중요한 것은 1.0 근처에 몰린 부채 규모와 같은 oracle 또는 같은 담보에 묶인 cluster다. 담보 하나가 흔들릴 때 청산 물량이 한꺼번에 몰릴 수 있기 때문이다.
흔한 오해와 실패 시나리오
| 오해 | 실패 시나리오 | 교정 방식 |
|---|---|---|
| LTV가 낮으면 안전하다 | liquidation threshold와 가격 변동성이 다르다 | HF와 shock simulation을 같이 본다 |
| stablecoin debt는 변하지 않는다 | depeg, oracle delay, borrow index가 영향을 준다 | price와 debt index를 검증한다 |
| HF 1.01이면 아직 괜찮다 | gas spike나 keeper delay로 손실이 커질 수 있다 | buffer bucket을 둔다 |
| 담보가 여러 개면 분산된다 | 같은 시장 요인에 상관될 수 있다 | correlation scenario를 넣는다 |
실습 과제
- Health factor 계산기 만들기: collateral list, debt list, price map을 받아 weighted liquidation threshold와 health factor를 계산한다.
- 담보 충격 시나리오 작성하기: ETH, stETH, stablecoin collateral에 각각 가격 충격을 주고 사용자 경고 기준을 정한다.
완료 기준
- collateral value와 liquidation threshold를 반영한 health factor 계산기를 만들었다.
- LTV와 liquidation threshold를 같은 값으로 쓰면 안 되는 이유를 설명했다.
근거 자료
- 02 Lending
- Aave Liquidations Help