MovescriptionsV4.1
4.1 版本比之前的版本增加了交易功能,交易功能的实现基本都是在 movescription_to_amm.move 合约中实现,所以本篇文章我们的重点关注点在 movescription_to_amm 合约,流动性池,交易等问题上
movescription
先看 movescription.move 合约中新增的结构体和函数。这些结构 体和函数给交易提供工具和支持 新增的这两个结构体是用于权限管理的。 合约中的交易采用了 Capability 模式。使用了 coin 包
struct Treasury<phantom T> has store{
cap: TreasuryCap<T>,
coin_type: String,
}
struct InitTreasuryArgs<phantom T> has key, store{
id: UID,
tick: String,
cap: Option<TreasuryCap<T>>,
}
先了解一下必须的工具函数,这样有助于后续的业务
movescription_to_coin 函数是将一个铭文销毁,然后返回内部的所有资产
并且,会根据铭文的数量(amount)来铸币(Balance<T>)并返回
这个函数主要用于使用铭文添加流动性
public(friend) fun movescription_to_coin<T: drop>(
tick_record: &mut TickRecordV2,
movescription: Movescription
): (Balance<SUI>, Option<Movescription>, Option<Metadata>, Balance<T>)
跟上面的相反,把 balance_t 铸造成铭文.参数中提供的资产全部放进新铸造的铭文中
public(friend) fun coin_to_movescription<T: drop>(
tick_record: &mut TickRecordV2,
acc: Balance<SUI>,
locked: Option<Movescription>,
metadata: Option<Metadata>,
balance_t: Balance<T>,
ctx: &mut TxContext
): (Movescription, Balance<T>)
movescription_to_amm.move
接下来是本篇的重点,所有的交易函数都在这个合约中实现 流动性池相关的接口,使用了cetus_clmm包,感兴趣的读者可以自行了解
结构体
结构体很简单,通过添加动态字段的方式这个结构会放进每种铭文的 TickRecordV2 结构体中,用于记录每个地址添加的流动性
struct Positions has store{
positions: Table<address, Position>,
}
业务逻辑和函数实现
创建一个货币交易市场,需要做的是创建流动性池,添加流动性,以及购买功能,接下来将逐步介绍
1.创建流动性池
public entry fun init_pool<T: drop>(pools: &mut Pools, config: &GlobalConfig, tick_record: &mut TickRecordV2, movescription: Movescription, clk: &Clock, ctx: &mut TxContext)
函数内部使用cetus_clmm::factory::create_pool_with_liquidity<T,SUI>创建流动性池,并使用参数中的 movescription 添加第一笔流动性
从泛型来看,这是一个 Balance<SUI> 类型的代币和 Balance<T> 的交易池
此后,这个流动性池 position 会被封装进 Positions 结构中,然后放入 tick_record 中,成为这种铭文的流动性池
2.添加流动性
为一种铭文的池子添加流动性,只能使用这种铭文
public entry fun add_liquidity<T: drop>(
config: &GlobalConfig,
pool: &mut Pool<T,SUI>,
tick_record: &mut TickRecordV2,
movescription: Movescription,
clk: &Clock,
ctx: &mut TxContext)
添加流动性的逻辑是,首先将使用上述的movescription_to_coin函数将 movescription 销毁,取出其中的资产,得到 Balance<SUI> 、 Balance<T> 两种货币。
之后会向 tick_record 的池子添加流动性并记录在 Positions 的 table 中,对应关系为 address(玩家地址)-->liquidity(此地址的总流动性)
添加流动性需要使用 add_liquidity_with_swap 函数实现:
fun add_liquidity_with_swap<T:drop>(
config: &GlobalConfig,
pool: &mut Pool<T,SUI>,
position_nft: &mut Position,
balance_a: Balance<T>,
balance_b: Balance<SUI>,
clk: &Clock):(Balance<T>, Balance<SUI>)
本函数中逻辑: 1、如果 balance_a/balance_b 值都不为 0,则先使用 add_liquidity_internal 函数添加流动性,将第一次添加完成后剩余的代币取回,此处为了方便,我们称取回的代币也为 balance_a/balance_b。如果 balance_a/balance_b 其中一个值为 0(假设 balance_a.value = 0),则直接下一步
2、使用 swap 函数将一半 balance_a 兑换成 balance_b
3、再次使用 add_liquidity_internal 函数添加流动性
为池子添加流动性即是添加池子中两种币的总量,要按照此时池子中两种币的比例添加。所以上面的逻辑中需要使用 swap 函数调整两种币的比例
swap 函数中实际上调用了cetus_clmm::pool中的三个函数实现功能:
pool::flash_swap<CoinTypeA, CoinTypeB>、
pool::swap_pay_amount(&flash_receipt)、
pool::repay_flash_swap<CoinTypeA, CoinTypeB>
最终实现添加流动性的函数是 add_liquidity_internal:
fun add_liquidity_internal<T:drop>(
config: &GlobalConfig,
pool: &mut Pool<T,SUI>,
position_nft: &mut Position,
balance_a: Balance<T>,
balance_b: Balance<SUI>,
clk: &Clock):(Balance<T>, Balance<SUI>, bool)
依旧是掉用cetus_clmm::pool中的函数pool::add_liquidity()和pool::repay_add_liquidity()实现。最终没有用完的代币会全部返回给玩家