Appearance
Coinfair 限价单系统 - 双重撮合策略实现指南
🎯 概述
Coinfair 限价单系统采用创新的双重撮合策略:优先通过订单间直接撮合实现零滑点交易,剩余部分通过CLMM池子确保执行,为用户提供最优的交易体验。
✨ 核心特性
- 双重撮合策略: 即时直接撮合 + 剩余部分CLMM撮合
- 零滑点优先: 优先通过订单间直接匹配实现零滑点
- 流动性保障: 剩余部分通过CLMM池子确保执行
- CLMM 原生: 与集中流动性做市商完全集成
🔄 双重撮合策略
策略概述
我们的系统采用两步撮合法,最大化用户利益:
第一步:即时直接撮合
- 新订单创建后立即尝试与对手订单匹配
- 实现零滑点交易,保护用户利益
- 使用Maker订单价格,保护流动性提供者
第二步:CLMM剩余撮合
- 未撮合部分通过CLMM池子执行
- 确保所有订单都能得到执行
- 通过池子流动性发现最优价格
策略优势
| 撮合方式 | 优势 | 适用场景 |
|---|---|---|
| 即时直接撮合 | 零滑点、即时执行、价格优先 | 有对手订单匹配时 |
| CLMM剩余撮合 | 流动性保障、价格发现、风险分散 | 无对手订单或部分撮合后 |
🏗️ 系统架构
双重撮合流程图
结果处理
第二步:CLMM剩余撮合
第一步:即时直接撮合
用户层
是
否
是
否
创建订单
验证并锁定代币
存储到订单簿
立即尝试撮合
找到匹配订单?
执行直接撮合
进入第二步
计算剩余数量
有剩余数量?
通过CLMM池子执行
订单完成
更新订单状态
转移代币
发布事件
核心架构组件
- 订单管理层: 订单创建、取消和生命周期管理
- 即时撮合引擎: 零滑点订单间直接撮合
- CLMM剩余撮合引擎: 处理未撮合部分
- 智能路由系统: 自动选择最优撮合路径
🔧 核心组件
1. 数据结构
LimitOrder
struct LimitOrder has key, store {
id: u64, // 唯一订单ID
owner: address, // 订单所有者
token_in: Object<Metadata>, // 输入代币元数据
token_out: Object<Metadata>, // 输出代币元数据
amount_in: u64, // 输入金额
tick: i64, // 目标价格tick
filled: u64, // 已成交金额
remaining: u64, // 剩余未成交金额
status: u8, // 订单状态
order_type: u8, // 订单类型 (买单/卖单)
created_at: u64, // 创建时间戳
updated_at: u64, // 最后更新时间戳
}OrderBook
struct OrderBook has key {
// 使用 SkipList 的价格索引
buy_orders: SkipList<i64, vector<u64>>, // 买单 (tick 高→低)
sell_orders: SkipList<i64, vector<u64>>, // 卖单 (tick 低→高)
// 使用 SmartTable 的订单存储
orders: SmartTable<u64, LimitOrder>, // 订单详情 (ID → 订单)
order_nodes: SmartTable<u64, SkipListNode>, // SkipList 节点 (ID → 节点)
user_orders: SmartTable<address, vector<u64>>, // 用户订单索引
// 系统状态
next_order_id: u64, // 下一个订单ID
total_orders: u64, // 总订单数量
total_volume: u128, // 总交易量
}2. 订单状态与类型
// 订单状态常量
const ORDER_STATUS_ACTIVE: u8 = 0; // 活跃
const ORDER_STATUS_PARTIALLY_FILLED: u8 = 1; // 部分成交(等待CLMM撮合)
const ORDER_STATUS_FILLED: u8 = 2; // 完全成交
const ORDER_STATUS_CANCELLED: u8 = 3; // 已取消
const ORDER_STATUS_EXPIRED: u8 = 4; // 已过期
const ORDER_STATUS_REJECTED: u8 = 5; // 已拒绝
// 订单类型常量
const ORDER_TYPE_BUY: u8 = 0; // 买单
const ORDER_TYPE_SELL: u8 = 1; // 卖单🚀 实现详情
1. 订单创建与双重撮合
创建订单(自动触发双重撮合)
public fun create_limit_order(
account: &signer,
token_in: Object<Metadata>,
token_out: Object<Metadata>,
amount_in: u64,
tick: i64,
order_type: u8,
expiration_time: u64
): u64执行流程:
- 参数验证和边界检查
- 代币转移和锁定
- 创建订单并存储
- 自动触发双重撮合策略
双重撮合执行逻辑
/// 新订单创建后的双重撮合流程
fun execute_dual_matching_strategy(
order_book: &mut OrderBook,
new_order_id: u64
): (u64, u64) // 返回:(直接撮合数量, CLMM撮合数量)
/// 第一步:即时直接撮合
fun execute_immediate_matching(
order_book: &mut OrderBook,
order_id: u64
): u64 // 返回直接撮合的数量
/// 第二步:CLMM剩余撮合
fun execute_clmm_remaining_matching(
order_book: &mut OrderBook,
order_id: u64,
remaining_amount: u64,
pool_address: address
): (u64, u64) // 返回:(实际输入, 实际输出)2. 即时直接撮合引擎
核心撮合函数
/// 查找可匹配的对手订单
fun find_matching_orders(
order_book: &OrderBook,
order_tick: i64,
order_type: u8,
pool: address
): vector<u64>
/// 执行两个订单的撮合
fun execute_order_match(
order_book: &mut OrderBook,
order_id1: u64,
order_id2: u64
): u64 // 返回撮合数量
/// 批量撮合处理
public fun execute_batch_matching(order_book_address: address): u64撮合条件:
- 买单撮合: 寻找
sell_tick <= buy_tick的卖单 - 卖单撮合: 寻找
buy_tick >= sell_tick的买单 - 价格优先: 使用Maker订单价格执行
- 时间优先: 相同价格下先来先服务(FIFO)
3. CLMM剩余撮合引擎
AfterSwap Hook 集成
public fun after_swap_hook(
pool_address: address,
current_tick: i64
): vector<u64>执行流程:
- 获取当前池子 tick
- 查找需要CLMM撮合的订单(基于 tick 范围)
- 按优先级排序(tick + 时间 + 数量)
- 执行剩余部分CLMM撮合
- 更新订单状态
- 发布执行事件
订单执行引擎
fun execute_limit_order_via_clmm(
order: &mut LimitOrder,
pool_address: address,
current_tick: i64
): (u64, u64)执行逻辑:
- tick 条件验证(买单:current_tick > order.tick,卖单:current_tick < order.tick)
- 数量计算和调整(仅处理剩余未撮合部分)
- 滑点保护检查
- CLMM池子交换调用
- 结果验证和更新
📡 事件系统
双重撮合事件链
#[event]
struct OrderCreatedEvent has drop, store {
order_id: u64,
owner: address,
token_in: Object<Metadata>,
token_out: Object<Metadata>,
amount_in: u64,
tick: i64,
order_type: u8,
expiration_time: u64,
timestamp: u64,
}
#[event]
struct OrderMatchedEvent has drop, store {
buy_order_id: u64, // 买单ID
sell_order_id: u64, // 卖单ID
buy_owner: address, // 买方地址
sell_owner: address, // 卖方地址
matched_amount: u64, // 撮合数量
execution_tick: i64, // 执行价格tick
match_type: u8, // 撮合类型:0=直接撮合,1=CLMM撮合
timestamp: u64, // 撮合时间戳
}
#[event]
struct OrderExecutedEvent has drop, store {
order_id: u64,
owner: address,
amount_filled: u64, // 本次成交数量
amount_out: u64, // 本次输出数量
remaining: u64, // 剩余数量
execution_tick: i64, // 执行价格tick
execution_type: u8, // 执行类型:0=直接撮合,1=CLMM撮合
timestamp: u64, // 执行时间戳
}
#[event]
struct OrderCompletedEvent has drop, store {
order_id: u64,
owner: address,
total_filled: u64, // 总成交数量
total_out: u64, // 总输出数量
direct_match_amount: u64, // 直接撮合数量
clmm_match_amount: u64, // CLMM撮合数量
completion_time: u64, // 完成时间戳
}⚡ 性能与优化
1. 双重撮合策略性能优势
即时直接撮合优势:
- 零滑点执行: 订单间直接匹配,无需通过AMM池子
- 即时响应: 新订单创建时立即尝试撮合
- 价格优先: 使用Maker订单价格,保护流动性提供者
- 高效处理: 双指针算法实现O(n)批量撮合
CLMM剩余撮合优势:
- 流动性保障: 确保所有订单都能得到执行
- 价格发现: 通过池子流动性发现最优价格
- 风险分散: 分散大单对市场的影响
- CLMM 原生: 直接 tick 索引,与池子 tick 系统完全兼容
🧪 测试与质量
双重撮合策略测试
#[test]
fun test_dual_matching_strategy() { /* 双重撮合策略测试 */ }
#[test]
fun test_immediate_matching_only() { /* 仅即时撮合测试 */ }
#[test]
fun test_clmm_remaining_only() { /* 仅CLMM剩余撮合测试 */ }
#[test]
fun test_mixed_execution_scenario() { /* 混合执行场景测试 */ }
#[test]
fun test_order_creation_flow() { /* 订单创建流程测试 */ }
#[test]
fun test_cancel_order() { /* 订单取消测试 */ }
#[test]
fun test_get_order_details() { /* 订单查询测试 */ }
#[test]
fun test_cancel_order_unauthorized() { /* 权限验证测试 */ }
#[test]
fun test_create_order_invalid_params() { /* 参数验证测试 */ }
#[test]
fun test_multiple_orders_same_price() { /* 价格聚合测试 */ }
#[test]
fun test_cancel_all_user_orders() { /* 批量操作测试 */ }
#[test]
fun test_order_expiration() { /* 过期处理测试 */ }
#[test]
fun test_large_order_book_performance() { /* 性能测试 */ }
#[test]
fun test_concurrent_order_creation() { /* 并发测试 */ }📋 使用示例
1. 基础订单操作(自动双重撮合)
创建买单
// 创建 USDC → APT 买单
let order_id = create_limit_order(
&user,
token_usdc,
token_apt,
1000000, // 1 USDC
276325, // 目标 tick (~1.25 USDC/APT)
ORDER_TYPE_BUY,
1735689600 // 过期时间
);
// 系统自动执行双重撮合策略:
// 1. 即时撮合:寻找匹配的卖单进行零滑点撮合
// 2. CLMM剩余撮合:未撮合部分通过CLMM池子执行创建卖单
// 创建 APT → USDC 卖单
let order_id = create_limit_order(
&user,
token_apt,
token_usdc,
100000000, // 1 APT
276325, // 目标 tick (~1.25 USDC/APT)
ORDER_TYPE_SELL,
1735689600 // 过期时间
);
// 系统自动执行双重撮合策略:
// 1. 即时撮合:寻找匹配的买单进行零滑点撮合
// 2. CLMM剩余撮合:未撮合部分通过CLMM池子执行2. 手动控制撮合策略
仅执行即时撮合
// 手动触发即时撮合
let matched_amount = execute_immediate_matching(
&mut order_book,
order_id
);
// 返回: 直接撮合的数量仅执行CLMM剩余撮合
// 手动触发CLMM剩余撮合
let (amount_in, amount_out) = execute_clmm_remaining_matching(
&mut order_book,
order_id,
remaining_amount,
pool_address
);
// 返回: (实际输入金额, 实际输出金额)完整双重撮合流程
// 手动执行完整双重撮合策略
let (direct_amount, clmm_amount) = execute_dual_matching_strategy(
&mut order_book,
order_id
);
// 返回: (直接撮合数量, CLMM撮合数量)3. 订单管理
// 取消特定订单
cancel_order(&user, order_id);
// 取消用户所有订单
let cancelled_count = cancel_all_user_orders(&user);
// 获取订单详情
let order_opt = get_order_details(order_id);
if (order_opt.is_some()) {
let order = order_opt.destroy_some();
// 处理订单信息
};
// 按 tick 查询订单
let orders_at_tick = get_orders_by_tick(276325, ORDER_TYPE_BUY);
// 按 tick 范围查询订单
let orders_in_range = get_orders_by_price_range(276000, 277000, ORDER_TYPE_BUY);4. 高级操作
批量撮合
// 执行全局批量撮合
let matched_pairs = execute_batch_matching(order_book_address);
// 返回: 成功撮合的订单对数量
// 获取订单簿统计信息
let stats = get_order_book_stats(order_book_address);
// 返回: (总订单数, 活跃订单数, 总成交量)事件监控
// 监控双重撮合事件
event::emit(OrderMatchedEvent {
buy_order_id: 123,
sell_order_id: 456,
buy_owner: @user_a,
sell_owner: @user_b,
matched_amount: 100000000, // 1 APT
execution_tick: 405000, // 执行价格tick
match_type: 0, // 0=直接撮合,1=CLMM撮合
timestamp: 1735689600,
});此实现采用创新的双重撮合策略,为 Coinfair DEX 提供专业级的限价单交易体验,最大化用户利益并确保流动性。