NAC_Blockchain/charter-std/defi/liquidity.ch

808 lines
24 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

///! # 流动性池
///!
///! Liquidity Pool (AMM)
///! 提供自动做市商AMM机制和流动性管理
///!
///! **版本**: v1.0
///! **模块**: charter-std/defi/liquidity.ch
use utils::math::{safe_mul, safe_div, safe_add, safe_sub, sqrt};
use utils::crypto::sha3_384_hash;
// ============================================================================
// 流动性池结构
// ============================================================================
/// 流动性池
struct LiquidityPool {
/// 池ID
pool_id: Hash,
/// 资产A
asset_a: Address,
/// 资产B
asset_b: Address,
/// 资产A储备量
reserve_a: u256,
/// 资产B储备量
reserve_b: u256,
/// LP代币总供应量
total_lp_supply: u256,
/// 手续费率基点例如30表示0.3%
fee_rate: u16,
/// 累计手续费A
accumulated_fee_a: u256,
/// 累计手续费B
accumulated_fee_b: u256,
/// 最后更新时间
last_updated: Timestamp,
/// K值恒定乘积
k_last: u256
}
/// 流动性提供者信息
struct LiquidityProvider {
/// 提供者地址
provider: Address,
/// 池ID
pool_id: Hash,
/// LP代币数量
lp_tokens: u256,
/// 提供时间
provided_at: Timestamp,
/// 已领取奖励A
claimed_reward_a: u256,
/// 已领取奖励B
claimed_reward_b: u256
}
/// 交换记录
struct SwapRecord {
/// 交换ID
swap_id: Hash,
/// 池ID
pool_id: Hash,
/// 交换者
swapper: Address,
/// 输入资产
asset_in: Address,
/// 输入数量
amount_in: u256,
/// 输出资产
asset_out: Address,
/// 输出数量
amount_out: u256,
/// 手续费
fee: u256,
/// 时间戳
timestamp: Timestamp
}
// ============================================================================
// 流动性事件
// ============================================================================
/// 添加流动性事件
event AddLiquidity {
pool_id: Hash,
provider: Address,
amount_a: u256,
amount_b: u256,
lp_tokens: u256,
timestamp: Timestamp
}
/// 移除流动性事件
event RemoveLiquidity {
pool_id: Hash,
provider: Address,
amount_a: u256,
amount_b: u256,
lp_tokens: u256,
timestamp: Timestamp
}
/// 交换事件
event Swap {
swap_id: Hash,
pool_id: Hash,
swapper: Address,
asset_in: Address,
amount_in: u256,
asset_out: Address,
amount_out: u256,
fee: u256,
timestamp: Timestamp
}
/// 领取奖励事件
event ClaimRewards {
pool_id: Hash,
provider: Address,
reward_a: u256,
reward_b: u256,
timestamp: Timestamp
}
// ============================================================================
// 流动性池协议
// ============================================================================
/// 流动性池协议
certificate LiquidityPoolProtocol {
/// 流动性池 (pool_id => pool)
let _pools: Map<Hash, LiquidityPool>;
/// 流动性提供者 (provider => pool_id => lp_info)
let _providers: Map<Address, Map<Hash, LiquidityProvider>>;
/// 交换记录 (swap_id => record)
let _swaps: Map<Hash, SwapRecord>;
/// 池索引 (asset_a => asset_b => pool_id)
let _pool_index: Map<Address, Map<Address, Hash>>;
/// 管理员地址
let _admin: Address;
/// 默认手续费率(基点)
let _default_fee_rate: u16;
/// 最小流动性(防止除零)
let _minimum_liquidity: u256;
// ========== 构造函数 ==========
constructor(fee_rate: u16) {
require(fee_rate <= 1000, "Fee rate too high"); // 最高10%
self._admin = msg.sender;
self._default_fee_rate = fee_rate;
self._minimum_liquidity = 1000; // 最小流动性锁定
}
// ========== 池管理 ==========
/// 创建流动性池
///
/// # 参数
/// - `asset_a`: 资产A地址
/// - `asset_b`: 资产B地址
/// - `initial_a`: 初始资产A数量
/// - `initial_b`: 初始资产B数量
///
/// # 返回
/// - `Hash`: 池ID
pub fn create_pool(
asset_a: Address,
asset_b: Address,
initial_a: u256,
initial_b: u256
) -> Hash {
require(!asset_a.is_zero(), "Invalid asset A");
require(!asset_b.is_zero(), "Invalid asset B");
require(asset_a != asset_b, "Assets must be different");
require(initial_a > 0, "Initial A must be positive");
require(initial_b > 0, "Initial B must be positive");
// 确保资产顺序一致A < B
let (token0, token1, amount0, amount1) = if asset_a < asset_b {
(asset_a, asset_b, initial_a, initial_b)
} else {
(asset_b, asset_a, initial_b, initial_a)
};
// 检查池是否已存在
if let Some(existing_pools) = self._pool_index.get(token0) {
require(!existing_pools.contains_key(token1), "Pool already exists");
}
// 生成池ID
let pool_id = self._generate_pool_id(token0, token1);
// 计算初始LP代币数量几何平均数
let initial_lp = sqrt(safe_mul(amount0, amount1));
require(initial_lp > self._minimum_liquidity, "Insufficient initial liquidity");
// 锁定最小流动性
let lp_to_provider = safe_sub(initial_lp, self._minimum_liquidity);
let pool = LiquidityPool {
pool_id: pool_id,
asset_a: token0,
asset_b: token1,
reserve_a: amount0,
reserve_b: amount1,
total_lp_supply: initial_lp,
fee_rate: self._default_fee_rate,
accumulated_fee_a: 0,
accumulated_fee_b: 0,
last_updated: block.timestamp,
k_last: safe_mul(amount0, amount1)
};
self._pools[pool_id] = pool;
// 更新索引
if !self._pool_index.contains_key(token0) {
self._pool_index[token0] = Map::new();
}
self._pool_index[token0][token1] = pool_id;
// 记录流动性提供者
if !self._providers.contains_key(msg.sender) {
self._providers[msg.sender] = Map::new();
}
let lp_info = LiquidityProvider {
provider: msg.sender,
pool_id: pool_id,
lp_tokens: lp_to_provider,
provided_at: block.timestamp,
claimed_reward_a: 0,
claimed_reward_b: 0
};
self._providers[msg.sender][pool_id] = lp_info;
// 实际需要转移资产到池中
emit AddLiquidity {
pool_id: pool_id,
provider: msg.sender,
amount_a: amount0,
amount_b: amount1,
lp_tokens: lp_to_provider,
timestamp: block.timestamp
};
return pool_id;
}
/// 获取池信息
///
/// # 参数
/// - `pool_id`: 池ID
///
/// # 返回
/// - `LiquidityPool`: 池信息
pub fn get_pool(pool_id: Hash) -> LiquidityPool {
require(self._pools.contains_key(pool_id), "Pool not found");
return self._pools[pool_id];
}
/// 通过资产对查找池
///
/// # 参数
/// - `asset_a`: 资产A地址
/// - `asset_b`: 资产B地址
///
/// # 返回
/// - `Option<Hash>`: 池ID
pub fn find_pool(asset_a: Address, asset_b: Address) -> Option<Hash> {
let (token0, token1) = if asset_a < asset_b {
(asset_a, asset_b)
} else {
(asset_b, asset_a)
};
return self._pool_index.get(token0)
.and_then(|m| m.get(token1));
}
// ========== 添加和移除流动性 ==========
/// 添加流动性
///
/// # 参数
/// - `pool_id`: 池ID
/// - `amount_a`: 资产A数量
/// - `amount_b`: 资产B数量
/// - `min_lp_tokens`: 最小LP代币数量滑点保护
///
/// # 返回
/// - `u256`: 获得的LP代币数量
pub fn add_liquidity(
pool_id: Hash,
amount_a: u256,
amount_b: u256,
min_lp_tokens: u256
) -> u256 {
require(self._pools.contains_key(pool_id), "Pool not found");
require(amount_a > 0, "Amount A must be positive");
require(amount_b > 0, "Amount B must be positive");
let mut pool = self._pools[pool_id];
// 计算最优添加比例
let optimal_b = safe_mul(amount_a, pool.reserve_b) / pool.reserve_a;
let (final_a, final_b) = if optimal_b <= amount_b {
(amount_a, optimal_b)
} else {
let optimal_a = safe_mul(amount_b, pool.reserve_a) / pool.reserve_b;
(optimal_a, amount_b)
};
// 计算LP代币数量
let lp_tokens = if pool.total_lp_supply == 0 {
sqrt(safe_mul(final_a, final_b))
} else {
let lp_a = safe_mul(final_a, pool.total_lp_supply) / pool.reserve_a;
let lp_b = safe_mul(final_b, pool.total_lp_supply) / pool.reserve_b;
if lp_a < lp_b { lp_a } else { lp_b }
};
require(lp_tokens >= min_lp_tokens, "Slippage too high");
// 更新池状态
pool.reserve_a = safe_add(pool.reserve_a, final_a);
pool.reserve_b = safe_add(pool.reserve_b, final_b);
pool.total_lp_supply = safe_add(pool.total_lp_supply, lp_tokens);
pool.k_last = safe_mul(pool.reserve_a, pool.reserve_b);
pool.last_updated = block.timestamp;
self._pools[pool_id] = pool;
// 更新流动性提供者信息
if !self._providers.contains_key(msg.sender) {
self._providers[msg.sender] = Map::new();
}
if let Some(mut lp_info) = self._providers[msg.sender].get(pool_id) {
lp_info.lp_tokens = safe_add(lp_info.lp_tokens, lp_tokens);
self._providers[msg.sender][pool_id] = lp_info;
} else {
let lp_info = LiquidityProvider {
provider: msg.sender,
pool_id: pool_id,
lp_tokens: lp_tokens,
provided_at: block.timestamp,
claimed_reward_a: 0,
claimed_reward_b: 0
};
self._providers[msg.sender][pool_id] = lp_info;
}
// 实际需要转移资产到池中
emit AddLiquidity {
pool_id: pool_id,
provider: msg.sender,
amount_a: final_a,
amount_b: final_b,
lp_tokens: lp_tokens,
timestamp: block.timestamp
};
return lp_tokens;
}
/// 移除流动性
///
/// # 参数
/// - `pool_id`: 池ID
/// - `lp_tokens`: LP代币数量
/// - `min_amount_a`: 最小资产A数量滑点保护
/// - `min_amount_b`: 最小资产B数量滑点保护
///
/// # 返回
/// - `(u256, u256)`: (资产A数量, 资产B数量)
pub fn remove_liquidity(
pool_id: Hash,
lp_tokens: u256,
min_amount_a: u256,
min_amount_b: u256
) -> (u256, u256) {
require(self._pools.contains_key(pool_id), "Pool not found");
require(lp_tokens > 0, "LP tokens must be positive");
require(self._providers.contains_key(msg.sender), "No liquidity provided");
require(
self._providers[msg.sender].contains_key(pool_id),
"No liquidity in this pool"
);
let mut lp_info = self._providers[msg.sender][pool_id];
require(lp_info.lp_tokens >= lp_tokens, "Insufficient LP tokens");
let mut pool = self._pools[pool_id];
// 计算可取回的资产数量
let amount_a = safe_mul(lp_tokens, pool.reserve_a) / pool.total_lp_supply;
let amount_b = safe_mul(lp_tokens, pool.reserve_b) / pool.total_lp_supply;
require(amount_a >= min_amount_a, "Slippage too high for A");
require(amount_b >= min_amount_b, "Slippage too high for B");
// 更新池状态
pool.reserve_a = safe_sub(pool.reserve_a, amount_a);
pool.reserve_b = safe_sub(pool.reserve_b, amount_b);
pool.total_lp_supply = safe_sub(pool.total_lp_supply, lp_tokens);
pool.k_last = safe_mul(pool.reserve_a, pool.reserve_b);
pool.last_updated = block.timestamp;
self._pools[pool_id] = pool;
// 更新流动性提供者信息
lp_info.lp_tokens = safe_sub(lp_info.lp_tokens, lp_tokens);
self._providers[msg.sender][pool_id] = lp_info;
// 实际需要转移资产给提供者
emit RemoveLiquidity {
pool_id: pool_id,
provider: msg.sender,
amount_a: amount_a,
amount_b: amount_b,
lp_tokens: lp_tokens,
timestamp: block.timestamp
};
return (amount_a, amount_b);
}
// ========== 交换 ==========
/// 交换(精确输入)
///
/// # 参数
/// - `pool_id`: 池ID
/// - `asset_in`: 输入资产
/// - `amount_in`: 输入数量
/// - `min_amount_out`: 最小输出数量(滑点保护)
///
/// # 返回
/// - `u256`: 输出数量
pub fn swap_exact_input(
pool_id: Hash,
asset_in: Address,
amount_in: u256,
min_amount_out: u256
) -> u256 {
require(self._pools.contains_key(pool_id), "Pool not found");
require(amount_in > 0, "Amount in must be positive");
let mut pool = self._pools[pool_id];
// 确定输入输出资产
let (reserve_in, reserve_out, asset_out) = if asset_in == pool.asset_a {
(pool.reserve_a, pool.reserve_b, pool.asset_b)
} else if asset_in == pool.asset_b {
(pool.reserve_b, pool.reserve_a, pool.asset_a)
} else {
revert("Invalid asset");
};
// 计算输出数量(扣除手续费)
let amount_in_with_fee = safe_mul(amount_in, (10000 - pool.fee_rate) as u256);
let numerator = safe_mul(amount_in_with_fee, reserve_out);
let denominator = safe_add(safe_mul(reserve_in, 10000), amount_in_with_fee);
let amount_out = numerator / denominator;
require(amount_out >= min_amount_out, "Slippage too high");
require(amount_out < reserve_out, "Insufficient liquidity");
// 计算手续费
let fee = safe_mul(amount_in, pool.fee_rate as u256) / 10000;
// 更新储备量
if asset_in == pool.asset_a {
pool.reserve_a = safe_add(pool.reserve_a, amount_in);
pool.reserve_b = safe_sub(pool.reserve_b, amount_out);
pool.accumulated_fee_a = safe_add(pool.accumulated_fee_a, fee);
} else {
pool.reserve_b = safe_add(pool.reserve_b, amount_in);
pool.reserve_a = safe_sub(pool.reserve_a, amount_out);
pool.accumulated_fee_b = safe_add(pool.accumulated_fee_b, fee);
}
pool.k_last = safe_mul(pool.reserve_a, pool.reserve_b);
pool.last_updated = block.timestamp;
self._pools[pool_id] = pool;
// 生成交换ID
let swap_id = self._generate_swap_id(pool_id, msg.sender);
// 记录交换
let swap_record = SwapRecord {
swap_id: swap_id,
pool_id: pool_id,
swapper: msg.sender,
asset_in: asset_in,
amount_in: amount_in,
asset_out: asset_out,
amount_out: amount_out,
fee: fee,
timestamp: block.timestamp
};
self._swaps[swap_id] = swap_record;
// 实际需要转移资产
emit Swap {
swap_id: swap_id,
pool_id: pool_id,
swapper: msg.sender,
asset_in: asset_in,
amount_in: amount_in,
asset_out: asset_out,
amount_out: amount_out,
fee: fee,
timestamp: block.timestamp
};
return amount_out;
}
/// 交换(精确输出)
///
/// # 参数
/// - `pool_id`: 池ID
/// - `asset_out`: 输出资产
/// - `amount_out`: 输出数量
/// - `max_amount_in`: 最大输入数量(滑点保护)
///
/// # 返回
/// - `u256`: 输入数量
pub fn swap_exact_output(
pool_id: Hash,
asset_out: Address,
amount_out: u256,
max_amount_in: u256
) -> u256 {
require(self._pools.contains_key(pool_id), "Pool not found");
require(amount_out > 0, "Amount out must be positive");
let mut pool = self._pools[pool_id];
// 确定输入输出资产
let (reserve_in, reserve_out, asset_in) = if asset_out == pool.asset_a {
(pool.reserve_b, pool.reserve_a, pool.asset_b)
} else if asset_out == pool.asset_b {
(pool.reserve_a, pool.reserve_b, pool.asset_a)
} else {
revert("Invalid asset");
};
require(amount_out < reserve_out, "Insufficient liquidity");
// 计算输入数量(包含手续费)
let numerator = safe_mul(safe_mul(reserve_in, amount_out), 10000);
let denominator = safe_mul(
safe_sub(reserve_out, amount_out),
(10000 - pool.fee_rate) as u256
);
let amount_in = safe_add(numerator / denominator, 1); // 向上取整
require(amount_in <= max_amount_in, "Slippage too high");
// 计算手续费
let fee = safe_mul(amount_in, pool.fee_rate as u256) / 10000;
// 更新储备量
if asset_out == pool.asset_a {
pool.reserve_b = safe_add(pool.reserve_b, amount_in);
pool.reserve_a = safe_sub(pool.reserve_a, amount_out);
pool.accumulated_fee_b = safe_add(pool.accumulated_fee_b, fee);
} else {
pool.reserve_a = safe_add(pool.reserve_a, amount_in);
pool.reserve_b = safe_sub(pool.reserve_b, amount_out);
pool.accumulated_fee_a = safe_add(pool.accumulated_fee_a, fee);
}
pool.k_last = safe_mul(pool.reserve_a, pool.reserve_b);
pool.last_updated = block.timestamp;
self._pools[pool_id] = pool;
// 生成交换ID
let swap_id = self._generate_swap_id(pool_id, msg.sender);
// 记录交换
let swap_record = SwapRecord {
swap_id: swap_id,
pool_id: pool_id,
swapper: msg.sender,
asset_in: asset_in,
amount_in: amount_in,
asset_out: asset_out,
amount_out: amount_out,
fee: fee,
timestamp: block.timestamp
};
self._swaps[swap_id] = swap_record;
emit Swap {
swap_id: swap_id,
pool_id: pool_id,
swapper: msg.sender,
asset_in: asset_in,
amount_in: amount_in,
asset_out: asset_out,
amount_out: amount_out,
fee: fee,
timestamp: block.timestamp
};
return amount_in;
}
/// 获取输出数量(不执行交换)
///
/// # 参数
/// - `pool_id`: 池ID
/// - `asset_in`: 输入资产
/// - `amount_in`: 输入数量
///
/// # 返回
/// - `u256`: 输出数量
pub fn get_amount_out(
pool_id: Hash,
asset_in: Address,
amount_in: u256
) -> u256 {
require(self._pools.contains_key(pool_id), "Pool not found");
let pool = self._pools[pool_id];
let (reserve_in, reserve_out) = if asset_in == pool.asset_a {
(pool.reserve_a, pool.reserve_b)
} else {
(pool.reserve_b, pool.reserve_a)
};
let amount_in_with_fee = safe_mul(amount_in, (10000 - pool.fee_rate) as u256);
let numerator = safe_mul(amount_in_with_fee, reserve_out);
let denominator = safe_add(safe_mul(reserve_in, 10000), amount_in_with_fee);
return numerator / denominator;
}
// ========== 奖励管理 ==========
/// 计算待领取奖励
///
/// # 参数
/// - `pool_id`: 池ID
/// - `provider`: 提供者地址
///
/// # 返回
/// - `(u256, u256)`: (奖励A, 奖励B)
pub fn calculate_rewards(
pool_id: Hash,
provider: Address
) -> (u256, u256) {
require(self._pools.contains_key(pool_id), "Pool not found");
require(self._providers.contains_key(provider), "No liquidity provided");
require(
self._providers[provider].contains_key(pool_id),
"No liquidity in this pool"
);
let pool = self._pools[pool_id];
let lp_info = self._providers[provider][pool_id];
// 计算份额
let share = safe_mul(lp_info.lp_tokens, 1e18) / pool.total_lp_supply;
// 计算奖励
let reward_a = safe_sub(
safe_mul(pool.accumulated_fee_a, share) / 1e18,
lp_info.claimed_reward_a
);
let reward_b = safe_sub(
safe_mul(pool.accumulated_fee_b, share) / 1e18,
lp_info.claimed_reward_b
);
return (reward_a, reward_b);
}
/// 领取奖励
///
/// # 参数
/// - `pool_id`: 池ID
///
/// # 返回
/// - `(u256, u256)`: (奖励A, 奖励B)
pub fn claim_rewards(pool_id: Hash) -> (u256, u256) {
let (reward_a, reward_b) = self.calculate_rewards(pool_id, msg.sender);
require(reward_a > 0 || reward_b > 0, "No rewards to claim");
// 更新已领取奖励
let mut lp_info = self._providers[msg.sender][pool_id];
lp_info.claimed_reward_a = safe_add(lp_info.claimed_reward_a, reward_a);
lp_info.claimed_reward_b = safe_add(lp_info.claimed_reward_b, reward_b);
self._providers[msg.sender][pool_id] = lp_info;
// 实际需要转移奖励
emit ClaimRewards {
pool_id: pool_id,
provider: msg.sender,
reward_a: reward_a,
reward_b: reward_b,
timestamp: block.timestamp
};
return (reward_a, reward_b);
}
// ========== 查询函数 ==========
/// 获取流动性提供者信息
///
/// # 参数
/// - `provider`: 提供者地址
/// - `pool_id`: 池ID
///
/// # 返回
/// - `Option<LiquidityProvider>`: 提供者信息
pub fn get_provider_info(
provider: Address,
pool_id: Hash
) -> Option<LiquidityProvider> {
return self._providers.get(provider)
.and_then(|m| m.get(pool_id));
}
/// 获取交换记录
///
/// # 参数
/// - `swap_id`: 交换ID
///
/// # 返回
/// - `SwapRecord`: 交换记录
pub fn get_swap(swap_id: Hash) -> SwapRecord {
require(self._swaps.contains_key(swap_id), "Swap not found");
return self._swaps[swap_id];
}
// ========== 内部函数 ==========
/// 生成池ID
fn _generate_pool_id(asset_a: Address, asset_b: Address) -> Hash {
let mut data = Bytes::new();
data.extend(asset_a.as_bytes());
data.extend(asset_b.as_bytes());
return sha3_384_hash(data);
}
/// 生成交换ID
fn _generate_swap_id(pool_id: Hash, swapper: Address) -> Hash {
let mut data = Bytes::new();
data.extend(pool_id.as_bytes());
data.extend(swapper.as_bytes());
data.extend(block.timestamp.to_bytes());
data.extend(tx.hash.as_bytes());
return sha3_384_hash(data);
}
}