前言本文主要介绍使用chainlink预言机中DataFeeds,全文包含了MockV3Aggregator合约和PriceConsumer合约的开发、测试、部署。注意:为了便于测试,在本地区块节点上部署一个MockV3Aggregator。Chainlink(去中心化预言机)Chain
本文主要介绍使用chainlink预言机中Data Feeds,全文包含了MockV3Aggregator合约和PriceConsumer合约的开发、测试、部署。
注意
:为了便于测试,在本地区块节点上部署一个MockV3Aggregator。
Chainlink定义:一个去中心化的预言机网络。它的主要作用是将区块链上的智能合约与现实世界的数据和事件连接起来;<br> Data Feeds(数据源):连接智能合约与现实世界数据的重要工具;<br> 作用:Chainlink Data Feeds通过提供高质量、安全可靠的外部数据,极大地扩展了智能合约的应用范围和功能;
说明:注意
<br>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
contract MockV3Aggregator is AggregatorV3Interface { uint256 public constant versionvar = 4;
uint8 public decimalsvar;
int256 public latestAnswer;
uint256 public latestTimestamp;
uint256 public latestRound;
mapping(uint256 => int256) public getAnswer;
mapping(uint256 => uint256) public getTimestamp;
mapping(uint256 => uint256) private getStartedAt;
string private descriptionvar;
constructor(
uint8 _decimals,
string memory _description,
int256 _initialAnswer
) {
decimalsvar = _decimals;
descriptionvar = _description;
updateAnswer(_initialAnswer);
}
function updateAnswer(int256 _answer) public {
latestAnswer = _answer;
latestTimestamp = block.timestamp;
latestRound++;
getAnswer[latestRound] = _answer;
getTimestamp[latestRound] = block.timestamp;
getStartedAt[latestRound] = block.timestamp;
}
function getRoundData(uint80 _roundId)
external
view
override
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return (
_roundId,
getAnswer[_roundId],
getStartedAt[_roundId],
getTimestamp[_roundId],
_roundId
);
}
function latestRoundData()
external
view
override
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return (
uint80(latestRound),
latestAnswer,
getStartedAt[latestRound],
latestTimestamp,
uint80(latestRound)
);
}
function decimals() external view override returns (uint8) {
return decimalsvar;
}
function description() external view override returns (string memory) {
return descriptionvar;
}
function version() external pure override returns (uint256) {
return versionvar;
}
}
##### PriceConsumer合约
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20;
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
contract PriceConsumer { AggregatorV3Interface internal priceFeed;
/**
* 网络: Sepolia
* 聚合器: ETH/USD
* 地址: 0x694AA1769357215DE4FAC081bf1f309aDC325306
*/
constructor(address _priceFeed) {
priceFeed = AggregatorV3Interface(_priceFeed);
}
/**
* 返回最新价格
*/
function getLatestPrice() public view returns (int) {
(
/* uint80 roundID */,
int price,
/*uint startedAt*/,
/*uint timeStamp*/,
/*uint80 answeredInRound*/
) = priceFeed.latestRoundData();
return price;
}
/**
* 返回价格小数位数
*/
function getDecimals() public view returns (uint8) {
return priceFeed.decimals();
}
/**
* 返回价格源描述
*/
function getDescription() public view returns (string memory) {
return priceFeed.description();
}
}
# 测试合约
const { ethers } = require("hardhat"); const { expect } = require("chai"); const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers");
describe("PriceConsumer", function () { // ETH/USD 价格配置 const DECIMALS = 8; const INITIAL_PRICE = 200000000000; // $2000.00000000 const UPDATED_PRICE = 210000000000; // $2100.00000000 const DESCRIPTION = "ETH/USD Price Feed";
async function deployFixture() {
const [owner, addr1] = await ethers.getSigners();
// 部署模拟价格源
const MockV3Aggregator = await ethers.getContractFactory("MockV3Aggregator");
const mockAggregator = await MockV3Aggregator.deploy(
DECIMALS,
DESCRIPTION,
INITIAL_PRICE
);
// 部署价格消费者合约
const PriceConsumer = await ethers.getContractFactory("PriceConsumer");
const priceConsumer = await PriceConsumer.deploy(
await mockAggregator.getAddress()
);
return { mockAggregator, priceConsumer, owner, addr1 };
}
describe("初始化", function () {
it("价格信息源地址", async function () {
const { mockAggregator, priceConsumer } = await loadFixture(deployFixture);
expect(await priceConsumer.priceFeed()).to.equal(await mockAggregator.getAddress());
});
it("小数点位数", async function () {
const { priceConsumer } = await loadFixture(deployFixture);
expect(await priceConsumer.getDecimals()).to.equal(DECIMALS);
});
it("返回正确的描述", async function () {
const { priceConsumer } = await loadFixture(deployFixture);
expect(await priceConsumer.getDescription()).to.equal(DESCRIPTION);
});
});
describe("价格更新", function () {
it("初始价格", async function () {
const { priceConsumer } = await loadFixture(deployFixture);
expect(await priceConsumer.getLatestPrice()).to.equal(INITIAL_PRICE);
});
it("更新后的价格", async function () {
const { mockAggregator, priceConsumer } = await loadFixture(deployFixture);
await mockAggregator.updateAnswer(UPDATED_PRICE);
expect(await priceConsumer.getLatestPrice()).to.equal(UPDATED_PRICE);
});
it("处理多个价格更新", async function () {
const { mockAggregator, priceConsumer } = await loadFixture(deployFixture);
const prices = [
210000000000, // $2100
220000000000, // $2200
215000000000 // $2150
];
for (const price of prices) {
await mockAggregator.updateAnswer(price);
expect(await priceConsumer.getLatestPrice()).to.equal(price);
}
});
});
describe("价格信息交互", function () {
it("负价格的情况", async function () {
const { mockAggregator, priceConsumer } = await loadFixture(deployFixture);
const negativePrice = -100000000; // -$1
await mockAggregator.updateAnswer(negativePrice);
expect(await priceConsumer.getLatestPrice()).to.equal(negativePrice);
});
it("0价格的情况", async function () {
const { mockAggregator, priceConsumer } = await loadFixture(deployFixture);
await mockAggregator.updateAnswer(0);
expect(await priceConsumer.getLatestPrice()).to.equal(0);
});
});
describe("Gas费", function () {
it("使用合理的气量(燃气量)进行价格查询", async function () {
const { priceConsumer } = await loadFixture(deployFixture);
const price = await priceConsumer.getLatestPrice();
expect(price).to.equal(INITIAL_PRICE);
// 获取交易的gas使用量
const gasEstimate = await priceConsumer.getLatestPrice.estimateGas();
expect(gasEstimate).to.be.lt(50000);
});
});
});
# 部署合约
#### MockV3Aggregator合约
module.exports = async ({ getNamedAccounts, deployments }) => { const firstAccount=(await getNamedAccounts()).firstAccount; const { deploy, log } = deployments const MockV3Aggregator = await deploy("MockV3Aggregator", { contract: "MockV3Aggregator", from: firstAccount, log: true, args: [8,"ETH/USD", 200000000000], // decimals, description, initial answer (2000 USD with 8 decimals) }) console.log("MockV3Aggregator合约地址",MockV3Aggregator.address)
} module.exports.tags = ["all", "MockV3Aggregator"]
#### PriceConsumer合约
module.exports = async ({ getNamedAccounts, deployments }) => { const firstAccount=(await getNamedAccounts()).firstAccount; const MockV3Aggregator=await deployments.get("MockV3Aggregator"); const MockV3AggregatorAddress = MockV3Aggregator.address; const { deploy, log } = deployments const PriceConsumer = await deploy("PriceConsumer", { contract: "PriceConsumer", from: firstAccount, log: true, args: [MockV3AggregatorAddress],//合约地址 }) console.log("PriceConsumer合约地址",PriceConsumer.address) } module.exports.tags = ["all", "PriceConsumer"]
# 总结
以上就是预言机中的数据流的智能合约的开发、测试、部署以及概念和作用的介绍;喂价主要场景的使用集中在代币之间的转换、结算;
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!