研究 | 深入Defi系列之Synthetix

在阅读本文前建议先阅读Synthetix Litepaper和一文读懂Defi热门项目Synthetix。这里先简单的介绍几个术语,Synthetix是一个Defi项目的名称,SNX是一种扩展了ERC20协议的代币,也是Synthetix的激励代币。Synth是指合成资产,比如sUSD、sBTC、iBTC等都是合成资产,其中s开头的是指做多,i开头的是指做空。债务池是指所有Synth的汇总,在Synthetix引入超额抵押借贷之后,要扣减借贷产生的Synth。债务池对应的抵押物SNX能捕获Synthetix交易合约产生的费用以及流动性挖矿产生的SNX,因此抵押SNX是有利可图的。

SNX

Synthetix的运行需要SNX,那么SNX是怎么产生的呢?根据icodrops的数据SNX在2018年3月启动ICO,初始发行100000000个,其中60%通过公开市场销售。

从2019年3月开始Synthetix启动了货币供应计划到2023年8月SNX的总供应量将会从100000000个增长到260263816个。新增的SNX会按比例分配给抵押了的SNX持有者,SNX奖励的细节会在后文讲述。

Synth

Synth有三种途径产生:

第一种是通过超额抵押铸造,这种方式的抵押物只有SNX,产生的Synth只有sUSD。第二种是通过超额抵押借贷,这种方式目前的抵押物只有ETH,产生的Synth有sUSD和sETH。第三种是通过交易。比如当你通过SNX抵押出sUSD之后如果想持有sBTC,那么可以在Synthetix的交易合约中先销毁sUSD然后铸造出sBTC,sUSD兑换sBTC的价格由Oracle提供。

抵押和交易产生Synth没有数量限制,而借贷产生的Synth有数量限制。借贷产生的债务不会进入债务池,也无法享有交易产生的手续费和流动性挖矿奖励。

SNX超额抵押铸造

SNX通过超额抵押可以铸造出sUSD,抵押后的SNX无法被转移,然后通过销毁sUSD可以解锁SNX使其重新能够流通,如果SNX的抵押率不足则会面临被清算的风险。

铸造

抵押账户上的SNX铸造sUSD的公式如下:

amount(sUSD) = amount(SNX) * price(SNX) * I-Ratio

Synthetix中很多运算(比如超额抵押铸造、计算账户的债务总量等)上都是以sUSD作为计价单位,而I-Ratio(Issue Ratio)是发行率(目前是0.2)。假定SNX的价格是100,那么抵押100个SNX(总价值是10000sUSD)产生的sUSD是2000个。

账户上所有可用来抵押的SNX由三个部分组成:

collateral(SNX) = amount(synthetix) + amount(synthetixEscrow) + amount(rewardEscrow)

amount(synthetix)是指SNX合约的余额,amount(synthetixEscrow)是指SNX托管合约的余额,amount(rewardEscrow)是指SNX奖励合约的余额。

抵押的SNX是被转移到哪个合约上了吗?不是的,抵押之后账户的SNX合约余额依然不会发生变化。但是当需要转移账户上的SNX时,合约会判断可以被转移的SNX数量。

tranferable(SNX) = amount(synthetix) – debt(SNX)

debt(SNX)是指以SNX作为计价单位的债务数量。由于债务池中的资产价格是在波动的,所以债务池的总债务数量也会波动,为了计算当前时刻账户的债务数量需要记录账户在债务池中的占比ownership。

debt = ownership * totalDebt

比如说账户在t0时刻的ownership是10%,totalDebt是100sUSD,则在t0时刻账户的debt是10sUSD。当t1(t1>t0)时刻totalDebt上升到200sUSD,则账户的debt变成了20sUSD。债务总量上升一般是债务池中资产价格的上涨导致的。debt(SNX)上升会导致tranferable(SNX)下降,账户的债务比上升。账户的债务比上升到一定程度就无法从FeePool中提取手续费和流动性挖矿奖励。当账户的债务比上升到一定程度的时候任何人都可以对这笔债务进行清算。

为了记录每个账户的债务占比,Synthetix引入了两个关键性的数据结构:IssuanceData和debtLedger

issuanceData记录每个账户的债务信息。initialDebtOwnership是指账户的债务在债务池中的占比,debtEntryIndex是debtLedger中对应的index。任何时候对账户进行新增债务或者销毁债务操作都会延展debtLedger,并重新设置账户的initialDebtOwnership和debtEntryIndex。

令在debtLedger的index=i时的总债务为t(i),debtLedger[i]为d(i),账户A的债务为d(A),在index=i+1时

initialDebtOwnership(A) = d(A)/t(i+1)
debtEntryIndex(A) = i + 1

d(i+1)的递推公式为:

