///! # 流动性池 ///! ///! 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; /// 流动性提供者 (provider => pool_id => lp_info) let _providers: Map>; /// 交换记录 (swap_id => record) let _swaps: Map; /// 池索引 (asset_a => asset_b => pool_id) let _pool_index: Map>; /// 管理员地址 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`: 池ID pub fn find_pool(asset_a: Address, asset_b: Address) -> Option { 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`: 提供者信息 pub fn get_provider_info( provider: Address, pool_id: Hash ) -> Option { 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); } }