[Alchemix series] 2. Alchemix 구성 알아보기

Mingyu Jo
Decipher Media |디사이퍼 미디어
18 min readFeb 22, 2022

[Alchemix series]

  1. Alchemix 톺아보기
  2. Alchemix 구성 알아보기
  3. Alchemix Review: 현재와 미래

Alchemix 톺아보기 시리즈 2편에서는 Alchemix를 구성하는 요소들인 Vault, Farm, Transmuter, Treasury에 대해 다뤄보겠습니다. 또한 몇몇 중요한 부분에서는 컨트랙트 코드와 함께 부록으로 설명을 추가했습니다.

Alchemix 프로토콜은 머니 레고를 통한 새로운 금융 상품이기에 그 여러 요소들이 유기적으로 연결되어 있는 형태입니다.

1. Alchemix 생태계의 중심, Vault

Vault는 유저들이 담보물로 스테이블 코인을 맡기는 곳으로, Alchemix 생태계에서 중심 역할을 한다고 볼 수 있습니다. Vault의 작동을 예시를 통해 단계별로 설명하면 다음과 같습니다.

  1. 유저가 Vault Contract에 DAI를 담보로 맡긴다.
  2. 담보물 가치의 최대 50%까지 alUSD를 빌린다.
  3. 담보로 예치된 DAI는 Yearn Finance 의 yDAI Vault에 예치한다. (Yield Aggregator로는 yearn.finance를 사용한다.)
  4. yDAI Vault에서 발생한 수익을 클레임해서 Vault로 가지고 온다.
  5. 발생하는 이자수익만큼 alUSD로 표시된 시스템 전체의 대출금을 감소시킨다. 이 때 유저 별로 맡긴 담보물의 양에 비례하여 대출금을 감소시켜 준다. 만약 대출한 금액이 없다면 alUSD borrow limit을 올려준다.
  6. 대출금이 줄어든 유저는 줄어든 만큼 추가로 alUSD를 대출 할 수 있다. 이때의 담보비율은 동일하게 50%를 지켜야 한다.
  7. Transmuter Contract로 5에서 처리해준 이자 수익을 넘겨준다.
  8. 만약 유저가 Transmuter에서 alUSD를 staking해 뒀다면 발생한 이자수익 한도 내에서 staking양에 비례해서 DAI로 출금해준다. DAI출금 이후에 해당하는 가치만큼의 alUSD는 소각된다.

유저들은 언제든 자신의 대출금을 상환하고 담보물을 찾아갈 수 있습니다. 대출금은 alUSD로 발행되었지만, DAI로도 상환할 수 있습니다. 또한 유저들은 언제든지 담보물 DAI의 일부를 alUSD로 liquidation해서, 상환에 활용할 수 있습니다. 이렇듯 Alchemix는 진입과 퇴출이 자유롭습니다.

한편, 다른 프로토콜 (yearn.finance) 에 이자 수익을 의존하기 때문에 yearn.finance에 문제가 생기면 바로 모든 토큰을 해당 aggregator에서 출금합니다. 이에 대한 기술적인 사항은 본 문서 최하단에 컨트랙트 코드와 함께 서술했으니 참고하시기 바랍니다.

스테이블 코인에 관한 정책들

Alchemix는 Chainlink price oracle을 사용하고 있으며, 오라클을 통해 페깅이 깨졌다는 것을 확인할 경우 해당 스테이블 코인과 관련된 모든 거래가 중지됩니다.

한편, 향후 Alchemix는 업데이트를 통해 여러 스테이블코인을 지원할 계획이라고 합니다. 이 때 각각의 스테이블코인의 페깅 안정성이 다르므로 담보비율에 차등을 둘 것입니다. 안정적으로 스테이블코인 페깅이 유지될 것이라는 신뢰가 갖춰진 경우, 유저들은 arbitrage를 통해서 alUSD의 페깅을 맞추는데에 기여할 것입니다. 또한 Alchemix에서 지원하는 스테이블코인 모두 Alchemix내에서 alUSD와 동일하게 취급받으므로, 이더리움 생태계 내의 스테이블코인 간 차익 거래가 Alchemix에서 가능해집니다. 위와 서술한 과정이 이뤄지면 Alchemix뿐만 아니라 전체 스테이블코인 생태계의 안정성에 기여하리라 기대합니다.

2. ALCX토큰의 분배와 alUSD의 유동성 확보전략, Farming

