前言
本文系统梳理了收益分层交易的相关知识体系,具体涵盖其核心定义、核心能力、解决的行业痛点、典型行业应用场景、核心优劣势,以及关键认知要点;在代码落地层面,将基于 Hardhat V3 开发框架,结合 OpenZeppelin V5 库与 Solidity 0.8.24 及以上版本,完整实现该业务从开发、测试到部署的全流程。
一、是什么
DeFi领域基于区块链的结构化金融合约,核心是按风险、兑付优先级拆分资产池为不同层级份额,自动分配交易收益、亏损与清算,全程去中心化、无人工干预,底层依托公链与预言机实现闭环。
核心分层:优先级(低风险低收益,优先兑付)、劣后级(高风险高收益,兜底亏损)、夹层(风险收益居中,可选设)。
二、能做什么与解决的问题
(一)核心能力
- 拆分风险收益,匹配不同偏好投资者;
- 链上自动执行分配、清算,结果可审计;
- 分层份额代币化,支持交易、质押流通;
- 设定风险阈值,管控极端行情风险。
(二)核心痛点
- 解决投资者风险偏好与产品不匹配问题;
- 规避传统结构化产品中心化、不透明、门槛高的弊端;
- 提升链上资产利用率,整合闲置资金与交易需求;
- 消除收益分配纠纷,实现透明化执行。
三、行业应用
主要落地于DeFi赛道,核心场景包括:
- 去中心化借贷:分层分配借贷利息,平衡风险与收益;
- 收益聚合器:拆分多策略收益池,适配不同风险需求;
- 衍生品与杠杆交易:保证金池分层,提供流动性与风险备付;
- NFTFi:拆分NFT收益池,覆盖租赁、抵押等收益;
- 实体资产通证化:分层分配实体资产现金流,降低参与门槛。
四、优劣势
(一)优势
- 透明可审计,信任成本低,无暗箱操作;
- 自动执行无偏差,7×24小时运行;
- 精准匹配风险收益,用户覆盖面广、门槛低;
- 提升资产效率,支持份额组合金融化。
(二)劣势
- 合约逻辑复杂,存在代码漏洞与审计风险;
- 专业门槛高,普通用户易产生认知误区;
- 极端行情下有连环清算、预言机依赖风险;
- 监管模糊,流动性碎片化,链上性能受限。
五、关键认知
- 非保本合约,优先层仅相对优先兑付;
- 核心价值是风险分层,而非单纯收益分配;
- 目前处于DeFi小众创新阶段,尚未大规模普及。
智能合约开发、测试、部署
智能合约
- 代币合约
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.5.0
pragma solidity ^0.8.24;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract BoykaYuriToken is ERC20, ERC20Burnable, Ownable, ERC20Permit {
constructor(address recipient, address initialOwner)
ERC20("MyToken", "MTK")
Ownable(initialOwner)
ERC20Permit("MyToken")
{
_mint(recipient, 1000000 * 10 ** decimals());
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
- 收益分层交易合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
// 模拟 PT 和 YT 代币
contract YieldToken is ERC20 {
constructor(string memory name, string memory symbol) ERC20(name, symbol) {}
function mint(address to, uint256 amount) external { _mint(to, amount); }
function burn(address from, uint256 amount) external { _burn(from, amount); }
}
contract YieldSplitVault is ReentrancyGuard {
IERC20 public immutable yieldBearingToken; // 生息代币 (如 stETH)
YieldToken public pt; // 本金代币
YieldToken public yt; // 收益代币
uint256 public totalUnderlying; // 记录初始存入的总本金
uint256 public expiry; // 到期时间
constructor(address _ybt, uint256 _duration) {
yieldBearingToken = IERC20(_ybt);
expiry = block.timestamp + _duration;
pt = new YieldToken("Principal Token", "PT");
yt = new YieldToken("Yield Token", "YT");
}
// 存入本金,铸造 PT 和 YT
function deposit(uint256 amount) external nonReentrant {
require(block.timestamp < expiry, "Expired");
yieldBearingToken.transferFrom(msg.sender, address(this), amount);
pt.mint(msg.sender, amount);
yt.mint(msg.sender, amount);
totalUnderlying += amount;
}
// 只有 YT 持有者可以随时提取当前产生的利息
function collectInterest() external nonReentrant {
uint256 currentBalance = yieldBearingToken.balanceOf(address(this));
// 利息 = 当前总余额 - 锁定的本金
uint256 interest = currentBalance > totalUnderlying ? currentBalance - totalUnderlying : 0;
require(interest > 0, "No interest");
// 简化的逻辑:根据调用者的 YT 持股比例分利(此处演示直接全取)
yieldBearingToken.transfer(msg.sender, interest);
}
// 到期后,销毁 PT 取回本金
function redeem(uint256 amount) external nonReentrant {
require(block.timestamp >= expiry, "Not expired yet");
pt.burn(msg.sender, amount);
totalUnderlying -= amount;
yieldBearingToken.transfer(msg.sender, amount);
}
}
测试脚本
测试用例:
- 用户存入资产应获得等额的 PT 和 YT
- 利息产生后,YT 持有者应能提取收益
- 未到期前无法赎回本金
import assert from "node:assert/strict";
import { describe, it, beforeEach } from "node:test";
import { parseEther, formatEther } from 'viem';
import { network } from "hardhat";
describe("YieldSplitVault 收益分层测试", function () {
let publicClient: any, vault: any, stETH: any;
let owner: any, user: any;
beforeEach(async function () {
const { viem } = await network.connect();
publicClient = await viem.getPublicClient();
[owner, user] = await viem.getWalletClients();
// 1. 部署一个模拟的 stETH (生息代币)
stETH = await viem.deployContract("BoykaYuriToken", [owner.account.address, owner.account.address]);
// 2. 部署分层金库 (有效期 1 小时)
vault = await viem.deployContract("YieldSplitVault", [stETH.address, 3600n]);
// 给用户一些 stETH
await stETH.write.transfer([user.account.address, parseEther("100")], { account: owner.account });
});
it("用户存入资产应获得等额的 PT 和 YT", async function () {
const depositAmount = parseEther("10");
// 授权并存入
await stETH.write.approve([vault.address, depositAmount], { account: user.account });
await vault.write.deposit([depositAmount], { account: user.account });
// 获取 PT 和 YT 地址
const ptAddress = await vault.read.pt();
const ytAddress = await vault.read.yt();
// 检查余额
const ptBalance = await publicClient.readContract({
address: ptAddress,
abi: [{ name: "balanceOf", type: "function", inputs: [{ type: "address" }], outputs: [{ type: "uint256" }] }],
functionName: "balanceOf",
args: [user.account.address]
});
assert.equal(ptBalance, depositAmount, "PT 铸造数量错误");
console.log("✅ 成功铸造 PT 和 YT");
});
it("利息产生后,YT 持有者应能提取收益", async function () {
const depositAmount = parseEther("10");
await stETH.write.approve([vault.address, depositAmount], { account: user.account });
await vault.write.deposit([depositAmount], { account: user.account });
// 模拟产生了 1 ETH 的利息 (直接向金库转账)
await stETH.write.transfer([vault.address, parseEther("1")], { account: owner.account });
const balanceBefore = await stETH.read.balanceOf([user.account.address]);
await vault.write.collectInterest({ account: user.account });
const balanceAfter = await stETH.read.balanceOf([user.account.address]);
assert.ok(balanceAfter > balanceBefore, "未成功提取利息");
console.log(`✅ 提取利息成功: ${formatEther(balanceAfter - balanceBefore)} stETH`);
});
it("未到期前无法赎回本金", async function () {
const depositAmount = parseEther("10");
await stETH.write.approve([vault.address, depositAmount], { account: user.account });
await vault.write.deposit([depositAmount], { account: user.account });
// 尝试提前赎回
await assert.rejects(
vault.write.redeem([depositAmount], { account: user.account }),
/Not expired yet/,
"不应允许提前赎回"
);
});
});
部署脚本
// scripts/deploy.js
import { network, artifacts } from "hardhat";
import { parseUnits } from "viem";
async function main() {
// 获取客户端(hardhat-viem 插件会自动处理网络连接)
const { viem } = await network.connect({ network: network.name });//指定网络进行链接
const [deployer, user1, user2] = await viem.getWalletClients();
const publicClient = await viem.getPublicClient();
const deployerAddress = deployer.account.address;
console.log("部署者地址:", deployerAddress);
// 1. 获取 ABI 和 Bytecode
const BoykaYuriTokenArtifact = await artifacts.readArtifact("BoykaYuriToken");
const YieldSplitVaultArtifact = await artifacts.readArtifact("YieldSplitVault");
// 2. 部署 BoykaYuriToken 合约
const BoykaYuriTokenHash = await deployer.deployContract({
abi: BoykaYuriTokenArtifact.abi,
bytecode: BoykaYuriTokenArtifact.bytecode,
args: [deployerAddress, deployerAddress],
});
const BoykaYuriToken= await publicClient.waitForTransactionReceipt({ hash: BoykaYuriTokenHash });
console.log("BoykaYuriToken 地址:", BoykaYuriToken.contractAddress);
// 3. 部署 YieldSplitVault 合约
const YieldSplitVaultHash = await deployer.deployContract({
abi: YieldSplitVaultArtifact.abi,
bytecode: YieldSplitVaultArtifact.bytecode,
args: [BoykaYuriToken.contractAddress,3600n],
});
const YieldSplitVault= await publicClient.waitForTransactionReceipt({ hash: YieldSplitVaultHash });
console.log("YieldSplitVault 地址:", YieldSplitVault.contractAddress);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
结语
至此,我们已完整实现收益分层交易从理论认知到代码实践的全流程落地,覆盖开发、测试与部署各核心环节。