// test/MyToken.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "forge-std/Test.sol";
import "../src/MyToken.sol";
contract MyTokenTest is Test {
MyToken public token;
address public alice = address(0x1);
address public bob = address(0x2);
function setUp() public {
token = new MyToken();
token.mint(alice, 1000 ether);
}
function testTransfer() public {
vm.prank(alice);
token.transfer(bob, 100 ether);
assertEq(token.balanceOf(alice), 900 ether);
assertEq(token.balanceOf(bob), 100 ether);
}
function testTransferInsufficientBalance() public {
vm.prank(alice);
vm.expectRevert("Insufficient balance");
token.transfer(bob, 2000 ether);
}
}
这段测试代码有几个值得注意的地方:
原生Solidity语法:测试代码与业务代码使用相同的语言,避免了在不同语言间切换的认知负担。
vm cheatcodes:Foundry提供了一系列vm.*函数,允许测试代码执行一些”作弊操作”,如模拟调用者(vm.prank)、修改区块参数(vm.warp)、伪造存储值(vm.store)等。
// test/MyToken.test.js
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("MyToken", function () {
let token;
let owner;
let addr1;
beforeEach(async function () {
[owner, addr1] = await ethers.getSigners();
const MyToken = await ethers.getContractFactory("MyToken");
token = await MyToken.deploy("My Token", "MTK");
await token.deployed();
await token.mint(owner.address, ethers.utils.parseEther("1000"));
});
describe("Transfers", function () {
it("Should transfer tokens between accounts", async function () {
await token.transfer(addr1.address, 100);
expect(await token.balanceOf(owner.address)).to.equal(
ethers.utils.parseEther("999.9")
);
expect(await token.balanceOf(addr1.address)).to.equal(100);
});
it("Should fail if sender doesn't have enough tokens", async function () {
await expect(
token.connect(addr1).transfer(owner.address, 1)
).to.be.revertedWith("Insufficient balance");
});
});
});
Hardhat Network:本地测试环境
Hardhat内置了一个以太坊虚拟机(EVM)实现,专门针对开发场景进行了优化:
javascript
// hardhat.config.js中的高级配置
networks: {
hardhat: {
chainId: 31337,
loggingEnabled: false,
gasPrice: 'auto',
accounts: {
mnemonic: "test test test test test test test test test test test junk",
count: 20
}
}
}
contract BlurAggregator {
mapping(address => bool) public supportedMarkets;
address[] public markets;
function execute(
ExecutionDetails[] calldata executions
) external payable {
for (uint i = 0; i < executions.length; i++) {
ExecutionDetails calldata details = executions[i];
// 根据目标市场路由执行
if (details.market == Blur) {
_executeBlur(details);
} else if (details.market == Seaport) {
_executeSeaport(details);
}
// ...其他市场
}
}
}
五、版税保护机制
5.1 EIP-2981:NFT版税标准
EIP-2981提供了查询NFT版税信息的标准接口:
solidity
interface IERC2981 {
/// @notice Query the royalty information for a given sale
/// @param tokenId The NFT token ID
/// @param salePrice The sale price of the NFT
/// @return receiver The address to receive royalty
/// @return royaltyAmount The royalty payment amount
function royaltyInfo(
uint256 tokenId,
uint256 salePrice
) external view returns (
address receiver,
uint256 royaltyAmount
);
}