Defi protocol이 원활하게 작동하기 위해서는 초기 사용자들이 유동성을 공급해주어야 합니다. 따라서 대부분의 Defi protocol은 초기에 유입된 사용자에게 인센티브를 주는 토크노믹스를 가지고 있는데, Alchemix도 예외는 아닙니다. Alchemix의 경우 Farming Pool을 런칭하여 유동성을 공급하면 다음의 비율로 가버넌스 토큰인 ALCX토큰을 민팅해주었습니다.

  • alUSD3CRV-f LP tokens: 18%
  • ALCX/ETH SLP(Sushi Liquidity Pool) tokens: 60%
  • alUSD tokens: 2%
  • ALCX tokens: 20%

이 중 프로젝트의 초기 성공에 가장 큰 역할을 한 것은 alUSD token pool이었습니다. alUSD의 circulating supply가 적었던 초기에 해당 풀의 수익을 누리기 위해 DAI를 예치하고 alUSD를 대출해가는 사람들이 많았고, self liquidation을 통해 맡긴 DAI를 청산시켜 프로토콜은 안정적으로 많은 DAI를 보유할 수 있게 되었습니다. 프로토콜이 보유한 DAI가 많아지며 alUSD-DAI의 페깅도 잘 유지할 수 있었습니다.

https://alchemix-finance.gitbook.io/alchemix-finance/token-distribution/alcx-monetary-policy

Alchemix의 가버넌스 토큰인 ALCX는 위 그래프의 파란색 선에서 확인할 수 있는 것처럼 런칭 후 3년간 발행량이 선형적으로 감소합니다. 첫 주에는 22,344개가 민팅되며 그 후부터 매주 130개씩 감소하여 런칭 후 3년 후부터는 매주 2200개로 고정됩니다. 이러한 토크노믹스를 채택함으로써 초기 진입자에게 인센티브를 주면서도 발행량을 직관적으로 예측 가능하게 하여 Alchemix 생태계를 안정화하는 데 기여했습니다.

https://www.defipulse.com/projects/alchemix

그 결과 Alchemix의 정식 런칭 이후 약 1년이 지난 지금까지 성공적으로 TVL을 늘려가면서 Ethereum Defi 생태계의 일원으로 자리 잡을 수 있었습니다.

3. alUSD-DAI 페깅을 위한 장치, Transmuter

Transmuter 는 Alchemix protocol에서 가장 도드라진 요소라고 할 수 있습니다. ‘변환기'라는 이름에 걸맞게 1alUSD를 스테이킹하면 점진적으로 1DAI로 바꿔주는 Transmuter는 페깅을 유지하는 중요한 역할을 합니다.

https://app.alchemix.fi/transmute

alUSD 페깅을 보장하기 위해서는 유저들이 1alUSD를 통해 1DAI 를 얻을 수 있어야 합니다. 만일 시장에서 1 alUSD가 1 DAI보다 낮은 가격으로 거래된다면 (높은 가격으로 거래되는 경우에는 일반적인 dex를 사용할때의 이익이 더 크기 때문에 다루지 않습니다.) 유저들은 자신의 alUSD를 다시 DAI로 전환할 필요를 느끼게 됩니다. 이때 Alchemix Transmuter에 alUSD를 스테이킹하게 되면 앞서 밝혔듯 yearn.finance에 유저들이 예치한 DAI로부터 나오는 수익의 90퍼센트를 사용하여 Transmuter의 alUSD를 점진적으로 DAI로 바꿔주고 이때 상환이 끝난 alUSD는 소각하게 됩니다. Transmuter 내부에서는 alUSD와 DAI의 가치를 동일하게 책정하기 때문에 Transmuter가 작동한다면 alUSD와 DAI의 1대1 페깅이 유지됩니다.

흥미로운 점은 transmuter에서 변환해주는 DAI 는 유저가 예치한 DAI를 통한 직접적인 변환이 아닌, 프로토콜의 이자 수익의 90퍼센트를 DAI로 넣어주는 점입니다. 이런 과정을 통해 유입된 자금이 빠져나가는 것을 막고 프로토콜이 관리하는 자금을 극대화하여 유저들에게 돌려주는 구조가 가능합니다.

Boost Yield

Yearn Finance로부터의 수익의 90퍼센트는 Transmuter로 저장됩니다. 만일 Transmuter의 누적 DAI양이 alUSD보다 많아지면 남는 DAI의 경우 잉여금이 되어 사용처가 없는 상태로 잔류하게 됩니다. Alchemix DAO는 필요한 경우에 Transmuter에 적은 수량(500만 DAI)의 버퍼를 유지한 채 나머지 Transmuter의 자금을 Yearn에 재투자하여 프로토콜의 수익을 올리는것을 결정했습니다. 가버넌스를 통한 위의 결정은 프로토콜 수익을 극대화하여 더 빠르게 DAI를 확보할 수 있게 하며 이를 Boost Yield로 칭하였습니다.

