Appearance
Pool 模块
模块路径: coinfair_clmm::pool
Pool 模块是整个 Coinfair DEX 的核心模块,实现了类似 Uniswap V3 的集中流动性机制。本版本实现了统一费用收取机制,所有费用都从代币B收取。
View 方法(只读)
get_pool_tokens
获取池子的代币类型。
move
#[view]
public fun get_pool_tokens(pool_address: address): (Object<Metadata>, Object<Metadata>)参数:
pool_address:address- 池子地址
返回: (Object<Metadata>, Object<Metadata>) - (代币A元数据, 代币B元数据)
get_fee_rate
获取池子费率。
move
#[view]
public fun get_fee_rate(pool_address: address): u64参数:
pool_address:address- 池子地址
返回: u64 - 池子费率(分子,分母为1_000_000)
is_pool_paused
检查池子是否暂停。
move
#[view]
public fun is_pool_paused(pool_address: address): bool参数:
pool_address:address- 池子地址
返回: bool - 池子是否暂停
get_current_tick_index
获取当前tick索引。
move
#[view]
public fun get_current_tick_index(pool_address: address): I64参数:
pool_address:address- 池子地址
返回: I64 - 当前tick索引
get_fee_growth_global
获取全局费用增长率。
move
#[view]
public fun get_fee_growth_global(pool_address: address): (u128, u128)参数:
pool_address:address- 池子地址
返回: (u128, u128) - (代币A全局费用增长率, 代币B全局费用增长率)(Q64.64格式)
get_protocol_fees
获取协议费用。
move
#[view]
public fun get_protocol_fees(pool_address: address): (u64, u64)参数:
pool_address:address- 池子地址
返回: (u64, u64) - (代币A协议费用, 代币B协议费用)
get_pool_balances
获取池子余额。
move
#[view]
public fun get_pool_balances(pool_address: address): (u64, u64)参数:
pool_address:address- 池子地址
返回: (u64, u64) - (代币A余额, 代币B余额)
get_pool_info
获取完整的池子信息。
move
#[view]
public fun get_pool_info(pool_address: address): PoolInfo参数:
pool_address:address- 池子地址
返回: PoolInfo - 完整的池子信息(包含所有已初始化的tick)
PoolInfo 结构:
move
struct PoolInfo {
index: u64,
collection_name: String,
metadata_a: Object<Metadata>,
metadata_b: Object<Metadata>,
tick_spacing: u64,
fee_rate: u64,
liquidity: u128,
current_fifrt_price: u128,
current_tick_index: I64,
fee_growth_global_a: u128,
fee_growth_global_b: u128,
fee_protocol_coin_a: u64,
fee_protocol_coin_b: u64,
rewarder_infos: vector<Rewarder>,
rewarder_last_updated_time: u64,
position_index: u64,
is_pause: bool,
uri: String,
initialized_ticks: vector<Tick>
}get_position_count
获取位置总数。
move
#[view]
public fun get_position_count(pool_address: address): u64参数:
pool_address:address- 池子地址
返回: u64 - 位置总数
get_collection_name
获取位置NFT集合名称。
move
#[view]
public fun get_collection_name(pool_address: address): String参数:
pool_address:address- 池子地址
返回: String - 位置NFT集合名称
get_pool_uri
获取池子URI。
move
#[view]
public fun get_pool_uri(pool_address: address): String参数:
pool_address:address- 池子地址
返回: String - 池子URI
get_rewarder_last_updated_time
获取奖励器最后更新时间。
move
#[view]
public fun get_rewarder_last_updated_time(pool_address: address): u64参数:
pool_address:address- 池子地址
返回: u64 - 奖励器最后更新时间(Unix时间戳)
get_rewarder_info
获取奖励器信息。
move
#[view]
public fun get_rewarder_info(
pool_address: address,
index: u8
): (Object<Metadata>, address, address, u128, u128)参数:
pool_address:address- 池子地址index:u8- 奖励器索引(0-2)
返回: (Object<Metadata>, address, address, u128, u128) - (奖励代币元数据, 权限地址, 待转移权限地址, 每秒发放数量, 全局奖励增长率)
position_exists
检查位置是否存在。
move
#[view]
public fun position_exists(pool_address: address, position_index: u64): bool参数:
pool_address:address- 池子地址position_index:u64- 位置索引
返回: bool - 位置是否存在
get_position_liquidity
获取位置流动性。
move
#[view]
public fun get_position_liquidity(pool_address: address, position_index: u64): u128参数:
pool_address:address- 池子地址position_index:u64- 位置索引
返回: u128 - 位置流动性数量
get_position_fees_owed
获取位置待收取费用。
move
#[view]
public fun get_position_fees_owed(
pool_address: address,
position_index: u64
): (u64, u64)参数:
pool_address:address- 池子地址position_index:u64- 位置索引
返回: (u64, u64) - (代币A待收取费用, 代币B待收取费用)
get_position_rewards_owed
获取位置待收取奖励。
move
#[view]
public fun get_position_rewards_owed(
pool_address: address,
position_index: u64
): vector<u64>参数:
pool_address:address- 池子地址position_index:u64- 位置索引
返回: vector<u64> - 各奖励器的待收取奖励数量向量(按奖励器索引顺序)
get_position
获取完整的位置信息。
move
#[view]
public fun get_position(
pool_address: address,
pos_index: u64
): Position参数:
pool_address:address- 池子地址pos_index:u64- 位置索引
返回: Position - 完整的位置信息
Position 结构:
move
struct Position {
pool: address,
index: u64,
liquidity: u128,
tick_lower_index: I64,
tick_upper_index: I64,
fee_growth_inside_a: u128,
fee_owed_a: u64,
fee_growth_inside_b: u128,
fee_owed_b: u64,
rewarder_infos: vector<PositionRewarder>
}get_position_tick_range
获取位置的tick范围。
move
#[view]
public fun get_position_tick_range(
pool_address: address,
position_index: u64
): (I64, I64)参数:
pool_address:address- 池子地址position_index:u64- 位置索引
返回: (I64, I64) - (下边界tick, 上边界tick)
get_user_positions
查询用户在某个池子里的所有位置索引。
move
#[view]
public fun get_user_positions(
pool_address: address,
user_address: address
): vector<u64>参数:
pool_address:address- 池子地址user_address:address- 用户地址
返回: vector<u64> - 用户拥有的所有位置索引向量
说明: 通过检查用户是否持有对应的位置NFT来判断位置所有权
get_user_positions_detail
查询用户在某个池子里的所有位置详细信息。
move
#[view]
public fun get_user_positions_detail(
pool_address: address,
user_address: address
): vector<Position>参数:
pool_address:address- 池子地址user_address:address- 用户地址
返回: vector<Position> - 用户拥有的所有位置的完整信息向量
说明: 通过检查用户是否持有对应的位置NFT来判断位置所有权,并返回完整的Position数据
fetch_ticks
分页获取池子中的tick数据。
move
#[view]
public fun fetch_ticks(
pool_address: address,
index: u64,
offset: u64,
limit: u64
): (u64, u64, vector<Tick>)参数:
pool_address:address- 池子地址index:u64- 起始索引组offset:u64- 起始偏移量limit:u64- 获取数量限制
返回: (u64, u64, vector<Tick>) - (下一个索引组, 下一个偏移量, tick数据向量)
fetch_positions
分页获取池子中的位置数据。
move
#[view]
public fun fetch_positions(
pool_address: address,
index: u64,
limit: u64
): (u64, vector<Position>)参数:
pool_address:address- 池子地址index:u64- 起始位置索引limit:u64- 获取数量限制
返回: (u64, vector<Position>) - (下一个索引, 位置数据向量)
calculate_swap_result
计算交换结果(不实际执行交换)。
move
#[view]
public fun calculate_swap_result(
pool_address: address,
a2b: bool,
by_amount_in: bool,
amount: u64
): CalculatedSwapResult参数:
pool_address:address- 池子地址a2b:bool- 交换方向(true: A换B, false: B换A)by_amount_in:bool- 按输入量还是输出量计算(true为按输入量,false为按输出量)amount:u64- 交换数量
返回: CalculatedSwapResult - 计算出的交换结果
CalculatedSwapResult 结构:
move
struct CalculatedSwapResult {
amount_in: u64, // 计算的输入代币数量
amount_out: u64, // 计算的输出代币数量
fee_amount: u64, // 计算的交易费用
fee_rate: u64, // 使用的费率
after_fifrt_price: u128, // 交换后的价格平方根
is_exceed: bool, // 是否超出了价格限制
step_results: vector<SwapStepResult> // 每一步的交换结果详情
}SwapStepResult 结构:
move
struct SwapStepResult {
current_fifrt_price: u128, // 当前步骤开始时的价格平方根
target_fifrt_price: u128, // 目标价格平方根
current_liquidity: u128, // 当前步骤的流动性
amount_in: u64, // 该步骤的输入数量
amount_out: u64, // 该步骤的输出数量
fee_amount: u64, // 该步骤的费用
remainer_amount: u64 // 剩余未处理的数量
}get_tick_spacing
获取池子的tick间距。
move
#[view]
public fun get_tick_spacing(pool: address): u64参数:
pool:address- 池子地址
返回: u64 - tick间距
get_fifrt_price
获取当前fifrt价格。
move
#[view]
public fun get_fifrt_price(pool: address): u128参数:
pool:address- 池子地址
返回: u128 - 当前fifrt价格(Q64.64格式)
get_pool_liquidity
获取池子总流动性。
move
#[view]
public fun get_pool_liquidity(pool: address): u128参数:
pool:address- 池子地址
返回: u128 - 池子总流动性
get_pool_index
获取池子索引。
move
#[view]
public fun get_pool_index(pool: address): u64参数:
pool:address- 池子地址
返回: u64 - 池子索引
get_rewarder_len
获取奖励器数量。
move
#[view]
public fun get_rewarder_len(pool_address: address): u8参数:
pool_address:address- 池子地址
返回: u8 - 奖励器数量(最多3个)
Public 方法(可写)
open_position
开启新的流动性位置。
move
public fun open_position(
account: &signer,
pool_address: address,
tick_lower_index: I64,
tick_upper_index: I64
): u64参数:
account:&signer- 位置所有者pool_address:address- 池子地址tick_lower_index:I64- 下边界tick(有符号整数)tick_upper_index:I64- 上边界tick(有符号整数)
返回: u64 - 位置索引
前置条件:
- tick_lower < tick_upper
- tick值必须是tick_spacing的倍数
事件: 触发 OpenPositionEvent
关联: 自动铸造位置NFT
add_liquidity
向位置添加指定数量的流动性。
move
public fun add_liquidity(
pool_address: address,
liquidity: u128,
position_index: u64
): AddLiquidityReceipt参数:
pool_address:address- 池子地址liquidity:u128- 要添加的流动性数量position_index:u64- 位置索引
返回: AddLiquidityReceipt - 添加流动性收据(热土豆模式,必须立即处理)
AddLiquidityReceipt 结构:
move
struct AddLiquidityReceipt {
pool_address: address,
amount_a: u64,
amount_b: u64
}注意: 需要调用 repay_add_liquidity 完成操作
事件: 触发 AddLiquidityEvent
add_liquidity_fix_coin
通过固定一种代币的数量来添加流动性。
move
public fun add_liquidity_fix_coin(
pool_address: address,
amount: u64,
fix_amount_a: bool,
position_index: u64
): AddLiquidityReceipt参数:
pool_address:address- 池子地址amount:u64- 固定的代币数量fix_amount_a:bool- true表示固定代币A,false表示固定代币Bposition_index:u64- 位置索引
返回: AddLiquidityReceipt - 添加流动性收据
注意: 需要调用 repay_add_liquidity 完成操作
repay_add_liquidity
支付代币完成流动性添加。
move
public fun repay_add_liquidity(
asset_a: FungibleAsset,
asset_b: FungibleAsset,
receipt: AddLiquidityReceipt
)参数:
asset_a:FungibleAsset- 代币A资产asset_b:FungibleAsset- 代币B资产receipt:AddLiquidityReceipt- 添加流动性收据
前置条件: 代币数量必须与收据要求一致
remove_liquidity
从位置移除流动性。
move
public fun remove_liquidity(
account: &signer,
pool_address: address,
liquidity: u128,
position_index: u64
): (FungibleAsset, FungibleAsset)参数:
account:&signer- 位置所有者pool_address:address- 池子地址liquidity:u128- 要移除的流动性数量position_index:u64- 位置索引
返回: (FungibleAsset, FungibleAsset) - (代币A资产, 代币B资产)
前置条件: 必须是位置所有者
事件: 触发 RemoveLiquidityEvent
checked_close_position
关闭空位置(流动性为0)。
move
public fun checked_close_position(
account: &signer,
pool_address: address,
position_index: u64
): bool参数:
account:&signer- 位置所有者pool_address:address- 池子地址position_index:u64- 位置索引
返回: bool - 是否成功关闭
前置条件: 位置流动性必须为0
事件: 触发 ClosePositionEvent
关联: 自动销毁位置NFT
collect_fee
收集位置累积的交易费用。
move
public fun collect_fee(
account: &signer,
pool_address: address,
position_index: u64,
update_reward: bool
): (FungibleAsset, FungibleAsset)参数:
account:&signer- 位置所有者pool_address:address- 池子地址position_index:u64- 位置索引update_reward:bool- 是否同时更新奖励
返回: (FungibleAsset, FungibleAsset) - (代币A费用, 代币B费用)
事件: 触发 CollectFeeEvent
collect_rewarder
收集位置累积的流动性挖矿奖励。
move
public fun collect_rewarder(
account: &signer,
pool_address: address,
position_index: u64,
rewarder_index: u8,
update_reward: bool
): FungibleAsset参数:
account:&signer- 位置所有者pool_address:address- 池子地址position_index:u64- 位置索引rewarder_index:u8- 奖励器索引(0-2)update_reward:bool- 是否更新奖励状态
返回: FungibleAsset - 奖励代币资产
事件: 触发 CollectRewardEvent
collect_protocol_fee
收集池子累积的协议费用。
move
public fun collect_protocol_fee(
account: &signer,
pool_address: address
): (FungibleAsset, FungibleAsset)参数:
account:&signer- 协议费用领取权限账户pool_address:address- 池子地址
返回: (FungibleAsset, FungibleAsset) - (代币A协议费用, 代币B协议费用)
前置条件: 必须是协议费用领取权限账户
事件: 触发 CollectProtocolFeeEvent
flash_swap
执行闪电交换(先获得输出,后支付输入)。
move
public fun flash_swap(
pool_address: address,
swap_from: address,
a2b: bool,
by_amount_in: bool,
amount: u64,
fifrt_price_limit: u128
): (FungibleAsset, FungibleAsset, FlashSwapReceipt, u64)参数:
pool_address:address- 池子地址swap_from:address- 交换发起者地址a2b:bool- true表示A换B,false表示B换Aby_amount_in:bool- true表示amount是输入数量,false表示是输出数量amount:u64- 交换数量fifrt_price_limit:u128- 价格限制(防止滑点过大)
返回:
FungibleAsset- 输出代币A(如果a2b则为零)FungibleAsset- 输出代币B(如果!a2b则为零)FlashSwapReceipt- 交换收据(热土豆模式)u64- 推荐费用数量
FlashSwapReceipt 结构:
move
struct FlashSwapReceipt {
pool_address: address,
a2b: bool,
pay_amount: u64
}注意: 需要调用 repay_flash_swap 完成支付
事件: 触发 SwapEvent
repay_flash_swap
支付代币完成闪电交换。
move
public fun repay_flash_swap(
asset_a: FungibleAsset,
asset_b: FungibleAsset,
receipt: FlashSwapReceipt
)参数:
asset_a:FungibleAsset- 代币A资产(a2b时包含支付金额)asset_b:FungibleAsset- 代币B资产(!a2b时包含支付金额)receipt:FlashSwapReceipt- 闪电交换收据
swap_pay_amount
从交换收据获取需要支付的数量。
move
public fun swap_pay_amount(receipt: &FlashSwapReceipt): u64参数:
receipt:&FlashSwapReceipt- 交换收据
返回: u64 - 需要支付的数量
add_liqudity_pay_amount
从添加流动性收据获取需要支付的数量。
move
public fun add_liqudity_pay_amount(
receipt: &AddLiquidityReceipt
): (u64, u64)参数:
receipt:&AddLiquidityReceipt- 添加流动性收据
返回: (u64, u64) - (代币A数量, 代币B数量)
pause
暂停池子。
move
public fun pause(
account: &signer,
pool_address: address
)参数:
account:&signer- 协议权限签名者pool_address:address- 池子地址
前置条件: 必须是协议权限账户
unpause
恢复池子。
move
public fun unpause(
account: &signer,
pool_address: address
)参数:
account:&signer- 协议权限签名者pool_address:address- 池子地址
前置条件: 必须是协议权限账户
update_fee_rate
更新池子费率。
move
public fun update_fee_rate(
account: &signer,
pool_address: address,
fee_rate: u64
)参数:
account:&signer- 协议权限签名者pool_address:address- 池子地址fee_rate:u64- 新的费率
前置条件: 必须是协议权限账户,费率不能超过最大允许值
事件: 触发 UpdateFeeRateEvent
update_pool_uri
更新池子的位置NFT URI。
move
public fun update_pool_uri(
account: &signer,
pool_address: address,
uri: String
)参数:
account:&signer- 设置者账户签名者pool_address:address- 池子地址uri:String- NFT URI
前置条件: 必须有设置位置NFT URI的权限
initialize_rewarder
初始化奖励器。
move
public fun initialize_rewarder(
account: &signer,
pool_address: address,
authority: address,
index: u64,
reward_token: Object<Metadata>
)参数:
account:&signer- 协议权限签名者pool_address:address- 池子地址authority:address- 奖励器权限地址index:u64- 奖励器索引(0-2)reward_token:Object<Metadata>- 奖励代币元数据
前置条件: 必须是协议权限账户
update_emission
更新奖励器发放速率。
move
public fun update_emission(
account: &signer,
pool_address: address,
index: u8,
emission_per_second: u128,
reward_token: Object<Metadata>
)参数:
account:&signer- 奖励器权限签名者pool_address:address- 池子地址index:u8- 奖励器索引(0-2)emission_per_second:u128- 每秒发放数量reward_token:Object<Metadata>- 奖励代币元数据
前置条件: 必须是奖励器权限账户
事件: 触发 UpdateEmissionEvent
transfer_rewarder_authority
转移奖励器权限。
move
public fun transfer_rewarder_authority(
account: &signer,
pool_address: address,
index: u8,
new_authority: address
)参数:
account:&signer- 当前奖励器权限签名者pool_address:address- 池子地址index:u8- 奖励器索引(0-2)new_authority:address- 新权限地址
事件: 触发 TransferRewardAuthEvent
accept_rewarder_authority
接受奖励器权限。
move
public fun accept_rewarder_authority(
account: &signer,
pool_address: address,
index: u8
)参数:
account:&signer- 新奖励器权限签名者pool_address:address- 池子地址index:u8- 奖励器索引(0-2)
事件: 触发 AcceptRewardAuthEvent
reset_init_price_v2
重置池子的初始价格(仅在池子无流动性时可用)。
move
public fun reset_init_price_v2(
account: &signer,
pool_address: address,
new_initialize_price: u128
)参数:
account:&signer- 设置者账户pool_address:address- 池子地址new_initialize_price:u128- 新的初始价格平方根
前置条件:
- 必须有重置初始价格的权限
- 池子从未添加过流动性(position_index为1)
check_position_authority
检查位置权限(内部函数,用于验证位置所有权)。
move
public fun check_position_authority(
account: &signer,
pool_address: address,
position_index: u64
)参数:
account:&signer- 账户签名者pool_address:address- 池子地址position_index:u64- 位置索引
前置条件: 账户必须持有对应的位置NFT
使用示例
TypeScript 示例
typescript
// 1. 查询池子信息
const poolInfo = await view('pool::get_pool_info', [poolAddress]);
console.log('Pool liquidity:', poolInfo.liquidity);
console.log('Current price:', poolInfo.current_fifrt_price);
// 2. 开启新位置
const positionIndex = await entry('pool::open_position', [
account,
poolAddress,
tickLower,
tickUpper
]);
// 3. 添加流动性
const receipt = await entry('pool::add_liquidity', [
poolAddress,
liquidity,
positionIndex
]);
const [amountA, amountB] = await view('pool::add_liqudity_pay_amount', [receipt]);
// 4. 支付代币完成添加流动性
await entry('pool::repay_add_liquidity', [assetA, assetB, receipt]);
// 5. 查询用户位置
const userPositions = await view('pool::get_user_positions', [
poolAddress,
userAddress
]);
// 6. 计算交换结果
const swapResult = await view('pool::calculate_swap_result', [
poolAddress,
true, // a2b
true, // by_amount_in
1000 // amount
]);
console.log('Expected output:', swapResult.amount_out);
console.log('Fee amount:', swapResult.fee_amount);
// 7. 收集费用
const [feeA, feeB] = await entry('pool::collect_fee', [
account,
poolAddress,
positionIndex,
true // update_reward
]);