[Compound Series] 4. 컴파운드 로직 분석 — 청산

[Compound series]

  1. 컴파운드 톺아보기
  2. 컴파운드 로직 분석 (예금, 출금)
  3. 컴파운드 로직 분석 (대출, 상환)
  4. 컴파운드 로직 분석 (청산)
  5. 컴파운드 이자율 계산 분석
  6. 컴파운드의 미래 — Compound Gateway

What is Liquidation?

지금까지 컴파운드의 핵심 로직 중 예금과 출금, 대출과 상환에 대해 각각 살펴보았습니다. 이번 포스팅에서 살펴볼 마지막 로직은 바로 ‘청산’(Liquidation)입니다.

Compound Protocol은 최소 담보대출비율에 미달하는 차입자의 담보를 청산함으로써 담보 부실화로 인한 대출자의 원금 손실을 미연에 방지합니다. 쉬운 예시로, A라는 사람이 자신의 10억짜리 부동산을 담보로 은행으로부터 5억을 빌린 상황을 가정해봅시다. 이 때 부동산의 가격이 5억 미만으로 내려갈 것으로 예상된다면, 은행은 A가 담보로 맡긴 자산만으로는 A의 채무 불이행으로부터 발생할 수 있는 손실을 메꿀 수 없을 것입니다. 따라서 은행은 부동산의 가격이 5억 아래로 내려가기 전에, 해당 부동산을 제 3자에게 5억 이상의 가격에 처분하여 A에게 대출해준 원금만큼의 금액을 회수할 수 있게 됩니다.

컴파운드 역시 위의 예시와 동일한 방식을 취합니다. 암호화폐를 예금한 사람들이 원금에 대해서 손실을 입지 않게 하기 위해 ‘청산’ 과정을 수행합니다. 여기서 일반적인 은행의 방식과 다른 점은, 블록체인에서 분산화되어 동작하는 Compound protocol의 경우 예금과 대출을 관리하는 중앙 기관이 없다는 것입니다. 따라서 위와 같이 청산을 수행하는 제 3자의 존재가 필수적입니다. 컴파운드에서는 ‘청산자’(Liquidator)라 불리는 제 3자가 프로토콜에 참여하여 청산을 수행합니다. 이번 포스팅에서는 컴파운드에서의 청산이 어떤 방식으로 이루어지는지, 실제 청산 알고리즘이 잘 구동되고 있는지를 차례로 살펴보겠습니다.

Liquidation Parameters