Boost Yield 덕분에 10퍼센트의 perfomance fee (수익의 10퍼센트가 Treasury 에 저장되는 것)를 제하고도 유저들은 DAI를 직접 yearn.finance에 예치하는 것보다 더 큰 수익을 기대할 수 있게 되었습니다. ALCX 가버넌스를 통한 위의 결정처럼 프로토콜의 이익이 직접적으로 유저에게 득이 되는 방향으로 앞으로 Alchemix DAO의 의제가 발의되고 진행될 것이 기대됩니다.

4. Treasury

Alchemix Treasury Account. Etherscan

Treasury는 구조적으로는 매우 간단합니다. Vault에 예치된 DAI yearn.finance에 투자하고 나오는 이자수익의 10퍼센트를 저장하는 역할을 하는데, Treasury에 저장된 DAI의 일부는 DAO의 참가자들에게, 그리고 개발자들과 Alchemix 재단의 프로토콜 확장을 위한 목적으로 사용됩니다. Alchemix DAO에 의해 관리될 예정입니다. 이자 수익의 10퍼센트에 그치지만 현재의 예치 규모를 고려 할 때 절대 무시할 수 없을만큼의 자본이 쌓이게 됩니다. 앞으로 Alchemix DAO의 방향성과 프로토콜 확장에 따른 시너지가 기대가 되는 상황입니다.

정리

앞서 Alchemix의 구성 요소들을 살펴보았는데 디파이를 통한 머니레고의 특장점들을 살려 대출금이 자동으로 갚아지는 렌딩 프로토콜을 만들기 위해 여러 장치들을 고안해 낸 점에서 관심을 끄는 Defi protocol입니다. 지금까지 살펴본 내용들에 기반하여 다음 글에서는 Alchemix가 지니는 리스크와 앞으로의 방향성에 대해 더욱 자세히 살펴보고 시리즈를 마무리할 생각입니다.

*부록1 : Alchemix Vault With Contract Code.

최상단에 기재한 Vault의 단계별 설명에서 5~6번의 과정과 비상 탈출 (emergencyExit) 함수를 Solidity 컨트랙트 코드와 함께 살펴보도록 하겠습니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/Alchemist.sol

Alchemist.sol에서 harvest 함수가 실행되어 Yield Aggregator에 쌓인 이자를 수확하고 나면, 먼저 이자 수익의 10%를 treausury에 protocol fee 로 예치합니다.(token.safeTransfer(rewards, _feeAmount)) 그후에 나머지 90%는 현재 전체 deposit 양으로 나눠서 누적 weight를 전역 _ctx에서 늘려줍니다. 그리고 나서 그 나머지 90% 이자를 transmuter로 전송해서 alUSD와 교환될 수 있게 해줍니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/libraries/alchemist/CDP.sol

이제 업데이트된 전역 _ctx를 가지고 각 유저가 가진 CDP(Collateralized Debt Position, 프로토콜에 관계된 담보, 대출금 관계)를 업데이트해줄 수 있습니다. CDP.solgetEarnedYield 함수를 유저의 개별 데이터인 _self를 가지고 호출하면(후술함) 이전의 accumulatedYieldWeight와 비교해서 차액분만큼이 아직 유저의 CDP에서 반영 안 된 그 동안의 담보물 1단위당 누적 이자수익입니다. totalDeposited만큼 곱해서 현재의 earnedYield를 계산할 수 있습니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/libraries/alchemist/CDP.sol

그러면 update 함수에서 해당 _earnedYield만큼을 debt에서 빼줄 수 있습니다. 만약 유저가 가진 totalDebt보다 EeanedYield가 크다면 차액분이 credit이 됩니다. 요컨대, CDP.solupdate 함수는 그 동안 Vault의 유저 몫에 쌓인 이자수익을 해당 시점에 정산해주면서 전체 Vault와 해당 유저의 싱크를 맞춰주는 역할을 합니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/Alchemist.sol

CDP.solupdate함수는 harvest가 일어날 때마다 모든 user CDP에 연산이 모두 적용되는 것이 아니라, 가스비를 아끼기 위해 유저가 어떤 액션들을 할 때 그 전에 싱크를 맞춰주는 식으로 사용됩니다. 액션들이란 다음의 5가지를 말합니다.

  • deposit : 담보 예치 함수
  • withdraw: 담보 상환 함수
  • repay: 대출금 일부 혹은 전부 상환 함수
  • liquidate: 담보물을 팔아서 alUSD를 구매하는 함수
  • mint: 담보물 가치의 최대 50%까지 alUSD를 민팅하여 대출해가는 함수

위의 코드 캡쳐는 withdraw를 예시로 들었습니다.

한편, 외부 컨트랙트 등에 문제가 생겼을 때비상 탈출 함수는 다음과 같이 구현되었습니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/Alchemist.sol

