如何设计一个 Compound 清算机器人?

区块链数字资产和加密货币市场已发展成为一个充满活力的金融生态系统。但相较于传统金融市场,绝大多数项目的设计思路都是基于数字资产或加密货币在空间上的转移,而金融本身仍作为时间定价的工具,塑造了一个关于可量化、可交易的时间维度。Compound 项目在此背景下应运而生,该项目是一种基于供求关系的分布式协议,设计了一种基于货币市场设定利率的算法,实现了用户无时间摩擦地交易以太坊资产。

本文分为三部分,第一部分简要介绍该项目中与清算相关的基本概念,第二部分通过示例讲解清算流程,第三部分介绍如何设计一个清算机器人。
清算的基本概念
Compound 项目中与清算相关的基本概念主要包括:cToken、Comptroller、Liquidity、Close factor 和 Liquidation Incentive。
//cToken
Compound 协议目前支持 Erc20 和 Ether 两类基础资产,cToken 是两类基础资产在 Compound 上的集成,转换公式为 cToken = 基础资产 / 当前汇率。cToken 在 Compound 上有两种作用,分别是作为利息的衡量标准和贷款的抵押物。有别于传统银行的计算方式,利率是通过复利的形式增长的。cToken 在 Compound 协议中作为度量衡使用。
//Comptroller
Comptroller 通过 collateral factor 对 Compound 协议进行风险管理,即 Comptroller 为协议的风险管理层。每类基础资产都有相互独立的 collateral factor,其数值大小根据基础资产的流动性和市值规模在0~90%浮动。流动性越强,市值规模越高数值越大。若 collateral factor 为0,该类基础资产不能用作抵押或者在清算中进行抵扣。Compound 根据 collateral factor 确定用户所需抵押品价值以及该用户是否可以被清算。
//Liquidity
Liquidity 是 Compound 协议清算的标志位。当账户的 Liquidity 不为正数时,将被该协议的其他用户清算,直到将 Liquidity 重新设置为正数。账户 Liquidity 计算由下列公式(1)、(2)、(3)求得:

其中,tokensToDenom 是将其他资产价格转换为ETH价格的汇率,oraclePrice 是从预言机中获得的单价。为解决在源码中 Liquidity 是 uint 类型、无法表示负数的问题,源码中定义 shortfall = sumBorrowPlusEffects – sumCollateral。很多清算程序为统一表示,将 Compound 协议清算标志位设为 health。Health 小于1,则表示该账户需要被清算。
//Close Factor
Close factor 是需要被清算的部分占未偿还贷款的百分比,即基础贷款需要被清算的部分。例,一个需要被清算的账户 close factor 为0.1,那么需要清算其贷款的10%。如果用户拥有多种借入资产,close factor 是某一资产的属性,并非该用户总资产的属性。
//Liquidation Incentive
Liquidation incentive 是为清算人提供额外的抵押品,以鼓励清算人对 underwater 账户进行清算。例如,Liquidation incentive 为1.1,则清算人会获得借款抵押品10%的奖励。目前 Liquidation incentive 在1.3~1.5之间。假设 Liquidation incentive 为1.05,可以使用公式(7)计算在清算完成时清算人的收益。

