1use {
2 crate::{
3 error::ErrorCode,
4 state::{
5 ExpressRelayMetadata,
6 FEE_BPS_TO_PPM,
7 FEE_SPLIT_PRECISION_PPM,
8 },
9 token::check_receiver_and_transfer_token_if_needed,
10 FeeToken,
11 Swap,
12 SwapArgs,
13 SwapV2Args,
14 FEE_SPLIT_PRECISION,
15 },
16 anchor_lang::{
17 accounts::interface_account::InterfaceAccount,
18 error::ErrorCode as AnchorErrorCode,
19 prelude::*,
20 },
21 anchor_spl::token_interface::TokenAccount,
22};
23
24pub struct PostFeeSwapArgs {
25 pub amount_searcher_after_fees: u64,
26 pub amount_user_after_fees: u64,
27}
28
29
30impl Swap<'_> {
31 pub fn convert_to_v2(&self, args: &SwapArgs) -> SwapV2Args {
32 args.convert_to_v2(self.express_relay_metadata.swap_platform_fee_bps)
33 }
34}
35
36impl<'info> Swap<'info> {
37 fn check_mint_user(&self, fee_token: FeeToken) -> Result<()> {
38 let correct_mint_fee_key = if fee_token == FeeToken::Searcher {
39 self.mint_searcher.key()
40 } else {
41 self.mint_user.key()
42 };
43
44 (self.mint_fee.key() == correct_mint_fee_key)
46 .then_some(())
47 .ok_or(AnchorErrorCode::ConstraintRaw.into())
48 }
49
50 fn check_token_program_fee(&self, fee_token: FeeToken) -> Result<()> {
51 let correct_token_program_fee = if fee_token == FeeToken::Searcher {
52 self.token_program_searcher.key()
53 } else {
54 self.token_program_user.key()
55 };
56
57 (self.token_program_fee.key() == correct_token_program_fee)
59 .then_some(())
60 .ok_or(AnchorErrorCode::ConstraintRaw.into())
61 }
62
63 pub fn check_raw_constraints(&self, fee_token: FeeToken) -> Result<()> {
64 self.check_mint_user(fee_token)?;
65 self.check_token_program_fee(fee_token)?;
66
67 Ok(())
68 }
69
70 pub fn compute_swap_fees<'a>(
71 &'a self,
72 args: &SwapV2Args,
73 ) -> Result<(TransferSwapFeeArgs<'info, 'a>, PostFeeSwapArgs)> {
74 match args.fee_token {
75 FeeToken::Searcher => {
76 let SwapFeesWithRemainingAmount {
77 fees,
78 remaining_amount,
79 } = self.express_relay_metadata.compute_swap_fees(
80 args.referral_fee_ppm,
81 args.swap_platform_fee_ppm,
82 args.amount_searcher,
83 )?;
84 Ok((
85 TransferSwapFeeArgs {
86 fees,
87 from: &self.searcher_ta_mint_searcher,
88 authority: &self.searcher,
89 },
90 PostFeeSwapArgs {
91 amount_searcher_after_fees: remaining_amount,
92 amount_user_after_fees: args.amount_user,
93 },
94 ))
95 }
96 FeeToken::User => {
97 let SwapFeesWithRemainingAmount {
98 fees,
99 remaining_amount,
100 } = self.express_relay_metadata.compute_swap_fees(
101 args.referral_fee_ppm,
102 args.swap_platform_fee_ppm,
103 args.amount_user,
104 )?;
105 Ok((
106 TransferSwapFeeArgs {
107 fees,
108 from: &self.user_ata_mint_user,
109 authority: &self.user,
110 },
111 PostFeeSwapArgs {
112 amount_searcher_after_fees: args.amount_searcher,
113 amount_user_after_fees: remaining_amount,
114 },
115 ))
116 }
117 }
118 }
119
120 pub fn transfer_swap_fees_cpi<'a>(&self, args: &TransferSwapFeeArgs<'info, 'a>) -> Result<()> {
121 self.transfer_swap_fee_cpi(
122 args.fees.router_fee,
123 &self.router_fee_receiver_ta,
124 None,
125 args,
126 )?;
127 self.transfer_swap_fee_cpi(
128 args.fees.relayer_fee,
129 &self.relayer_fee_receiver_ata,
130 Some(&self.express_relay_metadata.fee_receiver_relayer),
131 args,
132 )?;
133 self.transfer_swap_fee_cpi(
134 args.fees.express_relay_fee,
135 &self.express_relay_fee_receiver_ata,
136 Some(self.express_relay_metadata.to_account_info().key),
137 args,
138 )?;
139 Ok(())
140 }
141
142 fn transfer_swap_fee_cpi<'a>(
143 &self,
144 fee: u64,
145 receiver_ta: &UncheckedAccount<'info>,
146 receiver: Option<&Pubkey>,
147 args: &TransferSwapFeeArgs<'info, 'a>,
148 ) -> Result<()> {
149 check_receiver_and_transfer_token_if_needed(
150 args.from,
151 receiver_ta,
152 receiver,
153 &self.token_program_fee,
154 args.authority,
155 &self.mint_fee,
156 fee,
157 )?;
158 Ok(())
159 }
160
161 pub fn check_enough_balances(&self, args: &SwapV2Args) -> Result<()> {
162 require_gte!(
163 self.searcher_ta_mint_searcher.amount,
164 args.amount_searcher,
165 ErrorCode::InsufficientSearcherFunds
166 );
167 require_gte!(
168 self.user_ata_mint_user.amount,
169 args.amount_user,
170 ErrorCode::InsufficientUserFunds
171 );
172 Ok(())
173 }
174}
175
176pub struct TransferSwapFeeArgs<'info, 'a> {
177 pub fees: SwapFees,
178 pub from: &'a InterfaceAccount<'info, TokenAccount>,
179 pub authority: &'a Signer<'info>,
180}
181
182pub struct SwapFeesWithRemainingAmount {
183 pub fees: SwapFees,
184 pub remaining_amount: u64,
185}
186
187pub struct SwapFees {
188 pub router_fee: u64,
189 pub relayer_fee: u64,
190 pub express_relay_fee: u64,
191}
192impl ExpressRelayMetadata {
193 pub fn check_relayer_signer(&self, relayer_signer: &Pubkey) -> Result<()> {
194 if !self.relayer_signer.eq(relayer_signer)
195 && !self.secondary_relayer_signer.eq(relayer_signer)
196 {
197 return Err(AnchorErrorCode::ConstraintHasOne.into());
199 }
200 Ok(())
201 }
202
203 pub fn compute_swap_fees_with_default_platform_fee(
204 &self,
205 referral_fee_ppm: u64,
206 amount: u64,
207 ) -> Result<SwapFeesWithRemainingAmount> {
208 let swap_platform_fees_ppm = self.swap_platform_fee_bps * FEE_BPS_TO_PPM;
209
210 self.compute_swap_fees(referral_fee_ppm, swap_platform_fees_ppm, amount)
211 }
212
213 pub fn compute_swap_fees(
214 &self,
215 referral_fee_ppm: u64,
216 swap_platform_fee_ppm: u64,
217 amount: u64,
218 ) -> Result<SwapFeesWithRemainingAmount> {
219 if referral_fee_ppm > FEE_SPLIT_PRECISION_PPM {
220 return Err(ErrorCode::InvalidReferralFee.into());
221 }
222 let router_fee = amount
223 .checked_mul(referral_fee_ppm)
224 .ok_or(ProgramError::ArithmeticOverflow)?
225 / FEE_SPLIT_PRECISION_PPM;
226 let platform_fee = amount
227 .checked_mul(swap_platform_fee_ppm)
228 .ok_or(ProgramError::ArithmeticOverflow)?
229 / FEE_SPLIT_PRECISION_PPM;
230 let relayer_fee = platform_fee
231 .checked_mul(self.split_relayer)
232 .ok_or(ProgramError::ArithmeticOverflow)?
233 / FEE_SPLIT_PRECISION;
234
235 let remaining_amount = amount
236 .checked_sub(router_fee)
237 .ok_or(ProgramError::ArithmeticOverflow)?
238 .checked_sub(platform_fee)
239 .ok_or(ProgramError::ArithmeticOverflow)?;
240
241 let express_relay_fee = platform_fee
242 .checked_sub(relayer_fee)
243 .ok_or(ProgramError::ArithmeticOverflow)?;
244
245 Ok(SwapFeesWithRemainingAmount {
246 fees: SwapFees {
247 router_fee,
248 relayer_fee,
249 express_relay_fee,
250 },
251 remaining_amount,
252 })
253 }
254}