跳转到内容

预言机

预言机

本页内容正在整理中,欢迎贡献

概述

智能合约无法直接访问链外数据(如资产价格、天气、随机数)。预言机(Oracle)是连接区块链与现实世界的数据桥梁。选择可靠的预言机对于 DeFi 协议的安全性至关重要——许多重大安全事故正是源于预言机被操纵。

主要内容

预言机的分类

类型说明代表
价格 Feed提供资产实时价格Chainlink Price Feeds
随机数提供可验证随机数Chainlink VRF
自动化定时/条件触发合约Chainlink Automation
跨链消息跨链数据传递Chainlink CCIP
低延迟价格高频更新(DEX 场景)Pyth Network
去中心化 API任意 API 数据上链API3

最广泛使用的去中心化价格预言机:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract PriceConsumer {
AggregatorV3Interface internal priceFeed;
// ETH/USD 主网地址: 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
constructor(address _feedAddress) {
priceFeed = AggregatorV3Interface(_feedAddress);
}
function getLatestPrice() public view returns (int256, uint256) {
(
/* uint80 roundId */,
int256 price,
/* uint256 startedAt */,
uint256 updatedAt,
/* uint80 answeredInRound */
) = priceFeed.latestRoundData();
// 安全检查:确保数据不过时
require(block.timestamp - updatedAt <= 3600, "Price data is stale");
require(price > 0, "Invalid price");
return (price, updatedAt);
}
function getDecimals() public view returns (uint8) {
return priceFeed.decimals(); // ETH/USD 返回 8
}
}

常用价格 Feed 地址(以太坊主网):

地址
ETH/USD0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
BTC/USD0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c
USDC/USD0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6
LINK/USD0x2c1d072e956AFFC0D435Cb7AC38EF18d24d9127c

查询所有可用 Feed:data.chain.link

import "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2Plus.sol";
import "@chainlink/contracts/src/v0.8/vrf/interfaces/IVRFCoordinatorV2Plus.sol";
contract RandomNFT is VRFConsumerBaseV2Plus {
// 主网配置
address constant COORDINATOR = 0xD7f86b4b8Cae7D942340FF628F82735b7a20893a;
bytes32 constant KEY_HASH = 0x8...; // 参考 Chainlink 文档
uint256 immutable subscriptionId;
mapping(uint256 => address) public requestIdToMinter;
constructor(uint256 _subId) VRFConsumerBaseV2Plus(COORDINATOR) {
subscriptionId = _subId;
}
function requestRandomMint() external returns (uint256 requestId) {
requestId = s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: KEY_HASH,
subId: subscriptionId,
requestConfirmations: 3, // 等待 3 个区块确认
callbackGasLimit: 100_000,
numWords: 1,
extraArgs: VRFV2PlusClient._argsToBytes(
VRFV2PlusClient.ExtraArgsV1({ nativePayment: false })
)
})
);
requestIdToMinter[requestId] = msg.sender;
}
function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) internal override {
address minter = requestIdToMinter[requestId];
uint256 tokenId = randomWords[0] % 10000; // 0-9999 的随机 ID
_mint(minter, tokenId);
}
}

Pyth Network(低延迟价格)

适合 DEX、永续合约等需要高频价格更新的场景:

import "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol";
contract PythPriceExample {
IPyth pyth;
bytes32 constant ETH_USD_PRICE_ID =
0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace;
constructor(address _pyth) {
pyth = IPyth(_pyth);
}
function getETHPrice(bytes[] calldata priceUpdateData) external payable {
// 支付更新费用并更新价格
uint fee = pyth.getUpdateFee(priceUpdateData);
pyth.updatePriceFeeds{value: fee}(priceUpdateData);
// 获取价格(60 秒内有效)
PythStructs.Price memory price = pyth.getPriceNoOlderThan(
ETH_USD_PRICE_ID,
60
);
// price.price 为整数,price.expo 为指数(通常为 -8)
// 实际价格 = price.price * 10^price.expo
}
}

预言机安全注意事项

  1. 检查数据新鲜度:始终验证 updatedAt 时间戳,拒绝过期数据
  2. 检查正数:确保价格 > 0
  3. 使用 TWAP:用时间加权平均价格替代即时价格,防止价格操纵
  4. 多源验证:关键应用使用多个独立预言机交叉验证
  5. 避免使用 DEX 即时价格:Uniswap Spot Price 可以被 Flash Loan 操纵
// ❌ 危险:使用 DEX 即时价格
uint price = IUniswapV3Pool(pool).slot0().sqrtPriceX96; // 可被操纵!
// ✅ 安全:使用 Chainlink 价格 Feed
(int256 price,) = getLatestPrice();

深入阅读