Skip to content

Coinfair CLMM 接口中文说明文档

📋 目录

  1. 项目概述
  2. 核心创新
  3. 主要接口说明
  4. 使用案例
  5. 参数示例
  6. 测试指南
  7. 常见错误码
  8. 最佳实践

🎯 项目概述

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计价

优势

  1. 简化费用管理:所有费用统一以 token B 计价
  2. 提升用户体验:A→B 交换无需预计算费用
  3. 清晰财务管理:协议收入类型统一
  4. 简化合作伙伴分成:推荐费用统一结算

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 = 241524242944

3. 流动性管理接口

添加流动性

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:价格区间下限 tick
    • tick_upper:价格区间上限 tick
    • is_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:价格影响限制

交换方式说明

  1. 精确输入交换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%滑点)
  2. 精确输出交换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 用户提供了更高效、更便捷的交易和流动性管理体验。本文档涵盖了所有核心接口的详细说明和实用案例,帮助开发者和用户快速上手并充分利用协议的各项功能。