前言
这是我正在开发的链上 ETF 项目「BlockETF」的第二篇研发日志。
上一篇是:《链上ETF重启 Day 1:重新出发,我终于开始写代码了》。
这几天,我持续使用 Claude Code 这位 AI 员工协助我完成智能合约的开发。整个过程中,我一行代码都没亲自敲,主要负责的是 review、思路拆解和功能指令编写。我告诉它需要实现什么机制、哪些地方可以优化、哪里写得太啰嗦,再逐步迭代。
说实话,这种 Coding 方式挺爽的:脑力输出 + 自动产能,效率非常高,也让我能把注意力集中在机制设计和产品逻辑上,而不是陷在具体的代码细节里。
不过,这几天每次正爽着呢,Claude 就突然提示我「用量上限已达」,强行打断思路,实在有点扫兴。我本来订的是 Claude Pro 套餐,虽然早有预感它可能不够用,但没想到这么快就用满了。今天干脆一咬牙直接升到了 100 美刀的 Max 套餐 ,希望能支撑我每天的开发节奏。如果还不够用......那我可能就真的要上 200 美刀的顶级套餐 了。
今天,智能合约的代码已经开发完毕了,而接下来则要开始准备测试用例,编写单元测试了。
这一版的智能合约,主要分为了 6 个合约,其简单架构如下:
scss
BlockETFRouter (用户入口)
↓
BlockETFCore (核心逻辑) ← → RebalanceManager (再平衡)
↓ ↓
PriceOracle (价格) ← → DEXIntegrator (交易)
↓
FeeManager (费用管理)
下面我来详细介绍下这几个合约。
合约详解
1. BlockETFCore - 核心合约
投资组合的核心管理合约,实现 ERC20 代币标准,代币就是 ETF 份额。所有底层资产都存储在这个合约里。
主要功能:
- 📊 资产管理: 添加/移除投资组合资产,设置目标权重
- 💵 份额铸造: 按照投资金额铸造相应的 ETF 份额
- 🔄 资产赎回: 销毁份额并按比例返还底层资产
- 💰 费用收集: 自动收集管理费和赎回费
- 📈 价值计算: 实时计算投资组合总价值和每份额净值
关键接口:
solidity
function addAsset(address token, uint256 targetWeight) external
function investWithShares(uint256 targetShares, address to) external
function redeemToAssets(uint256 shares, address to) external
function getTotalValue() external view returns (uint256)
function getNavPerShare() external view returns (uint256)
2. BlockETFRouter - 用户接口
面向用户的便捷交易接口,支持 ETH/BNB 和各种代币的投资赎回。
主要功能:
- 🔄 ETH投资: 接受 ETH/BNB 来铸造 ETF 份额
- 💎 代币投资: 接受指定 ERC20 代币来铸造 ETF 份额
- 💸 灵活赎回: 赎回 ETF 份额并转换为 ETH/BNB 或指定代币
- 📊 预估功能: 提供投资和赎回的预估计算
关键接口:
solidity
function investWithETH(uint256 targetShares, address to) external payable
function investWithToken(address token, uint256 maxAmount, uint256 targetShares, address to) external
function redeemToETH(uint256 shares, address to) external
function redeemToToken(uint256 shares, address token, address to) external
function estimateInputForInvest(address token, uint256 shares) external view
function estimateOutputForRedeem(uint256 shares, address token) external view
3. PriceOracle - 价格预言机
基于 Chainlink 的价格数据服务,提供准确的资产定价。
主要功能:
- 📡 Chainlink集成: 获取实时加密货币价格数据
- 🎯 统一计价: 所有资产统一转换为 USDT 计价
- ⏰ 数据验证: 检查价格数据的时效性和有效性
- 🔧 精度处理: 自动处理不同代币的小数位精度
关键接口:
solidity
function getAssetValue(address token, uint256 amount) external view returns (uint256)
function setPriceFeed(address token, address priceFeed) external
function getPriceBaseToken() external view returns (address)
4. FeeManager - 费用管理
管理投资组合的各种费用计算。
主要功能:
- 📈 管理费: 按年化费率计算管理费用
- 💸 赎回费: 计算用户赎回时的费用
- ⚙️ 费率配置: 灵活设置各种费率参数
- 👤 费用接收者: 管理费用的接收地址
关键接口:
solidity
function calculateManagementFeeShares(uint256 totalShares, uint256 timeDelta) external view
function calculateRedemptionFeeShares(uint256 shares) external view
function setManagementFeeRate(uint256 annualRateBasisPoints) external
function setRedemptionFeeRate(uint256 rate) external
5. DEXIntegrator - DEX集成
与 PancakeSwap V3 的集成,提供代币交换功能。
主要功能:
- 🔄 代币交换: 执行精确输入/输出的代币交换
- 🏊 池选择: 自动选择最优流动性池
- 📊 价格查询: 获取交换的预估价格
- 🛡️ 滑点保护: 防止价格滑点过大的交易
关键接口:
solidity
function swapExactIn(address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOutMin, address recipient) external
function swapExactOut(address tokenIn, address tokenOut, uint256 amountOut, uint256 amountInMax, address recipient) external
function getAmountOut(address tokenIn, address tokenOut, uint256 amountIn) external
function getBestPool(address tokenA, address tokenB) external view
6. RebalanceManager - 再平衡管理
智能管理投资组合的权重平衡,确保符合目标配置。
主要功能:
- ⚖️ 权重监控: 实时监控投资组合权重偏离情况
- 🤖 自动再平衡: 当偏离超过阈值时触发再平衡
- 🔄 智能交易: 通过 DEX 执行买卖操作调整权重
- 🛡️ 风险控制: 滑点保护和时间间隔限制
关键接口:
solidity
function executeRebalance() external returns (bool success)
function isRebalanceNeeded() external view returns (bool needed, uint256 maxDeviation)
function calculateRequiredRebalance() external returns (RebalanceParams memory)
function setMaxSlippage(uint256 maxSlippage) external
使用流程
投资流程
- 用户调用
BlockETFRouter.investWithETH()
发送 ETH/BNB - Router 通过 DEX 将 ETH/BNB 换成各种底层资产
- 调用 Core 的
investWithShares()
铸造份额给用户 - 自动收集管理费
赎回流程
- 用户调用
BlockETFRouter.redeemToETH()
赎回份额 - Core 按比例分配底层资产给 Router
- Router 通过 DEX 将底层资产换成 ETH/BNB
- 扣除赎回费后转给用户
再平衡流程
- RebalanceManager 监控权重偏离
- 当偏离超过阈值时,计算需要买卖的资产
- 通过 DEX 执行交易调整权重
- 剩余资产处理和状态更新
下一步的工作
下一步的工作就是开始整理和输出测试用例,然后继续让 Claude Code 一点点完成单元测试,如果发现有 Bug 就修复。
不知道在 1 号前是否能完成这部分工作。