raydium-amm-v3---swap```rustusecrate::error::ErrorCode;//引入错误码模块usecrate::libraries::{big_num::U128,fixed_point_64,full_math::MulDiv,l
```rust
use crate::error::ErrorCode; // 引入错误码模块
use crate::libraries::{
big_num::U128, fixed_point_64, full_math::MulDiv, liquidity_math, swap_math, tick_math,
}; // 引入所需的库
use crate::states::*; // 引入状态模块
use crate::util::*; // 引入工具模块
use anchor_lang::prelude::*; // 引入 Anchor 框架的预处理模块
use anchor_spl::token::Token; // 引入 SPL 代币模块
use anchor_spl::token_interface::TokenAccount; // 引入 SPL 代币账户接口
use std::cell::RefMut; // 引入可变引用模块
use std::collections::VecDeque; // 引入双端队列模块
#[cfg(feature = "enable-log")]
use std::convert::identity; // 引入 identity 转换函数
use std::ops::{Deref, Neg}; // 引入运算符模块
#[derive(Accounts)]
pub struct SwapSingle<'info> {
/// 执行交换操作的用户
pub payer: Signer<'info>,
/// 用于读取协议费用的工厂状态
#[account(address = pool_state.load()?.amm_config)]
pub amm_config: Box<Account<'info, AmmConfig>>,
/// 进行交换操作的池的程序账户
#[account(mut)]
pub pool_state: AccountLoader<'info, PoolState>,
/// 输入代币的用户代币账户
#[account(
mut,
token::token_program = token_program,
)]
pub input_token_account: Box<InterfaceAccount<'info, TokenAccount>>,
/// 输出代币的用户代币账户
#[account(
mut,
token::token_program = token_program,
)]
pub output_token_account: Box<InterfaceAccount<'info, TokenAccount>>,
/// 输入代币的金库代币账户
#[account(
mut,
token::token_program = token_program,
)]
pub input_vault: Box<InterfaceAccount<'info, TokenAccount>>,
/// 输出代币的金库代币账户
#[account(
mut,
token::token_program = token_program,
)]
pub output_vault: Box<InterfaceAccount<'info, TokenAccount>>,
/// 最近一次预言机观察的程序账户
#[account(mut, address = pool_state.load()?.observation_key)]
pub observation_state: AccountLoader<'info, ObservationState>,
/// 用于代币转移的 SPL 程序
pub token_program: Program<'info, Token>,
/// 当前或下一个初始化的 tick_array 账户
#[account(mut, constraint = tick_array.load()?.pool_id == pool_state.key())]
pub tick_array: AccountLoader<'info, TickArrayState>,
}
pub struct SwapAccounts<'b, 'info> {
/// 执行交换操作的用户
pub signer: Signer<'info>,
/// 输入代币的用户代币账户
pub input_token_account: Box<InterfaceAccount<'info, TokenAccount>>,
/// 输出代币的用户代币账户
pub output_token_account: Box<InterfaceAccount<'info, TokenAccount>>,
/// 输入代币的金库代币账户
pub input_vault: Box<InterfaceAccount<'info, TokenAccount>>,
/// 输出代币的金库代币账户
pub output_vault: Box<InterfaceAccount<'info, TokenAccount>>,
/// 用于代币转移的 SPL 程序
pub token_program: Program<'info, Token>,
/// 用于读取协议费用的工厂状态
pub amm_config: &'b Box<Account<'info, AmmConfig>>,
/// 进行交换操作的池的程序账户
pub pool_state: &'b mut AccountLoader<'info, PoolState>,
/// 当前或下一个初始化的 tick_array 账户
pub tick_array_state: &'b mut AccountLoader<'info, TickArrayState>,
/// 预言机观察的程序账户
pub observation_state: &'b mut AccountLoader<'info, ObservationState>,
}
// 交换的顶级状态,其结果在最后记录到存储中
#[derive(Debug)]
pub struct SwapState {
// 剩余待交换的输入/输出资产数量
pub amount_specified_remaining: u64,
// 已交换的输出/输入资产数量
pub amount_calculated: u64,
// 当前的平方根价格
pub sqrt_price_x64: u128,
// 当前价格对应的 tick
pub tick: i32,
// 输入代币的全局费用增长
pub fee_growth_global_x64: u128,
// 输入代币的全局费用
pub fee_amount: u64,
// 输入代币支付的协议费用
pub protocol_fee: u64,
// 输入代币支付的基金费用
pub fund_fee: u64,
// 当前范围内的流动性
pub liquidity: u128,
}
#[derive(Default)]
struct StepComputations {
// 步骤开始时的价格
sqrt_price_start_x64: u128,
// 当前 tick 交换到的下一个 tick
tick_next: i32,
// 下一个 tick 是否已初始化
initialized: bool,
// 下一个 tick 的平方根价格
sqrt_price_next_x64: u128,
// 本步骤交换的输入量
amount_in: u64,
// 本步骤交换的输出量
amount_out: u64,
// 本步骤支付的费用
fee_amount: u64,
}
pub fn swap_internal<'b, 'info>(
amm_config: &AmmConfig,
pool_state: &mut RefMut<PoolState>,
tick_array_states: &mut VecDeque<RefMut<TickArrayState>>,
observation_state: &mut RefMut<ObservationState>,
tickarray_bitmap_extension: &Option<TickArrayBitmapExtension>,
amount_specified: u64,
sqrt_price_limit_x64: u128,
zero_for_one: bool,
is_base_input: bool,
block_timestamp: u32,
) -> Result<(u64, u64)> {
// 确保指定交换金额不为0
require!(amount_specified != 0, ErrorCode::InvaildSwapAmountSpecified);
// 检查池状态是否允许交换操作
if !pool_state.get_status_by_bit(PoolStatusBitIndex::Swap) {
return err!(ErrorCode::NotApproved);
}
// 检查价格限制是否有效
require!(
if zero_for_one {
sqrt_price_limit_x64 < pool_state.sqrt_price_x64
&& sqrt_price_limit_x64 > tick_math::MIN_SQRT_PRICE_X64
} else {
sqrt_price_limit_x64 > pool_state.sqrt_price_x64
&& sqrt_price_limit_x64 < tick_math::MAX_SQRT_PRICE_X64
},
ErrorCode::SqrtPriceLimitOverflow
);
let liquidity_start = pool_state.liquidity;
let updated_reward_infos = pool_state.update_reward_infos(block_timestamp as u64)?;
let mut state = SwapState {
amount_specified_remaining: amount_specified,
amount_calculated: 0,
sqrt_price_x64: pool_state.sqrt_price_x64,
tick: pool_state.tick_current,
fee_growth_global_x64: if zero_for_one {
pool_state.fee_growth_global_0_x64
} else {
pool_state.fee_growth_global_1_x64
},
fee_amount: 0,
protocol_fee: 0,
fund_fee: 0,
liquidity: liquidity_start,
};
// 检查观察账户是否由池拥有
require_keys_eq!(observation_state.pool_id, pool_state.key());
let (mut is_match_pool_current_tick_array, first_vaild_tick_array_start_index) =
pool_state.get_first_initialized_tick_array(&tickarray_bitmap_extension, zero_for_one)?;
let mut current_vaild_tick_array_start_index = first_vaild_tick_array_start_index;
let mut tick_array_current = tick_array_states.pop_front().unwrap();
// 查找第一个活动的 tick_array 账户
for _ in 0..tick_array_states.len() {
if tick_array_current.start_tick_index == current_vaild_tick_array_start_index {
break;
}
tick_array_current = tick_array_states
.pop_front()
.ok_or(ErrorCode::NotEnoughTickArrayAccount)?;
}
// 检查 tick_array 账户是否由池拥有
require_keys_eq!(tick_array_current.pool_id, pool_state.key());
// 检查第一个 tick_array 账户是否正确
require_eq!(
tick_array_current.start_tick_index,
current_vaild_tick_array_start_index,
ErrorCode::InvalidFirstTickArrayAccount
);
// 继续交换,直到消耗完所有输入/输出或达到价格限制
while state.amount_specified_remaining != 0 && state.sqrt_price_x64 != sqrt_price_limit_x64 {
#[cfg(feature = "enable-log")]
msg!(
"while begin, is_base_input:{},fee_growth_global_x32:{}, state_sqrt_price_x64:{}, state_tick:{},state_liquidity:{},state.protocol_fee:{}, protocol_fee_rate
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!