1. 初始化永续合约交易对

任务目标

在去中心化永续合约协议中,初始化一个交易对(Market),为其配置基础资产、报价资产、初始保证金率、维持保证金率等核心参数,并确保该交易对可以被查询与使用。

环境与依赖

本案例基于 Foundry 开发框架,使用 Solidity ^0.8.20。需要安装 Foundry(forge)并准备一个本地或测试网 RPC 用于部署验证。无需额外第三方库。

核心实现

以下合约实现了一个最小化的永续合约交易对初始化逻辑。合约部署时即完成交易对创建,并存储所有必要参数,提供查询接口以验证初始化结果。

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

/// @title 永续合约交易对初始化
/// @notice 部署即创建一个永续交易对,并记录基础资产、报价资产及保证金率参数
contract PerpMarket {
    // ---- 交易对参数 ----
    address public baseAsset;        // 基础资产(如 WBTC)
    address public quoteAsset;       // 报价资产(如 USDC)
    uint256 public initialMarginRate; // 初始保证金率,1e18 = 100%
    uint256 public maintenanceMarginRate; // 维持保证金率,1e18 = 100%
    bool public isActive;            // 交易对是否启用

    // ---- 事件 ----
    event MarketInitialized(
        address indexed baseAsset,
        address indexed quoteAsset,
        uint256 initialMarginRate,
        uint256 maintenanceMarginRate
    );

    /// @notice 构造函数:初始化交易对参数
    /// @param _base 基础资产地址
    /// @param _quote 报价资产地址
    /// @param _initialMarginRate 初始保证金率(1e18 = 100%,如 0.1e18 = 10%)
    /// @param _maintenanceMarginRate 维持保证金率(1e18 = 100%,如 0.05e18 = 5%)
    constructor(
        address _base,
        address _quote,
        uint256 _initialMarginRate,
        uint256 _maintenanceMarginRate
    ) {
        require(_base != address(0), "invalid base asset");
        require(_quote != address(0), "invalid quote asset");
        require(_initialMarginRate > _maintenanceMarginRate, "initial must be > maintenance");
        require(_maintenanceMarginRate > 0, "maintenance must be > 0");

        baseAsset = _base;
        quoteAsset = _quote;
        initialMarginRate = _initialMarginRate;
        maintenanceMarginRate = _maintenanceMarginRate;
        isActive = true;

        emit MarketInitialized(_base, _quote, _initialMarginRate, _maintenanceMarginRate);
    }

    /// @notice 查询交易对是否已初始化(isActive 即表示已初始化)
    function isInitialized() external view returns (bool) {
        return isActive;
    }
}

部署与验证

使用 Foundry 创建一个部署脚本,将合约部署到本地测试链并验证参数是否正确写入。

// scripts/Deploy.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Script} from "forge-std/Script.sol";
import {PerpMarket} from "../src/PerpMarket.sol";

contract Deploy is Script {
    function run() external returns (PerpMarket market) {
        // 使用虚拟代币地址作为示例(实际部署时应为真实代币地址)
        address wbtc = address(0x1000);
        address usdc = address(0x2000);

        vm.startBroadcast();
        market = new PerpMarket(wbtc, usdc, 0.1e18, 0.05e18);
        vm.stopBroadcast();
    }
}

在项目根目录执行以下命令完成部署与验证:

# 初始化 Foundry 项目(若尚未初始化)
forge init perp-market
cd perp-market

# 将上述 PerpMarket.sol 放入 src/,Deploy.s.sol 放入 script/

# 编译
forge build

# 在本地测试链上部署
forge script script/Deploy.s.sol --rpc-url http://127.0.0.1:8545 --broadcast

# 使用 cast 调用查询接口验证参数(替换为实际部署地址)
cast call <DEPLOYED_ADDRESS> "baseAsset()" --rpc-url http://127.0.0.1:8545
cast call <DEPLOYED_ADDRESS> "initialMarginRate()" --rpc-url http://127.0.0.1:8545
cast call <DEPLOYED_ADDRESS> "isActive()" --rpc-url http://127.0.0.1:8545

验证方法与通过条件

  • 编译通过:forge build 无报错。
  • 部署成功:forge script 返回合约地址,无 revert。
  • 参数正确:调用 baseAsset() 返回 0x...1000,quoteAsset() 返回 0x...2000,initialMarginRate() 返回 100000000000000000(即 0.1e18),maintenanceMarginRate() 返回 50000000000000000(即 0.05e18),isActive() 返回 true。
  • 事件日志:部署交易 receipt 中包含 MarketInitialized 事件,参数与构造输入一致。

常见问题

  • 保证金率精度:所有比率均以 1e18 为精度,10% 应传 0.1e18 而非 10。
  • 构造 revert:若初始保证金率 ≤ 维持保证金率,或任一资产地址为 0,构造函数会 revert,部署失败。
  • 本地测试链:若未启动本地节点,可先执行 anvil 启动默认 8545 端口测试链。