Codes in lesson7
AMM 原理 - 代币 在 AMM(自动做市商)池中,token_0、token_1 和 LP 这三种代币构成了流动性池的核心经济模型:
graph TD
A[代币类型] --> B[交易代币]
A --> C[流动性代币]
B --> D[token_0]
B --> E[token_1]
C --> F[LP代币] token_0、token_1(交易代币) 核心作用 - 交易媒介:用户用来交换的代币(如 SOL/USDC 对中的 SOL 和 USDC) - 流动性基础:组成交易对的基础资产 - 价值储存:代表实际资产价值
关键特性对比 1 #[account(constraint = token_0_mint.key() < token_1_mint.key())]
强制要求:token_0 的地址必须小于 token_1 的地址 比较方式:按字节顺序比较公钥(Pubkey) 结果:确保每个代币对只有唯一的排序方式 LP 代币(流动性提供者代币) 核心作用 - 流动性证明:代表用户在池中的份额 - 权益凭证:持有者有权获得交易手续费分成 - 可交易资产:可在二级市场交易
关键特性 特性 说明 发行机制 铸造给流动性提供者 价值基础 基于池中资产价值 小数位 固定9位小数(如 1.000000000) 控制权 由程序PDA控制铸造/销毁
经济模型 1 LP 代币价值 = (池中 token_0 总值 + 池中 token_1 总值) / LP 总供应量
AMM 原理 - 角色 核心操作账户 账户 类型 作用 关键特性 创建者(creator
) 签名账户 支付费用并提供初始流动性 必须签名,支付所有费用 权限账户(authority
) PDA 池的管理员,执行代币操作 程序控制,安全签名 AMM 配置(amm_config
) 状态账户 存储全局参数(如费率) 只读,定义池规则
代币相关账户 账户 类型 作用 关键特性 token_0 铸币(token_0_mint
) 铸币账户 定义 token_0 的属性 地址必须 < token_1 token_1 铸币(token_1_mint
) 铸币账户 定义 token_1 的属性 地址必须 > token_0 LP 铸币(lp_mint
) PDA 铸币 创建 LP 代币 固定9位小数,代表流动性份额 创建者 token_0 账户 代币账户 创建者的 token_0 余额 提供初始流动性 创建者 token_1 账户 代币账户 创建者的 token_1 余额 提供初始流动性 创建者 LP 账户 关联代币账户 接收 LP 代币 自动创建
池资产账户 账户 类型 作用 关键特性 token_0 金库(token_0_vault
) PDA 存储池中的 token_0 由权限账户控制 token_1 金库(token_1_vault
) PDA 存储池中的 token_1 由权限账户控制 费用接收账户 固定地址 接收创建池费用 预定义地址
状态记录账户 账户 类型 作用 关键特性 池状态(pool_state
) 状态账户 记录池的核心数据 存储余额/费率/状态等 预言机状态(observation_state
) PDA 记录价格历史 支持时间加权平均价
程序依赖 程序 作用 代币程序 处理标准 SPL 代币 Token2022 程序 处理扩展代币 关联代币程序 创建关联账户 系统程序 创建账户和转账 SOL
AMM 原理 - 协议费和基金费 协议费用(Protocol Fee) 协议费用 是 交易手续费中分配给协议开发团队或协议国库的部分。这部分费用用于支持协议的持续开发、维护和运营
用途 协议开发:支付开发团队工资,支持新功能研发 - 安全审计:资助智能合约安全审计 - 漏洞赏金:激励白帽黑客发现并报告漏洞 - 基础设施:维护服务器、节点等基础设施 - 法律合规:处理法律和合规事务 经济模型特点 通常为交易额的 0.01%-0.05% 从每笔交易的手续费中抽取 累积在池中,由协议定期收取 通常以交易对中的基础代币(如稳定币)形式存在 基金费用(Fund Fee) 基金费用是交易手续费中分配给生态系统发展基金的部分。这部分费用用于支持协议的长期发展和生态建设
用途 流动性激励:奖励流动性提供者(额外激励) - 社区建设:资助社区活动、教育项目 - 合作伙伴关系:与其他协议合作的市场活动 - 代币回购与销毁:维护代币经济模型 - 战略投资:投资生态内优质项目 经济模型特点 通常为交易额的 0.01%-0.03% 与协议费用分开管理 可能通过 DAO 治理决定用途 通常以协议原生代币或交易对代币形式收取 程序功能概述 这是一个基于 Solana 的恒定乘积自动做市商 (AMM) 程序,属于 Raydium 生态系统的一部分。程序实现了以下核心功能:
graph TD;
A[AMM 核心功能] --> B[池管理]
A --> C[流动性操作]
A --> D[代币交换]
A --> E[费用机制]
B --> B1[创建AMM配置]
B --> B2[更新AMM配置]
B --> B3[创建流动性池]
C --> C1[添加流动性]
C --> C2[移除流动性]
D --> D1[基础输入量交换]
D --> D2[基础输出量交换]
E --> E1[协议费用收取]
E --> E2[基金费用收取]
E --> E3[创建池费用] 角色 Admin create_amm_config
:创建 AMM 配置update_amm_config
:更新 AMM 配置update_pool_status
:更新流动池的状态collect_protocol_fee
:收取流动池中累积的协议费collecr_fund_fee
:收取流动池中累积的基金费User initialize
:创建流动池deposit
:存钱-增加流动性withdraw
:提现-减少流动性swap_base_input
:基于输入数量的代币交换swap_base_output
:基于输出数量的代币交换调用顺序 create_amm_config
管理员部署程序时调用,设置全局费率和规则 前端显示配置表单,提交后调用 initialize
用户创建新流动性池,设置初始流动性 前端提供代币选择和数量输入界面 deposit
用户增加流动性,获取 LP 代币 前端显示当前流动性池状态,计算并显示所需代币数量 用户进行交易 前端提供交易输入框,实时计算输出并显示滑点 withdraw
用户提取流动性 前端显示用户持有的 LP 代币,计算可提取的代币数量 collect_protocol_fee
& collect_fund_fee
管理员提取费用 前端提供管理界面,显示累积费用并允许提取 update_amm_config
& update_pool_status
AMM 曲线计算模块 核心功能详解 基础工具函数 map_zero_to_none
1 2 3 4 5 6 7 pub fn map_zero_to_none (x: u128 ) -> Option <u128 > { if x == 0 { None } else { Some (x) } }
作用:将零值转换为 None
用途:防止除零错误
示例:
输入 0 → None 输入 100 → Some(100) 交易方向枚举 TradeDirection
1 2 3 4 5 #[derive(Clone, Copy, Debug, PartialEq)] pub enum TradeDirection { ZeroForOne, OneForZero, }
关键方法:
1 2 3 4 5 6 7 8 impl TradeDirection { pub fn opposite (&self ) -> TradeDirection { match self { TradeDirection::ZeroForOne => TradeDirection::OneForZero, TradeDirection::OneForZero => TradeDirection::ZeroForOne, } } }
作用:获取相反交易方向
示例:ZeroForOne.opposite() = OneForZero
取整方向枚举 RoundDirection
1 2 3 4 5 6 #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum RoundDirection { Floor, Ceiling, }
用途:控制流动性计算时的取整方式
场景:
Floor:移除流动性时保护池 Ceiling:添加流动性时保护用户 计算结果结构 TradingTokenResult
1 2 3 4 5 #[derive(Debug, PartialEq)] pub struct TradingTokenResult { pub token_0_amount: u128 , pub token_1_amount: u128 , }
作用:存储流动性转换结果
场景:添加/移除流动性时计算代币数量
SwapResult
1 2 3 4 5 6 7 8 9 10 #[derive(Debug, PartialEq)] pub struct SwapResult { pub new_swap_source_amount: u128 , pub new_swap_destination_amount: u128 , pub source_amount_swapped: u128 , pub destination_amount_swapped: u128 , pub trade_fee: u128 , pub protocol_fee: u128 , pub fund_fee: u128 , }
字段说明:
new_swap_source_amount
:交换后源代币新余额new_swap_destination_amount
:交换后目标代币新余额source_amount_swapped
:实际交换的源代币数量destination_amount_swapped
:实际交换的目标代币数量trade_fee
:交易手续费protocol_fee
:协议费用fund_fee
:基金费用核心计算逻辑 CurveCalculator
结构体 1 2 #[derive(Clone, Debug, Default, PartialEq)] pub struct CurveCalculator {}
关键方法:
供应量验证 validate_supply
1 2 3 4 5 6 7 8 9 pub fn validate_supply (token_0_amount: u64 , token_1_amount: u64 ) -> Result <()> { if token_0_amount == 0 { return Err (ErrorCode::EmptySupply.into ()); } if token_1_amount == 0 { return Err (ErrorCode::EmptySupply.into ()); } Ok (()) }
作用:确保池中两种代币都有余额
错误:EmptySupply
如果任一余额为零
固定输入量交换 swap_base_input
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 pub fn swap_base_input ( source_amount: u128 , swap_source_amount: u128 , swap_destination_amount: u128 , trade_fee_rate: u64 , protocol_fee_rate: u64 , fund_fee_rate: u64 , ) -> Option <SwapResult> { let trade_fee = Fees::trading_fee (source_amount, trade_fee_rate)?; let protocol_fee = Fees::protocol_fee (trade_fee, protocol_fee_rate)?; let fund_fee = Fees::fund_fee (trade_fee, fund_fee_rate)?; let source_amount_less_fees = source_amount.checked_sub (trade_fee)?; let destination_amount_swapped = ConstantProductCurve::swap_base_input_without_fees ( source_amount_less_fees, swap_source_amount, swap_destination_amount, ); Some (SwapResult { new_swap_source_amount: swap_source_amount.checked_add (source_amount)?, new_swap_destination_amount: swap_destination_amount .checked_sub (destination_amount_swapped)?, source_amount_swapped: source_amount, destination_amount_swapped, trade_fee, protocol_fee, fund_fee, }) }
固定输出量交换 swap_base_output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 pub fn swap_base_output ( destination_amount: u128 , swap_source_amount: u128 , swap_destination_amount: u128 , trade_fee_rate: u64 , protocol_fee_rate: u64 , fund_fee_rate: u64 , ) -> Option <SwapResult> { let source_amount_swapped = ConstantProductCurve::swap_base_output_without_fees ( destination_amount, swap_source_amount, swap_destination_amount, ); let source_amount = Fees::calculate_pre_fee_amount (source_amount_swapped, trade_fee_rate)?; let trade_fee = Fees::trading_fee (source_amount, trade_fee_rate)?; let protocol_fee = Fees::protocol_fee (trade_fee, protocol_fee_rate)?; let fund_fee = Fees::fund_fee (trade_fee, fund_fee_rate)?; Some (SwapResult { new_swap_source_amount: swap_source_amount.checked_add (source_amount)?, new_swap_destination_amount: swap_destination_amount .checked_sub (destination_amount)?, source_amount_swapped: source_amount, destination_amount_swapped: destination_amount, trade_fee, protocol_fee, fund_fee, }) }
LP 代币转换 lp_tokens_to_trading_tokens
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 pub fn lp_tokens_to_trading_tokens ( lp_token_amount: u128 , lp_token_supply: u128 , swap_token_0_amount: u128 , swap_token_1_amount: u128 , round_direction: RoundDirection, ) -> Option <TradingTokenResult> { ConstantProductCurve::lp_tokens_to_trading_tokens ( lp_token_amount, lp_token_supply, swap_token_0_amount, swap_token_1_amount, round_direction, ) }
公式:token0_amount = (lp_token_amount / lp_token_supply) * swap_token_0_amount
token1_amount = (lp_token_amount / lp_token_supply) * swap_token_1_amount
取整方向:
Floor:移除流动性时使用,保护池 Ceiling:添加流动性时使用,保护用户 测试工具模块 核心测试函数:
标准化价值计算 normalized_value
1 2 3 4 5 6 7 8 9 10 pub fn normalized_value ( swap_token_a_amount: u128 , swap_token_b_amount: u128 , ) -> Option <PreciseNumber> { let swap_token_a_amount = PreciseNumber::new (swap_token_a_amount)?; let swap_token_b_amount = PreciseNumber::new (swap_token_b_amount)?; swap_token_a_amount .checked_mul (&swap_token_b_amount)? .sqrt () }
作用:计算池的标准化价值(几何平均数)
公式:√(token_a * token_b)
交换价值验证 check_curve_value_from_swap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 pub fn check_curve_value_from_swap ( source_token_amount: u128 , swap_source_amount: u128 , swap_destination_amount: u128 , trade_direction: TradeDirection, ) { let destination_amount_swapped = ...; let previous_value = swap_token_0_amount * swap_token_1_amount; let new_value = new_swap_token_0_amount * new_swap_token_1_amount; assert! (new_value >= previous_value); }
目的:确保交换不会减少池的总价值
原理:常数乘积 k 应增加或保持不变
流动性操作价值验证 check_pool_value_from_deposit
1 2 3 4 5 6 pub fn check_pool_value_from_deposit (...) { } pub fn check_pool_value_from_withdraw (...) { }
数学原理:
存款后:new_token_a / new_pool_token_supply >= token_a / pool_token_supply
取款后:new_value / new_pool_token_supply >= value / pool_token_supply
属性测试生成器 total_and_intermediate
1 2 3 4 5 6 7 prop_compose! { pub fn total_and_intermediate (max_value: u64 )(total in 1 ..max_value) (intermediate in 1 ..total, total in Just (total)) -> (u64 , u64 ) { (total, intermediate) } }
作用:生成测试用的总量和中间值
用途:测试部分存款/取款场景
恒定乘积曲线实现 核心公式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 pub fn swap_base_input_without_fees ( source_amount: u128 , swap_source_amount: u128 , swap_destination_amount: u128 , ) -> u128 { let invariant = swap_source_amount.checked_mul (swap_destination_amount).unwrap (); let new_source_amount = swap_source_amount.checked_add (source_amount).unwrap (); swap_destination_amount.checked_sub (invariant / new_source_amount).unwrap () } pub fn swap_base_output_without_fees ( destination_amount: u128 , swap_source_amount: u128 , swap_destination_amount: u128 , ) -> u128 { let invariant = swap_source_amount.checked_mul (swap_destination_amount).unwrap (); let new_destination_amount = swap_destination_amount.checked_sub (destination_amount).unwrap (); (invariant / new_destination_amount).checked_sub (swap_source_amount).unwrap () } pub fn lp_tokens_to_trading_tokens ( lp_token_amount: u128 , lp_token_supply: u128 , swap_token_0_amount: u128 , swap_token_1_amount: u128 , round_direction: RoundDirection, ) -> Option <TradingTokenResult> { let token_0_amount = lp_token_amount .checked_mul (swap_token_0_amount)? .checked_div (lp_token_supply)?; let token_1_amount = lp_token_amount .checked_mul (swap_token_1_amount)? .checked_div (lp_token_supply)?; let (token_0_amount, token_1_amount) = match round_direction { RoundDirection::Floor => (token_0_amount, token_1_amount), RoundDirection::Ceiling => { let token_0_remainder = lp_token_amount .checked_mul (swap_token_0_amount)? .checked_rem (lp_token_supply)?; let token_1_remainder = lp_token_amount .checked_mul (swap_token_1_amount)? .checked_rem (lp_token_supply)?; ( token_0_amount + if token_0_remainder > 0 { 1 } else { 0 }, token_1_amount + if token_1_remainder > 0 { 1 } else { 0 }, ) } }; Some (TradingTokenResult { token_0_amount, token_1_amount, }) }
费用计算模块 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 mod Fees { pub fn trading_fee (amount: u128 , fee_rate: u64 ) -> Option <u128 > { amount .checked_mul (u128 ::from (fee_rate))? .checked_div (FEE_DENOMINATOR) } pub fn protocol_fee (trade_fee: u128 , protocol_fee_rate: u64 ) -> Option <u128 > { trade_fee .checked_mul (u128 ::from (protocol_fee_rate))? .checked_div (FEE_DENOMINATOR) } pub fn fund_fee (trade_fee: u128 , fund_fee_rate: u64 ) -> Option <u128 > { trade_fee .checked_mul (u128 ::from (fund_fee_rate))? .checked_div (FEE_DENOMINATOR) } pub fn calculate_pre_fee_amount (post_fee_amount: u128 , fee_rate: u64 ) -> Option <u128 > { let numerator = post_fee_amount.checked_mul (FEE_DENOMINATOR)?; let denominator = FEE_DENOMINATOR.checked_sub (u128 ::from (fee_rate))?; numerator.checked_div (denominator) } }