d(i+1)=d(i)*[t(i)/t(i+1)], i > 0
d(0)=1, i = 0

如下图所示账户A给系统新增第一笔债务100sUSD,系统总债务是100sUSD,账户A的债务占比是1

然后当B增加900sUSD之后,d(1)=d(0)*t(0)/t(1)=0.1,如下所示

此时账户A的债务占比计算公式为:

debtOwnership(A) = [debtLedger(1)/debtLedger(0)] * initialDebtOwnership(A) = [0.1/1] * 1 = 0.1

事实上当账户A的debtEntryIndex为i,对于任意debtLedger的index为j(j>i)时计算账户A的债务占比公式为:

debtOwnership(A)= [debtLedger(j)/debtLedger(i)] * initialDebtOwnership(A)

公式右侧的推导过程如下:

[debtLedger(j)/debtLedger(i)] * initialDebtOwnership(A) = [d(j)/d(j-1)] * [d(j-1)/d(j-2)] * .. * [d(i+1)/d(i)] * initialDebtOwnership(A) = [t(j-1)/t(j)] * [t(j-2)/t(j-1)] * .. * [(t(i)/t(i+1))] * initialDebtOwnership(A) = [t(i)/t(j)] * [d(A)/t(i)] = d(A)/t(j)

而d(A)/t(j)正好就是账户A在index=j时的债务占比。

销毁

一般情况下铸造sUSD之后再销毁会有一个等待期,这个等待期目前是1天。销毁sUSD能降低debt(SNX),从而使tranferable(SNX)变大。销毁的过程跟铸造类似,比如账户B销毁200个sUSD,系统总债务变为800sUSD,B的债务占比变成0.875

而A的债务占比根据公式计算为0.125

debtOwnership(A)= [debtLedger(2)/debtLedger(0)] * initialDebtOwnership(A)=[0.125/1]*1=0.125
debtOwnership(A)=d(A)/t(2)=100/800=0.125

清算

账户的债务比C-Ratio是指账户的债务(以SNX为单位计价)与账户上可用的SNX之间的比值:

C-Ratio=debt(SNX)/collateral(SNX)

债务池中的资产的报价单位都是以sUSD,因此debt(SNX)会同时受到资产价格和SNX价格的影响。也就是说假如SNX价格不变,债务池中的资产价格上涨则debt(SNX)会变大。相对的,如果SNX价格下跌,而债务池中的资产价格不变,debt(SNX)也会变大。

当账户的C-Ratio超过一定的阈值(目前是0.5)会被清算,任何人都可以对C-Ratio超过阈值的账户进行清算。但是清算有一个缓冲期(目前是3天),在缓冲期内等待被清算的账户依然可以通过增加collateral(SNX)(比如购买SNX)或者销毁一定的债务来降低C-Ratio。

被清算的账户会施加一定比率的罚金p(目前这个值是0.1)。假定被清算账户是A,清算账户是B,清算过程是将B的sUSD销毁,然后将A的(1+p)倍等值的SNX转移给B,因此B的清算收益率是p。清算的目标是使账户A的C-Ratio恢复到初始的I-Ratio。令账户A的债务为D,抵押物为C,罚金比率为p,I-Ratio为r,需要清算掉的债务为F,则F必须要满足如下公式:

(D-F)/(V-(1+p)*F) = r
从而得到
F = (D-V*r)/(1-(1+p)*r)

ETH超额抵押借贷

通过抵押ETH可以从Synthetix系统中借出sETH和sUSD,抵押1个ETH可以借出0.8个sETH或者借出0.67个sUSD。为了控制风险,借出的sETH和sUSD总量是有上限的,sETH最多能借出5000个,sUSD最多能借出1000万个。赎回债务需要付出一定的利息,产生的利息会转换成sUSD注入到FeePool中分配给SNX的抵押持有者。如果ETH价格下跌导致抵押率不足,则债务会面临被清算的风险。

Synthetix交易

在Synthetix中除了sUSD和sETH可以通过铸造或者借贷发行外,其它的Synth都是通过交易产生的。Synthetix交易对以(src,dest)来表示,src指将会销毁的Synth,dest指将会发行的Synth,比如(sUSD,sBTC)意味着销毁sUSD然后发行sBTC。这点跟订单簿或者AMM区别很大,由于没有对手方所以Synthetix也不会有滑点和深度的问题,但风险就在于流动性可能不足,举个极端的例子:

系统总债务暴涨到10100sUSD之后,A和B分别承担5050sUSD的债务。为了保证债务比符合0.2的要求账户A必须要补充价值24750sUSD的SNX,对A来说这是没啥意义的,也不会有人愿意清算这笔债务。账户B可以销毁5050sUSD的债务来解锁价值500sUSD的SNX,但是剩下的4950sUSD只有名义上价值500sUSD的SNX作为抵押,使得sUSD基本上毫无价值,所以这笔获利也无法兑现。