청산이 정확히 어떻게 동작하는지 이해하기 전에, Compound에서 청산 과정을 수행하는데 사용하는 몇 가지 변수들을 알아보겠습니다. 앞선 예시를 다시 살펴보면, 집값이 10억에서 9억으로 낮아졌다고 은행이 이를 마음대로 청산해 버리면 사람들은 부동산 담보 대출을 받으려고 하지 않을 것입니다. 자신이 소유한 자산이 어떤 규칙에 의해서 청산될 수 있는지 모르는 데다가, 갑자기 청산이 되어 버리면 차입자 입장에서는 많은 손해를 입게 되기 때문입니다. 이는 금융상품의 계약 조건을 알지 못하고 이용하는 것과 동일합니다. 따라서 이러한 청산에 대한 ‘규칙’ 이 필요하게 됩니다. 어떠한 상황에서, 어느만큼 청산이 가능한지 등을 미리 알려주는 역할을 하는 것이죠.

  1. 담보비율(Collateral Factor): 담보 비율이 50%라면, 자신이 맡긴 담보물의 가치의 50%만큼 암호화폐를 새로 빌릴 수 있게 됩니다. 즉 담보 비율이 50%일때 자신이 $100어치의 이더리움을 담보로 맡긴다면, $50만큼의 다른 암호화폐를 빌릴 수 있게 됩니다. 반대로 말하면, 이러한 담보 비율을 지키지 못할 경우 차입자 자신의 담보물을 청산 당하게 됩니다. 담보 비율은 0에서 90%까지의 값을 가지는데, 0%라면 해당 암호화폐를 담보로 할 수 없다는 뜻이 됩니다. 이러한 담보 비율은 해당 암호화폐의 유동성이 높을수록 비례해 높아지는데, 쉽게 유동화를 할 수 있는 암호화폐라면 그렇지 않은 것보다 청산하는 과정에서의 리스크가 더 적다고 볼 수 있기 때문입니다. 이러한 담보 비율은 컴파운드의 거버넌스에 따라서 변경될 수 있습니다.
  2. Close Factor: 청산자의 청산이 담보물의 몇 %까지 한번에 청산할 수 있는지를 나타내는 지표입니다. 이는 0%에서 100%까지의 값을 가질 수 있습니다. 담보물의 가치 * 담보 비율의 값이 자신이 빌린 암호화폐의 가치보다 낮아졌을 경우(자신이 담보 비율을 지키지 못했을 경우), 차입자는 자신이 맡긴 담보물에 close factor를 곱해준 값 만큼 청산당하게 됩니다. 굳이 한번에 청산을 하지 않고 close factor라는 개념을 둔 것은, 1) 차입자 담보의 일정 부분만 청산을 해 주어도 충분히 건강한 대출로 변환될 수 있고(이는 추후 예시를 통해 더 자세히 알아 보겠습니다) 2) 담보물이 한꺼번에 청산될 경우 대출자는 한번에 청산될 위험에 프로토콜 사용을 꺼리게 되며, 3) 추가적으로 담보물 청산이 한꺼번에 몰려 거래소에 판매되며 담보물의 가격이 연속적으로 급락하게 되는 상황을 미연에 방지하기 위함입니다.
  3. Liquidiation Incentive: 청산자에게 청산 대상 담보물 외로 추가적으로 주어지는 인센티브입니다. 만약 Liquidation incentive가 1.1 이라면, 청산자는 자신이 청산한 담보물을 10% 할인하여 구매할 수 있게 됩니다. 이 인센티브는 차입자의 담보물에서 지급되므로 대출자에게는 대출 청산에 대한 패널티인 동시에, 청산자에게는 청산에 대한 인센티브이므로 열심히 청산을 할 유인을 만들어 주게 됩니다.

Liquidation Process

밑의 이미지는 실제 Compound protocol 에서 2021.5.19 일어난 청산 이벤트입니다.

(https://etherscan.io/tx/0xe34661703e248bf3f24c21f8fcb84a5088e7b55fa9ebecf406c70785672a6e86)

위의 이미지에서 Liquidator가 $1906의 USDC를 repay하고, 약 0.7 ETH($2081)의 청산을 일으킨 것을 확인할 수 있습니다. 여기서 repay의 경우, ‘$2081만큼의 이더를 $1906만큼의 USDC로 할인하여 구입했다’ 라고 볼 수 있습니다.

그렇다면 이제부터 이러한 청산 과정이 어떠한 과정으로 일어나는지 알아 보도록 하겠습니다. (현재 Compound는 대출자와 차입자에게 COMP 토큰을 배분하고 있는데, 이 부분은 설명의 간결성을 위해 생략 하였습니다.) 이는 모두 청산자 입장에서 쓰여진 것으로, 1) 청산자가 어떠한 방법으로 청산 대상을 탐색하고, 2) 청산 대상 담보물을 청산하고, 3) 해당 담보물을 사용하는지 순서로 서술되어 있습니다.

1. 청산 대상의 탐색

