跳到主要内容

智能合约

OtcHub 智能合约是平台的核心组件,实现了安全的去中心化 OTC 交易功能。

合约概览

主合约:OtcHub.sol

OtcHub 主合约管理所有交易生命周期,包括交易创建、资金锁定、争议处理和最终结算。

合约地址:

  • Ethereum 主网: 0x... (即将部署)
  • Sepolia 测试网: 0xD07851B206CE3BdD6a0f491b159C6eE4ac039F74

关键特性

双重抵押机制

  • 交易双方都必须提供抵押品
  • 降低违约风险,确保交易安全
  • 抵押品在交易完成后自动返还

支持的交易方向

  • MakerSells: 卖家发起交易,出售资产
  • MakerBuys: 买家发起交易,购买资产

交易状态管理

enum TradeStatus {
Open, // 交易开放,等待资金
Funded, // 双方已注资
Settled, // 交易已完成
Cancelled, // 交易已取消
Disputed // 交易存在争议
}

流程图

争议处理(扩展)

  • 管理员在 Disputed 状态下的处理路径:
    • adminResolveDispute(tradeId, winner, reason): 扣除手续费后将全部托管资金划转给胜方,状态置为 AdminClosed,记录事件。
    • adminClearDispute(tradeId, reason): 解除争议、状态回到 Funded,不触碰资金,记录事件。
    • adminWithdraw(tradeId): 兜底方案,管理员提走资金,状态 AdminClosed

合约接口

核心函数

createTrade

创建新的 OTC 交易。

function createTrade(
address taker,
address depositToken,
uint256 price,
uint256 deposit,
uint256 fundingDeadline,
TradeDirection direction,
bytes32 agreementHash
) external returns (uint256 tradeId)

参数说明:

  • taker: 交易对手地址
  • depositToken: 抵押代币合约地址
  • price: 交易价格(以抵押代币计价)
  • deposit: 抵押金额
  • fundingDeadline: 注资截止时间
  • direction: 交易方向(MakerSells/MakerBuys)
  • agreementHash: 交易协议哈希

fundTrade

为交易提供资金。

function fundTrade(uint256 tradeId) external

参数说明:

  • tradeId: 交易ID

注意事项:

  • 调用前需先授权合约操作对应代币
  • 必须在资金截止时间前调用
  • 根据交易方向和角色存入不同金额

confirmTrade

确认交易完成。

function confirmTrade(uint256 tradeId) external

参数说明:

  • tradeId: 交易ID

确认逻辑:

  • 双方都必须调用此函数
  • 确认后自动执行资金分配
  • 扣除平台费用并分配给各方

raisePriceDispute

发起价格争议。

function raisePriceDispute(uint256 tradeId) external payable

参数说明:

  • tradeId: 交易ID
  • msg.value: 争议处理费用

cancelTrade

取消交易。

function cancelTrade(uint256 tradeId) external

参数说明:

  • tradeId: 交易ID

取消条件:

  • 只有交易创建者可以取消
  • 只能在特定状态下取消
  • 已注资的交易需要特殊处理

查询函数

getTrade

获取交易详细信息。

function getTrade(uint256 tradeId) external view returns (Trade memory)

getTradeStatus

获取交易状态。

function getTradeStatus(uint256 tradeId) external view returns (TradeStatus)

getUserTrades

获取用户的所有交易。

function getUserTrades(address user) external view returns (uint256[] memory)

事件

TradeCreated

新交易创建事件。

event TradeCreated(
uint256 indexed tradeId,
address indexed maker,
address indexed taker,
address depositToken,
uint256 price,
uint256 deposit,
TradeDirection direction,
bytes32 agreementHash
);

TradeFunded

交易注资事件。

event TradeFunded(
uint256 indexed tradeId,
address indexed funder,
uint256 amount,
bool makerFunded,
bool takerFunded
);

TradeConfirmed

交易确认事件。

event TradeConfirmed(
uint256 indexed tradeId,
address indexed confirmer,
bool makerConfirmed,
bool takerConfirmed
);

TradeSettled

交易结算事件。