除了流动性问题还有另外一个问题,那就是单个交易对发生报价错误会导致全体SNX抵押者极大的损失。比如上面那个BTC价格暴涨的例子,可能真实的价格是101,但是由于报价错误导致价格暴涨了100倍。如果抵押的SNX足够多,则B就获利巨大,而损失则由全体SNX持有人承担。再加上没有深度限制,B如果发现Oracle还在mempool中的交易价格为10000,而真实价格为101,则B可以提前(也就是通常所说的抢跑)以100的价格买入足够多的sBTC,等到Oracle的报价上链,再以10000的价格卖出sBTC,这个过程SNX抵押者的损失会无限放大。也许Oracle是诚实的,但Oracle也可能犯错,然后上报一个跟真实价格差异巨大的价格。

为了避免这个问题SIP-65引入了一种价格保护机制,Synthetix会记录每个Synth上一次交易的报价lastExchangeRate,使用lastExchangeRate与当前交易时的报价currentRate进行对比。如果倍数(currentRate/lastExchangeRate或者lastExchangeRate/currentRate)超过一定的阈值(目前这个值是3)交易会失败,这个交易对会被暂停直到protocalDao查明原因再重新恢复交易。

正常情况下行情不会在短时间内有一个超过3倍的插针,所以由于价格保护机制导致交易对被暂停实际上是非常罕见的情况。但是因为以太坊拥堵导致Oracle的价格不能及时的上链倒是可能经常发生。一旦价格不能及时上链就会有被套利的空间,比如

在上图所示过程中先观察到未上链的Oracle报价会比链上最新的报价高10%,所以立即买入1sBTC(通过提高TX的网络手续费率或者与矿工合谋使得TX0比Oracle的报价交易更早上链),然后等Oracle的报价交易上链再以这个价格卖出1sBTC,这样就可以无风险套利10%。为了缓解这个问题SIP-37引入了交易修正机制,通过交易得到的dest必须等待一个交易窗口期(目前是6分钟)之后才能卖出。比如上面这个例子假设在交易窗口期内t1时刻Oracle的报价上链了,那么再卖出1sBTC时需要先对TX0的交易进行修正。TX0会重新以1sBTC=110sUSD的价格来核算,账户需要给系统退还100*(1/100-1/110)约为0.09个sBTC。之所以说是缓解而不是解决是因为Oracle的报价可能过了窗口期都没能上链,那么套利还是会发生。反过来如果链上价格比实际价格高,那么购买1个sBTC就亏了,这个时候系统会将差价返还给账户。交易修正除了在交易过程中会引入,凡是需要转出或者销毁Synth的地方都会引入,比如转出Synth、铸造sUSD、销毁债务、清算债务。

FeePool

FeePool负责收集交易产生的费用和流动性挖矿产生的奖励,费用和奖励的分配要依照SNX抵押者在债务池中的债务占比来决定。比如产生了100sUSD的交易费用,账户A的债务占比是10%,那么账户A就可以分配10sUSD的交易费用。假如账户A刚发行债务把奖励取走,然后就立即把债务销毁,那A就基本上不用承担债务池膨胀的风险而获得收益。实际上这个风险就由其它一直进行SNX抵押的账户在承担,显然这对其它账户来说是不公平的。

为了解决这个问题FeePool引入了结算周期的概念(目前每个结算周期是7天),结算周期有两类,一类是已经封闭的结算周期,一类是开放的结算周期。封闭的结算周期内的费用和奖励可以领取,开放的不行。一个开放的结算周期达到7天后就可以开启新的结算周期,然后这个开放的结算周期就变成了封闭的结算周期,而之前封闭的结算周期内的费用和奖励延展到这个新产生的封闭结算周期中。结算周期的数据结构如下:

FeePool会缓存账户的债务占比信息,然后找到离费用周期结束的debtLedger index最近的债务占比来计算费用和奖励。如下图所示,F0和F1是已经封闭且延展过的的结算周期,F2是可以提取奖励和费用的结算周期,F3是正在开放的结算周期,d10是F2结束时刻对应的debtLedger,d0是由账户A的债务变更引发的。

账户A如果提取奖励和费用,其占比的计算公式为:

p = (d10/d0) * initialDebtOwnership(A)

也就是计算账户A在d10时的债务占比。如果账户A有多次债务变更操作,比如d0和d5

则p的计算公式为:

p = (d10/d5) * initialDebtOwnership(A)

也就是说取尽可能离d10近的债务变更操作对应的debtLedger值。