清算流程
为保证 Compound 系统平稳运行,该协议设计了一套完备的风险和清算规则。为了降低贷款风险,Compound 协议在每类资产中增加了 collateral factor 属性。该属性定义了某类资产单位抵押物可以借贷其他资产的数量。即,抵押率的一种表示方式。目前的主要借贷协议都是通过超额抵押的方式借款,通常要求抵押率低于 150% ,比如:加入市场的抵押率为150%,用户在 Compound 超额抵押 ETH 借出一笔 DAI 贷款,但不巧的是,在贷款期间恰逢 ETH 的价格大幅下跌,使得该借款人的抵押品价值跌破了对 ETH 要求的抵押品比率 150%。
如果没有补足或者出售抵押品,就会触发清算程序,此外,借款人还要缴纳清算罚金,这个时候清算人可以触发 Compound 清算程序,可以以低于市场价格 3% -5% 的折扣获得ETH抵押品,这部分差价便是 Liquidation Incentive 的由来。由此,借款人偿还了 Compound 系统的贷款,避免 Compound 平台出现债务和坏账,维持了系统的偿付能力,同时,清算人也获得了单笔3%~5%的收益,类似于矿工费,清算人获得了收益,平台也行以正常运行。
在 Compound 的清算机制中,只要清算人通过监控合约发现借款人的抵押率过低,一旦触发清算程序,清算人就会立刻启动清算。
如何设计清算机器人?
清算机器人的总体设计原则为更快地发现 Liquidation incentive 高、且需要被清算的 underwater accounts,从而获得更高的清算收益。
如何发现 underwater accounts
Account API 能够实现与 Compound 协议交互各种账户信息,可以使用此 API 按地址检索特定用户的数据,或获取 unhealthy accounts 列表。Compound 协议 API 的输入输出格式是由 Protocol Buffers 指定的。与典型的 protobufs 不同的是,Compound 除了支持 protobufs 二进制格式外,还支持JSON格式。若在输入输出中都使用 JSON 格式,需要在请求中标明“Content-Type: application / json”和“Accept: application / json”。
决定清算人清算的因素
· 必须有 unhealthy accounts 才能进行清算,这是清算的前提条件。
· 在清算时,应尽量选择可在交易所轻松清算的抵押品作为抵押的账户进行清算。流动性高的抵押品更容易实现数字资产的货币化;
· 应尽量选择抵押品和债务集中在少数几类资产的 unhealthy accounts 进行清算。若 unhealthy accounts 的抵押品和债务分散在众多资产上,每次调用 liquidateBorrow 交易时都需指定一个 debt contract 和一个 collateral contract,以至于需要多次调用才能完成清算,增加清算的成本;
· Ethereum 虚拟机(EVM)是一个全局状态机,必须按顺序处理 liquidateBorrow 事务。因此,清算人要想获得更高收益,需要更快地发现并清算 unhealthy accounts;
· 假设某个 unhealthy accounts 全局 close factor 为0.5,并拥有N个债务和M个抵押资产,要最大程度地增加清算量。这是一个背包问题的具体应用,即将每个项目建模为<debt.weight,collateral.value>元组,项目总数为N * M。债务权重必须小于等于 close factor,且最大化抵押物价值。
寻找 unhealthy accounts 速度的决定性因素
· 网络延迟和硬件速度
· Gas 花费
· 使用高 Gas 花费来广播一条清算交易优于广播多条。若同时广播多条清算交易,可能某一清算交易已经在以太坊的有效块中,从而导致区块链打包失败;
· 应选择拥有足够抵押品的 unhealthy accounts 进行清算,如抵押品价值不足将导致交易失败;
· 建立链下缓存程序,该程序将 health 值小于1.2的账户标记为存在清算风险的账户,进行重点监控。一旦满足清算要求第一时刻发起清算交易,减少与 Compound 协议交互次数。
执行清算的成本
· 执行清算是一项资金密集型操作,为清算100万美元的贷款,清算人需要有100万美元的资金;
· 清算交易是一个高度周期性交易行为。币值市场的重大波动会造成清算交易集中式爆发,从而增加交易成本,并导致短期内大量被清算人走向破产,进而影响整个 Compound 项目的平稳运行;
· 为加快发现 unhealthy accounts,需要一个监控程序对可能被清算的账户进行监控,增加了准入的技术门槛;
· Gas 的费用可能会对最终收益产生巨大影响。所有交易的基础成本为21000 Gas,若与合约进行交互会增加相应的 Gas。因此,清算程序需要预先计算预期收益。
清算与收取抵押物最大值计算方式
某些账户的抵押品价值可能少于最大清算金额,如果最大清算量或最大可收集抵押品价值小于交易所花费的 Gas 乘以 Gas 的单价,那么清算交易永远不可能获利。计算最大清算数量和抵押品最大收取量公式如下:

需要注意的是 sum (token_borrow_balance_underlying_in_eth) != total_borrow_value_in_eth。通过调用 Account API 可以获得更加准确的 Oracle Price,但会降低运算速度。为了优化速度,在可以接受的误差范围内牺牲准确性,使用近似价格计算。通过 PriceOracle 可以获取 cToken 的 getUnderlyingPrice 和 liquidateCalculateSeizeTokens,通过 cUSDC 合约获取 exchangeRateStored。通过汇率计算便可以快速、近似地计算出所需收取抵押物的数量。