Basis Cash 採用了三幣模型,BAC (Basis Cash)、BAS (Basis Share)、BAB (Basis Bond)三者相當於貨幣、股票和債券。

推薦閱讀:《鏈聞精選|讀懂算法穩定幣:Ampleforth、Basis Cash、ESD 和 Terra

原文標題:《Code Review 回顧:算法穩定幣 Basis》
撰文:要飛的 Harry

2021 年 1 月 6 日晚上 9 點,我們組織大家一起 review 了算法穩定幣中的 Basis,視頻回顧在 這裏 ,非常感謝菠菜的分享。

目前的穩定幣一共分爲三種:

  • 錨定法幣,比如 USDT 和 USDC,也包括交易所發行的穩定幣,例如 BUSD、HUSD 等。
  • 鏈上資產抵押型,比如 MakerDAO 的 DAI 和 Synthetix 的 sUSD。
  • 算法穩定幣,比如 AMPL、ESD、Frax,還有今天要說的 Basis。

算法穩定幣經歷了幾個階段,basis 是一個很新的項目,採用了三幣模型。

Basis 機制

Basis 有三個幣:BAC (Basis Cash)、BAS (Basis Share)、BAB (Basis Bond),三者相當於貨幣,股票和債券。可以將 Basis 理解爲一個央行,BAC 是央行發行的貨幣;BAS 是央行的股東持有的股票,需要承擔系統風險,也獲取系統的收益;BAB 是債券,相當於央行的債券。這 3 個都是 erc20 token,BAB 目前沒有日期限制,只要在合適的價格就可以兌付。

BAC 價格調節機制就是一個市場供需的調節機制。

  • 當 BAC 價格少於 1 美元,需要減少 BAC 流通,讓 BAC 的價格自然上升到 1 美元

    • BAC 價格少於 1 美元,用戶可以用申購債券 BAB,方式是銷燬 BAC,得到 BAB

    • BAB 價格 = BAC 價格的平方,因爲 BAC 價格小於 1,所以平方後的 BAB 的價格會更低

    • 未來可以用一個 BAB 換回一個 BAC

  • 當 BAC 價格超過 1 美元,需要增加 BAC 流通,讓 BAC 的價格自然下降到 1 美元

    • 目前的閾值是當 BAC > 1.05 時,可以觸發系統增發 BAC

    • 增發的 BAC 會發給持有 BAB 和 BAS 的用戶

    • 優先還債,所以先給持有 BAB 的用戶,方式是銷燬 BAB,得到 BAC

    • 剩下的 BAC 給 BAS 持有人,如果沒有剩餘,則不給 BAS 持有人分配

    • BAS 相當於股東,只有鎖定到 boardroom 合約 的 BAS 才能獲得這部分收益

代碼解讀

源碼

treasury.sol

合約中主要的方法包括:

setFund:修改社區發展基金接收地址

setFundAllocationRate:修改社區發展基金從 BAC 增發中接收的比率

getBondOraclePrice:通過預言機獲取 Uniswap 上 BAB 的價格

getSeigniorageOraclePrice:通過預言機獲取 Uniswap 上 BAC 的價格

bugBonds:購買債券,targetPrice 參數是給前端進行校驗的,只有當 BAC 小於 1 美元才能執行

redeemBonds:贖回債券,BAC 價格要大於 1.05 美元才能執行

allocateSeigniorage:分配系統收入

  • 價格小於 1.05 不執行,大於 1.05 才計算髮多少錢

  • 需要在一個 epoch (週期)開始後才能執行, 代碼中的 checkEpoch 是 1 個 modifier,用來檢查這個條件

  • 計算增髮量,並增發

uint256 seigniorage = cashSupply.mul(percentage).p(1e18); 

IBasisAsset(cash).mint(address(this), seigniorage);
  • 每次增發的總量的 2% 會進入到 Community Development Fund (社區發展基金)
    uint256 fundReserve = seigniorage.mul(fundAllocationRate).p(100);

    IERC20(cash).safeApprove(fund, fundReserve);

    ISimpleERCFund(fund).deposit(...)  
  • 發給債券持有人
    uint256 treasuryReserve = ...;

    accumulatedSeigniorage = accumulatedSeigniorage.add(treasuryReserve);

    emit TreasuryFunded(now, treasuryReserve);  
  • 給股票持有人(BAS),也就是給 boardroom
    IBoardroom(boardroom).allocateSeigniorage(boardroomReserve);

Boardroom.sol

Boardroom 相當於董事會,是 Basis 股份的持有者。合約的主要方法有:

  • allocateSeigniorage:計算可以分配多少錢
  • claimReward:取錢操作

Timelock.sol

時間鎖是治理體系不可或缺的一部分,通過 Timelock 限制超級用戶對系統參數的修改,使普通用戶有足夠的時間進行決策,這裏的 Timelock,參數需要等待至少 2 天才能生效。

    uint256 public constant MINIMUM_DELAY = 2 days;  
    uint256 public constant GRACE_PERIOD = 14 days;  
    uint256 public constant MAXIMUM_DELAY = 30 days;  

還有個巧妙的 onlyOneBlock, 限制 1 個塊中只能有 1 個操作者,防止多次調用。

  _status[block.number][tx.origin] = true;  
  _status[block.number][msg.sender] = true;  

總結

Basis 的代碼很巧妙,化繁爲簡,也很整潔,通過 3 種 token 的互相轉化,保持價格穩定。AMPL 的供應量是自動調整的,而 Basis 的 token 供應調整是通過激勵用戶的投機行爲,讓用戶主動參與的。