위와 같이 setEmergencyExit에서 emergencyExittrue로 선언해줍니다. governance 투표/의논 결과가 있어야 움직일 수 있는 governance address (sentinel은 우선 생략)만이 해당 함수를 호출할 수 있습니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/Alchemist.sol

그 후 위와 같이 _recallFunds 함수를 호출하여 Vault들의 자금들을 Contract 내부로 이동시켜줄 수 있습니다(valut.withDraw(address(this), _amount) ). 이 함수는 internal 함수이므로 address(this)는 컨트랙트 내부 주소를 의미합니다.

부록2 : Alchemix Transmuter With Contract Code.

Transmuter는 Alchemix의 도드라진 특징이므로 코드와 함께 Transmuter에 staking부터 claim까지의 과정을 순서대로 코드와 함께 다뤄보도록 하겠습니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/Transmuter.sol

alUSD를 DAI로 바꾸고 싶은 유저는 Transmuter.solstake함수를 통해 유저의 alUSD를 Transmuter에 staking 합니다. 해당 함수는 totalSupplyAltokens의 총량을 유저가 스테이킹한 수량만큼 증가시키고, 해당 유저에 대해 depositedAlTokens를 staking 수량만큼 증가시킵니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/Transmuter.sol

Vault로부터 발생한 이자 수익은 increaseAllocation함수를 통해 Transmuter에 전달되는데, 이때의 amount는 Treasury에 할당된 10퍼센트를 제외한 90퍼센트의 수량입니다. 이때 두가지 경우가 생기는데 totalSupplyAltokens 가 0을 초과하거나 0인 경우입니다. amount 조건에 대해서는 언급하지 않았는데 이는 0인 경우 아무런 변화가 없기 때문에 1이상인 경우를 가정하고 진행하겠습니다.

먼저 totalSupplyAltokens > 0 이며 amount > 0 인 경우를 살펴보도록 하겠습니다. 이 경우 totalDividendPointsunclaimedDividends를 업데이트 하는데 pointMultiplier는 10e18로 정밀 계산을 위한 상수 정도로만 알고 있으면 됩니다. 위의 계산식은 Transmuter 가 받은 DAI수량을 전체 alUSD 수량으로 나누어 각각 받을 수 있는 가중치를 계산하는 것이고 unclaimedDividends 에는 수령 가능한 총량을 추가하게 됩니다.

다음으로 totalSupplyAltokens == 0이거나 amount == 0인 경우입니다. 해당 분기는 현재 Transmuter에 예치된 alUSD가 없는 상태인데 이 경우에는 Transmuter의 DAI 보유량을 늘리는 것으로 마칩니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/Transmuter.sol
tokensInBucket : 유저가 claimable한 baseToken의 수량
depositedAlTokens: 유저가 staking한 alToken의 수량

다음은 각 유저가 호출하는 transmute함수에 대한 설명입니다. 유저가 수령가능한 ( claimable ) baseToken의 수량은 tokensInBucket mapping에 저장되어 있습니다. 순차적으로 살펴보자면

  1. claimable한 양이 staking한 양보다 많으면 diff를 미리 저장하게 됩니다. ( 나중에 해당 수량 만큼을 다시 increaseAllocation을 통해 Transmuter 에 재분배 됩니다. )
  2. staking된 양에서 claimable한 양을 줄입니다.
  3. transmute함수를 통해 유저에게 할당할 baseToken만큼의 alToken을 소각합니다.
  4. 1번에서 over claim할 수 있는 양을 위의 increaseAllocation 함수를 통해 전체 alToken staker들에게 재분배합니다.
  5. realisedTokens에 해당 유저가 claim 가능한 baseToken의 수량이 저장됩니다.

사실 위의 과정에서 간과한 것이 하나 있는데 어떤 유저에게 할당된 수량이 이미 예치 수량을 넘긴 경우 해당 수량을 다시 분배하는 로직이 필요합니다. Transmuter.sol 에서는 이를 forceTransmute 함수를 통해 해결합니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/Transmuter.sol

forceTransmute 는 다른 유저의 unclaimed 된 수량을 강제로 realisedTokens 에 담아 해당 유저의 포지션을 종료시키는 역할을 합니다. 함수 실행 조건이 수령가능한 수량이 예치 수량을 넘어갔을 때 실행된다는 점을 제외하면 위에서 언급한 transmute 함수와 동일합니다.

https://github.com/alchemix-finance/alchemix-protocol/blob/master/contracts/Transmuter.sol

위의 과정들을 모두 거치면 최종적으로 유저가 수령할 수 있는 baseToken을 가져오는 claim 함수를 실행시켜 realisedTokens 의 수량 만큼을 유저의 지갑으로 전송합니다. 이로써 Transmuter의 코어 로직을 모두 살펴보았습니다.

--

--