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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| use super::swap_base_input::Swap;
pub fn swap_base_output( ctx: Context<Swap>, max_amount_in: u64, amount_out_received: u64, ) -> Result<()> { require_gt!(amount_out_received, 0); let block_timestamp = solana_program::clock::Clock::get()?.unix_timestamp as u64; let pool_state = &mut ctx.accounts.pool_state.load_mut()?;
if !pool_state.get_status_by_bit(PoolStatusBitIndex::Swap) || block_timestamp < pool_state.open_time { return err!(ErrorCode::NotApproved); }
let out_transfer_fee = get_transfer_inverse_fee(&output_token_mint, amount_out_received)?; let amount_out_with_transfer_fee = amount_out_received.checked_add(out_transfer_fee).unwrap();
let SwapParams { trade_direction, total_input_token_amount, total_output_token_amount, token_0_price_x64, token_1_price_x64, is_creator_fee_on_input, } = pool_state.get_swap_params()?;
let constant_before = u128::from(total_input_token_amount) .checked_mul(u128::from(total_output_token_amount)) .unwrap();
let creator_fee_rate = pool_state.adjust_creator_fee_rate(amm_config.creator_fee_rate); let result = CurveCalculator::swap_base_output( u128::from(amount_out_with_transfer_fee), u128::from(total_input_token_amount), u128::from(total_output_token_amount), amm_config.trade_fee_rate, creator_fee_rate, amm_config.protocol_fee_rate, amm_config.fund_fee_rate, is_creator_fee_on_input, ).ok_or(ErrorCode::ZeroTradingTokens)?;
let constant_after = u128::from(result.new_input_vault_amount) .checked_mul(u128::from(result.new_output_vault_amount)) .unwrap(); require_gte!(constant_after, constant_before);
let input_amount = u64::try_from(result.input_amount).unwrap(); let input_transfer_fee = get_transfer_inverse_fee(&input_token_mint, input_amount)?; let input_transfer_amount = input_amount.checked_add(input_transfer_fee).unwrap(); require_gte!(max_amount_in, input_transfer_amount, ErrorCode::ExceededSlippage);
pool_state.update_fees( u64::try_from(result.protocol_fee).unwrap(), u64::try_from(result.fund_fee).unwrap(), u64::try_from(result.creator_fee).unwrap(), trade_direction, )?;
transfer_from_user_to_pool_vault( ctx.accounts.payer.to_account_info(), ctx.accounts.input_token_account.to_account_info(), ctx.accounts.input_vault.to_account_info(), ctx.accounts.input_token_mint.to_account_info(), ctx.accounts.input_token_program.to_account_info(), input_transfer_amount, ctx.accounts.input_token_mint.decimals, )?;
transfer_from_pool_vault_to_user( ctx.accounts.authority.to_account_info(), ctx.accounts.output_vault.to_account_info(), ctx.accounts.output_token_account.to_account_info(), ctx.accounts.output_token_mint.to_account_info(), ctx.accounts.output_token_program.to_account_info(), amount_out_with_transfer_fee, ctx.accounts.output_token_mint.decimals, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], )?;
ctx.accounts.observation_state.load_mut()?.update( oracle::block_timestamp(), token_0_price_x64, token_1_price_x64, ); pool_state.recent_epoch = Clock::get()?.epoch;
Ok(()) }
|