raydium-amm-v3---swap

raydium-amm-v3---swap```rustusecrate::error::ErrorCode;//引入错误码模块usecrate::libraries::{big_num::U128,fixed_point_64,full_math::MulDiv,l

raydium-amm-v3---swap


```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
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
blockchain002
blockchain002
江湖只有他的大名,没有他的介绍。