FeePool这种工作模式会带来一个问题,如果F0和F1有未提取的费用和奖励延展到F2,那么可以在F2中发行债务,然后等F2进入封闭期提取费用。令F0、F1和F2未提取的费用分别为f0、f1和f2,账户A在F2期间的费用占比为p,则账户A可以提取非费用为

f = p * (f0 + f1 + f2)

也就是说虽然账户A在F0和F1期间对系统不承担任何债务,但依然能拿到一部分费用。所以当费用周期结束后应该尽可能的把账户上的费用和奖励提取干净,否则会便宜后面周期发行债务的账户。

提取费用和奖励的前提是账户的债务比不能过高,这个阈值目前是1.01*I-Ratio。费用是直接打到账户地址上,而SNX奖励是放在了第三方托管合约上。

SNX供应计划

SNX奖励由SNX供应计划合约注入到FeePool,然后FeePool发放给SNX托管合约,被托管的奖励要延迟一年才能领取。为什么要给抵押SNX的账户奖励呢?首先我们看一下比特币的激励机制,比特币给矿工奖励,矿工通过挖矿来保障比特币网络的安全。在比特币总量没有达到2100万个之前,比特币跟央行的法币一样是一个通胀币,只不过通胀速率逐年降低而已。那为什么持有者认为比特币是有稀缺性呢?原因在于通胀预期是固定的,也即所有人都知道比特币的发行规律,并且知道当发行完2100万个之后就不再发行。所以一个去中心化的激励机制中,一定时间内的货币发行并不可怕,只要货币发行是对网络的核心价值有用,然后发行计划是有预期(不会随意调整)那么对整个网络就是有正面意义的。

在SNX网络中最核心的价值就是抵押物,只有足额的抵押物才能有更多的做多和做空交易(抵押物太少,赚了钱也没法兑现),才能产生更多的交易手续费从而提升网络的价值形成一个正向循环。基于此SNX从2019年3月开启了投放SNX的计划,这个投放计划类似于比特币也是按周期奖励减半:

但货币新增突然断崖式的下降会可能会对系统产生一个不可预测的不好结果。比如在比特币网络上如果减半周期叠加币价低迷,那么减半周期到来时很多老的矿机因为无利可图而关机,这个会导致比特币算力出现断崖式下降。为了避免这个问题,Synthetix后来又优化了货币投放计划:

这个优化首先是让货币供应速率平缓下降,其次是在货币供应计划结束后继续以2.5%每年的速率增发SNX。

Synth价格

Synth分为做多的Synth(比如sBTC)和做空的Synth(比如iBTC),sBTC的价格就是Oracle的报价,其中sUSD的价格总是1。做空的价格跟基准报价有关:

如图所示,黑色的箭头表示sBTC的价格走势,红色的箭头表示iBTC的价格走势。当sBTC的价格为120时,iBTC的价格为200-120=80;

当sBTC的价格为10时,iBTC的价格为200-10=190,但由于190超过的upperLimit,所以最终iBTC的价格为180。如果frozenAtUpperLimit为false,则iBTC的价格不会被锁定在上边界,等到sBTC价格上升时,iBTC的价格会回落。反之,iBTC的价格就会一直被锁定在上边界。

反向价格信息由系统提供,并且反向价格信息也可以根据需要更新,比如说重新设置基准价。

结束语

Synthetix是一个非常优秀的Defi项目,它可以让我们交易各种资产的风险敞口,由于是与系统对赌所以交易的深度极佳。以太坊的特性使得开发一个复杂的Defi项目变得十分困难,在这个黑暗森林里不仅仅面临合约逻辑错误这种基础性风险,还面临交易抢跑、Oracle报价延迟、报价错误等业务性风险。Synthetix在这方面做了非常多的努力,比如通过交易熔断来控制单个交易对报价错误的风险、通过交易修正来缓解Oracle报价不及时的问题。Synthetix对去中心化项目的激励问题理解的也非常深刻,为什么激励?怎么激励?这些都需要想清楚,而不仅仅是增发token去割韭菜,激励过程也要注意减少一些不必要的经济学博弈。在项目的开发上,Synthetix对Gas的优化也做了一些努力,比如缓存全局债务总量来减少计算量。

Synthetix也有一些需要改进的地方,在费用和奖励的分配上更有利于巨鲸账户,这点倒是可以参考sushi的分配方式进行优化。使用Proxy的模式虽然便于迁移,但是业务上需要向后兼容容易带来代码的复杂性。随着功能的越来越复杂,代码出现逻辑错误的可能性也会越来越大。

本文链接:https://www.8btc.com/article/6589014
转载请注明文章出处

未经允许不得转载:区块联盟 » 研究 | 深入Defi系列之Synthetix

赞 (0) 打赏

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