947 lines
30 KiB
Markdown
947 lines
30 KiB
Markdown
# Genex Chain 区块链开发指南
|
||
|
||
> 自建EVM兼容应用链 + 智能合约体系
|
||
|
||
---
|
||
|
||
## 1. 链架构总览
|
||
|
||
| 组件 | 技术选型 | 说明 |
|
||
|------|---------|------|
|
||
| **链框架** | Cosmos SDK(最新版本) | 200+生产链验证,模块化 |
|
||
| **共识引擎** | CometBFT(原Tendermint) | 拜占庭容错,**即时终结性** |
|
||
| **EVM模块** | **cosmos/evm**(官方Cosmos EVM) | Apache 2.0,替代已弃用的Ethermint |
|
||
| **跨链通信** | IBC | Cosmos生态原生跨链协议 |
|
||
| **跨链桥** | Axelar(主)/ Wormhole(备) | 稳定币从Ethereum桥入 |
|
||
| **撮合架构** | 链下内存订单簿 + 链上结算 | 参考dYdX v4 |
|
||
|
||
### 参考链
|
||
|
||
| 链 | 价值 | 关键参考 |
|
||
|----|------|---------|
|
||
| **Cronos** | Cosmos SDK + EVM最成熟实现 | <1s出块、Block-STM并行执行 |
|
||
| **dYdX v4** | 交易平台专用链标杆 | 链下订单簿+链上结算 |
|
||
| **Injective** | 金融应用Layer-1 | 链上CLOB、机构级合规 |
|
||
|
||
---
|
||
|
||
## 2. 链设计参数
|
||
|
||
| 参数 | 目标值 |
|
||
|------|--------|
|
||
| 共识机制 | CometBFT PoS(初期平台运营验证节点) |
|
||
| EVM兼容 | 完全兼容(Solidity、Hardhat、MetaMask全套工具链) |
|
||
| 出块时间 | **≤ 1秒**(CometBFT即时终结性) |
|
||
| TPS | ≥ 5,000(Block-STM并行执行) |
|
||
| Gas策略 | 平台前期全额补贴,用户零Gas |
|
||
| 原生代币 | GNX(Gas + 治理;前期Gas补贴,用户不接触) |
|
||
| 节点运营 | 平台自营验证节点 + 未来开放合格机构节点 |
|
||
| 跨链 | IBC连接Cosmos生态 + Axelar桥连接Ethereum |
|
||
|
||
### 为什么自建链
|
||
|
||
| 维度 | 公链/L2 | Genex Chain |
|
||
|------|---------|-------------|
|
||
| Gas控制 | 受市场波动 | 平台完全控制,可设为零 |
|
||
| 合规执行 | 链层面无法强制 | 链级OFAC/Travel Rule内置 |
|
||
| 性能调优 | 共享资源 | 独享资源,针对券业务优化 |
|
||
| 升级自主 | 依赖链治理 | 平台自主决定升级 |
|
||
| 数据主权 | 完全公开 | 可控可见性 |
|
||
| 监管对接 | 难以定制 | 专属节点/API |
|
||
|
||
---
|
||
|
||
## 3. 开发环境搭建
|
||
|
||
### 3.1 前置依赖
|
||
|
||
```bash
|
||
# Go 1.21+
|
||
go version
|
||
|
||
# Node.js 20+(合约开发工具)
|
||
node --version
|
||
|
||
# Foundry(合约开发框架)
|
||
curl -L https://foundry.paradigm.xyz | bash
|
||
foundryup
|
||
|
||
# Cosmos SDK CLI
|
||
go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@latest
|
||
```
|
||
|
||
### 3.2 Genex Chain本地开发
|
||
|
||
```bash
|
||
# 克隆Genex Chain仓库
|
||
git clone https://git.gogenex.com/genex-chain.git
|
||
cd genex-chain
|
||
|
||
# 编译
|
||
make build
|
||
|
||
# 初始化本地测试链
|
||
./genexd init test-node --chain-id genex-localnet
|
||
|
||
# 创建创世账户
|
||
./genexd keys add validator
|
||
./genexd genesis add-genesis-account validator 1000000000ugnx
|
||
|
||
# 启动本地节点
|
||
./genexd start
|
||
```
|
||
|
||
### 3.3 合约开发环境
|
||
|
||
```bash
|
||
# 创建合约工程
|
||
mkdir genex-contracts && cd genex-contracts
|
||
|
||
# 使用Foundry初始化
|
||
forge init
|
||
|
||
# 项目结构
|
||
genex-contracts/
|
||
├── src/
|
||
│ ├── CouponFactory.sol
|
||
│ ├── Coupon.sol
|
||
│ ├── Settlement.sol
|
||
│ ├── Redemption.sol
|
||
│ ├── Treasury.sol
|
||
│ ├── Compliance.sol
|
||
│ └── Governance.sol
|
||
├── test/
|
||
│ ├── CouponFactory.t.sol
|
||
│ ├── Settlement.t.sol
|
||
│ └── ...
|
||
├── script/
|
||
│ └── Deploy.s.sol
|
||
└── foundry.toml
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 智能合约体系(7合约系统)
|
||
|
||
### 4.1 合约架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────┐
|
||
│ Governance(治理) │
|
||
│ Gas参数调整 | 紧急冻结多签 | 合约升级管理 │
|
||
├─────────────────────────────────────────────┤
|
||
│ │
|
||
│ ┌──────────────┐ ┌───────────────────┐ │
|
||
│ │CouponFactory │ │ Compliance │ │
|
||
│ │ 券发行工厂 │ │ OFAC筛查 │ │
|
||
│ │ 铸造+类型标记 │ │ Travel Rule │ │
|
||
│ └──────┬───────┘ │ 紧急冻结 │ │
|
||
│ │ └───────────────────┘ │
|
||
│ ┌──────┴───────┐ │
|
||
│ │ Coupon │ ┌───────────────────┐ │
|
||
│ │ ERC-721/1155 │ │ Treasury │ │
|
||
│ │ 所有权+转移 │ │ 资金托管 │ │
|
||
│ └──────┬───────┘ │ 退款原子交换 │ │
|
||
│ │ └───────────────────┘ │
|
||
│ ┌──────┴───────────────────────┐ │
|
||
│ │ │ │
|
||
│ │ Settlement Redemption │ │
|
||
│ │ 交易结算 兑付清算 │ │
|
||
│ │ 原子交换 券销毁 │ │
|
||
│ └──────────────────────────────┘ │
|
||
└─────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 4.2 CouponFactory — 券发行工厂
|
||
|
||
```solidity
|
||
// SPDX-License-Identifier: MIT
|
||
pragma solidity ^0.8.20;
|
||
|
||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
||
|
||
contract CouponFactory is Initializable, AccessControlUpgradeable {
|
||
enum CouponType { Utility, Security }
|
||
|
||
struct CouponConfig {
|
||
CouponType couponType; // 券类型(铸造后不可更改)
|
||
bool transferable; // 是否可转让
|
||
uint8 maxResaleCount; // 最大转售次数(Utility默认2-3)
|
||
uint256 maxPrice; // 价格上限(Utility = 面值)
|
||
uint256 expiryDate; // 到期日
|
||
uint256 minPurchase; // 最低消费金额
|
||
bool stackable; // 是否可叠加
|
||
bytes32[] allowedStores; // 限定门店
|
||
}
|
||
|
||
event CouponBatchMinted(
|
||
address indexed issuer,
|
||
uint256 indexed batchId,
|
||
uint256 faceValue,
|
||
uint256 quantity,
|
||
CouponType couponType
|
||
);
|
||
|
||
function mintBatch(
|
||
address issuer,
|
||
uint256 faceValue,
|
||
uint256 quantity,
|
||
CouponConfig calldata config
|
||
) external onlyRole(MINTER_ROLE) returns (uint256[] memory tokenIds) {
|
||
// MVP阶段只允许Utility类型
|
||
require(config.couponType == CouponType.Utility, "Only Utility Track in MVP");
|
||
|
||
// Utility Track强制:价格上限 = 面值
|
||
if (config.couponType == CouponType.Utility) {
|
||
require(config.maxPrice <= faceValue, "Utility: maxPrice <= faceValue");
|
||
require(config.expiryDate <= block.timestamp + 365 days, "Utility: max 12 months");
|
||
}
|
||
|
||
// 铸造逻辑
|
||
tokenIds = _mintTokens(issuer, faceValue, quantity, config);
|
||
|
||
emit CouponBatchMinted(issuer, batchId, faceValue, quantity, config.couponType);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.3 Settlement — 交易结算
|
||
|
||
```solidity
|
||
contract Settlement is Initializable, AccessControlUpgradeable {
|
||
ICoupon public couponContract;
|
||
IERC20 public stablecoin; // USDC
|
||
ICompliance public compliance;
|
||
|
||
event TradeSettled(
|
||
uint256 indexed tokenId,
|
||
address indexed buyer,
|
||
address indexed seller,
|
||
uint256 price
|
||
);
|
||
|
||
/// @notice 原子交换:券 ↔ 稳定币 同时转移
|
||
function executeSwap(
|
||
uint256 tokenId,
|
||
address buyer,
|
||
address seller,
|
||
uint256 price
|
||
) external onlyRole(SETTLER_ROLE) {
|
||
// 合规检查
|
||
require(!compliance.isBlacklisted(buyer), "Buyer blacklisted");
|
||
require(!compliance.isBlacklisted(seller), "Seller blacklisted");
|
||
|
||
// Utility Track: 价格 ≤ 面值
|
||
CouponConfig memory config = couponContract.getConfig(tokenId);
|
||
if (config.couponType == CouponType.Utility) {
|
||
require(price <= config.maxPrice, "Utility: price exceeds face value");
|
||
}
|
||
|
||
// 转售次数检查
|
||
require(
|
||
couponContract.getResaleCount(tokenId) < config.maxResaleCount,
|
||
"Max resale count exceeded"
|
||
);
|
||
|
||
// 原子交换(要么全部成功,要么全部回滚)
|
||
stablecoin.transferFrom(buyer, seller, price);
|
||
couponContract.safeTransferFrom(seller, buyer, tokenId);
|
||
couponContract.incrementResaleCount(tokenId);
|
||
|
||
emit TradeSettled(tokenId, buyer, seller, price);
|
||
}
|
||
|
||
/// @notice 退款:反向原子交换
|
||
function executeRefund(
|
||
uint256 tokenId,
|
||
address buyer,
|
||
address seller,
|
||
uint256 refundAmount
|
||
) external onlyRole(SETTLER_ROLE) {
|
||
couponContract.safeTransferFrom(buyer, seller, tokenId);
|
||
stablecoin.transferFrom(seller, buyer, refundAmount);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.4 Redemption — 兑付合约
|
||
|
||
```solidity
|
||
contract Redemption is Initializable {
|
||
ICoupon public couponContract;
|
||
|
||
event CouponRedeemed(
|
||
uint256 indexed tokenId,
|
||
address indexed consumer,
|
||
address indexed issuer,
|
||
bytes32 storeId
|
||
);
|
||
|
||
/// @notice 消费者直接与发行方结算,平台不介入
|
||
function redeem(
|
||
uint256 tokenId,
|
||
bytes32 storeId
|
||
) external {
|
||
require(couponContract.ownerOf(tokenId) == msg.sender, "Not owner");
|
||
|
||
CouponConfig memory config = couponContract.getConfig(tokenId);
|
||
|
||
// 验证到期
|
||
require(block.timestamp <= config.expiryDate, "Coupon expired");
|
||
|
||
// 验证门店限定
|
||
if (config.allowedStores.length > 0) {
|
||
require(_isAllowedStore(storeId, config.allowedStores), "Store not allowed");
|
||
}
|
||
|
||
// 销毁券(burn)
|
||
couponContract.burn(tokenId);
|
||
|
||
// 通知发行方(event),平台不介入消费数据
|
||
emit CouponRedeemed(tokenId, msg.sender, config.issuer, storeId);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.5 Compliance — 合规合约
|
||
|
||
```solidity
|
||
contract Compliance is Initializable, AccessControlUpgradeable {
|
||
mapping(address => bool) private _blacklist; // OFAC黑名单
|
||
|
||
/// @notice OFAC筛查
|
||
function isBlacklisted(address account) external view returns (bool) {
|
||
return _blacklist[account];
|
||
}
|
||
|
||
/// @notice Travel Rule(≥$3,000强制)
|
||
function recordTravelRule(
|
||
address sender,
|
||
address receiver,
|
||
bytes32 senderInfoHash, // 身份信息哈希(明文链下保存)
|
||
bytes32 receiverInfoHash
|
||
) external {
|
||
emit TravelRuleRecorded(sender, receiver, senderInfoHash, receiverInfoHash);
|
||
}
|
||
|
||
/// @notice 紧急冻结(需Governance多签)
|
||
function freezeAccount(address account) external onlyRole(GOVERNANCE_ROLE) {
|
||
_blacklist[account] = true;
|
||
emit AccountFrozen(account);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.6 Governance — 治理合约
|
||
|
||
```solidity
|
||
contract Governance is Initializable {
|
||
uint256 public constant REQUIRED_SIGNATURES = 3; // 3/5多签
|
||
uint256 public constant TIMELOCK = 48 hours; // 时间锁
|
||
uint256 public constant EMERGENCY_TIMELOCK = 4 hours;
|
||
|
||
struct Proposal {
|
||
bytes callData;
|
||
address target;
|
||
uint256 executeAfter;
|
||
uint256 approvalCount;
|
||
bool executed;
|
||
mapping(address => bool) approvals;
|
||
}
|
||
|
||
function propose(address target, bytes calldata data) external onlyMultisig {
|
||
// 创建提案,设置时间锁
|
||
}
|
||
|
||
function approve(uint256 proposalId) external onlyMultisig {
|
||
// 审批提案
|
||
}
|
||
|
||
function execute(uint256 proposalId) external {
|
||
Proposal storage p = proposals[proposalId];
|
||
require(p.approvalCount >= REQUIRED_SIGNATURES, "Not enough approvals");
|
||
require(block.timestamp >= p.executeAfter, "Timelock not expired");
|
||
require(!p.executed, "Already executed");
|
||
|
||
p.executed = true;
|
||
(bool success,) = p.target.call(p.callData);
|
||
require(success, "Execution failed");
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 合约升级策略
|
||
|
||
**模式:Transparent Proxy(透明代理)**
|
||
|
||
```
|
||
用户/前端 → Proxy合约(地址不变)→ Implementation合约(可替换)
|
||
```
|
||
|
||
**升级流程:**
|
||
```
|
||
发起升级提案 → 多签审批(3/5)→ 时间锁48h → 自动执行
|
||
↓
|
||
紧急通道:4/5多签 → 4h时间锁
|
||
```
|
||
|
||
**不可升级的逻辑(安全红线):**
|
||
- 券类型标记(Utility/Security)— 不可修改
|
||
- 所有权记录 — 不可被升级篡改
|
||
- 链上转售计数器 — 防止绕过Utility Track限制
|
||
|
||
---
|
||
|
||
## 6. 链级合规能力
|
||
|
||
| 能力 | 实现 |
|
||
|------|------|
|
||
| 链级OFAC过滤 | 验证节点拒绝处理制裁地址交易 |
|
||
| 链级Travel Rule | 大额转移必须携带身份哈希,否则拒绝打包 |
|
||
| 链级监控 | 节点内置异常交易检测模块 |
|
||
| 监管API | 监管机构专属只读API |
|
||
| 紧急冻结 | Governance多签冻结涉案地址 |
|
||
|
||
---
|
||
|
||
## 7. Gas费策略
|
||
|
||
### 前期(全额补贴)
|
||
|
||
| 操作 | Gas承担方 |
|
||
|------|----------|
|
||
| 券发行(铸造) | 平台补贴 |
|
||
| 一级/二级市场交易 | 平台补贴 |
|
||
| P2P转移 | 平台补贴 |
|
||
| 券兑付(消费) | 平台补贴 |
|
||
|
||
> 自建链Gas = 平台运营成本(服务器/节点),非公链ETH支付。
|
||
|
||
### 技术实现
|
||
|
||
```toml
|
||
# 创世配置
|
||
[app_state.evm.params]
|
||
min_gas_price = "0"
|
||
|
||
# 或使用ERC-4337 Paymaster
|
||
```
|
||
|
||
Gas参数通过Governance合约动态调整(无需硬分叉)。
|
||
|
||
---
|
||
|
||
## 8. 测试策略
|
||
|
||
### 8.1 合约测试(Foundry)
|
||
|
||
```solidity
|
||
// test/Settlement.t.sol
|
||
contract SettlementTest is Test {
|
||
Settlement settlement;
|
||
MockCoupon coupon;
|
||
MockERC20 usdc;
|
||
|
||
function setUp() public {
|
||
usdc = new MockERC20("USDC", "USDC", 6);
|
||
coupon = new MockCoupon();
|
||
settlement = new Settlement();
|
||
settlement.initialize(address(coupon), address(usdc));
|
||
}
|
||
|
||
function test_UtilityCannotExceedFaceValue() public {
|
||
// 面值100的Utility券,尝试以110价格交易,应被拒绝
|
||
vm.expectRevert("Utility: price exceeds face value");
|
||
settlement.executeSwap(tokenId, buyer, seller, 110e6);
|
||
}
|
||
|
||
function test_AtomicSwapSuccess() public {
|
||
// 正常交易:券和稳定币同时转移
|
||
settlement.executeSwap(tokenId, buyer, seller, 85e6);
|
||
assertEq(coupon.ownerOf(tokenId), buyer);
|
||
assertEq(usdc.balanceOf(seller), 85e6);
|
||
}
|
||
|
||
function test_RefundReverseSwap() public {
|
||
// 退款:反向原子交换
|
||
settlement.executeRefund(tokenId, buyer, seller, 85e6);
|
||
assertEq(coupon.ownerOf(tokenId), seller);
|
||
assertEq(usdc.balanceOf(buyer), 85e6);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.2 测试覆盖要求
|
||
|
||
| 测试类型 | 覆盖 |
|
||
|---------|------|
|
||
| 单元测试 | 每个合约函数 |
|
||
| Fuzz测试 | 价格边界、数量溢出 |
|
||
| 集成测试 | 完整发行→交易→核销流程 |
|
||
| Gas优化 | 批量操作Gas消耗 |
|
||
| 安全审计 | 第三方审计(上线前必须) |
|
||
|
||
---
|
||
|
||
## 9. 部署流程
|
||
|
||
```bash
|
||
# 部署到本地测试链
|
||
forge script script/Deploy.s.sol --rpc-url http://localhost:8545 --broadcast
|
||
|
||
# 部署到Genex Chain测试网
|
||
forge script script/Deploy.s.sol \
|
||
--rpc-url https://testnet-rpc.gogenex.com \
|
||
--broadcast \
|
||
--verify
|
||
|
||
# 部署到Genex Chain主网(需多签审批)
|
||
forge script script/Deploy.s.sol \
|
||
--rpc-url https://rpc.gogenex.com \
|
||
--broadcast \
|
||
--verify \
|
||
--etherscan-api-key $GENEX_EXPLORER_KEY
|
||
```
|
||
|
||
### 合约验证
|
||
|
||
```bash
|
||
forge verify-contract \
|
||
--chain-id 8888 \
|
||
--compiler-version v0.8.20 \
|
||
$CONTRACT_ADDRESS \
|
||
src/CouponFactory.sol:CouponFactory
|
||
```
|
||
|
||
---
|
||
|
||
## 10. GCFN全球清算节点架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────┐
|
||
│ Global Coupon Financial Network (GCFN) │
|
||
├─────────────────────────────────────────────┤
|
||
│ ROOT NODE │
|
||
│ (US / Global Hub) │
|
||
│ 全球路由 | 跨境清算 | 合规协调 │
|
||
├──────────────┬──────────────┬───────────────┤
|
||
│ ASIA-PACIFIC │ EMEA │ AMERICAS │
|
||
├──────────────┼──────────────┼───────────────┤
|
||
│ 新加坡(MAS) │ 伦敦(FCA) │ 美国(FinCEN) │
|
||
│ 香港(SFC) │ 法兰克福 │ │
|
||
│ 日本(FSA) │ (BaFin) │ │
|
||
└──────────────┴──────────────┴───────────────┘
|
||
```
|
||
|
||
| 节点类型 | 职责 |
|
||
|---------|------|
|
||
| 根节点 | 全球路由、跨境清算、主验证节点 |
|
||
| 区域节点 | 区域清算、监管报送、本地化 |
|
||
| 本地节点 | 用户服务、本地支付、法规遵从 |
|
||
| 监管节点 | 只读审计、实时监控 |
|
||
|
||
---
|
||
|
||
## 11. 安全规范
|
||
|
||
- 所有合约上线前必须通过第三方安全审计
|
||
- 核心合约采用Transparent Proxy部署
|
||
- 升级需3/5多签 + 48小时时间锁
|
||
- Bug Bounty计划:严重漏洞奖励$10K-$100K
|
||
- MPC/HSM密钥管理
|
||
- 合约代码开源并在区块浏览器验证
|
||
|
||
---
|
||
|
||
## 12. GNX原生代币经济模型
|
||
|
||
### 12.1 代币用途(MVP阶段)
|
||
|
||
| 用途 | 说明 | MVP状态 |
|
||
|------|------|---------|
|
||
| **Gas消耗** | 支付交易费用(平台全额补贴) | 用户不接触 |
|
||
| **治理投票** | 参与链参数决策 | 仅平台内部 |
|
||
| **质押收益** | 验证节点质押获奖励 | 暂不开放 |
|
||
| **二级市场交易** | 交易所买卖GNX | 暂不开放 |
|
||
|
||
> MVP阶段GNX仅用于Gas(平台补贴),不上交易所,回避SEC证券风险。质押开放需取得法律意见书。
|
||
|
||
### 12.2 代币分配(预留设计)
|
||
|
||
```
|
||
总供应量: 1,000,000,000 GNX
|
||
├── 平台运营/Gas补贴: 40%(4亿)— 前期Gas支出从此池扣除
|
||
├── 团队与顾问: 20%(2亿)— 4年线性释放,1年锁定期
|
||
├── 生态基金: 15%(1.5亿)— 开发者激励、做市商激励
|
||
├── 未来融资预留: 15%(1.5亿)— Reg D/Reg S豁免发行
|
||
└── 社区治理: 10%(1亿)— DAO治理基金
|
||
```
|
||
|
||
### 12.3 Gas经济模型
|
||
|
||
```go
|
||
// genex-chain/x/evm/keeper/gas.go
|
||
// MVP阶段:Gas Price = 0,平台全额补贴
|
||
// 后期可通过Governance合约调整Gas参数
|
||
|
||
func (k Keeper) GetBaseFee(ctx sdk.Context) *big.Int {
|
||
params := k.GetParams(ctx)
|
||
if params.MinGasPrice.IsZero() {
|
||
return big.NewInt(0) // 免费Gas
|
||
}
|
||
return params.MinGasPrice.BigInt()
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 13. Coupon合约补充 — 不可转让券
|
||
|
||
```solidity
|
||
// src/Coupon.sol — 补充transfer限制逻辑
|
||
contract Coupon is ERC721Upgradeable, AccessControlUpgradeable {
|
||
mapping(uint256 => CouponConfig) private _configs;
|
||
|
||
/// @notice 重写transfer,不可转让券直接revert
|
||
function _beforeTokenTransfer(
|
||
address from,
|
||
address to,
|
||
uint256 tokenId,
|
||
uint256 /* batchSize */
|
||
) internal virtual override {
|
||
// 铸造(from=0)和销毁(to=0)不受限
|
||
if (from == address(0) || to == address(0)) return;
|
||
|
||
CouponConfig memory config = _configs[tokenId];
|
||
|
||
// 不可转让券:revert
|
||
require(config.transferable, "Coupon: non-transferable");
|
||
|
||
// 转售次数检查
|
||
require(
|
||
_resaleCount[tokenId] < config.maxResaleCount,
|
||
"Coupon: max resale count exceeded"
|
||
);
|
||
}
|
||
|
||
/// @notice 批量转移(批量P2P/批量交易)
|
||
function batchTransfer(
|
||
address from,
|
||
address to,
|
||
uint256[] calldata tokenIds
|
||
) external {
|
||
for (uint256 i = 0; i < tokenIds.length; i++) {
|
||
safeTransferFrom(from, to, tokenIds[i]);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 14. Compliance合约补充 — 差异化KYC检查
|
||
|
||
```solidity
|
||
// src/Compliance.sol — 补充KYC等级差异化检查
|
||
contract Compliance is Initializable, AccessControlUpgradeable {
|
||
// KYC等级映射
|
||
mapping(address => uint8) private _kycLevels; // 0=L0, 1=L1, 2=L2, 3=L3
|
||
|
||
// 不同操作要求不同KYC等级
|
||
function requireKycLevel(address account, uint8 requiredLevel) public view {
|
||
require(_kycLevels[account] >= requiredLevel, "Compliance: insufficient KYC level");
|
||
}
|
||
|
||
/// @notice 交易前合规检查(Settlement调用)
|
||
function preTradeCheck(
|
||
address buyer,
|
||
address seller,
|
||
uint256 amount,
|
||
CouponType couponType
|
||
) external view {
|
||
// OFAC黑名单检查
|
||
require(!_blacklist[buyer], "Buyer blacklisted");
|
||
require(!_blacklist[seller], "Seller blacklisted");
|
||
|
||
// Utility Track: 双方至少KYC L1
|
||
if (couponType == CouponType.Utility) {
|
||
requireKycLevel(buyer, 1);
|
||
requireKycLevel(seller, 1);
|
||
}
|
||
// Securities Track: 双方至少KYC L2
|
||
else {
|
||
requireKycLevel(buyer, 2);
|
||
requireKycLevel(seller, 2);
|
||
}
|
||
|
||
// 大额交易: KYC L2+
|
||
if (amount >= 10000e6) { // $10,000
|
||
requireKycLevel(buyer, 2);
|
||
requireKycLevel(seller, 2);
|
||
}
|
||
|
||
// 做市商: KYC L3
|
||
// (做市商身份由链下服务标记,链上通过MARKET_MAKER_ROLE验证)
|
||
}
|
||
|
||
/// @notice P2P转移合规路由
|
||
function p2pComplianceCheck(
|
||
address sender,
|
||
address receiver,
|
||
uint256 amount
|
||
) external {
|
||
require(!_blacklist[sender], "Sender blacklisted");
|
||
require(!_blacklist[receiver], "Receiver blacklisted");
|
||
|
||
// ≥$3,000 强制Travel Rule
|
||
if (amount >= 3000e6) {
|
||
requireKycLevel(sender, 2);
|
||
requireKycLevel(receiver, 2);
|
||
// Travel Rule数据必须已记录
|
||
require(_travelRuleRecorded[sender][receiver], "Travel Rule data required");
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 15. 验证节点级交易拦截
|
||
|
||
```go
|
||
// genex-chain/x/evm/ante/compliance_ante.go
|
||
// 验证节点在打包交易前执行合规检查
|
||
|
||
type ComplianceAnteHandler struct {
|
||
ofacList map[string]bool
|
||
travelRule TravelRuleChecker
|
||
}
|
||
|
||
func (h ComplianceAnteHandler) AnteHandle(
|
||
ctx sdk.Context, tx sdk.Tx, simulate bool,
|
||
) (sdk.Context, error) {
|
||
for _, msg := range tx.GetMsgs() {
|
||
evmMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
||
if !ok { continue }
|
||
|
||
from := evmMsg.GetFrom()
|
||
to := evmMsg.GetTo()
|
||
|
||
// 1. OFAC地址拦截(链级强制)
|
||
if h.ofacList[from.Hex()] || h.ofacList[to.Hex()] {
|
||
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized,
|
||
"OFAC sanctioned address, transaction rejected at validator level")
|
||
}
|
||
|
||
// 2. Structuring检测(拆分交易规避$3,000阈值)
|
||
if h.isStructuringPattern(ctx, from, evmMsg.GetValue()) {
|
||
// 不拒绝,但标记为可疑(升级为Travel Rule流程)
|
||
ctx = ctx.WithValue("suspicious_structuring", true)
|
||
}
|
||
|
||
// 3. Travel Rule预打包检查
|
||
if evmMsg.GetValue().Cmp(big.NewInt(3000e6)) >= 0 {
|
||
if !h.travelRule.HasRecord(from, *to) {
|
||
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized,
|
||
"Travel Rule: identity data required for transfers >= $3,000")
|
||
}
|
||
}
|
||
}
|
||
return ctx, nil
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 16. Treasury合约 — 保障资金锁定
|
||
|
||
```solidity
|
||
// src/Treasury.sol — 补充保障资金逻辑
|
||
contract Treasury is Initializable, AccessControlUpgradeable {
|
||
IERC20 public stablecoin;
|
||
|
||
// 发行方保障资金(自愿缴纳,提升信用评级)
|
||
mapping(address => uint256) public guaranteeFunds;
|
||
|
||
// 发行方冻结的销售款(自愿,作为兑付保障)
|
||
mapping(address => uint256) public frozenSalesRevenue;
|
||
|
||
/// @notice 发行方缴纳保障资金
|
||
function depositGuaranteeFund(uint256 amount) external {
|
||
stablecoin.transferFrom(msg.sender, address(this), amount);
|
||
guaranteeFunds[msg.sender] += amount;
|
||
emit GuaranteeFundDeposited(msg.sender, amount);
|
||
}
|
||
|
||
/// @notice 发行方违约时启用保障资金赔付
|
||
function activateGuaranteeFund(
|
||
address issuer,
|
||
address[] calldata claimants,
|
||
uint256[] calldata amounts
|
||
) external onlyRole(GOVERNANCE_ROLE) {
|
||
uint256 totalClaim = 0;
|
||
for (uint256 i = 0; i < claimants.length; i++) {
|
||
totalClaim += amounts[i];
|
||
}
|
||
require(guaranteeFunds[issuer] >= totalClaim, "Insufficient guarantee fund");
|
||
|
||
guaranteeFunds[issuer] -= totalClaim;
|
||
for (uint256 i = 0; i < claimants.length; i++) {
|
||
stablecoin.transfer(claimants[i], amounts[i]);
|
||
}
|
||
emit GuaranteeFundActivated(issuer, totalClaim);
|
||
}
|
||
|
||
/// @notice 交易资金托管(原子交换中间态)
|
||
function escrow(
|
||
uint256 orderId,
|
||
address buyer,
|
||
uint256 amount
|
||
) external onlyRole(SETTLER_ROLE) {
|
||
stablecoin.transferFrom(buyer, address(this), amount);
|
||
emit FundsEscrowed(orderId, buyer, amount);
|
||
}
|
||
|
||
/// @notice 释放托管资金给卖方
|
||
function release(
|
||
uint256 orderId,
|
||
address seller,
|
||
uint256 amount,
|
||
uint256 platformFee
|
||
) external onlyRole(SETTLER_ROLE) {
|
||
stablecoin.transfer(seller, amount - platformFee);
|
||
// 平台手续费归集
|
||
stablecoin.transfer(platformFeeCollector, platformFee);
|
||
emit FundsReleased(orderId, seller, amount);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 17. 合约升级回滚能力
|
||
|
||
```solidity
|
||
// src/Governance.sol — 补充回滚能力
|
||
contract Governance is Initializable {
|
||
// 保留前一版Implementation地址
|
||
mapping(address => address) public previousImplementations;
|
||
|
||
/// @notice 紧急回滚至上一版本(需4/5多签)
|
||
function rollback(address proxy) external {
|
||
require(
|
||
_getApprovalCount(currentProposalId) >= 4,
|
||
"Rollback requires 4/5 multisig"
|
||
);
|
||
address prevImpl = previousImplementations[proxy];
|
||
require(prevImpl != address(0), "No previous version");
|
||
|
||
// 执行回滚
|
||
ITransparentUpgradeableProxy(proxy).upgradeTo(prevImpl);
|
||
emit ContractRolledBack(proxy, prevImpl);
|
||
}
|
||
|
||
/// @notice 升级时自动记录前一版本
|
||
function _recordPreviousImpl(address proxy, address newImpl) internal {
|
||
address currentImpl = ITransparentUpgradeableProxy(proxy).implementation();
|
||
previousImplementations[proxy] = currentImpl;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 18. 多稳定币支持
|
||
|
||
```solidity
|
||
// src/Settlement.sol — 补充多稳定币支持
|
||
contract Settlement is Initializable, AccessControlUpgradeable {
|
||
// 支持多种稳定币
|
||
mapping(address => bool) public supportedStablecoins;
|
||
// 默认稳定币
|
||
address public defaultStablecoin; // USDC
|
||
|
||
function addStablecoin(address token) external onlyRole(GOVERNANCE_ROLE) {
|
||
supportedStablecoins[token] = true;
|
||
emit StablecoinAdded(token);
|
||
}
|
||
|
||
/// @notice 原子交换(支持指定稳定币)
|
||
function executeSwap(
|
||
uint256 tokenId,
|
||
address buyer,
|
||
address seller,
|
||
uint256 price,
|
||
address stablecoin // 买方选择的稳定币
|
||
) external onlyRole(SETTLER_ROLE) {
|
||
require(supportedStablecoins[stablecoin], "Unsupported stablecoin");
|
||
|
||
// 合规检查 + 原子交换
|
||
// ...(同原有逻辑,使用传入的stablecoin地址)
|
||
IERC20(stablecoin).transferFrom(buyer, seller, price);
|
||
couponContract.safeTransferFrom(seller, buyer, tokenId);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 19. Oracle集成(汇率)
|
||
|
||
```solidity
|
||
// src/Oracle.sol — 汇率预言机集成
|
||
interface IChainlinkPriceFeed {
|
||
function latestRoundData() external view returns (
|
||
uint80 roundId, int256 answer, uint256 startedAt,
|
||
uint256 updatedAt, uint80 answeredInRound
|
||
);
|
||
}
|
||
|
||
contract ExchangeRateOracle is Initializable {
|
||
// 各币种对USD汇率Feed
|
||
mapping(string => address) public priceFeeds;
|
||
|
||
function getRate(string calldata currency) external view returns (uint256) {
|
||
address feed = priceFeeds[currency];
|
||
require(feed != address(0), "Unsupported currency");
|
||
|
||
(, int256 answer,, uint256 updatedAt,) = IChainlinkPriceFeed(feed).latestRoundData();
|
||
// 汇率不能太旧(最多15分钟)
|
||
require(block.timestamp - updatedAt <= 900, "Stale price data");
|
||
return uint256(answer);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 20. 资产证券化合约预留(Phase 4)
|
||
|
||
```solidity
|
||
// src/future/CouponBackedSecurity.sol — 预留设计
|
||
// Phase 4: 券收益流打包为CBS(Coupon-Backed Securities)
|
||
// 仅在Securities Track + Broker-Dealer牌照后启用
|
||
|
||
/**
|
||
* @notice 预留接口定义,不在MVP实现
|
||
* - 券收益流打包
|
||
* - 信用评级接口
|
||
* - 收益曲线计算
|
||
*/
|
||
interface ICouponBackedSecurity {
|
||
function createPool(uint256[] calldata couponIds) external returns (uint256 poolId);
|
||
function getCreditRating(uint256 poolId) external view returns (string memory);
|
||
function getYieldCurve(uint256 poolId) external view returns (uint256[] memory);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
*文档版本: v2.0*
|
||
*基于: Genex 券交易平台 - 软件需求规格说明书 v4.1 + 技术架构开发需求 v3.0*
|
||
*技术栈: Cosmos SDK + cosmos/evm + CometBFT + Solidity + Foundry*
|
||
*更新: 补充GNX代币经济/不可转让revert/差异化KYC/验证节点拦截/批量转移/Treasury保障资金/回滚能力/多稳定币/Oracle/资产证券化预留*
|