청산 대상 탐색의 경우 이더리움의 데이터를 통해 compound의 컨트랙트에 거래를 보낸 기록이 있는 계정들의 1) 현재 담보물 가치 및 2) 빌린 토큰의 가치를 collateral factor 등과 비교함으로써 이뤄질 수 있습니다. 다만 청산자들의 역할이 Compound를 건전하게 유지하는데 굉장히 중요하기 때문에, Compound 측에서 이미 간편하게 API를 만들어 개발자들에게 제공하고 있습니다(Compound API 문서: https://compound.finance/docs/api 참고). 따라서 이 아티클에서는 해당 API에 대해 간략하게 기술하겠습니다.

Compound의 AccountService API를 통해 Compound를 사용했던 account들의 정보를 받아올 수 있습니다. 예시로, AccountRequest API 에 다음과 같은 파라메터들을 사용해 호출할 수 있습니다.

참고로, max_health 의 경우 계정들의 health 값(빌린 토큰의 가치를 담보물 가치로 나눈 값으로, 만약 1 미만이라면 청산 대상)을 필터하는 파라메터로, 10이라면 health가 10 미만의 계정을 리턴하게 됩니다.

Response로는 특히 account에 대한 정보를 다음 예시와 같이 리턴해 줍니다. 해당 계정의 health 값 뿐만 아니라, 얼마만큼의 암호화폐를 담보로 잡았는지 / 빌렸는지에 대한 정보까지 알 수 있습니다.

실제 청산자의 입장에서는 account.health가 1 미만인 계정을 빠르게 파악해 청산을 시작하게 됩니다.

실제 https://chiragkhatri.me/compound-liquidator/ 링크로 들어가면, 이더리움 계정별로 가지고 있는 health값이나 담보물 가치 등을 확인할 수 있습니다.

이 외로도 Compound는, 개발자들이 Compound protocol을 손쉽게 이용할 수 있도록 CTokenService(특정 cToken 시장의 borrow rate, collateral factor, total_supply 등을 리턴해주는 API) 등 다양한 API들을 제공하고 있습니다.

2. 청산

앞선 1)청산 대상 탐색 과정을 통해 청산 대상인 계정과 해당 계정의 담보물 토큰 주소(cToken 주소)를 알아 냈다면, 해당 cToken contract (이 경우에는 cETH contract) 의 liquidateborrow 라는 함수를 호출하게 됩니다. (예시: https://etherscan.io/tx/0xb7ba825294f757f8b8b6303b2aef542bcaebc9cc0217ddfaf822200a00594ed9 )

다음과 같은 형태로 liquidateBorrow를 호출할 수 있습니다. 차입자 주소(청산 대상 계정 주소)와 cTokenCollateral(담보물 컨트랙트의 주소)의 주소를 같이 입력하고, Message value에 repay할(담보물을 얼마나 구매할 것인지) ETH의 양을 입력합니다.

function liquidateBorrow(address borrower, address cTokenCollateral) payable

(참고: https://compound.finance/docs/ctokens#liquidate-borrow)

Web3 1.0 예시로는 다음과 같습니다. 그리고 다음 함수는 cToken 컨트랙트의 liquidateBorrow 함수를 트리거하게 됩니다.

LiquidateBorrow

Liquidateborrow가 cTokenCollateral 컨트랙트에서 호출되면, 곧바로 CToken에서 정의된 liquidateBorrowInternal를 호출하게 됩니다.

이어 CToken.sol에서 정의된 liquidateBorrowInternal 함수를 살펴 보겠습니다.

이 함수는 accureInterest()를 통해 대출 컨트랙트의 interest 업데이트를 해 주고, CTokenCollateral로 받은 담보물 컨트랙트 또한 interest update를 해주게 됩니다. 이후 liquidateBorrowFresh를 호출하며, 실질적인 청산 과정은 liquidateBorrowFresh 함수에서 일어나게 됩니다.

liquidateBorrowFresh 함수 중 liquidateBorrowAllowed 함수의 경우 Comptroller.sol 컨트랙트에 속한 함수로, 경우 주요하게 다음 두가지를 검사해 실제 청산이 가능한지 리턴하게 됩니다.

  1. 청산 대상이 되는 borrower가 실제 liquidate 가능한 계정이 맞는지 확인
  2. Repay amount를 검사해 closeFactor에서 정의된 청산량 이상으로 청산하지 않는 것인지 확인

(구체적인 코드는 링크의 Comptroller.sol — liquidateBorrowAllowed 참고)

청산이 가능하다면, repayBorrowFresh(liquidator, borrower, repayAmount) 함수를 호출해 repay amount만큼 담보를 구매하게 됩니다.

RepayborrowFresh 함수의 경우 liquidateBorrowFresh와 동일하게 repayBorrowAllowed 함수를 통해 실제 repay가 가능한지 검사하고, repay를 수행하여 tx fee등을 고려해 실제 repaid amount를 계산하게 됩니다. 수행 이후 이에 따라 Borrower의 borrow 양 또한 감소하며, 해당 시장의 totalBorrow 양 또한 동일하게 감소하게 됩니다.

(구체적인 코드는 링크의 cToken.sol — repayBorrowFresh참고)

이후 liquidateCalculateSeizeTokens 함수를 통해 담보물 중 압류(seize)할 토큰의 갯수를 계산합니다.

(구체적인 코드는 링크의 Comptroller.sol — liquidateCalculateSeizeTokens참고)

압류당할 토큰의 갯수를 계산하기 위해,

  1. Price oracle을 통해 대출금과 담보물의 가치를 계산합니다.
  2. 다음과 같은 식을 통해, 실제 repay amount중 얼마만큼의 토큰을 담보로 잡을 것인지 계산합니다. 이때

식은 다음과 같습니다.

  • seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral 이고
  • seizeTokens = seizeAmount / exchangeRate 이므로,
  • seizeTokens = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)
  • 입니다. (seizeAmount = actualRepayamount 이므로)

여기서 exchangeRate는 cToken과 underlying asset의 교환 비율입니다.

이후 실제 seize 함수를 통해 borrower와 청산자의 잔고를 업데이트 하게 됩니다.

(구체적인 코드는 링크의 CToken.sol — seize참고)

3. 청산 이후

잔고가 업데이트 되면, 청산자는 자신의 청산한 만큼의 cToken을 얻게 됩니다. 청산자는 이를 통해 추가 이자 수익을 받을수도 있고, 아니면 cToken을 변환해 거래소에 바로 판매해도 됩니다. 일반적으로는 가격 변동 리스크를 줄이기 위해, 거래소에 판매합니다.

Recap: 예시를 통한 청산과정 이해

우선 예시를 단순화하기 위해 아래와 같은 가정을 하겠습니다.

< 가정 >

  1. 1 ETH = 1 DAI = $1
  2. 담보비율(Collateral Factor) = 70%
  3. 5% < Close Factor < 90%
  4. Liquidation Incentive = 5%

차입자 A가 150 ETH($150)를 담보로 105 DAI($105)를 빌렸다고 생각해봅시다. 담보비율이 70%이기 때문에 A가 빌릴 수 있는 최고금액은 $105, 즉 105 DAI가 될 것이므로 A는 차입가능한 최대 금액을 빌린 것입니다.

이후에 ETH의 가격이 10% 떨어졌다고 가정하면, 결과적으로 A는 150 ETH($135)를 담보로 105 DAI($105)를 빌린 것이 됩니다. 담보물 가치의 하락으로 담보 부실화가 발생한 것입니다. 담보비율을 계산해보면 기존의 70%에서 77%로 약 7%p 상승하였습니다. 담보비율의 상승으로 계좌 유동성이 0보다 작아졌기 때문에 해당 계좌는 청산의 대상이 됩니다.

청산자 L이 20 DAI($20) 정도를 청산하고자 한다면, L은 cDAI 컨트랙트에서 liquidationBorrow 함수를 호출합니다. 컴파운드에서는 해당 함수의 호출이 적절한 것인지 검사하는데, Comptroller의 함수를 통해 이를 수행합니다. 검사가 끝나면 L은 20 DAI만큼을 repay하여 일정 비율의 담보물을 seize하게 되는데, A가 가진 담보물에 대응되는 cToken을 L이 가져가는 형태로 이루어집니다. 이때 일정 비율이란 A의 전체 담보물에 close factor를 곱한 값이며, L은 close factor에 해당하는 비율의 담보물에 더해 liquidaton incentive의 명목으로 추가적으로 지급되는 부분까지 한 번에 받게 됩니다.

결과적으로 L은 20 DAI($20)을 지불하여 20*1.05 = $21의 가치를 가지는 cETH를 받게 되고 이를 현재 시장가격에 판매하여 $1의 차익을 얻을 수 있습니다. 청산 이후 A는 $114만큼의 ETH를 담보로 85 DAI를 빌린 상태가 되고, 담보비율이 74%로 청산 이전보다 약 3%p 낮아진 것을 확인할 수 있습니다. 담보비율이 70%로 회귀할 때까지 청산자들에 의한 청산은 위의 절차를 거치면서 반복될 것입니다.

청산 관련 통계

그림 1
그림 2
그림 3

위의 세 가지 그림은 모두 EtherScan에 기록된 정보들을 바탕으로 실제 청산 활동이 어떤 노드들에 의해 얼마나 활발히 이루어지고 있는지 나타낸 자료입니다.

그림1은 암호화폐 가격 변동성이 높던 2019년 5월에서 12월까지 8개월간 월별 청산 활동의 발생 횟수와 청산금액을 나타낸 막대 그래프입니다. 이를 바탕으로 11월 담보물의 Price Volatility가 10%에 육박하면서 가장 높은 청산 횟수를 기록하였으며, 약 $2M만큼의 청산 금액이 발생하였음을 알 수 있습니다. 일반적으로 자산 가격의 변동성이 높을수록 청산자의 입장에서 청산 유인이 높아집니다. 담보 부실화가 진행되는 방향으로 가격이 크게 움직이면 청산의 대상이 되는 계좌도 많아지고, 담보비율의 급격한 변동으로 전체 담보물 중 청산이 가능한 부분도 커지기 때문입니다.

그림2는 각각 청산 활동이 높은 상위 청산자 노드들의 주소와, 청산당한 차입자 노드 중 청산 금액이 높은 상위 노드들의 주소를 표시한 것입니다. 청산자 노드들의 경우 총 119명의 청산자가 평균 $3.4 만큼의 차익을 내는 것으로 확인할 수 있으며, 상위 20개 청산자 노드들이 전체 이익의 50% 가까이 차지함을 알 수 있습니다.

차입자 노드들의 경우 역시 특정 노드들이 높은 청산 횟수와 청산 금액을 보이고 있습니다. 이와 같은 불균형적인 분포는 암호화폐 투자에 있어 가격 변동 위험을 감수한 차입자들의 잘못된 가격 예측에서 기인하였다고 볼 수 있습니다. 레버리지 투자를 통해 막대한 차익을 노린 차입자가 많은 금액의 암호화폐를 차입한 경우 그에 상회하는 담보물을 설정해야 합니다. 차입자의 예측과 반대로 암호화폐 가격이 변동하게 되면 담보 부실화로 인해 청산 대상이 되는 금액의 크기는 차입한 금액에 비례하여 엄청나게 커질 것입니다. 따라서 차입자 노드들을 기록한 표는 차입자의 차입 금액과 차입 횟수를 나타낸다고 볼 수도 있을 것입니다.

Summary

이제까지 Compound protocol의 청산 과정을 살펴 보았습니다. 글에서도 언급했듯, Liquidator로 인한 청산은 Compound의 대출을 건전하게 만드는 굉장히 중요한 과정입니다. 그리고 Defi에 익숙한 개발자라면 돈을 벌수 있는 기회이기도 합니다. Dune analytics를 통해 실제 청산 수익 데이터를 보았을때, Compound V2의 청산자 계정 중 top 2는 각각 $3.4M, $2.2M 정도의 수익을 얻기도 했습니다. 아직까지는 이러한 청산 시장이 매우 커지지는 않았지만, 앞으로 Defi 시장이 커지면 커질수록 이러한 청산 시장의 크기와 중요성 또한 계속해서 부각되어 갈 것으로 예측됩니다.

다만 이러한 청산 과정을 조사하면서 이더리움 자체의 한계(비싼 수수료)로 인해 소액대출의 경우에는 청산이 잘 이루어지지 않는 것도 함께 관찰할 수 있었습니다. https://chiragkhatri.me/compound-liquidator/ 대시보드를 통해 보더라도, unsafe 하지만 거래 수수료보다 청산으로 얻는 기대수익이 더 작은 소액대출의 경우 청산이 잘 이뤄지지 않고 있음을 볼 수 있습니다. 이러한 청산되지 않는 소액 대출이 점점 누적된다면, Compound 자체의 대출 건전성에도 영향을 미칠수 있다는 리스크가 존재하며 앞으로 해결되어야 할 부분들 중 하나입니다.

--

--