event TradeSettled(
uint256 indexed tradeId,
uint256 makerAmount,
uint256 takerAmount,
uint256 platformFee
);

DisputeRaised

争议发起事件。

event DisputeRaised(
uint256 indexed tradeId,
address indexed disputer,
uint256 disputeFee
);

安全特性

重入保护

所有状态变更函数都使用 nonReentrant 修饰符防止重入攻击。

modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}

权限控制

使用 OpenZeppelin 的 AccessControl 进行权限管理。

// 管理员角色
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");

// 争议解决者角色
bytes32 public constant DISPUTE_RESOLVER_ROLE = keccak256("DISPUTE_RESOLVER_ROLE");

时间锁机制

  • 设置合理的注资期限
  • 防止资金无限期锁定
  • 超时自动触发特殊处理逻辑

数学安全

使用 OpenZeppelin 的 SafeMath 库防止整数溢出。

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

using SafeMath for uint256;

Gas 优化

存储优化

  • 使用紧密打包的结构体
  • 合理安排变量顺序
  • 减少不必要的存储操作

批量操作

支持批量交易操作以减少 Gas 消耗。

function batchFundTrades(uint256[] calldata tradeIds) external {
for (uint i = 0; i < tradeIds.length; i++) {
fundTrade(tradeIds[i]);
}
}

版本控制

合约当前版本:

string public constant VERSION = "1.0.0";

平台费用结构

OTC Hub 实施透明公平的费用结构:

交易手续费

  • 基础费率:买卖双方各自支付交易金额的 0.5%
  • 总平台费用:交易金额的 1%(双方各支付 0.5%)
  • 费用收取:在交易结算时自动扣除

争议解决费用

  • 标准争议:发起争议无额外费用
  • 争议解决:从过错方的抵押品中扣除交易金额的 10%
  • 争议处理:由平台管理员进行全面证据审查后解决

费用分配结构

struct FeeStructure {
uint256 platformFeeRate; // 基础平台费率 (基点)
uint256 disputePenaltyRate; // 争议惩罚费率 (基点)
address feeRecipient; // 费用收取地址
}

部署和验证

部署脚本

// scripts/deploy.js
const { ethers } = require("hardhat");

async function main() {
const OtcHub = await ethers.getContractFactory("OtcHub");
const otcHub = await OtcHub.deploy(
platformFeeRate, // 平台费率 (基点)
disputePenaltyRate, // 争议惩罚费率 (基点)
feeRecipient // 费用收取地址
);

await otcHub.deployed();
console.log("OtcHub deployed to:", otcHub.address);
}

验证命令

# Etherscan 验证
npx hardhat verify --network mainnet DEPLOYED_CONTRACT_ADDRESS

# 构造函数参数
npx hardhat verify --network mainnet DEPLOYED_CONTRACT_ADDRESS \
50 1000 0x742d35Cc6641C7FB22d02bBf5F5e2B5B3a3E5A7C

测试覆盖率

单元测试

  • ✅ 交易创建和注资
  • ✅ 正常交易流程
  • ✅ 争议处理机制
  • ✅ 权限控制
  • ✅ 错误条件处理

集成测试

  • ✅ 前端集成
  • ✅ 后端事件监听
  • ✅ 多用户交互场景

安全测试

  • ✅ 重入攻击防护
  • ✅ 整数溢出保护
  • ✅ 权限绕过测试
  • ✅ 前端运行状态恢复

常见问题

Q: 如何计算所需的抵押金额?

A: 抵押金额 = 交易金额 × 保证金倍数。例如,$1000 交易,2x 倍数需要 $2000 抵押。

Q: 交易可以部分成交吗?

A: 是的,Taker 可以选择部分数量进行交易,剩余部分保持开放状态。

Q: 争议处理需要多长时间?

A: 通常在 24-48 小时内完成,复杂情况可能需要更长时间。

Q: 如何获取测试代币?

A: 在 Sepolia 测试网上,可以通过水龙头获取测试 ETH 和 ERC20 代币。

开发资源

开发工具

  • Hardhat: 智能合约开发和测试框架
  • OpenZeppelin: 安全的智能合约库
  • Ethers.js: 以太坊交互库

相关链接