价格数据的可靠性是很多DeFi协议可靠运行的基石,Chainlink作为预言机头部平台,一般来说它提供的价格数据是非常可靠的。但是在我们这个行业从来都不缺二般情况...
价格数据的可靠性是很多 DeFi 协议可靠运行的基石,Chainlink 作为预言机头部平台,一般来说它提供的价格数据是非常可靠的。但是在我们这个行业从来都不缺二般情况...
官方给的示例是非常简单直接的。下面的代码就是原封不动的从官方文档拷贝过来的。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract PriceConsumerV3 {
AggregatorV3Interface internal priceFeed;
/**
* Network: Sepolia
* Aggregator: BTC/USD
* Address: 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43
*/
constructor() {
priceFeed = AggregatorV3Interface(
0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43
);
}
/**
* Returns the latest price.
*/
function getLatestPrice() public view returns (int) {
// prettier-ignore
(
/* uint80 roundID */,
int price,
/*uint startedAt*/,
/*uint timeStamp*/,
/*uint80 answeredInRound*/
) = priceFeed.latestRoundData();
return price;
}
}
这个代码直接通过调用 AggregatorV3Interface 的 latestRoundData 方法来获取价格数据,并且完全忽略掉了 latestRoundData 方法返回的其它数据。
估计很多在正式环境部署的 DeFi 协议也是这样使用 Chainlink 价格数据的,这样会有什么问题呢?最大的问题就是过于依赖 Chainlink 单一平台,并假定 Chainlink 永远不会有问题。当初币安链上最大的借贷应用 Venus 估计也是这样假设的,于是在上次 Luna 事件中出现了安全事故,我在该文也做过相应分析。Luna 事件暴露出来的预言机问题 Chainlink 很快就修复掉了,但谁又能保证没有其它 Chainlink 没有完全考虑到的情况呢?Chainlink 那边价格出现的一个小问题,对于依赖的 DeFi 应用可能都会带来灭顶之灾。
对 Chainlink 返回的数据进行完整性检查 Chainlink 返回的数据可不是只有价格,还有与价格相关的上下文信息:
function latestRoundData() external view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
roundId: Chainlink 每次更新价格都是一个 round(轮次),round id 会加 1,正常情况下 roundId 是个大于 0 的数字。 answer: 价格数据,对于币种价格来说,正常情况下是个大于 0 的数字 startedAt: 该轮报价开始时间 updatedAt: 该轮报价信息更新时间 answeredInRound: 现在已经不推荐使用 我们应该对这些返回值做基本的完整性检查:
if (
roundId != 0 &&
answer > 0 &&
updatedAt != 0 &&
updatedAt <= block.timestamp
) {
// 通过检查
} else {
// 未通过检查
}
对数据的实效性检查
if (block.timestamp - updatedAt <= TIMEOUT) {
// 通过检查
} else {
// 未通过检查
}
TIMEOUT 是我们根据应用对数据的实时性要求自定义的一个时间,比如 30 分钟
记下来上次通过检查的报价并计算价格偏差 lastGoodPrice = answer; if (abs(answer - lastGoodPrice) / lastGoodPrice <= ACCETABLE_DEVIATON) { // 通过检查 } else { // 未通过检查 }
如果价格未通过检查,启动容错机制,这里可能需要准备一个备用预言机,当 Chainlink 预言机不可用时,可以切换到备用预言机来读取价格。 对于备用预言机,可以用 Uniswap TWAP,可以用另一个可靠性还可以的第三方预言机,也可以用自建预言机。如果备用预言机也不好使了,可以返回上次报价数据并通知应用预言机处于不可用状态,这样对应用来说,相当于价格停止更新了,可以根据场景做针对性的处理。比如对于借贷应用来说,价格停更一段时间后再重新更新时,对清算操作做一定的缓冲处理,避免预言机价格剧烈波动带来的不合理清算。
今年开始基于 rollup 的 L2 开始变得非常火爆,L2 极大的提高了以太坊的交易处理能力。但有一点儿我们要注意,就是 L2 排序器当机的概率要远远高于以太坊网络。
假设我们在 L2 上部署了一个借贷协议,有一天该 L2 排序器出现故障,交易无法处理,预言机价格无法更新。若干小时之后,当排序器重新上线并且预言机更新它们的价格时,停机期间发生的所有价格变动都会立即起作用。如果这些价格变动幅度很大,就可能会造成非常大的混乱。借款人会急于保住头寸,而清算人会急于清算借款人。由于清算主要由机器人处理,借款人可能会面临被大规模清算的风险。
这对借款人是不公平的,因为如果不是因为 L2 故障,借款人可以有足够的时间来还款或补充抵押物。这时候如果我们的借贷协议能够检测到 L2 故障,并在 L2 恢复后给借款人一个处理借款头寸的缓冲期,就可以避免此类问题了。
Chainlink 专门提供了相关服务 来检测 L2 的状态。
AAVE V3 也做了专门处理 可以作为实现参考。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!