Appearance
Coinfair CLMM 接口中文说明文档
📋 目录
🎯 项目概述
Coinfair CLMM(Concentrated Liquidity Market Maker)是基于 Aptos 区块链的去中心化交易所,采用集中流动性机制,类似于 Uniswap V3,但具有重大创新:
主要特性
- BMM 定价曲线:使用
x^4 * y = k替代传统的x * y = k - 统一费用机制:所有费用都以 token B(第二个代币)收取,简化费用管理
- Fungible Asset 标准:采用 Aptos Fungible Asset 框架,而非 legacy Coin 泛型
- NFT 化位置:流动性位置以 NFT 形式管理,可转移和交易
- 流动性挖矿:支持最多 3 种奖励代币同时发放
🔥 核心创新
统一费用机制
核心原则:无论交换方向如何,所有费用都从 token B 中收取
A→B 交换(卖 A 买 B)
输入:精确的token A数量
输出:token B(已扣除费用)
费用来源:从输出的token B中自动扣除
用户体验:无需预先计算费用B→A 交换(卖 B 买 A)
输入:token B(包含交换量+费用)
输出:精确的token A数量
费用来源:从输入的token B中扣除
一致性:费用仍然以token B计价优势
- 简化费用管理:所有费用统一以 token B 计价
- 提升用户体验:A→B 交换无需预计算费用
- 清晰财务管理:协议收入类型统一
- 简化合作伙伴分成:推荐费用统一结算
BMM 曲线:x^4 * y = k
相比传统 AMM 的优势:
- 更高的资本效率:在集中价格区间内
- 更好的价格发现:价格变化更敏感
- 减少无常损失:在稳定价格区间内
📝 主要接口说明
1. 协议管理接口
权限管理
transfer_protocol_authority
public entry fun transfer_protocol_authority(
protocol_authority: &signer,
next_protocol_authority: address
)功能:转移协议管理权限(第一步)
参数:
protocol_authority:当前协议管理员next_protocol_authority:新管理员地址
权限:仅协议管理员
注意:需要新管理员调用
accept_protocol_authority确认
accept_protocol_authority
public entry fun accept_protocol_authority(
next_protocol_authority: &signer
)功能:接受协议管理权限(第二步)
参数:
next_protocol_authority:新管理员账户
权限:待确认的新管理员
费用配置
update_protocol_fee_rate
public entry fun update_protocol_fee_rate(
protocol_authority: &signer,
protocol_fee_rate: u64
)功能:更新全局协议费率
参数:
protocol_authority:协议管理员protocol_fee_rate:新费率(0-4000,表示 0-40%)
示例:设置 2%协议费率
protocol_fee_rate = 200 // 2%
add_fee_tier
public entry fun add_fee_tier(
protocol_authority: &signer,
tick_spacing: u64,
fee_rate: u64
)功能:添加费率等级配置
参数:
tick_spacing:tick 间距(1, 10, 50, 100 等)fee_rate:费率(0-200000,表示 0-20%)
示例:添加 0.05%费率等级
tick_spacing = 10 fee_rate = 500 // 0.05%
2. 池子管理接口
创建池子
create_pool
public entry fun create_pool(
account: &signer,
token_a: Object<Metadata>,
token_b: Object<Metadata>,
tick_spacing: u64,
initialize_fifrt_price: u128,
uri: String
)功能:创建新的流动性池
参数:
token_a:第一个代币元数据对象token_b:第二个代币元数据对象tick_spacing:tick 间距(必须是已配置的费率等级)initialize_fifrt_price:初始化的 fifth-root 价格uri:位置 NFT 的 URI
权限:池创建权限账户(可配置为任何人)
价格计算示例:
// 假设希望初始价格为 1 USDC = 0.0001 BTC
// price = 0.0001
// fifrt_price = fifth_root(price) << 32
// fifrt_price ≈ 0.0562 << 32 = 241524242944
initialize_fifrt_price = 2415242429443. 流动性管理接口
添加流动性
add_liquidity
public entry fun add_liquidity(
account: &signer,
pool_address: address,
delta_liquidity: u128,
max_amount_a: u64,
max_amount_b: u64,
tick_lower: u64,
tick_upper: u64,
is_open: bool,
index: u64
)功能:添加指定数量的流动性
参数:
pool_address:池子地址delta_liquidity:要添加的流动性数量max_amount_a:token A 最大消费量(滑点保护)max_amount_b:token B 最大消费量(滑点保护)tick_lower:价格区间下限 ticktick_upper:价格区间上限 tickis_open:是否创建新位置index:现有位置索引(当 is_open=false 时使用)
使用示例:
// 添加流动性到价格区间 [0.95, 1.05]
// 假设当前价格为1.0
tick_lower = -512 // 对应价格约0.95
tick_upper = 512 // 对应价格约1.05
delta_liquidity = 1000000000000 // 1万亿流动性单位
max_amount_a = 1000000000 // 最大10 token A
max_amount_b = 1000000000 // 最大10 token B
is_open = true // 创建新位置add_liquidity_fix_token
public entry fun add_liquidity_fix_token(
account: &signer,
pool_address: address,
amount_a: u64,
amount_b: u64,
fix_amount_a: bool,
tick_lower: u64,
tick_upper: u64,
is_open: bool,
index: u64,
metadata_a: Object<Metadata>,
metadata_b: Object<Metadata>
)功能:固定一种代币数量添加流动性
参数:
amount_a:token A 数量(固定或最大值)amount_b:token B 数量(固定或最大值)fix_amount_a:是否固定 token A 数量metadata_a:token A 元数据metadata_b:token B 元数据
使用示例:
// 固定使用1000个token A,自动计算需要多少token B
amount_a = 1000000000 // 固定1000 token A
amount_b = 2000000000 // 最大2000 token B
fix_amount_a = true // 固定token A移除流动性
remove_liquidity
public entry fun remove_liquidity(
account: &signer,
pool_address: address,
delta_liquidity: u128,
min_amount_a: u64,
min_amount_b: u64,
position_index: u64,
is_close: bool
)功能:从位置中移除流动性
参数:
delta_liquidity:要移除的流动性数量min_amount_a:token A 最小接收量(滑点保护)min_amount_b:token B 最小接收量(滑点保护)position_index:位置索引is_close:流动性为零时是否关闭位置
位置管理
close_position
public entry fun close_position(
account: &signer,
pool_address: address,
position_index: u64
)功能:关闭空的流动性位置
参数:
position_index:位置索引
前提条件:位置流动性必须为零
collect_fee
public entry fun collect_fee(
account: &signer,
pool_address: address,
position_index: u64
)功能:收集位置累积的交易费用
参数:
position_index:位置索引
返回:直接转入用户钱包
collect_rewarder
public entry fun collect_rewarder(
account: &signer,
pool_address: address,
rewarder_index: u8,
pos_index: u64
)功能:收集流动性挖矿奖励
参数:
rewarder_index:奖励器索引(0, 1, 2)pos_index:位置索引
4. 交易接口
swap
public entry fun swap(
account: &signer,
pool_address: address,
a_to_b: bool,
by_amount_in: bool,
amount: u64,
amount_limit: u64,
fifrt_price_limit: u128,
metadata_a: Object<Metadata>,
metadata_b: Object<Metadata>
)功能:代币交换
参数:
a_to_b:交换方向(true=A 换 B,false=B 换 A)by_amount_in:按输入量(true)还是输出量(false)amount:交换数量amount_limit:滑点保护限制fifrt_price_limit:价格影响限制
交换方式说明:
精确输入交换(
by_amount_in = true)// A换B:我有100个A,能换多少B? a_to_b = true by_amount_in = true amount = 100000000 // 100 token A amount_limit = 95000000 // 最少95 token B(5%滑点)精确输出交换(
by_amount_in = false)// A换B:我要得到100个B,需要多少A? a_to_b = true by_amount_in = false amount = 100000000 // 想要100 token B amount_limit = 105000000 // 最多105 token A(5%滑点)
5. 流动性挖矿接口
奖励器管理
initialize_rewarder
public entry fun initialize_rewarder(
account: &signer,
pool_address: address,
authority: address,
index: u64,
reward_token: Object<Metadata>
)功能:初始化奖励器
参数:
authority:奖励器管理员地址index:奖励器索引(0-2)reward_token:奖励代币类型
权限:协议管理员
update_rewarder_emission
public entry fun update_rewarder_emission(
account: &signer,
pool_address: address,
index: u8,
emission_per_second: u128,
reward_token: Object<Metadata>
)功能:更新奖励发放速率
参数:
index:奖励器索引emission_per_second:每秒发放的奖励数量
权限:奖励器管理员
发放速率计算:
// 每天发放1000个奖励代币
daily_reward = 1000 * 10^8 // 假设8位小数
emission_per_second = daily_reward / 86400 // 86400秒/天📚 使用案例
案例 1: 创建 USDC-APT 流动性池
# 1. 部署协议(仅需一次)
aptos move run --function-id "0xYOUR_ADDRESS::clmm_router::init_module"
# 2. 添加费率等级
aptos move run --function-id "0xYOUR_ADDRESS::clmm_router::add_fee_tier" \
--args u64:10 u64:500 # 0.05%费率,tick间距10
# 3. 创建池子
aptos move run --function-id "0xYOUR_ADDRESS::clmm_router::create_pool" \
--args \
address:0xUSDC_METADATA \
address:0xAPT_METADATA \
u64:10 \
u128:4294967296000000 \
string:"https://example.com/nft"案例 2: 添加流动性到现有池子
# 1. 添加流动性(创建新位置)
aptos move run --function-id "0xYOUR_ADDRESS::clmm_router::add_liquidity_fix_token" \
--args \
address:0xPOOL_ADDRESS \
u64:1000000000 \ # 1000 USDC
u64:100000000000 \ # 最大1000 APT
bool:true \ # 固定USDC数量
u64:18446744073709551104 \ # tick_lower (-512)
u64:512 \ # tick_upper
bool:true \ # 创建新位置
u64:0 \ # 位置索引(创建时忽略)
address:0xUSDC_METADATA \
address:0xAPT_METADATA
# 2. 收集累积费用
aptos move run --function-id "0xYOUR_ADDRESS::clmm_router::collect_fee" \
--args address:0xPOOL_ADDRESS u64:0 # 位置索引0案例 3: 代币交换
# 精确输入交换:用100 USDC换APT
aptos move run --function-id "0xYOUR_ADDRESS::clmm_router::swap" \
--args \
address:0xPOOL_ADDRESS \
bool:true \ # USDC -> APT
bool:true \ # 按输入量
u64:100000000 \ # 100 USDC
u64:95000000000 \ # 最少95 APT(5%滑点)
u128:0 \ # 无价格限制
address:0xUSDC_METADATA \
address:0xAPT_METADATA
# 精确输出交换:想得到100 APT
aptos move run --function-id "0xYOUR_ADDRESS::clmm_router::swap" \
--args \
address:0xPOOL_ADDRESS \
bool:true \ # USDC -> APT
bool:false \ # 按输出量
u64:100000000000 \ # 要100 APT
u64:105000000 \ # 最多105 USDC(5%滑点)
u128:0 \ # 无价格限制
address:0xUSDC_METADATA \
address:0xAPT_METADATA案例 4: 设置流动性挖矿
# 1. 初始化奖励器(协议管理员)
aptos move run --function-id "0xYOUR_ADDRESS::clmm_router::initialize_rewarder" \
--args \
address:0xPOOL_ADDRESS \
address:0xREWARD_AUTHORITY \
u64:0 \ # 奖励器索引0
address:0xREWARD_TOKEN_METADATA
# 2. 设置发放速率(奖励器管理员)
aptos move run --function-id "0xYOUR_ADDRESS::clmm_router::update_rewarder_emission" \
--args \
address:0xPOOL_ADDRESS \
u8:0 \ # 奖励器索引
u128:115740740740741 \ # 每秒发放约10个代币(86400秒/天 * 10)
address:0xREWARD_TOKEN_METADATA
# 3. 收集奖励(流动性提供者)
aptos move run --function-id "0xYOUR_ADDRESS::clmm_router::collect_rewarder" \
--args \
address:0xPOOL_ADDRESS \
u8:0 \ # 奖励器索引
u64:0 # 位置索引🔧 参数示例
Tick 和价格转换
// 价格到tick的转换关系(BMM曲线 x^4*y=k)
价格 = 1.0001^(tick_index / 4) // 每个tick约0.0025%价格变化
// 常用tick值
tick = -2000 => 价格 ≈ 0.6065
tick = -1000 => 价格 ≈ 0.7788
tick = -500 => 价格 ≈ 0.8825
tick = 0 => 价格 = 1.0000
tick = 500 => 价格 ≈ 1.1331
tick = 1000 => 价格 ≈ 1.2840
tick = 2000 => 价格 ≈ 1.6487流动性数量计算
// 根据代币数量估算流动性
// 在当前价格为1.0,价格区间[0.9, 1.1]时
// 如果投入1000 token A + 1000 token B
// 大约得到流动性:2,000,000,000,000 单位
// 流动性与代币数量的关系是非线性的,取决于:
// 1. 当前价格在区间中的位置
// 2. 价格区间的宽度
// 3. BMM曲线的特性费率参数
// 费率分母:1,000,000
// 常见费率设置:
fee_rate = 500 // 0.05%
fee_rate = 3000 // 0.30%
fee_rate = 10000 // 1.00%
fee_rate = 30000 // 3.00%
// 协议费率分母:10,000
// 协议费率(从交易费中抽取):
protocol_fee_rate = 100 // 1%(从交易费中)
protocol_fee_rate = 200 // 2%(从交易费中)价格限制参数
// fifrt_price = fifth_root(price) << 32
// 最大价格限制:MAX_FIFRT_PRICE_X32 = 30629544679783
// 最小价格限制:MIN_FIFRT_PRICE_X32 = 602253
// 常用价格限制示例:
no_limit = 0 // 无限制
price_limit_up_5 = current_price * 1.05 << 32 // 上涨5%限制
price_limit_down_5 = current_price * 0.95 << 32 // 下跌5%限制🧪 测试指南
环境准备
# 1. 编译项目
cd CoinfairClmm
aptos move build
# 2. 运行所有测试
aptos move test
# 3. 运行特定测试模块
aptos move test --filter basic_math_test
aptos move test --filter swap_e2e_test本地测试网部署
# 1. 启动本地测试网
aptos node run-local-testnet --with-faucet
# 2. 创建测试账户
aptos init --profile alice
aptos account fund-with-faucet --profile alice
# 3. 部署合约
aptos move publish --profile alice
# 4. 创建测试代币
aptos move run --function-id "0x1::coin::initialize" \
--args string:"Test USDC" string:"TUSDC" u8:8 bool:false bool:false
# 5. 铸造测试代币
aptos move run --function-id "0x1::coin::mint" \
--args address:alice u64:1000000000000单元测试案例
#[test]
fun test_add_liquidity() {
// 测试添加流动性的完整流程
let (alice, _) = setup_test_accounts();
let pool_addr = create_test_pool();
// 添加流动性
add_liquidity(
&alice,
pool_addr,
1000000000000, // 1万亿流动性单位
1000000000, // 最大1000 token A
1000000000, // 最大1000 token B
-500, // tick_lower
500, // tick_upper
true, // 创建新位置
0 // 位置索引
);
// 验证结果
let position = get_position_info(pool_addr, 0);
assert!(position.liquidity > 0, 1);
}
#[test]
fun test_swap() {
// 测试交换功能
let (alice, bob) = setup_test_accounts_with_tokens();
let pool_addr = create_test_pool_with_liquidity();
// 执行A->B交换
swap(
&alice,
pool_addr,
true, // A to B
true, // by amount in
100000000, // 100 token A
95000000, // 最少95 token B
0, // 无价格限制
token_a_metadata(),
token_b_metadata()
);
// 验证交换结果
let balance_b = get_token_balance(alice_addr(), token_b_metadata());
assert!(balance_b >= 95000000, 2);
}⚠️ 常见错误码
// clmm_router.move错误码
EAMOUNT_IN_ABOVE_MAX_LIMIT = 1 // 输入量超过最大限制
EAMOUNT_OUT_BELOW_MIN_LIMIT = 2 // 输出量低于最小限制
EIS_NOT_VALID_TICK = 3 // 无效的tick
EINVALID_LIQUIDITY = 4 // 无效的流动性
EPOOL_ADDRESS_ERROR = 5 // 池子地址错误
EINVALID_POOL_PAIR = 6 // 无效的池子配对
ESWAP_AMOUNT_INCORRECT = 7 // 交换数量错误
EPOSITION_INDEX_ERROR = 8 // 位置索引错误
EPOSITION_IS_NOT_ZERO = 9 // 位置流动性不为零
// pool.move错误码
EAMOUNT_IN_ABOVE_MAX_LIMIT = 1 // 输入超限
EAMOUNT_OUT_BELOW_MIN_LIMIT = 2 // 输出不足
EFIFRT_PRICE_LIMIT_EXCEEDED = 3 // 价格限制超出
EINVALID_TICK = 4 // 无效tick
EINVALID_FIFRT_PRICE = 5 // 无效价格
ELIQUIDITY_OVERFLOW = 6 // 流动性溢出
ELIQUIDITY_UNDERFLOW = 7 // 流动性不足
ETICK_LOWER_OVERFLOW = 8 // 下限tick溢出
ETICK_UPPER_OVERFLOW = 9 // 上限tick溢出
ETICK_SPACING_ERROR = 10 // tick间距错误
ETICK_ORDER_ERROR = 11 // tick顺序错误
EINSUFFICIENT_LIQUIDITY = 12 // 流动性不足
ELIQUIDITY_ZERO = 13 // 流动性为零
EPOSITION_NOT_EXIST = 22 // 位置不存在
EPOOL_IS_PAUSED = 32 // 池子已暂停📖 最佳实践
1. 价格区间选择策略
// 稳定币池(如USDC-USDT):窄区间,高资本效率
tick_spacing = 1 // 最小间距
price_range = ±0.1% // 99.9%-100.1%
// 主流币池(如ETH-USDC):中等区间
tick_spacing = 10
price_range = ±5% // 95%-105%
// 长尾币池:宽区间,分散风险
tick_spacing = 100
price_range = ±20% // 80%-120%2. 流动性管理策略
// 分层流动性策略
Position 1: 窄区间(90%-110%)- 70%资金
Position 2: 中区间(80%-125%)- 20%资金
Position 3: 宽区间(50%-200%)- 10%资金
// 定期重平衡
if (current_price < lower_bound * 1.1) {
// 价格接近下边界,考虑重新平衡
rebalance_positions();
}3. 风险控制
// 滑点保护:设置合理的amount_limit
expected_output = simulate_swap(input_amount);
min_output = expected_output * 0.95; // 5%滑点容忍
// 价格影响控制:大额交换分批执行
if (amount > pool_liquidity * 0.1) {
// 超过池子流动性10%,考虑分批
split_into_smaller_swaps(amount);
}
// 时间窗口控制:避免MEV攻击
add_time_delay_or_commit_reveal();4. Gas 优化技巧
// 批量操作
collect_fee_and_rewarder_together(); // 一次性收集费用和奖励
// 选择合适的交换方式
if (know_exact_input) {
use_exact_input_swap(); // Gas更低
} else {
use_exact_output_swap(); // 功能更精确
}
// 位置管理
if (liquidity_very_low) {
close_position_to_save_gas(); // 避免零流动性位置的维护成本
}5. 监控和维护
// 位置健康度监控
function monitor_position_health(position_index: u64) {
let (current_price, lower_tick, upper_tick) = get_position_info(position_index);
// 价格偏离度检查
let distance_to_lower = current_price - lower_tick;
let distance_to_upper = upper_tick - current_price;
if (min(distance_to_lower, distance_to_upper) < 0.05) {
// 价格接近边界,考虑调整
consider_rebalance(position_index);
}
}
// 收益率分析
function calculate_position_apy(position_index: u64, time_period: u64) {
let initial_value = get_historical_position_value(position_index, time_period);
let current_value = get_current_position_value(position_index);
let fees_earned = get_fees_earned(position_index, time_period);
let total_return = (current_value + fees_earned - initial_value) / initial_value;
let apy = total_return * (365 * 24 * 3600 / time_period);
return apy;
}🎓 总结
Coinfair CLMM 通过创新的统一费用机制和 BMM 定价曲线,为 DeFi 用户提供了更高效、更便捷的交易和流动性管理体验。本文档涵盖了所有核心接口的详细说明和实用案例,帮助开发者和用户快速上手并充分利用协议的各项功能。