如何在本地网络中部署 Chainlink 模拟喂价合约?【Foundry 开发】

Foundry 模拟合约

本文目标:实现在本地网络中,部署模拟喂价合约,并成功将其部署和测试。

当我们在测试 Chainlink 喂价函数时,我们需要从区块链上的喂价合约中读取数据。

上一篇文章中,我们提到如何在不同的区块链网络中,进行 Chainlink 喂价函数的测试。而这一次,我们将说明如何在本地网络中进行喂价函数的测试。

本地测试的思路

在本地测试喂价函数时,需要完成以下几个步骤:

  1. 环境配置:比如创建 .env 环境变量。
  2. 创建目标合约:写下我们想要部署和测试的合约 FundMe.sol
  3. 创建模拟喂价合约:由于本地网络上不存在模拟喂价合约,因此我们需要先创建它,然后将它部署上去。
  4. 获取模拟喂价合约的地址,然后部署并测试目标合约。

由于 Chainlink 喂价合约只存在于 Mainnet, Sepolia, Goerli 上面,因此当我们尝试从本地网络上读取喂价数据时,会发现没有相应的喂价合约为我们提供数据。

因此,我们需要在本地网络测试喂价函数之前,先本地部署一个模拟喂价合约(Mock Contract),这个合约的功能和数据类似于真实的喂价合约,不同之处是其中的数据是由我们控制的。

项目目录

为了在本地网络上完成喂价函数的测试,我们需要用到以下代码结构:

$ tree -I '.github|broadcast|cache|lib|out|.env|.gitignore|gitmodules|foundry.toml'
.
├── script
│   ├── FundMe.s.sol
│   └── HelperConfig.s.sol
├── src
│   ├── FundMe.sol
│   └── PriceConverter.sol
└── test
    ├── FundMe.t.sol
    └── mocks
        └── MockV3Aggregator.sol

4 directories, 6 files

其中,src 文件夹用来存放核心的合约文件,其中的 FundMe.solPriceConverter 代码,可以通过该链接查看。

本地测试的步骤

1. 环境配置

这一步可以参考[[Foundry 环境配置]],然后添加 FundMe.sol, PriceConverter.sol 文件到 src 文件夹。

2. 创建模拟喂价合约

首先,我们需要在 test 文件夹中新建 mocks 文件夹,用于存储所有用于测试的模拟合约。

然后,创建模拟喂价合约 MockV3Aggregator.sol,它可以产生类似于真实喂价合约的数据,其代码可以通过该链接查看。

3. 部署模拟喂价合约

在创建了模拟喂价合约后,我们需要让部署脚本有能力在检测到部署网络为本地网络时,自当将这一模拟喂价合约部署,并获取该合约的信息。

方法是在 HelperConfig.s.sol 文件中,添加以下代码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "forge-std/Script.sol";
import "../test/mocks/MockV3Aggregator.sol";

// 创建配置合约,用于确认网络 ID,并获取模拟喂价合约的信息
contract HelperConfig is Script {
	// 该结构体用于存储模拟喂价合约的数据
	NetworkConfig public networkConfig;
	
	// 提供模拟喂价合约的构造函数所需的参数
	uint8 public constant DECIMALS = 8; // 小数位数
	int256 public constant INITIAL_ANSWER = 2000e8; // 初始答案的值
	
	struct NetworkConfig {
		address priceFeedContractAddress;
	}
	
	// 该构造函数仅在本地网络环境中触发
	constructor() {
		if (block.chainid == 31337) { // 31337 是本地网络的 ID
			networkConfig = createOrGetAnvilConfig(); // 将模拟喂价合约的信息存储在结构体中
		}
	}
	
	// 部署模拟喂价合约,并获取其信息
	function createOrGetAnvilConfig() public returns(NetworkConfig memory) {
		// 如果检测到模拟喂价合约已部署于本地网络,那么直接返回存储了模拟喂价合约的数据的结构体
		if (networkConfig.priceFeedContractAddress != address(0)) {
			return networkConfig;
		}
		
		// 将下一个语句内容广播
		vm.broadcast();
		// 部署模拟喂价合约,并获取该合约的实例
		MockV3Aggregator mockPriceFeed = new MockV3Aggregator(DECIMALS, INITIAL_ANSWER);
		
		// 将模拟喂价合约实例的地址,存储在结构体中
		NetworkConfig memory anvilConfig = NetworkConfig({
			priceFeedContractAddress: address(mockPriceFeed)
		});
		
		// 返回结构体
		return anvilConfig;
	}
}

在以上代码中,我们创建了 HelperConfig 合约,它主要用于配置模拟的喂价合约,根据当前的区块链网络,获取对应的喂价合约的地址。

其中,NetworkConfig 结构体用于存储所需的喂价数据,在这里我们仅包含一个成员变量——喂价合约的地址 priceFeedContractAddress

接下来我们创建了该结构体的实例 networkConfig, 它负责存储当前区块链网络下的喂价合约的数据。

接下来,我们通过函数 createOrGetAnvilConfig() 判断 Anvil 网络中是否已经存在模拟喂价合约,如果不存在,则部署模拟喂价合约,并将该合约的地址传递给 networkConfig 结构体。

最后,我们通过构造函数 constructor() 来识别当前区块链网络,并选择相应的喂价合约。如果区块链网络 ID 为 31337,即处于本地网络时,我们需要通过 createOrGetAnvilConfig() 函数获取本地网络上模拟喂价函数的地址。

4. 关联模拟喂价合约

到目前为止,我们已经有能力通过 HelperConfig 合约在本地网络上部署模拟喂价合约了。

接下来,我们只需要通过 HelperConfig 合约的实例,获取到模拟喂价合约的地址,就可以成功部署合约了。

我们可以为部署脚本 FundMe.s.sol 添加以下代码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "forge-std/Script.sol";
import "../src/FundMe.sol";
import "./HelperConfig.s.sol";

contract FundMeScript is Script{
    function run() external returns(FundMe) {
        HelperConfig helperConfig = new HelperConfig();
        
        (address ethUsdPriceFeedAddress) = helperConfig.networkConfig();

        vm.broadcast();
        FundMe fundMe = new FundMe(ethUsdPriceFeedAddress);

        return fundMe;
    }
}

5. 测试喂价函数

接下来,我们可以完成喂价函数的测试代码 FundMe.t.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;

import "forge-std/Test.sol";
import "../src/FundMe.sol";
import "../script/FundMe.s.sol";

contract FundMeTest is Test {
    FundMe fundMe;
	
    function setUp() public {
        FundMeScript fundMeScript = new FundMeScript();
        fundMe = fundMeScript.run();
    }
    
    function testGetVersion() public {
        assertEq(fundMe.getVersion(), 4);
    }
}

6. 执行测试命令

最后,可以执行 Foundry 的测试命令:

forge test --match-contract FundMeTest --match-test testGetPrice

正确情况下,测试结果为:

Running 1 test for test/FundMe.t.sol:FundMeTest
[PASS] testGetVersion() (gas: 10702)
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.66ms
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值