1use crate::constraints::{SwapConstraints, SWAP_CONSTRAINTS};
4use crate::{
5 curve::{
6 base::SwapCurve,
7 calculator::{RoundDirection, TradeDirection},
8 fees::Fees,
9 },
10 error::SwapError,
11 instruction::{
12 DepositAllTokenTypes, DepositSingleTokenTypeExactAmountIn, Initialize, Swap,
13 SwapInstruction, WithdrawAllTokenTypes, WithdrawSingleTokenTypeExactAmountOut,
14 },
15 state::{SwapState, SwapV1, SwapVersion},
16};
17use num_traits::FromPrimitive;
18use gemachain_program::{
19 account_info::{next_account_info, AccountInfo},
20 decode_error::DecodeError,
21 entrypoint::ProgramResult,
22 msg,
23 program::invoke_signed,
24 program_error::{PrintProgramError, ProgramError},
25 program_option::COption,
26 program_pack::Pack,
27 pubkey::Pubkey,
28};
29use std::convert::TryInto;
30
31pub struct Processor {}
33impl Processor {
34 pub fn unpack_token_account(
36 account_info: &AccountInfo,
37 token_program_id: &Pubkey,
38 ) -> Result<gpl_token::state::Account, SwapError> {
39 if account_info.owner != token_program_id {
40 Err(SwapError::IncorrectTokenProgramId)
41 } else {
42 gpl_token::state::Account::unpack(&account_info.data.borrow())
43 .map_err(|_| SwapError::ExpectedAccount)
44 }
45 }
46
47 pub fn unpack_mint(
49 account_info: &AccountInfo,
50 token_program_id: &Pubkey,
51 ) -> Result<gpl_token::state::Mint, SwapError> {
52 if account_info.owner != token_program_id {
53 Err(SwapError::IncorrectTokenProgramId)
54 } else {
55 gpl_token::state::Mint::unpack(&account_info.data.borrow())
56 .map_err(|_| SwapError::ExpectedMint)
57 }
58 }
59
60 pub fn authority_id(
62 program_id: &Pubkey,
63 my_info: &Pubkey,
64 bump_seed: u8,
65 ) -> Result<Pubkey, SwapError> {
66 Pubkey::create_program_address(&[&my_info.to_bytes()[..32], &[bump_seed]], program_id)
67 .or(Err(SwapError::InvalidProgramAddress))
68 }
69
70 pub fn token_burn<'a>(
72 swap: &Pubkey,
73 token_program: AccountInfo<'a>,
74 burn_account: AccountInfo<'a>,
75 mint: AccountInfo<'a>,
76 authority: AccountInfo<'a>,
77 bump_seed: u8,
78 amount: u64,
79 ) -> Result<(), ProgramError> {
80 let swap_bytes = swap.to_bytes();
81 let authority_signature_seeds = [&swap_bytes[..32], &[bump_seed]];
82 let signers = &[&authority_signature_seeds[..]];
83
84 let ix = gpl_token::instruction::burn(
85 token_program.key,
86 burn_account.key,
87 mint.key,
88 authority.key,
89 &[],
90 amount,
91 )?;
92
93 invoke_signed(
94 &ix,
95 &[burn_account, mint, authority, token_program],
96 signers,
97 )
98 }
99
100 pub fn token_mint_to<'a>(
102 swap: &Pubkey,
103 token_program: AccountInfo<'a>,
104 mint: AccountInfo<'a>,
105 destination: AccountInfo<'a>,
106 authority: AccountInfo<'a>,
107 bump_seed: u8,
108 amount: u64,
109 ) -> Result<(), ProgramError> {
110 let swap_bytes = swap.to_bytes();
111 let authority_signature_seeds = [&swap_bytes[..32], &[bump_seed]];
112 let signers = &[&authority_signature_seeds[..]];
113 let ix = gpl_token::instruction::mint_to(
114 token_program.key,
115 mint.key,
116 destination.key,
117 authority.key,
118 &[],
119 amount,
120 )?;
121
122 invoke_signed(&ix, &[mint, destination, authority, token_program], signers)
123 }
124
125 pub fn token_transfer<'a>(
127 swap: &Pubkey,
128 token_program: AccountInfo<'a>,
129 source: AccountInfo<'a>,
130 destination: AccountInfo<'a>,
131 authority: AccountInfo<'a>,
132 bump_seed: u8,
133 amount: u64,
134 ) -> Result<(), ProgramError> {
135 let swap_bytes = swap.to_bytes();
136 let authority_signature_seeds = [&swap_bytes[..32], &[bump_seed]];
137 let signers = &[&authority_signature_seeds[..]];
138 let ix = gpl_token::instruction::transfer(
139 token_program.key,
140 source.key,
141 destination.key,
142 authority.key,
143 &[],
144 amount,
145 )?;
146 invoke_signed(
147 &ix,
148 &[source, destination, authority, token_program],
149 signers,
150 )
151 }
152
153 #[allow(clippy::too_many_arguments)]
154 fn check_accounts(
155 token_swap: &dyn SwapState,
156 program_id: &Pubkey,
157 swap_account_info: &AccountInfo,
158 authority_info: &AccountInfo,
159 token_a_info: &AccountInfo,
160 token_b_info: &AccountInfo,
161 pool_mint_info: &AccountInfo,
162 token_program_info: &AccountInfo,
163 user_token_a_info: Option<&AccountInfo>,
164 user_token_b_info: Option<&AccountInfo>,
165 pool_fee_account_info: Option<&AccountInfo>,
166 ) -> ProgramResult {
167 if swap_account_info.owner != program_id {
168 return Err(ProgramError::IncorrectProgramId);
169 }
170 if *authority_info.key
171 != Self::authority_id(program_id, swap_account_info.key, token_swap.bump_seed())?
172 {
173 return Err(SwapError::InvalidProgramAddress.into());
174 }
175 if *token_a_info.key != *token_swap.token_a_account() {
176 return Err(SwapError::IncorrectSwapAccount.into());
177 }
178 if *token_b_info.key != *token_swap.token_b_account() {
179 return Err(SwapError::IncorrectSwapAccount.into());
180 }
181 if *pool_mint_info.key != *token_swap.pool_mint() {
182 return Err(SwapError::IncorrectPoolMint.into());
183 }
184 if *token_program_info.key != *token_swap.token_program_id() {
185 return Err(SwapError::IncorrectTokenProgramId.into());
186 }
187 if let Some(user_token_a_info) = user_token_a_info {
188 if token_a_info.key == user_token_a_info.key {
189 return Err(SwapError::InvalidInput.into());
190 }
191 }
192 if let Some(user_token_b_info) = user_token_b_info {
193 if token_b_info.key == user_token_b_info.key {
194 return Err(SwapError::InvalidInput.into());
195 }
196 }
197 if let Some(pool_fee_account_info) = pool_fee_account_info {
198 if *pool_fee_account_info.key != *token_swap.pool_fee_account() {
199 return Err(SwapError::IncorrectFeeAccount.into());
200 }
201 }
202 Ok(())
203 }
204
205 pub fn process_initialize(
207 program_id: &Pubkey,
208 fees: Fees,
209 swap_curve: SwapCurve,
210 accounts: &[AccountInfo],
211 swap_constraints: &Option<SwapConstraints>,
212 ) -> ProgramResult {
213 let account_info_iter = &mut accounts.iter();
214 let swap_info = next_account_info(account_info_iter)?;
215 let authority_info = next_account_info(account_info_iter)?;
216 let token_a_info = next_account_info(account_info_iter)?;
217 let token_b_info = next_account_info(account_info_iter)?;
218 let pool_mint_info = next_account_info(account_info_iter)?;
219 let fee_account_info = next_account_info(account_info_iter)?;
220 let destination_info = next_account_info(account_info_iter)?;
221 let token_program_info = next_account_info(account_info_iter)?;
222
223 let token_program_id = *token_program_info.key;
224 if SwapVersion::is_initialized(&swap_info.data.borrow()) {
225 return Err(SwapError::AlreadyInUse.into());
226 }
227
228 let (swap_authority, bump_seed) =
229 Pubkey::find_program_address(&[&swap_info.key.to_bytes()], program_id);
230 if *authority_info.key != swap_authority {
231 return Err(SwapError::InvalidProgramAddress.into());
232 }
233 let token_a = Self::unpack_token_account(token_a_info, &token_program_id)?;
234 let token_b = Self::unpack_token_account(token_b_info, &token_program_id)?;
235 let fee_account = Self::unpack_token_account(fee_account_info, &token_program_id)?;
236 let destination = Self::unpack_token_account(destination_info, &token_program_id)?;
237 let pool_mint = Self::unpack_mint(pool_mint_info, &token_program_id)?;
238 if *authority_info.key != token_a.owner {
239 return Err(SwapError::InvalidOwner.into());
240 }
241 if *authority_info.key != token_b.owner {
242 return Err(SwapError::InvalidOwner.into());
243 }
244 if *authority_info.key == destination.owner {
245 return Err(SwapError::InvalidOutputOwner.into());
246 }
247 if *authority_info.key == fee_account.owner {
248 return Err(SwapError::InvalidOutputOwner.into());
249 }
250 if COption::Some(*authority_info.key) != pool_mint.mint_authority {
251 return Err(SwapError::InvalidOwner.into());
252 }
253
254 if token_a.mint == token_b.mint {
255 return Err(SwapError::RepeatedMint.into());
256 }
257 swap_curve
258 .calculator
259 .validate_supply(token_a.amount, token_b.amount)?;
260 if token_a.delegate.is_some() {
261 return Err(SwapError::InvalidDelegate.into());
262 }
263 if token_b.delegate.is_some() {
264 return Err(SwapError::InvalidDelegate.into());
265 }
266 if token_a.close_authority.is_some() {
267 return Err(SwapError::InvalidCloseAuthority.into());
268 }
269 if token_b.close_authority.is_some() {
270 return Err(SwapError::InvalidCloseAuthority.into());
271 }
272
273 if pool_mint.supply != 0 {
274 return Err(SwapError::InvalidSupply.into());
275 }
276 if pool_mint.freeze_authority.is_some() {
277 return Err(SwapError::InvalidFreezeAuthority.into());
278 }
279 if *pool_mint_info.key != fee_account.mint {
280 return Err(SwapError::IncorrectPoolMint.into());
281 }
282
283 if let Some(swap_constraints) = swap_constraints {
284 let owner_key = swap_constraints
285 .owner_key
286 .parse::<Pubkey>()
287 .map_err(|_| SwapError::InvalidOwner)?;
288 if fee_account.owner != owner_key {
289 return Err(SwapError::InvalidOwner.into());
290 }
291 swap_constraints.validate_curve(&swap_curve)?;
292 swap_constraints.validate_fees(&fees)?;
293 }
294 fees.validate()?;
295 swap_curve.calculator.validate()?;
296
297 let initial_amount = swap_curve.calculator.new_pool_supply();
298
299 Self::token_mint_to(
300 swap_info.key,
301 token_program_info.clone(),
302 pool_mint_info.clone(),
303 destination_info.clone(),
304 authority_info.clone(),
305 bump_seed,
306 to_u64(initial_amount)?,
307 )?;
308
309 let obj = SwapVersion::SwapV1(SwapV1 {
310 is_initialized: true,
311 bump_seed,
312 token_program_id,
313 token_a: *token_a_info.key,
314 token_b: *token_b_info.key,
315 pool_mint: *pool_mint_info.key,
316 token_a_mint: token_a.mint,
317 token_b_mint: token_b.mint,
318 pool_fee_account: *fee_account_info.key,
319 fees,
320 swap_curve,
321 });
322 SwapVersion::pack(obj, &mut swap_info.data.borrow_mut())?;
323 Ok(())
324 }
325
326 pub fn process_swap(
328 program_id: &Pubkey,
329 amount_in: u64,
330 minimum_amount_out: u64,
331 accounts: &[AccountInfo],
332 ) -> ProgramResult {
333 let account_info_iter = &mut accounts.iter();
334 let swap_info = next_account_info(account_info_iter)?;
335 let authority_info = next_account_info(account_info_iter)?;
336 let user_transfer_authority_info = next_account_info(account_info_iter)?;
337 let source_info = next_account_info(account_info_iter)?;
338 let swap_source_info = next_account_info(account_info_iter)?;
339 let swap_destination_info = next_account_info(account_info_iter)?;
340 let destination_info = next_account_info(account_info_iter)?;
341 let pool_mint_info = next_account_info(account_info_iter)?;
342 let pool_fee_account_info = next_account_info(account_info_iter)?;
343 let token_program_info = next_account_info(account_info_iter)?;
344
345 if swap_info.owner != program_id {
346 return Err(ProgramError::IncorrectProgramId);
347 }
348 let token_swap = SwapVersion::unpack(&swap_info.data.borrow())?;
349
350 if *authority_info.key
351 != Self::authority_id(program_id, swap_info.key, token_swap.bump_seed())?
352 {
353 return Err(SwapError::InvalidProgramAddress.into());
354 }
355 if !(*swap_source_info.key == *token_swap.token_a_account()
356 || *swap_source_info.key == *token_swap.token_b_account())
357 {
358 return Err(SwapError::IncorrectSwapAccount.into());
359 }
360 if !(*swap_destination_info.key == *token_swap.token_a_account()
361 || *swap_destination_info.key == *token_swap.token_b_account())
362 {
363 return Err(SwapError::IncorrectSwapAccount.into());
364 }
365 if *swap_source_info.key == *swap_destination_info.key {
366 return Err(SwapError::InvalidInput.into());
367 }
368 if swap_source_info.key == source_info.key {
369 return Err(SwapError::InvalidInput.into());
370 }
371 if swap_destination_info.key == destination_info.key {
372 return Err(SwapError::InvalidInput.into());
373 }
374 if *pool_mint_info.key != *token_swap.pool_mint() {
375 return Err(SwapError::IncorrectPoolMint.into());
376 }
377 if *pool_fee_account_info.key != *token_swap.pool_fee_account() {
378 return Err(SwapError::IncorrectFeeAccount.into());
379 }
380 if *token_program_info.key != *token_swap.token_program_id() {
381 return Err(SwapError::IncorrectTokenProgramId.into());
382 }
383
384 let source_account =
385 Self::unpack_token_account(swap_source_info, token_swap.token_program_id())?;
386 let dest_account =
387 Self::unpack_token_account(swap_destination_info, token_swap.token_program_id())?;
388 let pool_mint = Self::unpack_mint(pool_mint_info, token_swap.token_program_id())?;
389
390 let trade_direction = if *swap_source_info.key == *token_swap.token_a_account() {
391 TradeDirection::AtoB
392 } else {
393 TradeDirection::BtoA
394 };
395 let result = token_swap
396 .swap_curve()
397 .swap(
398 to_u128(amount_in)?,
399 to_u128(source_account.amount)?,
400 to_u128(dest_account.amount)?,
401 trade_direction,
402 token_swap.fees(),
403 )
404 .ok_or(SwapError::ZeroTradingTokens)?;
405 if result.destination_amount_swapped < to_u128(minimum_amount_out)? {
406 return Err(SwapError::ExceededSlippage.into());
407 }
408
409 let (swap_token_a_amount, swap_token_b_amount) = match trade_direction {
410 TradeDirection::AtoB => (
411 result.new_swap_source_amount,
412 result.new_swap_destination_amount,
413 ),
414 TradeDirection::BtoA => (
415 result.new_swap_destination_amount,
416 result.new_swap_source_amount,
417 ),
418 };
419
420 Self::token_transfer(
421 swap_info.key,
422 token_program_info.clone(),
423 source_info.clone(),
424 swap_source_info.clone(),
425 user_transfer_authority_info.clone(),
426 token_swap.bump_seed(),
427 to_u64(result.source_amount_swapped)?,
428 )?;
429
430 let mut pool_token_amount = token_swap
431 .swap_curve()
432 .withdraw_single_token_type_exact_out(
433 result.owner_fee,
434 swap_token_a_amount,
435 swap_token_b_amount,
436 to_u128(pool_mint.supply)?,
437 trade_direction,
438 token_swap.fees(),
439 )
440 .ok_or(SwapError::FeeCalculationFailure)?;
441
442 if pool_token_amount > 0 {
443 if let Ok(host_fee_account_info) = next_account_info(account_info_iter) {
445 let host_fee_account = Self::unpack_token_account(
446 host_fee_account_info,
447 token_swap.token_program_id(),
448 )?;
449 if *pool_mint_info.key != host_fee_account.mint {
450 return Err(SwapError::IncorrectPoolMint.into());
451 }
452 let host_fee = token_swap
453 .fees()
454 .host_fee(pool_token_amount)
455 .ok_or(SwapError::FeeCalculationFailure)?;
456 if host_fee > 0 {
457 pool_token_amount = pool_token_amount
458 .checked_sub(host_fee)
459 .ok_or(SwapError::FeeCalculationFailure)?;
460 Self::token_mint_to(
461 swap_info.key,
462 token_program_info.clone(),
463 pool_mint_info.clone(),
464 host_fee_account_info.clone(),
465 authority_info.clone(),
466 token_swap.bump_seed(),
467 to_u64(host_fee)?,
468 )?;
469 }
470 }
471 Self::token_mint_to(
472 swap_info.key,
473 token_program_info.clone(),
474 pool_mint_info.clone(),
475 pool_fee_account_info.clone(),
476 authority_info.clone(),
477 token_swap.bump_seed(),
478 to_u64(pool_token_amount)?,
479 )?;
480 }
481
482 Self::token_transfer(
483 swap_info.key,
484 token_program_info.clone(),
485 swap_destination_info.clone(),
486 destination_info.clone(),
487 authority_info.clone(),
488 token_swap.bump_seed(),
489 to_u64(result.destination_amount_swapped)?,
490 )?;
491
492 Ok(())
493 }
494
495 pub fn process_deposit_all_token_types(
497 program_id: &Pubkey,
498 pool_token_amount: u64,
499 maximum_token_a_amount: u64,
500 maximum_token_b_amount: u64,
501 accounts: &[AccountInfo],
502 ) -> ProgramResult {
503 let account_info_iter = &mut accounts.iter();
504 let swap_info = next_account_info(account_info_iter)?;
505 let authority_info = next_account_info(account_info_iter)?;
506 let user_transfer_authority_info = next_account_info(account_info_iter)?;
507 let source_a_info = next_account_info(account_info_iter)?;
508 let source_b_info = next_account_info(account_info_iter)?;
509 let token_a_info = next_account_info(account_info_iter)?;
510 let token_b_info = next_account_info(account_info_iter)?;
511 let pool_mint_info = next_account_info(account_info_iter)?;
512 let dest_info = next_account_info(account_info_iter)?;
513 let token_program_info = next_account_info(account_info_iter)?;
514
515 let token_swap = SwapVersion::unpack(&swap_info.data.borrow())?;
516 let calculator = &token_swap.swap_curve().calculator;
517 if !calculator.allows_deposits() {
518 return Err(SwapError::UnsupportedCurveOperation.into());
519 }
520 Self::check_accounts(
521 token_swap.as_ref(),
522 program_id,
523 swap_info,
524 authority_info,
525 token_a_info,
526 token_b_info,
527 pool_mint_info,
528 token_program_info,
529 Some(source_a_info),
530 Some(source_b_info),
531 None,
532 )?;
533
534 let token_a = Self::unpack_token_account(token_a_info, token_swap.token_program_id())?;
535 let token_b = Self::unpack_token_account(token_b_info, token_swap.token_program_id())?;
536 let pool_mint = Self::unpack_mint(pool_mint_info, token_swap.token_program_id())?;
537 let current_pool_mint_supply = to_u128(pool_mint.supply)?;
538 let (pool_token_amount, pool_mint_supply) = if current_pool_mint_supply > 0 {
539 (to_u128(pool_token_amount)?, current_pool_mint_supply)
540 } else {
541 (calculator.new_pool_supply(), calculator.new_pool_supply())
542 };
543
544 let results = calculator
545 .pool_tokens_to_trading_tokens(
546 pool_token_amount,
547 pool_mint_supply,
548 to_u128(token_a.amount)?,
549 to_u128(token_b.amount)?,
550 RoundDirection::Ceiling,
551 )
552 .ok_or(SwapError::ZeroTradingTokens)?;
553 let token_a_amount = to_u64(results.token_a_amount)?;
554 if token_a_amount > maximum_token_a_amount {
555 return Err(SwapError::ExceededSlippage.into());
556 }
557 if token_a_amount == 0 {
558 return Err(SwapError::ZeroTradingTokens.into());
559 }
560 let token_b_amount = to_u64(results.token_b_amount)?;
561 if token_b_amount > maximum_token_b_amount {
562 return Err(SwapError::ExceededSlippage.into());
563 }
564 if token_b_amount == 0 {
565 return Err(SwapError::ZeroTradingTokens.into());
566 }
567
568 let pool_token_amount = to_u64(pool_token_amount)?;
569
570 Self::token_transfer(
571 swap_info.key,
572 token_program_info.clone(),
573 source_a_info.clone(),
574 token_a_info.clone(),
575 user_transfer_authority_info.clone(),
576 token_swap.bump_seed(),
577 token_a_amount,
578 )?;
579 Self::token_transfer(
580 swap_info.key,
581 token_program_info.clone(),
582 source_b_info.clone(),
583 token_b_info.clone(),
584 user_transfer_authority_info.clone(),
585 token_swap.bump_seed(),
586 token_b_amount,
587 )?;
588 Self::token_mint_to(
589 swap_info.key,
590 token_program_info.clone(),
591 pool_mint_info.clone(),
592 dest_info.clone(),
593 authority_info.clone(),
594 token_swap.bump_seed(),
595 pool_token_amount,
596 )?;
597
598 Ok(())
599 }
600
601 pub fn process_withdraw_all_token_types(
603 program_id: &Pubkey,
604 pool_token_amount: u64,
605 minimum_token_a_amount: u64,
606 minimum_token_b_amount: u64,
607 accounts: &[AccountInfo],
608 ) -> ProgramResult {
609 let account_info_iter = &mut accounts.iter();
610 let swap_info = next_account_info(account_info_iter)?;
611 let authority_info = next_account_info(account_info_iter)?;
612 let user_transfer_authority_info = next_account_info(account_info_iter)?;
613 let pool_mint_info = next_account_info(account_info_iter)?;
614 let source_info = next_account_info(account_info_iter)?;
615 let token_a_info = next_account_info(account_info_iter)?;
616 let token_b_info = next_account_info(account_info_iter)?;
617 let dest_token_a_info = next_account_info(account_info_iter)?;
618 let dest_token_b_info = next_account_info(account_info_iter)?;
619 let pool_fee_account_info = next_account_info(account_info_iter)?;
620 let token_program_info = next_account_info(account_info_iter)?;
621
622 let token_swap = SwapVersion::unpack(&swap_info.data.borrow())?;
623 Self::check_accounts(
624 token_swap.as_ref(),
625 program_id,
626 swap_info,
627 authority_info,
628 token_a_info,
629 token_b_info,
630 pool_mint_info,
631 token_program_info,
632 Some(dest_token_a_info),
633 Some(dest_token_b_info),
634 Some(pool_fee_account_info),
635 )?;
636
637 let token_a = Self::unpack_token_account(token_a_info, token_swap.token_program_id())?;
638 let token_b = Self::unpack_token_account(token_b_info, token_swap.token_program_id())?;
639 let pool_mint = Self::unpack_mint(pool_mint_info, token_swap.token_program_id())?;
640
641 let calculator = &token_swap.swap_curve().calculator;
642
643 let withdraw_fee: u128 = if *pool_fee_account_info.key == *source_info.key {
644 0
646 } else {
647 token_swap
648 .fees()
649 .owner_withdraw_fee(to_u128(pool_token_amount)?)
650 .ok_or(SwapError::FeeCalculationFailure)?
651 };
652 let pool_token_amount = to_u128(pool_token_amount)?
653 .checked_sub(withdraw_fee)
654 .ok_or(SwapError::CalculationFailure)?;
655
656 let results = calculator
657 .pool_tokens_to_trading_tokens(
658 pool_token_amount,
659 to_u128(pool_mint.supply)?,
660 to_u128(token_a.amount)?,
661 to_u128(token_b.amount)?,
662 RoundDirection::Floor,
663 )
664 .ok_or(SwapError::ZeroTradingTokens)?;
665 let token_a_amount = to_u64(results.token_a_amount)?;
666 let token_a_amount = std::cmp::min(token_a.amount, token_a_amount);
667 if token_a_amount < minimum_token_a_amount {
668 return Err(SwapError::ExceededSlippage.into());
669 }
670 if token_a_amount == 0 && token_a.amount != 0 {
671 return Err(SwapError::ZeroTradingTokens.into());
672 }
673 let token_b_amount = to_u64(results.token_b_amount)?;
674 let token_b_amount = std::cmp::min(token_b.amount, token_b_amount);
675 if token_b_amount < minimum_token_b_amount {
676 return Err(SwapError::ExceededSlippage.into());
677 }
678 if token_b_amount == 0 && token_b.amount != 0 {
679 return Err(SwapError::ZeroTradingTokens.into());
680 }
681
682 if withdraw_fee > 0 {
683 Self::token_transfer(
684 swap_info.key,
685 token_program_info.clone(),
686 source_info.clone(),
687 pool_fee_account_info.clone(),
688 user_transfer_authority_info.clone(),
689 token_swap.bump_seed(),
690 to_u64(withdraw_fee)?,
691 )?;
692 }
693 Self::token_burn(
694 swap_info.key,
695 token_program_info.clone(),
696 source_info.clone(),
697 pool_mint_info.clone(),
698 user_transfer_authority_info.clone(),
699 token_swap.bump_seed(),
700 to_u64(pool_token_amount)?,
701 )?;
702
703 if token_a_amount > 0 {
704 Self::token_transfer(
705 swap_info.key,
706 token_program_info.clone(),
707 token_a_info.clone(),
708 dest_token_a_info.clone(),
709 authority_info.clone(),
710 token_swap.bump_seed(),
711 token_a_amount,
712 )?;
713 }
714 if token_b_amount > 0 {
715 Self::token_transfer(
716 swap_info.key,
717 token_program_info.clone(),
718 token_b_info.clone(),
719 dest_token_b_info.clone(),
720 authority_info.clone(),
721 token_swap.bump_seed(),
722 token_b_amount,
723 )?;
724 }
725 Ok(())
726 }
727
728 pub fn process_deposit_single_token_type_exact_amount_in(
730 program_id: &Pubkey,
731 source_token_amount: u64,
732 minimum_pool_token_amount: u64,
733 accounts: &[AccountInfo],
734 ) -> ProgramResult {
735 let account_info_iter = &mut accounts.iter();
736 let swap_info = next_account_info(account_info_iter)?;
737 let authority_info = next_account_info(account_info_iter)?;
738 let user_transfer_authority_info = next_account_info(account_info_iter)?;
739 let source_info = next_account_info(account_info_iter)?;
740 let swap_token_a_info = next_account_info(account_info_iter)?;
741 let swap_token_b_info = next_account_info(account_info_iter)?;
742 let pool_mint_info = next_account_info(account_info_iter)?;
743 let destination_info = next_account_info(account_info_iter)?;
744 let token_program_info = next_account_info(account_info_iter)?;
745
746 let token_swap = SwapVersion::unpack(&swap_info.data.borrow())?;
747 let source_account =
748 Self::unpack_token_account(source_info, token_swap.token_program_id())?;
749 let swap_token_a =
750 Self::unpack_token_account(swap_token_a_info, token_swap.token_program_id())?;
751 let swap_token_b =
752 Self::unpack_token_account(swap_token_b_info, token_swap.token_program_id())?;
753
754 let trade_direction = if source_account.mint == swap_token_a.mint {
755 TradeDirection::AtoB
756 } else if source_account.mint == swap_token_b.mint {
757 TradeDirection::BtoA
758 } else {
759 return Err(SwapError::IncorrectSwapAccount.into());
760 };
761
762 let (source_a_info, source_b_info) = match trade_direction {
763 TradeDirection::AtoB => (Some(source_info), None),
764 TradeDirection::BtoA => (None, Some(source_info)),
765 };
766
767 Self::check_accounts(
768 token_swap.as_ref(),
769 program_id,
770 swap_info,
771 authority_info,
772 swap_token_a_info,
773 swap_token_b_info,
774 pool_mint_info,
775 token_program_info,
776 source_a_info,
777 source_b_info,
778 None,
779 )?;
780
781 let pool_mint = Self::unpack_mint(pool_mint_info, token_swap.token_program_id())?;
782 let pool_mint_supply = to_u128(pool_mint.supply)?;
783 let pool_token_amount = if pool_mint_supply > 0 {
784 token_swap
785 .swap_curve()
786 .deposit_single_token_type(
787 to_u128(source_token_amount)?,
788 to_u128(swap_token_a.amount)?,
789 to_u128(swap_token_b.amount)?,
790 pool_mint_supply,
791 trade_direction,
792 token_swap.fees(),
793 )
794 .ok_or(SwapError::ZeroTradingTokens)?
795 } else {
796 token_swap.swap_curve().calculator.new_pool_supply()
797 };
798
799 let pool_token_amount = to_u64(pool_token_amount)?;
800 if pool_token_amount < minimum_pool_token_amount {
801 return Err(SwapError::ExceededSlippage.into());
802 }
803 if pool_token_amount == 0 {
804 return Err(SwapError::ZeroTradingTokens.into());
805 }
806
807 match trade_direction {
808 TradeDirection::AtoB => {
809 Self::token_transfer(
810 swap_info.key,
811 token_program_info.clone(),
812 source_info.clone(),
813 swap_token_a_info.clone(),
814 user_transfer_authority_info.clone(),
815 token_swap.bump_seed(),
816 source_token_amount,
817 )?;
818 }
819 TradeDirection::BtoA => {
820 Self::token_transfer(
821 swap_info.key,
822 token_program_info.clone(),
823 source_info.clone(),
824 swap_token_b_info.clone(),
825 user_transfer_authority_info.clone(),
826 token_swap.bump_seed(),
827 source_token_amount,
828 )?;
829 }
830 }
831 Self::token_mint_to(
832 swap_info.key,
833 token_program_info.clone(),
834 pool_mint_info.clone(),
835 destination_info.clone(),
836 authority_info.clone(),
837 token_swap.bump_seed(),
838 pool_token_amount,
839 )?;
840
841 Ok(())
842 }
843
844 pub fn process_withdraw_single_token_type_exact_amount_out(
846 program_id: &Pubkey,
847 destination_token_amount: u64,
848 maximum_pool_token_amount: u64,
849 accounts: &[AccountInfo],
850 ) -> ProgramResult {
851 let account_info_iter = &mut accounts.iter();
852 let swap_info = next_account_info(account_info_iter)?;
853 let authority_info = next_account_info(account_info_iter)?;
854 let user_transfer_authority_info = next_account_info(account_info_iter)?;
855 let pool_mint_info = next_account_info(account_info_iter)?;
856 let source_info = next_account_info(account_info_iter)?;
857 let swap_token_a_info = next_account_info(account_info_iter)?;
858 let swap_token_b_info = next_account_info(account_info_iter)?;
859 let destination_info = next_account_info(account_info_iter)?;
860 let pool_fee_account_info = next_account_info(account_info_iter)?;
861 let token_program_info = next_account_info(account_info_iter)?;
862
863 let token_swap = SwapVersion::unpack(&swap_info.data.borrow())?;
864 let destination_account =
865 Self::unpack_token_account(destination_info, token_swap.token_program_id())?;
866 let swap_token_a =
867 Self::unpack_token_account(swap_token_a_info, token_swap.token_program_id())?;
868 let swap_token_b =
869 Self::unpack_token_account(swap_token_b_info, token_swap.token_program_id())?;
870
871 let trade_direction = if destination_account.mint == swap_token_a.mint {
872 TradeDirection::AtoB
873 } else if destination_account.mint == swap_token_b.mint {
874 TradeDirection::BtoA
875 } else {
876 return Err(SwapError::IncorrectSwapAccount.into());
877 };
878
879 let (destination_a_info, destination_b_info) = match trade_direction {
880 TradeDirection::AtoB => (Some(destination_info), None),
881 TradeDirection::BtoA => (None, Some(destination_info)),
882 };
883 Self::check_accounts(
884 token_swap.as_ref(),
885 program_id,
886 swap_info,
887 authority_info,
888 swap_token_a_info,
889 swap_token_b_info,
890 pool_mint_info,
891 token_program_info,
892 destination_a_info,
893 destination_b_info,
894 Some(pool_fee_account_info),
895 )?;
896
897 let pool_mint = Self::unpack_mint(pool_mint_info, token_swap.token_program_id())?;
898 let pool_mint_supply = to_u128(pool_mint.supply)?;
899 let swap_token_a_amount = to_u128(swap_token_a.amount)?;
900 let swap_token_b_amount = to_u128(swap_token_b.amount)?;
901
902 let burn_pool_token_amount = token_swap
903 .swap_curve()
904 .withdraw_single_token_type_exact_out(
905 to_u128(destination_token_amount)?,
906 swap_token_a_amount,
907 swap_token_b_amount,
908 pool_mint_supply,
909 trade_direction,
910 token_swap.fees(),
911 )
912 .ok_or(SwapError::ZeroTradingTokens)?;
913
914 let withdraw_fee: u128 = if *pool_fee_account_info.key == *source_info.key {
915 0
917 } else {
918 token_swap
919 .fees()
920 .owner_withdraw_fee(burn_pool_token_amount)
921 .ok_or(SwapError::FeeCalculationFailure)?
922 };
923 let pool_token_amount = burn_pool_token_amount
924 .checked_add(withdraw_fee)
925 .ok_or(SwapError::CalculationFailure)?;
926
927 if to_u64(pool_token_amount)? > maximum_pool_token_amount {
928 return Err(SwapError::ExceededSlippage.into());
929 }
930 if pool_token_amount == 0 {
931 return Err(SwapError::ZeroTradingTokens.into());
932 }
933
934 if withdraw_fee > 0 {
935 Self::token_transfer(
936 swap_info.key,
937 token_program_info.clone(),
938 source_info.clone(),
939 pool_fee_account_info.clone(),
940 user_transfer_authority_info.clone(),
941 token_swap.bump_seed(),
942 to_u64(withdraw_fee)?,
943 )?;
944 }
945 Self::token_burn(
946 swap_info.key,
947 token_program_info.clone(),
948 source_info.clone(),
949 pool_mint_info.clone(),
950 user_transfer_authority_info.clone(),
951 token_swap.bump_seed(),
952 to_u64(burn_pool_token_amount)?,
953 )?;
954
955 match trade_direction {
956 TradeDirection::AtoB => {
957 Self::token_transfer(
958 swap_info.key,
959 token_program_info.clone(),
960 swap_token_a_info.clone(),
961 destination_info.clone(),
962 authority_info.clone(),
963 token_swap.bump_seed(),
964 destination_token_amount,
965 )?;
966 }
967 TradeDirection::BtoA => {
968 Self::token_transfer(
969 swap_info.key,
970 token_program_info.clone(),
971 swap_token_b_info.clone(),
972 destination_info.clone(),
973 authority_info.clone(),
974 token_swap.bump_seed(),
975 destination_token_amount,
976 )?;
977 }
978 }
979
980 Ok(())
981 }
982
983 pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {
985 Self::process_with_constraints(program_id, accounts, input, &SWAP_CONSTRAINTS)
986 }
987
988 pub fn process_with_constraints(
990 program_id: &Pubkey,
991 accounts: &[AccountInfo],
992 input: &[u8],
993 swap_constraints: &Option<SwapConstraints>,
994 ) -> ProgramResult {
995 let instruction = SwapInstruction::unpack(input)?;
996 match instruction {
997 SwapInstruction::Initialize(Initialize { fees, swap_curve }) => {
998 msg!("Instruction: Init");
999 Self::process_initialize(program_id, fees, swap_curve, accounts, swap_constraints)
1000 }
1001 SwapInstruction::Swap(Swap {
1002 amount_in,
1003 minimum_amount_out,
1004 }) => {
1005 msg!("Instruction: Swap");
1006 Self::process_swap(program_id, amount_in, minimum_amount_out, accounts)
1007 }
1008 SwapInstruction::DepositAllTokenTypes(DepositAllTokenTypes {
1009 pool_token_amount,
1010 maximum_token_a_amount,
1011 maximum_token_b_amount,
1012 }) => {
1013 msg!("Instruction: DepositAllTokenTypes");
1014 Self::process_deposit_all_token_types(
1015 program_id,
1016 pool_token_amount,
1017 maximum_token_a_amount,
1018 maximum_token_b_amount,
1019 accounts,
1020 )
1021 }
1022 SwapInstruction::WithdrawAllTokenTypes(WithdrawAllTokenTypes {
1023 pool_token_amount,
1024 minimum_token_a_amount,
1025 minimum_token_b_amount,
1026 }) => {
1027 msg!("Instruction: WithdrawAllTokenTypes");
1028 Self::process_withdraw_all_token_types(
1029 program_id,
1030 pool_token_amount,
1031 minimum_token_a_amount,
1032 minimum_token_b_amount,
1033 accounts,
1034 )
1035 }
1036 SwapInstruction::DepositSingleTokenTypeExactAmountIn(
1037 DepositSingleTokenTypeExactAmountIn {
1038 source_token_amount,
1039 minimum_pool_token_amount,
1040 },
1041 ) => {
1042 msg!("Instruction: DepositSingleTokenTypeExactAmountIn");
1043 Self::process_deposit_single_token_type_exact_amount_in(
1044 program_id,
1045 source_token_amount,
1046 minimum_pool_token_amount,
1047 accounts,
1048 )
1049 }
1050 SwapInstruction::WithdrawSingleTokenTypeExactAmountOut(
1051 WithdrawSingleTokenTypeExactAmountOut {
1052 destination_token_amount,
1053 maximum_pool_token_amount,
1054 },
1055 ) => {
1056 msg!("Instruction: WithdrawSingleTokenTypeExactAmountOut");
1057 Self::process_withdraw_single_token_type_exact_amount_out(
1058 program_id,
1059 destination_token_amount,
1060 maximum_pool_token_amount,
1061 accounts,
1062 )
1063 }
1064 }
1065 }
1066}
1067
1068impl PrintProgramError for SwapError {
1069 fn print<E>(&self)
1070 where
1071 E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive,
1072 {
1073 match self {
1074 SwapError::AlreadyInUse => msg!("Error: Swap account already in use"),
1075 SwapError::InvalidProgramAddress => {
1076 msg!("Error: Invalid program address generated from bump seed and key")
1077 }
1078 SwapError::InvalidOwner => {
1079 msg!("Error: The input account owner is not the program address")
1080 }
1081 SwapError::InvalidOutputOwner => {
1082 msg!("Error: Output pool account owner cannot be the program address")
1083 }
1084 SwapError::ExpectedMint => msg!("Error: Deserialized account is not an GPL Token mint"),
1085 SwapError::ExpectedAccount => {
1086 msg!("Error: Deserialized account is not an GPL Token account")
1087 }
1088 SwapError::EmptySupply => msg!("Error: Input token account empty"),
1089 SwapError::InvalidSupply => msg!("Error: Pool token mint has a non-zero supply"),
1090 SwapError::RepeatedMint => msg!("Error: Swap input token accounts have the same mint"),
1091 SwapError::InvalidDelegate => msg!("Error: Token account has a delegate"),
1092 SwapError::InvalidInput => msg!("Error: InvalidInput"),
1093 SwapError::IncorrectSwapAccount => {
1094 msg!("Error: Address of the provided swap token account is incorrect")
1095 }
1096 SwapError::IncorrectPoolMint => {
1097 msg!("Error: Address of the provided pool token mint is incorrect")
1098 }
1099 SwapError::InvalidOutput => msg!("Error: InvalidOutput"),
1100 SwapError::CalculationFailure => msg!("Error: CalculationFailure"),
1101 SwapError::InvalidInstruction => msg!("Error: InvalidInstruction"),
1102 SwapError::ExceededSlippage => {
1103 msg!("Error: Swap instruction exceeds desired slippage limit")
1104 }
1105 SwapError::InvalidCloseAuthority => msg!("Error: Token account has a close authority"),
1106 SwapError::InvalidFreezeAuthority => {
1107 msg!("Error: Pool token mint has a freeze authority")
1108 }
1109 SwapError::IncorrectFeeAccount => msg!("Error: Pool fee token account incorrect"),
1110 SwapError::ZeroTradingTokens => {
1111 msg!("Error: Given pool token amount results in zero trading tokens")
1112 }
1113 SwapError::FeeCalculationFailure => msg!(
1114 "Error: The fee calculation failed due to overflow, underflow, or unexpected 0"
1115 ),
1116 SwapError::ConversionFailure => msg!("Error: Conversion to or from u64 failed."),
1117 SwapError::InvalidFee => {
1118 msg!("Error: The provided fee does not match the program owner's constraints")
1119 }
1120 SwapError::IncorrectTokenProgramId => {
1121 msg!("Error: The provided token program does not match the token program expected by the swap")
1122 }
1123 SwapError::UnsupportedCurveType => {
1124 msg!("Error: The provided curve type is not supported by the program owner")
1125 }
1126 SwapError::InvalidCurve => {
1127 msg!("Error: The provided curve parameters are invalid")
1128 }
1129 SwapError::UnsupportedCurveOperation => {
1130 msg!("Error: The operation cannot be performed on the given curve")
1131 }
1132 }
1133 }
1134}
1135
1136fn to_u128(val: u64) -> Result<u128, SwapError> {
1137 val.try_into().map_err(|_| SwapError::ConversionFailure)
1138}
1139
1140fn to_u64(val: u128) -> Result<u64, SwapError> {
1141 val.try_into().map_err(|_| SwapError::ConversionFailure)
1142}
1143
1144#[cfg(test)]
1145mod tests {
1146 use super::*;
1147 use crate::{
1148 curve::calculator::{CurveCalculator, INITIAL_SWAP_POOL_AMOUNT},
1149 curve::{
1150 base::CurveType, constant_price::ConstantPriceCurve,
1151 constant_product::ConstantProductCurve, offset::OffsetCurve,
1152 },
1153 instruction::{
1154 deposit_all_token_types, deposit_single_token_type_exact_amount_in, initialize, swap,
1155 withdraw_all_token_types, withdraw_single_token_type_exact_amount_out,
1156 },
1157 };
1158 use gemachain_program::{instruction::Instruction, program_stubs, rent::Rent};
1159 use gemachain_sdk::account::{create_account_for_test, create_is_signer_account_infos, Account};
1160 use gpl_token::{
1161 error::TokenError,
1162 instruction::{
1163 approve, initialize_account, initialize_mint, mint_to, revoke, set_authority,
1164 AuthorityType,
1165 },
1166 };
1167
1168 const SWAP_PROGRAM_ID: Pubkey = Pubkey::new_from_array([2u8; 32]);
1170
1171 struct TestSyscallStubs {}
1172 impl program_stubs::SyscallStubs for TestSyscallStubs {
1173 fn gema_invoke_signed(
1174 &self,
1175 instruction: &Instruction,
1176 account_infos: &[AccountInfo],
1177 signers_seeds: &[&[&[u8]]],
1178 ) -> ProgramResult {
1179 msg!("TestSyscallStubs::gema_invoke_signed()");
1180
1181 let mut new_account_infos = vec![];
1182
1183 if !account_infos.iter().any(|x| *x.key == gpl_token::id()) {
1185 return Err(ProgramError::InvalidAccountData);
1186 }
1187
1188 for meta in instruction.accounts.iter() {
1189 for account_info in account_infos.iter() {
1190 if meta.pubkey == *account_info.key {
1191 let mut new_account_info = account_info.clone();
1192 for seeds in signers_seeds.iter() {
1193 let signer =
1194 Pubkey::create_program_address(seeds, &SWAP_PROGRAM_ID).unwrap();
1195 if *account_info.key == signer {
1196 new_account_info.is_signer = true;
1197 }
1198 }
1199 new_account_infos.push(new_account_info);
1200 }
1201 }
1202 }
1203
1204 gpl_token::processor::Processor::process(
1205 &instruction.program_id,
1206 &new_account_infos,
1207 &instruction.data,
1208 )
1209 }
1210 }
1211
1212 fn test_syscall_stubs() {
1213 use std::sync::Once;
1214 static ONCE: Once = Once::new();
1215
1216 ONCE.call_once(|| {
1217 program_stubs::set_syscall_stubs(Box::new(TestSyscallStubs {}));
1218 });
1219 }
1220
1221 struct SwapAccountInfo {
1222 bump_seed: u8,
1223 authority_key: Pubkey,
1224 fees: Fees,
1225 swap_curve: SwapCurve,
1226 swap_key: Pubkey,
1227 swap_account: Account,
1228 pool_mint_key: Pubkey,
1229 pool_mint_account: Account,
1230 pool_fee_key: Pubkey,
1231 pool_fee_account: Account,
1232 pool_token_key: Pubkey,
1233 pool_token_account: Account,
1234 token_a_key: Pubkey,
1235 token_a_account: Account,
1236 token_a_mint_key: Pubkey,
1237 token_a_mint_account: Account,
1238 token_b_key: Pubkey,
1239 token_b_account: Account,
1240 token_b_mint_key: Pubkey,
1241 token_b_mint_account: Account,
1242 }
1243
1244 impl SwapAccountInfo {
1245 pub fn new(
1246 user_key: &Pubkey,
1247 fees: Fees,
1248 swap_curve: SwapCurve,
1249 token_a_amount: u64,
1250 token_b_amount: u64,
1251 ) -> Self {
1252 let swap_key = Pubkey::new_unique();
1253 let swap_account = Account::new(0, SwapVersion::LATEST_LEN, &SWAP_PROGRAM_ID);
1254 let (authority_key, bump_seed) =
1255 Pubkey::find_program_address(&[&swap_key.to_bytes()[..]], &SWAP_PROGRAM_ID);
1256
1257 let (pool_mint_key, mut pool_mint_account) =
1258 create_mint(&gpl_token::id(), &authority_key, None);
1259 let (pool_token_key, pool_token_account) = mint_token(
1260 &gpl_token::id(),
1261 &pool_mint_key,
1262 &mut pool_mint_account,
1263 &authority_key,
1264 user_key,
1265 0,
1266 );
1267 let (pool_fee_key, pool_fee_account) = mint_token(
1268 &gpl_token::id(),
1269 &pool_mint_key,
1270 &mut pool_mint_account,
1271 &authority_key,
1272 user_key,
1273 0,
1274 );
1275 let (token_a_mint_key, mut token_a_mint_account) =
1276 create_mint(&gpl_token::id(), user_key, None);
1277 let (token_a_key, token_a_account) = mint_token(
1278 &gpl_token::id(),
1279 &token_a_mint_key,
1280 &mut token_a_mint_account,
1281 user_key,
1282 &authority_key,
1283 token_a_amount,
1284 );
1285 let (token_b_mint_key, mut token_b_mint_account) =
1286 create_mint(&gpl_token::id(), user_key, None);
1287 let (token_b_key, token_b_account) = mint_token(
1288 &gpl_token::id(),
1289 &token_b_mint_key,
1290 &mut token_b_mint_account,
1291 user_key,
1292 &authority_key,
1293 token_b_amount,
1294 );
1295
1296 SwapAccountInfo {
1297 bump_seed,
1298 authority_key,
1299 fees,
1300 swap_curve,
1301 swap_key,
1302 swap_account,
1303 pool_mint_key,
1304 pool_mint_account,
1305 pool_fee_key,
1306 pool_fee_account,
1307 pool_token_key,
1308 pool_token_account,
1309 token_a_key,
1310 token_a_account,
1311 token_a_mint_key,
1312 token_a_mint_account,
1313 token_b_key,
1314 token_b_account,
1315 token_b_mint_key,
1316 token_b_mint_account,
1317 }
1318 }
1319
1320 pub fn initialize_swap(&mut self) -> ProgramResult {
1321 do_process_instruction(
1322 initialize(
1323 &SWAP_PROGRAM_ID,
1324 &gpl_token::id(),
1325 &self.swap_key,
1326 &self.authority_key,
1327 &self.token_a_key,
1328 &self.token_b_key,
1329 &self.pool_mint_key,
1330 &self.pool_fee_key,
1331 &self.pool_token_key,
1332 self.fees.clone(),
1333 self.swap_curve.clone(),
1334 )
1335 .unwrap(),
1336 vec![
1337 &mut self.swap_account,
1338 &mut Account::default(),
1339 &mut self.token_a_account,
1340 &mut self.token_b_account,
1341 &mut self.pool_mint_account,
1342 &mut self.pool_fee_account,
1343 &mut self.pool_token_account,
1344 &mut Account::default(),
1345 ],
1346 )
1347 }
1348
1349 pub fn setup_token_accounts(
1350 &mut self,
1351 mint_owner: &Pubkey,
1352 account_owner: &Pubkey,
1353 a_amount: u64,
1354 b_amount: u64,
1355 pool_amount: u64,
1356 ) -> (Pubkey, Account, Pubkey, Account, Pubkey, Account) {
1357 let (token_a_key, token_a_account) = mint_token(
1358 &gpl_token::id(),
1359 &self.token_a_mint_key,
1360 &mut self.token_a_mint_account,
1361 mint_owner,
1362 account_owner,
1363 a_amount,
1364 );
1365 let (token_b_key, token_b_account) = mint_token(
1366 &gpl_token::id(),
1367 &self.token_b_mint_key,
1368 &mut self.token_b_mint_account,
1369 mint_owner,
1370 account_owner,
1371 b_amount,
1372 );
1373 let (pool_key, pool_account) = mint_token(
1374 &gpl_token::id(),
1375 &self.pool_mint_key,
1376 &mut self.pool_mint_account,
1377 &self.authority_key,
1378 account_owner,
1379 pool_amount,
1380 );
1381 (
1382 token_a_key,
1383 token_a_account,
1384 token_b_key,
1385 token_b_account,
1386 pool_key,
1387 pool_account,
1388 )
1389 }
1390
1391 fn get_token_account(&self, account_key: &Pubkey) -> &Account {
1392 if *account_key == self.token_a_key {
1393 return &self.token_a_account;
1394 } else if *account_key == self.token_b_key {
1395 return &self.token_b_account;
1396 }
1397 panic!("Could not find matching swap token account");
1398 }
1399
1400 fn set_token_account(&mut self, account_key: &Pubkey, account: Account) {
1401 if *account_key == self.token_a_key {
1402 self.token_a_account = account;
1403 return;
1404 } else if *account_key == self.token_b_key {
1405 self.token_b_account = account;
1406 return;
1407 }
1408 panic!("Could not find matching swap token account");
1409 }
1410
1411 #[allow(clippy::too_many_arguments)]
1412 pub fn swap(
1413 &mut self,
1414 user_key: &Pubkey,
1415 user_source_key: &Pubkey,
1416 mut user_source_account: &mut Account,
1417 swap_source_key: &Pubkey,
1418 swap_destination_key: &Pubkey,
1419 user_destination_key: &Pubkey,
1420 mut user_destination_account: &mut Account,
1421 amount_in: u64,
1422 minimum_amount_out: u64,
1423 ) -> ProgramResult {
1424 let user_transfer_key = Pubkey::new_unique();
1425 do_process_instruction(
1427 approve(
1428 &gpl_token::id(),
1429 user_source_key,
1430 &user_transfer_key,
1431 user_key,
1432 &[],
1433 amount_in,
1434 )
1435 .unwrap(),
1436 vec![
1437 &mut user_source_account,
1438 &mut Account::default(),
1439 &mut Account::default(),
1440 ],
1441 )
1442 .unwrap();
1443
1444 let mut swap_source_account = self.get_token_account(swap_source_key).clone();
1445 let mut swap_destination_account = self.get_token_account(swap_destination_key).clone();
1446
1447 do_process_instruction(
1449 swap(
1450 &SWAP_PROGRAM_ID,
1451 &gpl_token::id(),
1452 &self.swap_key,
1453 &self.authority_key,
1454 &user_transfer_key,
1455 user_source_key,
1456 swap_source_key,
1457 swap_destination_key,
1458 user_destination_key,
1459 &self.pool_mint_key,
1460 &self.pool_fee_key,
1461 None,
1462 Swap {
1463 amount_in,
1464 minimum_amount_out,
1465 },
1466 )
1467 .unwrap(),
1468 vec![
1469 &mut self.swap_account,
1470 &mut Account::default(),
1471 &mut Account::default(),
1472 &mut user_source_account,
1473 &mut swap_source_account,
1474 &mut swap_destination_account,
1475 &mut user_destination_account,
1476 &mut self.pool_mint_account,
1477 &mut self.pool_fee_account,
1478 &mut Account::default(),
1479 ],
1480 )?;
1481
1482 self.set_token_account(swap_source_key, swap_source_account);
1483 self.set_token_account(swap_destination_key, swap_destination_account);
1484
1485 Ok(())
1486 }
1487
1488 #[allow(clippy::too_many_arguments)]
1489 pub fn deposit_all_token_types(
1490 &mut self,
1491 depositor_key: &Pubkey,
1492 depositor_token_a_key: &Pubkey,
1493 mut depositor_token_a_account: &mut Account,
1494 depositor_token_b_key: &Pubkey,
1495 mut depositor_token_b_account: &mut Account,
1496 depositor_pool_key: &Pubkey,
1497 mut depositor_pool_account: &mut Account,
1498 pool_token_amount: u64,
1499 maximum_token_a_amount: u64,
1500 maximum_token_b_amount: u64,
1501 ) -> ProgramResult {
1502 let user_transfer_authority = Pubkey::new_unique();
1503 do_process_instruction(
1504 approve(
1505 &gpl_token::id(),
1506 depositor_token_a_key,
1507 &user_transfer_authority,
1508 depositor_key,
1509 &[],
1510 maximum_token_a_amount,
1511 )
1512 .unwrap(),
1513 vec![
1514 &mut depositor_token_a_account,
1515 &mut Account::default(),
1516 &mut Account::default(),
1517 ],
1518 )
1519 .unwrap();
1520
1521 do_process_instruction(
1522 approve(
1523 &gpl_token::id(),
1524 depositor_token_b_key,
1525 &user_transfer_authority,
1526 depositor_key,
1527 &[],
1528 maximum_token_b_amount,
1529 )
1530 .unwrap(),
1531 vec![
1532 &mut depositor_token_b_account,
1533 &mut Account::default(),
1534 &mut Account::default(),
1535 ],
1536 )
1537 .unwrap();
1538
1539 do_process_instruction(
1540 deposit_all_token_types(
1541 &SWAP_PROGRAM_ID,
1542 &gpl_token::id(),
1543 &self.swap_key,
1544 &self.authority_key,
1545 &user_transfer_authority,
1546 depositor_token_a_key,
1547 depositor_token_b_key,
1548 &self.token_a_key,
1549 &self.token_b_key,
1550 &self.pool_mint_key,
1551 depositor_pool_key,
1552 DepositAllTokenTypes {
1553 pool_token_amount,
1554 maximum_token_a_amount,
1555 maximum_token_b_amount,
1556 },
1557 )
1558 .unwrap(),
1559 vec![
1560 &mut self.swap_account,
1561 &mut Account::default(),
1562 &mut Account::default(),
1563 &mut depositor_token_a_account,
1564 &mut depositor_token_b_account,
1565 &mut self.token_a_account,
1566 &mut self.token_b_account,
1567 &mut self.pool_mint_account,
1568 &mut depositor_pool_account,
1569 &mut Account::default(),
1570 ],
1571 )
1572 }
1573
1574 #[allow(clippy::too_many_arguments)]
1575 pub fn withdraw_all_token_types(
1576 &mut self,
1577 user_key: &Pubkey,
1578 pool_key: &Pubkey,
1579 mut pool_account: &mut Account,
1580 token_a_key: &Pubkey,
1581 mut token_a_account: &mut Account,
1582 token_b_key: &Pubkey,
1583 mut token_b_account: &mut Account,
1584 pool_token_amount: u64,
1585 minimum_token_a_amount: u64,
1586 minimum_token_b_amount: u64,
1587 ) -> ProgramResult {
1588 let user_transfer_authority_key = Pubkey::new_unique();
1589 do_process_instruction(
1591 approve(
1592 &gpl_token::id(),
1593 pool_key,
1594 &user_transfer_authority_key,
1595 user_key,
1596 &[],
1597 pool_token_amount,
1598 )
1599 .unwrap(),
1600 vec![
1601 &mut pool_account,
1602 &mut Account::default(),
1603 &mut Account::default(),
1604 ],
1605 )
1606 .unwrap();
1607
1608 do_process_instruction(
1610 withdraw_all_token_types(
1611 &SWAP_PROGRAM_ID,
1612 &gpl_token::id(),
1613 &self.swap_key,
1614 &self.authority_key,
1615 &user_transfer_authority_key,
1616 &self.pool_mint_key,
1617 &self.pool_fee_key,
1618 pool_key,
1619 &self.token_a_key,
1620 &self.token_b_key,
1621 token_a_key,
1622 token_b_key,
1623 WithdrawAllTokenTypes {
1624 pool_token_amount,
1625 minimum_token_a_amount,
1626 minimum_token_b_amount,
1627 },
1628 )
1629 .unwrap(),
1630 vec![
1631 &mut self.swap_account,
1632 &mut Account::default(),
1633 &mut Account::default(),
1634 &mut self.pool_mint_account,
1635 &mut pool_account,
1636 &mut self.token_a_account,
1637 &mut self.token_b_account,
1638 &mut token_a_account,
1639 &mut token_b_account,
1640 &mut self.pool_fee_account,
1641 &mut Account::default(),
1642 ],
1643 )
1644 }
1645
1646 #[allow(clippy::too_many_arguments)]
1647 pub fn deposit_single_token_type_exact_amount_in(
1648 &mut self,
1649 depositor_key: &Pubkey,
1650 deposit_account_key: &Pubkey,
1651 mut deposit_token_account: &mut Account,
1652 deposit_pool_key: &Pubkey,
1653 mut deposit_pool_account: &mut Account,
1654 source_token_amount: u64,
1655 minimum_pool_token_amount: u64,
1656 ) -> ProgramResult {
1657 let user_transfer_authority_key = Pubkey::new_unique();
1658 do_process_instruction(
1659 approve(
1660 &gpl_token::id(),
1661 deposit_account_key,
1662 &user_transfer_authority_key,
1663 depositor_key,
1664 &[],
1665 source_token_amount,
1666 )
1667 .unwrap(),
1668 vec![
1669 &mut deposit_token_account,
1670 &mut Account::default(),
1671 &mut Account::default(),
1672 ],
1673 )
1674 .unwrap();
1675
1676 do_process_instruction(
1677 deposit_single_token_type_exact_amount_in(
1678 &SWAP_PROGRAM_ID,
1679 &gpl_token::id(),
1680 &self.swap_key,
1681 &self.authority_key,
1682 &user_transfer_authority_key,
1683 deposit_account_key,
1684 &self.token_a_key,
1685 &self.token_b_key,
1686 &self.pool_mint_key,
1687 deposit_pool_key,
1688 DepositSingleTokenTypeExactAmountIn {
1689 source_token_amount,
1690 minimum_pool_token_amount,
1691 },
1692 )
1693 .unwrap(),
1694 vec![
1695 &mut self.swap_account,
1696 &mut Account::default(),
1697 &mut Account::default(),
1698 &mut deposit_token_account,
1699 &mut self.token_a_account,
1700 &mut self.token_b_account,
1701 &mut self.pool_mint_account,
1702 &mut deposit_pool_account,
1703 &mut Account::default(),
1704 ],
1705 )
1706 }
1707
1708 #[allow(clippy::too_many_arguments)]
1709 pub fn withdraw_single_token_type_exact_amount_out(
1710 &mut self,
1711 user_key: &Pubkey,
1712 pool_key: &Pubkey,
1713 mut pool_account: &mut Account,
1714 destination_key: &Pubkey,
1715 mut destination_account: &mut Account,
1716 destination_token_amount: u64,
1717 maximum_pool_token_amount: u64,
1718 ) -> ProgramResult {
1719 let user_transfer_authority_key = Pubkey::new_unique();
1720 do_process_instruction(
1722 approve(
1723 &gpl_token::id(),
1724 pool_key,
1725 &user_transfer_authority_key,
1726 user_key,
1727 &[],
1728 maximum_pool_token_amount,
1729 )
1730 .unwrap(),
1731 vec![
1732 &mut pool_account,
1733 &mut Account::default(),
1734 &mut Account::default(),
1735 ],
1736 )
1737 .unwrap();
1738
1739 do_process_instruction(
1740 withdraw_single_token_type_exact_amount_out(
1741 &SWAP_PROGRAM_ID,
1742 &gpl_token::id(),
1743 &self.swap_key,
1744 &self.authority_key,
1745 &user_transfer_authority_key,
1746 &self.pool_mint_key,
1747 &self.pool_fee_key,
1748 pool_key,
1749 &self.token_a_key,
1750 &self.token_b_key,
1751 destination_key,
1752 WithdrawSingleTokenTypeExactAmountOut {
1753 destination_token_amount,
1754 maximum_pool_token_amount,
1755 },
1756 )
1757 .unwrap(),
1758 vec![
1759 &mut self.swap_account,
1760 &mut Account::default(),
1761 &mut Account::default(),
1762 &mut self.pool_mint_account,
1763 &mut pool_account,
1764 &mut self.token_a_account,
1765 &mut self.token_b_account,
1766 &mut destination_account,
1767 &mut self.pool_fee_account,
1768 &mut Account::default(),
1769 ],
1770 )
1771 }
1772 }
1773
1774 fn mint_minimum_balance() -> u64 {
1775 Rent::default().minimum_balance(gpl_token::state::Mint::get_packed_len())
1776 }
1777
1778 fn account_minimum_balance() -> u64 {
1779 Rent::default().minimum_balance(gpl_token::state::Account::get_packed_len())
1780 }
1781
1782 fn do_process_instruction_with_fee_constraints(
1783 instruction: Instruction,
1784 accounts: Vec<&mut Account>,
1785 swap_constraints: &Option<SwapConstraints>,
1786 ) -> ProgramResult {
1787 test_syscall_stubs();
1788
1789 let mut account_clones = accounts.iter().map(|x| (*x).clone()).collect::<Vec<_>>();
1792 let mut meta = instruction
1793 .accounts
1794 .iter()
1795 .zip(account_clones.iter_mut())
1796 .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account))
1797 .collect::<Vec<_>>();
1798 let mut account_infos = create_is_signer_account_infos(&mut meta);
1799 let res = if instruction.program_id == SWAP_PROGRAM_ID {
1800 Processor::process_with_constraints(
1801 &instruction.program_id,
1802 &account_infos,
1803 &instruction.data,
1804 swap_constraints,
1805 )
1806 } else {
1807 gpl_token::processor::Processor::process(
1808 &instruction.program_id,
1809 &account_infos,
1810 &instruction.data,
1811 )
1812 };
1813
1814 if res.is_ok() {
1815 let mut account_metas = instruction
1816 .accounts
1817 .iter()
1818 .zip(accounts)
1819 .map(|(account_meta, account)| (&account_meta.pubkey, account))
1820 .collect::<Vec<_>>();
1821 for account_info in account_infos.iter_mut() {
1822 for account_meta in account_metas.iter_mut() {
1823 if account_info.key == account_meta.0 {
1824 let account = &mut account_meta.1;
1825 account.owner = *account_info.owner;
1826 account.carats = **account_info.carats.borrow();
1827 account.data = account_info.data.borrow().to_vec();
1828 }
1829 }
1830 }
1831 }
1832 res
1833 }
1834
1835 fn do_process_instruction(
1836 instruction: Instruction,
1837 accounts: Vec<&mut Account>,
1838 ) -> ProgramResult {
1839 do_process_instruction_with_fee_constraints(instruction, accounts, &SWAP_CONSTRAINTS)
1840 }
1841
1842 fn mint_token(
1843 program_id: &Pubkey,
1844 mint_key: &Pubkey,
1845 mut mint_account: &mut Account,
1846 mint_authority_key: &Pubkey,
1847 account_owner_key: &Pubkey,
1848 amount: u64,
1849 ) -> (Pubkey, Account) {
1850 let account_key = Pubkey::new_unique();
1851 let mut account_account = Account::new(
1852 account_minimum_balance(),
1853 gpl_token::state::Account::get_packed_len(),
1854 program_id,
1855 );
1856 let mut mint_authority_account = Account::default();
1857 let mut rent_sysvar_account = create_account_for_test(&Rent::free());
1858
1859 do_process_instruction(
1860 initialize_account(program_id, &account_key, mint_key, account_owner_key).unwrap(),
1861 vec![
1862 &mut account_account,
1863 &mut mint_account,
1864 &mut mint_authority_account,
1865 &mut rent_sysvar_account,
1866 ],
1867 )
1868 .unwrap();
1869
1870 if amount > 0 {
1871 do_process_instruction(
1872 mint_to(
1873 program_id,
1874 mint_key,
1875 &account_key,
1876 mint_authority_key,
1877 &[],
1878 amount,
1879 )
1880 .unwrap(),
1881 vec![
1882 &mut mint_account,
1883 &mut account_account,
1884 &mut mint_authority_account,
1885 ],
1886 )
1887 .unwrap();
1888 }
1889
1890 (account_key, account_account)
1891 }
1892
1893 fn create_mint(
1894 program_id: &Pubkey,
1895 authority_key: &Pubkey,
1896 freeze_authority: Option<&Pubkey>,
1897 ) -> (Pubkey, Account) {
1898 let mint_key = Pubkey::new_unique();
1899 let mut mint_account = Account::new(
1900 mint_minimum_balance(),
1901 gpl_token::state::Mint::get_packed_len(),
1902 program_id,
1903 );
1904 let mut rent_sysvar_account = create_account_for_test(&Rent::free());
1905
1906 do_process_instruction(
1907 initialize_mint(program_id, &mint_key, authority_key, freeze_authority, 2).unwrap(),
1908 vec![&mut mint_account, &mut rent_sysvar_account],
1909 )
1910 .unwrap();
1911
1912 (mint_key, mint_account)
1913 }
1914
1915 #[test]
1916 fn test_token_program_id_error() {
1917 test_syscall_stubs();
1918 let swap_key = Pubkey::new_unique();
1919 let mut mint = (Pubkey::new_unique(), Account::default());
1920 let mut destination = (Pubkey::new_unique(), Account::default());
1921 let token_program = (gpl_token::id(), Account::default());
1922 let (authority_key, bump_seed) =
1923 Pubkey::find_program_address(&[&swap_key.to_bytes()[..]], &SWAP_PROGRAM_ID);
1924 let mut authority = (authority_key, Account::default());
1925 let swap_bytes = swap_key.to_bytes();
1926 let authority_signature_seeds = [&swap_bytes[..32], &[bump_seed]];
1927 let signers = &[&authority_signature_seeds[..]];
1928 let ix = mint_to(
1929 &token_program.0,
1930 &mint.0,
1931 &destination.0,
1932 &authority.0,
1933 &[],
1934 10,
1935 )
1936 .unwrap();
1937 let mint = (&mut mint).into();
1938 let destination = (&mut destination).into();
1939 let authority = (&mut authority).into();
1940
1941 let err = invoke_signed(&ix, &[mint, destination, authority], signers).unwrap_err();
1942 assert_eq!(err, ProgramError::InvalidAccountData);
1943 }
1944
1945 #[test]
1946 fn test_initialize() {
1947 let user_key = Pubkey::new_unique();
1948 let trade_fee_numerator = 1;
1949 let trade_fee_denominator = 2;
1950 let owner_trade_fee_numerator = 1;
1951 let owner_trade_fee_denominator = 10;
1952 let owner_withdraw_fee_numerator = 1;
1953 let owner_withdraw_fee_denominator = 5;
1954 let host_fee_numerator = 20;
1955 let host_fee_denominator = 100;
1956 let fees = Fees {
1957 trade_fee_numerator,
1958 trade_fee_denominator,
1959 owner_trade_fee_numerator,
1960 owner_trade_fee_denominator,
1961 owner_withdraw_fee_numerator,
1962 owner_withdraw_fee_denominator,
1963 host_fee_numerator,
1964 host_fee_denominator,
1965 };
1966
1967 let token_a_amount = 1000;
1968 let token_b_amount = 2000;
1969 let pool_token_amount = 10;
1970 let curve_type = CurveType::ConstantProduct;
1971 let swap_curve = SwapCurve {
1972 curve_type,
1973 calculator: Box::new(ConstantProductCurve {}),
1974 };
1975
1976 let mut accounts =
1977 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
1978
1979 {
1981 let old_account = accounts.token_a_account;
1982 accounts.token_a_account = Account::new(0, 0, &gpl_token::id());
1983 assert_eq!(
1984 Err(SwapError::ExpectedAccount.into()),
1985 accounts.initialize_swap()
1986 );
1987 accounts.token_a_account = old_account;
1988 }
1989
1990 {
1992 let old_account = accounts.token_b_account;
1993 accounts.token_b_account = Account::new(0, 0, &gpl_token::id());
1994 assert_eq!(
1995 Err(SwapError::ExpectedAccount.into()),
1996 accounts.initialize_swap()
1997 );
1998 accounts.token_b_account = old_account;
1999 }
2000
2001 {
2003 let old_account = accounts.pool_mint_account;
2004 accounts.pool_mint_account = Account::new(0, 0, &gpl_token::id());
2005 assert_eq!(
2006 Err(SwapError::ExpectedMint.into()),
2007 accounts.initialize_swap()
2008 );
2009 accounts.pool_mint_account = old_account;
2010 }
2011
2012 {
2014 let (_token_a_key, token_a_account) = mint_token(
2015 &gpl_token::id(),
2016 &accounts.token_a_mint_key,
2017 &mut accounts.token_a_mint_account,
2018 &user_key,
2019 &user_key,
2020 0,
2021 );
2022 let old_account = accounts.token_a_account;
2023 accounts.token_a_account = token_a_account;
2024 assert_eq!(
2025 Err(SwapError::InvalidOwner.into()),
2026 accounts.initialize_swap()
2027 );
2028 accounts.token_a_account = old_account;
2029 }
2030
2031 {
2033 let (_token_b_key, token_b_account) = mint_token(
2034 &gpl_token::id(),
2035 &accounts.token_b_mint_key,
2036 &mut accounts.token_b_mint_account,
2037 &user_key,
2038 &user_key,
2039 0,
2040 );
2041 let old_account = accounts.token_b_account;
2042 accounts.token_b_account = token_b_account;
2043 assert_eq!(
2044 Err(SwapError::InvalidOwner.into()),
2045 accounts.initialize_swap()
2046 );
2047 accounts.token_b_account = old_account;
2048 }
2049
2050 {
2052 let (_pool_token_key, pool_token_account) = mint_token(
2053 &gpl_token::id(),
2054 &accounts.pool_mint_key,
2055 &mut accounts.pool_mint_account,
2056 &accounts.authority_key,
2057 &accounts.authority_key,
2058 0,
2059 );
2060 let old_account = accounts.pool_token_account;
2061 accounts.pool_token_account = pool_token_account;
2062 assert_eq!(
2063 Err(SwapError::InvalidOutputOwner.into()),
2064 accounts.initialize_swap()
2065 );
2066 accounts.pool_token_account = old_account;
2067 }
2068
2069 {
2071 let (_pool_fee_key, pool_fee_account) = mint_token(
2072 &gpl_token::id(),
2073 &accounts.pool_mint_key,
2074 &mut accounts.pool_mint_account,
2075 &accounts.authority_key,
2076 &accounts.authority_key,
2077 0,
2078 );
2079 let old_account = accounts.pool_fee_account;
2080 accounts.pool_fee_account = pool_fee_account;
2081 assert_eq!(
2082 Err(SwapError::InvalidOutputOwner.into()),
2083 accounts.initialize_swap()
2084 );
2085 accounts.pool_fee_account = old_account;
2086 }
2087
2088 {
2090 let (_pool_mint_key, pool_mint_account) =
2091 create_mint(&gpl_token::id(), &user_key, None);
2092 let old_mint = accounts.pool_mint_account;
2093 accounts.pool_mint_account = pool_mint_account;
2094 assert_eq!(
2095 Err(SwapError::InvalidOwner.into()),
2096 accounts.initialize_swap()
2097 );
2098 accounts.pool_mint_account = old_mint;
2099 }
2100
2101 {
2103 let (_pool_mint_key, pool_mint_account) =
2104 create_mint(&gpl_token::id(), &accounts.authority_key, Some(&user_key));
2105 let old_mint = accounts.pool_mint_account;
2106 accounts.pool_mint_account = pool_mint_account;
2107 assert_eq!(
2108 Err(SwapError::InvalidFreezeAuthority.into()),
2109 accounts.initialize_swap()
2110 );
2111 accounts.pool_mint_account = old_mint;
2112 }
2113
2114 {
2116 let (_token_a_key, mut token_a_account) = mint_token(
2117 &gpl_token::id(),
2118 &accounts.token_a_mint_key,
2119 &mut accounts.token_a_mint_account,
2120 &user_key,
2121 &accounts.authority_key,
2122 token_a_amount,
2123 );
2124 token_a_account.owner = SWAP_PROGRAM_ID;
2125 let old_account = accounts.token_a_account;
2126 accounts.token_a_account = token_a_account;
2127 assert_eq!(
2128 Err(SwapError::IncorrectTokenProgramId.into()),
2129 accounts.initialize_swap()
2130 );
2131 accounts.token_a_account = old_account;
2132 }
2133
2134 {
2136 let (_token_b_key, mut token_b_account) = mint_token(
2137 &gpl_token::id(),
2138 &accounts.token_b_mint_key,
2139 &mut accounts.token_b_mint_account,
2140 &user_key,
2141 &accounts.authority_key,
2142 token_b_amount,
2143 );
2144 token_b_account.owner = SWAP_PROGRAM_ID;
2145 let old_account = accounts.token_b_account;
2146 accounts.token_b_account = token_b_account;
2147 assert_eq!(
2148 Err(SwapError::IncorrectTokenProgramId.into()),
2149 accounts.initialize_swap()
2150 );
2151 accounts.token_b_account = old_account;
2152 }
2153
2154 {
2156 let (_token_a_key, token_a_account) = mint_token(
2157 &gpl_token::id(),
2158 &accounts.token_a_mint_key,
2159 &mut accounts.token_a_mint_account,
2160 &user_key,
2161 &accounts.authority_key,
2162 0,
2163 );
2164 let old_account = accounts.token_a_account;
2165 accounts.token_a_account = token_a_account;
2166 assert_eq!(
2167 Err(SwapError::EmptySupply.into()),
2168 accounts.initialize_swap()
2169 );
2170 accounts.token_a_account = old_account;
2171 }
2172
2173 {
2175 let (_token_b_key, token_b_account) = mint_token(
2176 &gpl_token::id(),
2177 &accounts.token_b_mint_key,
2178 &mut accounts.token_b_mint_account,
2179 &user_key,
2180 &accounts.authority_key,
2181 0,
2182 );
2183 let old_account = accounts.token_b_account;
2184 accounts.token_b_account = token_b_account;
2185 assert_eq!(
2186 Err(SwapError::EmptySupply.into()),
2187 accounts.initialize_swap()
2188 );
2189 accounts.token_b_account = old_account;
2190 }
2191
2192 {
2194 let old_mint = accounts.pool_mint_account;
2195 let old_pool_account = accounts.pool_token_account;
2196
2197 let (_pool_mint_key, pool_mint_account) =
2198 create_mint(&gpl_token::id(), &accounts.authority_key, None);
2199 accounts.pool_mint_account = pool_mint_account;
2200
2201 let (_empty_pool_token_key, empty_pool_token_account) = mint_token(
2202 &gpl_token::id(),
2203 &accounts.pool_mint_key,
2204 &mut accounts.pool_mint_account,
2205 &accounts.authority_key,
2206 &user_key,
2207 0,
2208 );
2209
2210 let (_pool_token_key, pool_token_account) = mint_token(
2211 &gpl_token::id(),
2212 &accounts.pool_mint_key,
2213 &mut accounts.pool_mint_account,
2214 &accounts.authority_key,
2215 &user_key,
2216 pool_token_amount,
2217 );
2218
2219 accounts.pool_token_account = pool_token_account;
2221 assert_eq!(
2222 Err(SwapError::InvalidSupply.into()),
2223 accounts.initialize_swap()
2224 );
2225
2226 accounts.pool_token_account = empty_pool_token_account;
2228 assert_eq!(
2229 Err(SwapError::InvalidSupply.into()),
2230 accounts.initialize_swap()
2231 );
2232
2233 accounts.pool_mint_account = old_mint;
2234 accounts.pool_token_account = old_pool_account;
2235 }
2236
2237 {
2239 let (_pool_fee_key, pool_fee_account) = mint_token(
2240 &gpl_token::id(),
2241 &accounts.token_a_mint_key,
2242 &mut accounts.token_a_mint_account,
2243 &user_key,
2244 &user_key,
2245 0,
2246 );
2247 let old_account = accounts.pool_fee_account;
2248 accounts.pool_fee_account = pool_fee_account;
2249 assert_eq!(
2250 Err(SwapError::IncorrectPoolMint.into()),
2251 accounts.initialize_swap()
2252 );
2253 accounts.pool_fee_account = old_account;
2254 }
2255
2256 {
2258 do_process_instruction(
2259 approve(
2260 &gpl_token::id(),
2261 &accounts.token_a_key,
2262 &user_key,
2263 &accounts.authority_key,
2264 &[],
2265 1,
2266 )
2267 .unwrap(),
2268 vec![
2269 &mut accounts.token_a_account,
2270 &mut Account::default(),
2271 &mut Account::default(),
2272 ],
2273 )
2274 .unwrap();
2275 assert_eq!(
2276 Err(SwapError::InvalidDelegate.into()),
2277 accounts.initialize_swap()
2278 );
2279
2280 do_process_instruction(
2281 revoke(
2282 &gpl_token::id(),
2283 &accounts.token_a_key,
2284 &accounts.authority_key,
2285 &[],
2286 )
2287 .unwrap(),
2288 vec![&mut accounts.token_a_account, &mut Account::default()],
2289 )
2290 .unwrap();
2291 }
2292
2293 {
2295 do_process_instruction(
2296 approve(
2297 &gpl_token::id(),
2298 &accounts.token_b_key,
2299 &user_key,
2300 &accounts.authority_key,
2301 &[],
2302 1,
2303 )
2304 .unwrap(),
2305 vec![
2306 &mut accounts.token_b_account,
2307 &mut Account::default(),
2308 &mut Account::default(),
2309 ],
2310 )
2311 .unwrap();
2312 assert_eq!(
2313 Err(SwapError::InvalidDelegate.into()),
2314 accounts.initialize_swap()
2315 );
2316
2317 do_process_instruction(
2318 revoke(
2319 &gpl_token::id(),
2320 &accounts.token_b_key,
2321 &accounts.authority_key,
2322 &[],
2323 )
2324 .unwrap(),
2325 vec![&mut accounts.token_b_account, &mut Account::default()],
2326 )
2327 .unwrap();
2328 }
2329
2330 {
2332 do_process_instruction(
2333 set_authority(
2334 &gpl_token::id(),
2335 &accounts.token_a_key,
2336 Some(&user_key),
2337 AuthorityType::CloseAccount,
2338 &accounts.authority_key,
2339 &[],
2340 )
2341 .unwrap(),
2342 vec![&mut accounts.token_a_account, &mut Account::default()],
2343 )
2344 .unwrap();
2345 assert_eq!(
2346 Err(SwapError::InvalidCloseAuthority.into()),
2347 accounts.initialize_swap()
2348 );
2349
2350 do_process_instruction(
2351 set_authority(
2352 &gpl_token::id(),
2353 &accounts.token_a_key,
2354 None,
2355 AuthorityType::CloseAccount,
2356 &user_key,
2357 &[],
2358 )
2359 .unwrap(),
2360 vec![&mut accounts.token_a_account, &mut Account::default()],
2361 )
2362 .unwrap();
2363 }
2364
2365 {
2367 do_process_instruction(
2368 set_authority(
2369 &gpl_token::id(),
2370 &accounts.token_b_key,
2371 Some(&user_key),
2372 AuthorityType::CloseAccount,
2373 &accounts.authority_key,
2374 &[],
2375 )
2376 .unwrap(),
2377 vec![&mut accounts.token_b_account, &mut Account::default()],
2378 )
2379 .unwrap();
2380 assert_eq!(
2381 Err(SwapError::InvalidCloseAuthority.into()),
2382 accounts.initialize_swap()
2383 );
2384
2385 do_process_instruction(
2386 set_authority(
2387 &gpl_token::id(),
2388 &accounts.token_b_key,
2389 None,
2390 AuthorityType::CloseAccount,
2391 &user_key,
2392 &[],
2393 )
2394 .unwrap(),
2395 vec![&mut accounts.token_b_account, &mut Account::default()],
2396 )
2397 .unwrap();
2398 }
2399
2400 {
2402 let wrong_program_id = Pubkey::new_unique();
2403 assert_eq!(
2404 Err(SwapError::IncorrectTokenProgramId.into()),
2405 do_process_instruction(
2406 initialize(
2407 &SWAP_PROGRAM_ID,
2408 &wrong_program_id,
2409 &accounts.swap_key,
2410 &accounts.authority_key,
2411 &accounts.token_a_key,
2412 &accounts.token_b_key,
2413 &accounts.pool_mint_key,
2414 &accounts.pool_fee_key,
2415 &accounts.pool_token_key,
2416 accounts.fees.clone(),
2417 accounts.swap_curve.clone(),
2418 )
2419 .unwrap(),
2420 vec![
2421 &mut accounts.swap_account,
2422 &mut Account::default(),
2423 &mut accounts.token_a_account,
2424 &mut accounts.token_b_account,
2425 &mut accounts.pool_mint_account,
2426 &mut accounts.pool_fee_account,
2427 &mut accounts.pool_token_account,
2428 &mut Account::default(),
2429 ],
2430 )
2431 );
2432 }
2433
2434 {
2436 let (_token_a_repeat_key, token_a_repeat_account) = mint_token(
2437 &gpl_token::id(),
2438 &accounts.token_a_mint_key,
2439 &mut accounts.token_a_mint_account,
2440 &user_key,
2441 &accounts.authority_key,
2442 10,
2443 );
2444 let old_account = accounts.token_b_account;
2445 accounts.token_b_account = token_a_repeat_account;
2446 assert_eq!(
2447 Err(SwapError::RepeatedMint.into()),
2448 accounts.initialize_swap()
2449 );
2450 accounts.token_b_account = old_account;
2451 }
2452
2453 accounts.initialize_swap().unwrap();
2455
2456 {
2458 let token_b_price = 0;
2459 let fees = Fees {
2460 trade_fee_numerator,
2461 trade_fee_denominator,
2462 owner_trade_fee_numerator,
2463 owner_trade_fee_denominator,
2464 owner_withdraw_fee_numerator,
2465 owner_withdraw_fee_denominator,
2466 host_fee_numerator,
2467 host_fee_denominator,
2468 };
2469 let swap_curve = SwapCurve {
2470 curve_type: CurveType::ConstantPrice,
2471 calculator: Box::new(ConstantPriceCurve { token_b_price }),
2472 };
2473 let mut accounts =
2474 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
2475 assert_eq!(
2476 Err(SwapError::InvalidCurve.into()),
2477 accounts.initialize_swap()
2478 );
2479 }
2480
2481 {
2483 let fees = Fees {
2484 trade_fee_numerator,
2485 trade_fee_denominator,
2486 owner_trade_fee_numerator,
2487 owner_trade_fee_denominator,
2488 owner_withdraw_fee_numerator,
2489 owner_withdraw_fee_denominator,
2490 host_fee_numerator,
2491 host_fee_denominator,
2492 };
2493 let token_b_price = 10_000;
2494 let swap_curve = SwapCurve {
2495 curve_type: CurveType::ConstantPrice,
2496 calculator: Box::new(ConstantPriceCurve { token_b_price }),
2497 };
2498 let mut accounts =
2499 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
2500 accounts.initialize_swap().unwrap();
2501 }
2502
2503 {
2505 let token_b_offset = 0;
2506 let fees = Fees {
2507 trade_fee_numerator,
2508 trade_fee_denominator,
2509 owner_trade_fee_numerator,
2510 owner_trade_fee_denominator,
2511 owner_withdraw_fee_numerator,
2512 owner_withdraw_fee_denominator,
2513 host_fee_numerator,
2514 host_fee_denominator,
2515 };
2516 let swap_curve = SwapCurve {
2517 curve_type: CurveType::Offset,
2518 calculator: Box::new(OffsetCurve { token_b_offset }),
2519 };
2520 let mut accounts =
2521 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
2522 assert_eq!(
2523 Err(SwapError::InvalidCurve.into()),
2524 accounts.initialize_swap()
2525 );
2526 }
2527
2528 {
2530 let token_b_offset = 10;
2531 let fees = Fees {
2532 trade_fee_numerator,
2533 trade_fee_denominator,
2534 owner_trade_fee_numerator,
2535 owner_trade_fee_denominator,
2536 owner_withdraw_fee_numerator,
2537 owner_withdraw_fee_denominator,
2538 host_fee_numerator,
2539 host_fee_denominator,
2540 };
2541 let swap_curve = SwapCurve {
2542 curve_type: CurveType::Offset,
2543 calculator: Box::new(OffsetCurve { token_b_offset }),
2544 };
2545 let mut accounts =
2546 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
2547 accounts.initialize_swap().unwrap();
2548 }
2549
2550 {
2552 let new_key = Pubkey::new_unique();
2553 let trade_fee_numerator = 25;
2554 let trade_fee_denominator = 10000;
2555 let owner_trade_fee_numerator = 5;
2556 let owner_trade_fee_denominator = 10000;
2557 let host_fee_numerator = 20;
2558 let host_fee_denominator = 100;
2559 let fees = Fees {
2560 trade_fee_numerator,
2561 trade_fee_denominator,
2562 owner_trade_fee_numerator,
2563 owner_trade_fee_denominator,
2564 owner_withdraw_fee_numerator,
2565 owner_withdraw_fee_denominator,
2566 host_fee_numerator,
2567 host_fee_denominator,
2568 };
2569 let curve = ConstantProductCurve {};
2570 let swap_curve = SwapCurve {
2571 curve_type: CurveType::ConstantProduct,
2572 calculator: Box::new(curve),
2573 };
2574 let owner_key = &new_key.to_string();
2575 let valid_curve_types = &[CurveType::ConstantProduct];
2576 let constraints = Some(SwapConstraints {
2577 owner_key,
2578 valid_curve_types,
2579 fees: &fees,
2580 });
2581 let mut accounts = SwapAccountInfo::new(
2582 &user_key,
2583 fees.clone(),
2584 swap_curve,
2585 token_a_amount,
2586 token_b_amount,
2587 );
2588 assert_eq!(
2589 Err(SwapError::InvalidOwner.into()),
2590 do_process_instruction_with_fee_constraints(
2591 initialize(
2592 &SWAP_PROGRAM_ID,
2593 &gpl_token::id(),
2594 &accounts.swap_key,
2595 &accounts.authority_key,
2596 &accounts.token_a_key,
2597 &accounts.token_b_key,
2598 &accounts.pool_mint_key,
2599 &accounts.pool_fee_key,
2600 &accounts.pool_token_key,
2601 accounts.fees.clone(),
2602 accounts.swap_curve.clone(),
2603 )
2604 .unwrap(),
2605 vec![
2606 &mut accounts.swap_account,
2607 &mut Account::default(),
2608 &mut accounts.token_a_account,
2609 &mut accounts.token_b_account,
2610 &mut accounts.pool_mint_account,
2611 &mut accounts.pool_fee_account,
2612 &mut accounts.pool_token_account,
2613 &mut Account::default(),
2614 ],
2615 &constraints,
2616 )
2617 );
2618 }
2619
2620 {
2622 let trade_fee_numerator = 25;
2623 let trade_fee_denominator = 10000;
2624 let owner_trade_fee_numerator = 5;
2625 let owner_trade_fee_denominator = 10000;
2626 let host_fee_numerator = 20;
2627 let host_fee_denominator = 100;
2628 let fees = Fees {
2629 trade_fee_numerator,
2630 trade_fee_denominator,
2631 owner_trade_fee_numerator,
2632 owner_trade_fee_denominator,
2633 owner_withdraw_fee_numerator,
2634 owner_withdraw_fee_denominator,
2635 host_fee_numerator,
2636 host_fee_denominator,
2637 };
2638 let curve = ConstantProductCurve {};
2639 let swap_curve = SwapCurve {
2640 curve_type: CurveType::ConstantProduct,
2641 calculator: Box::new(curve),
2642 };
2643 let owner_key = &user_key.to_string();
2644 let valid_curve_types = &[CurveType::ConstantProduct];
2645 let constraints = Some(SwapConstraints {
2646 owner_key,
2647 valid_curve_types,
2648 fees: &fees,
2649 });
2650 let mut bad_fees = fees.clone();
2651 bad_fees.trade_fee_numerator = trade_fee_numerator - 1;
2652 let mut accounts = SwapAccountInfo::new(
2653 &user_key,
2654 bad_fees,
2655 swap_curve,
2656 token_a_amount,
2657 token_b_amount,
2658 );
2659 assert_eq!(
2660 Err(SwapError::InvalidFee.into()),
2661 do_process_instruction_with_fee_constraints(
2662 initialize(
2663 &SWAP_PROGRAM_ID,
2664 &gpl_token::id(),
2665 &accounts.swap_key,
2666 &accounts.authority_key,
2667 &accounts.token_a_key,
2668 &accounts.token_b_key,
2669 &accounts.pool_mint_key,
2670 &accounts.pool_fee_key,
2671 &accounts.pool_token_key,
2672 accounts.fees.clone(),
2673 accounts.swap_curve.clone(),
2674 )
2675 .unwrap(),
2676 vec![
2677 &mut accounts.swap_account,
2678 &mut Account::default(),
2679 &mut accounts.token_a_account,
2680 &mut accounts.token_b_account,
2681 &mut accounts.pool_mint_account,
2682 &mut accounts.pool_fee_account,
2683 &mut accounts.pool_token_account,
2684 &mut Account::default(),
2685 ],
2686 &constraints,
2687 )
2688 );
2689 }
2690
2691 {
2693 let trade_fee_numerator = 25;
2694 let trade_fee_denominator = 10000;
2695 let owner_trade_fee_numerator = 5;
2696 let owner_trade_fee_denominator = 10000;
2697 let host_fee_numerator = 20;
2698 let host_fee_denominator = 100;
2699 let fees = Fees {
2700 trade_fee_numerator,
2701 trade_fee_denominator,
2702 owner_trade_fee_numerator,
2703 owner_trade_fee_denominator,
2704 owner_withdraw_fee_numerator,
2705 owner_withdraw_fee_denominator,
2706 host_fee_numerator,
2707 host_fee_denominator,
2708 };
2709 let curve = ConstantProductCurve {};
2710 let swap_curve = SwapCurve {
2711 curve_type: CurveType::ConstantProduct,
2712 calculator: Box::new(curve),
2713 };
2714 let owner_key = &user_key.to_string();
2715 let valid_curve_types = &[CurveType::ConstantProduct];
2716 let constraints = Some(SwapConstraints {
2717 owner_key,
2718 valid_curve_types,
2719 fees: &fees,
2720 });
2721 let mut accounts = SwapAccountInfo::new(
2722 &user_key,
2723 fees.clone(),
2724 swap_curve,
2725 token_a_amount,
2726 token_b_amount,
2727 );
2728 do_process_instruction_with_fee_constraints(
2729 initialize(
2730 &SWAP_PROGRAM_ID,
2731 &gpl_token::id(),
2732 &accounts.swap_key,
2733 &accounts.authority_key,
2734 &accounts.token_a_key,
2735 &accounts.token_b_key,
2736 &accounts.pool_mint_key,
2737 &accounts.pool_fee_key,
2738 &accounts.pool_token_key,
2739 accounts.fees,
2740 accounts.swap_curve.clone(),
2741 )
2742 .unwrap(),
2743 vec![
2744 &mut accounts.swap_account,
2745 &mut Account::default(),
2746 &mut accounts.token_a_account,
2747 &mut accounts.token_b_account,
2748 &mut accounts.pool_mint_account,
2749 &mut accounts.pool_fee_account,
2750 &mut accounts.pool_token_account,
2751 &mut Account::default(),
2752 ],
2753 &constraints,
2754 )
2755 .unwrap();
2756 }
2757
2758 {
2760 assert_eq!(
2761 Err(SwapError::AlreadyInUse.into()),
2762 accounts.initialize_swap()
2763 );
2764 }
2765 let swap_state = SwapVersion::unpack(&accounts.swap_account.data).unwrap();
2766 assert!(swap_state.is_initialized());
2767 assert_eq!(swap_state.bump_seed(), accounts.bump_seed);
2768 assert_eq!(
2769 swap_state.swap_curve().curve_type,
2770 accounts.swap_curve.curve_type
2771 );
2772 assert_eq!(*swap_state.token_a_account(), accounts.token_a_key);
2773 assert_eq!(*swap_state.token_b_account(), accounts.token_b_key);
2774 assert_eq!(*swap_state.pool_mint(), accounts.pool_mint_key);
2775 assert_eq!(*swap_state.token_a_mint(), accounts.token_a_mint_key);
2776 assert_eq!(*swap_state.token_b_mint(), accounts.token_b_mint_key);
2777 assert_eq!(*swap_state.pool_fee_account(), accounts.pool_fee_key);
2778 let token_a = gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
2779 assert_eq!(token_a.amount, token_a_amount);
2780 let token_b = gpl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap();
2781 assert_eq!(token_b.amount, token_b_amount);
2782 let pool_account =
2783 gpl_token::state::Account::unpack(&accounts.pool_token_account.data).unwrap();
2784 let pool_mint = gpl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap();
2785 assert_eq!(pool_mint.supply, pool_account.amount);
2786 }
2787
2788 #[test]
2789 fn test_deposit() {
2790 let user_key = Pubkey::new_unique();
2791 let depositor_key = Pubkey::new_unique();
2792 let trade_fee_numerator = 1;
2793 let trade_fee_denominator = 2;
2794 let owner_trade_fee_numerator = 1;
2795 let owner_trade_fee_denominator = 10;
2796 let owner_withdraw_fee_numerator = 1;
2797 let owner_withdraw_fee_denominator = 5;
2798 let host_fee_numerator = 20;
2799 let host_fee_denominator = 100;
2800
2801 let fees = Fees {
2802 trade_fee_numerator,
2803 trade_fee_denominator,
2804 owner_trade_fee_numerator,
2805 owner_trade_fee_denominator,
2806 owner_withdraw_fee_numerator,
2807 owner_withdraw_fee_denominator,
2808 host_fee_numerator,
2809 host_fee_denominator,
2810 };
2811
2812 let token_a_amount = 1000;
2813 let token_b_amount = 9000;
2814 let curve_type = CurveType::ConstantProduct;
2815 let swap_curve = SwapCurve {
2816 curve_type,
2817 calculator: Box::new(ConstantProductCurve {}),
2818 };
2819
2820 let mut accounts =
2821 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
2822
2823 let pool_amount = INITIAL_SWAP_POOL_AMOUNT / 10;
2826 let deposit_a = token_a_amount / 10;
2827 let deposit_b = token_b_amount / 10;
2828
2829 {
2831 let (
2832 token_a_key,
2833 mut token_a_account,
2834 token_b_key,
2835 mut token_b_account,
2836 pool_key,
2837 mut pool_account,
2838 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
2839 assert_eq!(
2840 Err(ProgramError::UninitializedAccount),
2841 accounts.deposit_all_token_types(
2842 &depositor_key,
2843 &token_a_key,
2844 &mut token_a_account,
2845 &token_b_key,
2846 &mut token_b_account,
2847 &pool_key,
2848 &mut pool_account,
2849 pool_amount.try_into().unwrap(),
2850 deposit_a,
2851 deposit_b,
2852 )
2853 );
2854 }
2855
2856 accounts.initialize_swap().unwrap();
2857
2858 {
2860 let (
2861 token_a_key,
2862 mut token_a_account,
2863 token_b_key,
2864 mut token_b_account,
2865 pool_key,
2866 mut pool_account,
2867 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
2868 let old_swap_account = accounts.swap_account;
2869 let mut wrong_swap_account = old_swap_account.clone();
2870 wrong_swap_account.owner = gpl_token::id();
2871 accounts.swap_account = wrong_swap_account;
2872 assert_eq!(
2873 Err(ProgramError::IncorrectProgramId),
2874 accounts.deposit_all_token_types(
2875 &depositor_key,
2876 &token_a_key,
2877 &mut token_a_account,
2878 &token_b_key,
2879 &mut token_b_account,
2880 &pool_key,
2881 &mut pool_account,
2882 pool_amount.try_into().unwrap(),
2883 deposit_a,
2884 deposit_b,
2885 )
2886 );
2887 accounts.swap_account = old_swap_account;
2888 }
2889
2890 {
2892 let (
2893 token_a_key,
2894 mut token_a_account,
2895 token_b_key,
2896 mut token_b_account,
2897 pool_key,
2898 mut pool_account,
2899 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
2900 let old_authority = accounts.authority_key;
2901 let (bad_authority_key, _bump_seed) = Pubkey::find_program_address(
2902 &[&accounts.swap_key.to_bytes()[..]],
2903 &gpl_token::id(),
2904 );
2905 accounts.authority_key = bad_authority_key;
2906 assert_eq!(
2907 Err(SwapError::InvalidProgramAddress.into()),
2908 accounts.deposit_all_token_types(
2909 &depositor_key,
2910 &token_a_key,
2911 &mut token_a_account,
2912 &token_b_key,
2913 &mut token_b_account,
2914 &pool_key,
2915 &mut pool_account,
2916 pool_amount.try_into().unwrap(),
2917 deposit_a,
2918 deposit_b,
2919 )
2920 );
2921 accounts.authority_key = old_authority;
2922 }
2923
2924 {
2926 let (
2927 token_a_key,
2928 mut token_a_account,
2929 token_b_key,
2930 mut token_b_account,
2931 pool_key,
2932 mut pool_account,
2933 ) = accounts.setup_token_accounts(
2934 &user_key,
2935 &depositor_key,
2936 deposit_a / 2,
2937 deposit_b,
2938 0,
2939 );
2940 assert_eq!(
2941 Err(TokenError::InsufficientFunds.into()),
2942 accounts.deposit_all_token_types(
2943 &depositor_key,
2944 &token_a_key,
2945 &mut token_a_account,
2946 &token_b_key,
2947 &mut token_b_account,
2948 &pool_key,
2949 &mut pool_account,
2950 pool_amount.try_into().unwrap(),
2951 deposit_a,
2952 deposit_b,
2953 )
2954 );
2955 }
2956
2957 {
2959 let (
2960 token_a_key,
2961 mut token_a_account,
2962 token_b_key,
2963 mut token_b_account,
2964 pool_key,
2965 mut pool_account,
2966 ) = accounts.setup_token_accounts(
2967 &user_key,
2968 &depositor_key,
2969 deposit_a,
2970 deposit_b / 2,
2971 0,
2972 );
2973 assert_eq!(
2974 Err(TokenError::InsufficientFunds.into()),
2975 accounts.deposit_all_token_types(
2976 &depositor_key,
2977 &token_a_key,
2978 &mut token_a_account,
2979 &token_b_key,
2980 &mut token_b_account,
2981 &pool_key,
2982 &mut pool_account,
2983 pool_amount.try_into().unwrap(),
2984 deposit_a,
2985 deposit_b,
2986 )
2987 );
2988 }
2989
2990 {
2992 let (
2993 token_a_key,
2994 mut token_a_account,
2995 token_b_key,
2996 mut token_b_account,
2997 pool_key,
2998 mut pool_account,
2999 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3000 assert_eq!(
3001 Err(TokenError::MintMismatch.into()),
3002 accounts.deposit_all_token_types(
3003 &depositor_key,
3004 &token_b_key,
3005 &mut token_b_account,
3006 &token_a_key,
3007 &mut token_a_account,
3008 &pool_key,
3009 &mut pool_account,
3010 pool_amount.try_into().unwrap(),
3011 deposit_a,
3012 deposit_b,
3013 )
3014 );
3015 }
3016
3017 {
3019 let (
3020 token_a_key,
3021 mut token_a_account,
3022 token_b_key,
3023 mut token_b_account,
3024 _pool_key,
3025 mut _pool_account,
3026 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3027 let (
3028 wrong_token_key,
3029 mut wrong_token_account,
3030 _token_b_key,
3031 mut _token_b_account,
3032 _pool_key,
3033 mut _pool_account,
3034 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3035 assert_eq!(
3036 Err(TokenError::MintMismatch.into()),
3037 accounts.deposit_all_token_types(
3038 &depositor_key,
3039 &token_a_key,
3040 &mut token_a_account,
3041 &token_b_key,
3042 &mut token_b_account,
3043 &wrong_token_key,
3044 &mut wrong_token_account,
3045 pool_amount.try_into().unwrap(),
3046 deposit_a,
3047 deposit_b,
3048 )
3049 );
3050 }
3051
3052 {
3054 let (
3055 token_a_key,
3056 mut token_a_account,
3057 token_b_key,
3058 mut token_b_account,
3059 pool_key,
3060 mut pool_account,
3061 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3062 let user_transfer_authority_key = Pubkey::new_unique();
3063 assert_eq!(
3064 Err(TokenError::OwnerMismatch.into()),
3065 do_process_instruction(
3066 deposit_all_token_types(
3067 &SWAP_PROGRAM_ID,
3068 &gpl_token::id(),
3069 &accounts.swap_key,
3070 &accounts.authority_key,
3071 &user_transfer_authority_key,
3072 &token_a_key,
3073 &token_b_key,
3074 &accounts.token_a_key,
3075 &accounts.token_b_key,
3076 &accounts.pool_mint_key,
3077 &pool_key,
3078 DepositAllTokenTypes {
3079 pool_token_amount: pool_amount.try_into().unwrap(),
3080 maximum_token_a_amount: deposit_a,
3081 maximum_token_b_amount: deposit_b,
3082 },
3083 )
3084 .unwrap(),
3085 vec![
3086 &mut accounts.swap_account,
3087 &mut Account::default(),
3088 &mut Account::default(),
3089 &mut token_a_account,
3090 &mut token_b_account,
3091 &mut accounts.token_a_account,
3092 &mut accounts.token_b_account,
3093 &mut accounts.pool_mint_account,
3094 &mut pool_account,
3095 &mut Account::default(),
3096 ],
3097 )
3098 );
3099 }
3100
3101 {
3103 let (
3104 token_a_key,
3105 mut token_a_account,
3106 token_b_key,
3107 mut token_b_account,
3108 pool_key,
3109 mut pool_account,
3110 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3111 let wrong_key = Pubkey::new_unique();
3112 assert_eq!(
3113 Err(SwapError::IncorrectTokenProgramId.into()),
3114 do_process_instruction(
3115 deposit_all_token_types(
3116 &SWAP_PROGRAM_ID,
3117 &wrong_key,
3118 &accounts.swap_key,
3119 &accounts.authority_key,
3120 &accounts.authority_key,
3121 &token_a_key,
3122 &token_b_key,
3123 &accounts.token_a_key,
3124 &accounts.token_b_key,
3125 &accounts.pool_mint_key,
3126 &pool_key,
3127 DepositAllTokenTypes {
3128 pool_token_amount: pool_amount.try_into().unwrap(),
3129 maximum_token_a_amount: deposit_a,
3130 maximum_token_b_amount: deposit_b,
3131 },
3132 )
3133 .unwrap(),
3134 vec![
3135 &mut accounts.swap_account,
3136 &mut Account::default(),
3137 &mut Account::default(),
3138 &mut token_a_account,
3139 &mut token_b_account,
3140 &mut accounts.token_a_account,
3141 &mut accounts.token_b_account,
3142 &mut accounts.pool_mint_account,
3143 &mut pool_account,
3144 &mut Account::default(),
3145 ],
3146 )
3147 );
3148 }
3149
3150 {
3152 let (
3153 token_a_key,
3154 mut token_a_account,
3155 token_b_key,
3156 mut token_b_account,
3157 pool_key,
3158 mut pool_account,
3159 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3160
3161 let old_a_key = accounts.token_a_key;
3162 let old_a_account = accounts.token_a_account;
3163
3164 accounts.token_a_key = token_a_key;
3165 accounts.token_a_account = token_a_account.clone();
3166
3167 assert_eq!(
3169 Err(SwapError::IncorrectSwapAccount.into()),
3170 accounts.deposit_all_token_types(
3171 &depositor_key,
3172 &token_a_key,
3173 &mut token_a_account,
3174 &token_b_key,
3175 &mut token_b_account,
3176 &pool_key,
3177 &mut pool_account,
3178 pool_amount.try_into().unwrap(),
3179 deposit_a,
3180 deposit_b,
3181 )
3182 );
3183
3184 accounts.token_a_key = old_a_key;
3185 accounts.token_a_account = old_a_account;
3186
3187 let old_b_key = accounts.token_b_key;
3188 let old_b_account = accounts.token_b_account;
3189
3190 accounts.token_b_key = token_b_key;
3191 accounts.token_b_account = token_b_account.clone();
3192
3193 assert_eq!(
3195 Err(SwapError::IncorrectSwapAccount.into()),
3196 accounts.deposit_all_token_types(
3197 &depositor_key,
3198 &token_a_key,
3199 &mut token_a_account,
3200 &token_b_key,
3201 &mut token_b_account,
3202 &pool_key,
3203 &mut pool_account,
3204 pool_amount.try_into().unwrap(),
3205 deposit_a,
3206 deposit_b,
3207 )
3208 );
3209
3210 accounts.token_b_key = old_b_key;
3211 accounts.token_b_account = old_b_account;
3212 }
3213
3214 {
3216 let (
3217 token_a_key,
3218 mut token_a_account,
3219 token_b_key,
3220 mut token_b_account,
3221 pool_key,
3222 mut pool_account,
3223 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3224 let (pool_mint_key, pool_mint_account) =
3225 create_mint(&gpl_token::id(), &accounts.authority_key, None);
3226 let old_pool_key = accounts.pool_mint_key;
3227 let old_pool_account = accounts.pool_mint_account;
3228 accounts.pool_mint_key = pool_mint_key;
3229 accounts.pool_mint_account = pool_mint_account;
3230
3231 assert_eq!(
3232 Err(SwapError::IncorrectPoolMint.into()),
3233 accounts.deposit_all_token_types(
3234 &depositor_key,
3235 &token_a_key,
3236 &mut token_a_account,
3237 &token_b_key,
3238 &mut token_b_account,
3239 &pool_key,
3240 &mut pool_account,
3241 pool_amount.try_into().unwrap(),
3242 deposit_a,
3243 deposit_b,
3244 )
3245 );
3246
3247 accounts.pool_mint_key = old_pool_key;
3248 accounts.pool_mint_account = old_pool_account;
3249 }
3250
3251 {
3253 let (
3254 token_a_key,
3255 mut token_a_account,
3256 token_b_key,
3257 mut token_b_account,
3258 pool_key,
3259 mut pool_account,
3260 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3261 assert_eq!(
3262 Err(SwapError::ZeroTradingTokens.into()),
3263 accounts.deposit_all_token_types(
3264 &depositor_key,
3265 &token_a_key,
3266 &mut token_a_account,
3267 &token_b_key,
3268 &mut token_b_account,
3269 &pool_key,
3270 &mut pool_account,
3271 1,
3272 deposit_a,
3273 deposit_b,
3274 )
3275 );
3276 }
3277
3278 {
3280 let (
3281 token_a_key,
3282 mut token_a_account,
3283 token_b_key,
3284 mut token_b_account,
3285 pool_key,
3286 mut pool_account,
3287 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3288 assert_eq!(
3290 Err(SwapError::ExceededSlippage.into()),
3291 accounts.deposit_all_token_types(
3292 &depositor_key,
3293 &token_a_key,
3294 &mut token_a_account,
3295 &token_b_key,
3296 &mut token_b_account,
3297 &pool_key,
3298 &mut pool_account,
3299 pool_amount.try_into().unwrap(),
3300 deposit_a / 10,
3301 deposit_b,
3302 )
3303 );
3304 assert_eq!(
3306 Err(SwapError::ExceededSlippage.into()),
3307 accounts.deposit_all_token_types(
3308 &depositor_key,
3309 &token_a_key,
3310 &mut token_a_account,
3311 &token_b_key,
3312 &mut token_b_account,
3313 &pool_key,
3314 &mut pool_account,
3315 pool_amount.try_into().unwrap(),
3316 deposit_a,
3317 deposit_b / 10,
3318 )
3319 );
3320 }
3321
3322 {
3324 let (
3325 _token_a_key,
3326 _token_a_account,
3327 _token_b_key,
3328 _token_b_account,
3329 pool_key,
3330 mut pool_account,
3331 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3332 let swap_token_a_key = accounts.token_a_key;
3333 let mut swap_token_a_account = accounts.get_token_account(&swap_token_a_key).clone();
3334 let swap_token_b_key = accounts.token_b_key;
3335 let mut swap_token_b_account = accounts.get_token_account(&swap_token_b_key).clone();
3336 let authority_key = accounts.authority_key;
3337 assert_eq!(
3338 Err(SwapError::InvalidInput.into()),
3339 accounts.deposit_all_token_types(
3340 &authority_key,
3341 &swap_token_a_key,
3342 &mut swap_token_a_account,
3343 &swap_token_b_key,
3344 &mut swap_token_b_account,
3345 &pool_key,
3346 &mut pool_account,
3347 pool_amount.try_into().unwrap(),
3348 deposit_a,
3349 deposit_b,
3350 )
3351 );
3352 }
3353
3354 {
3356 let (
3357 token_a_key,
3358 mut token_a_account,
3359 token_b_key,
3360 mut token_b_account,
3361 pool_key,
3362 mut pool_account,
3363 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
3364 accounts
3365 .deposit_all_token_types(
3366 &depositor_key,
3367 &token_a_key,
3368 &mut token_a_account,
3369 &token_b_key,
3370 &mut token_b_account,
3371 &pool_key,
3372 &mut pool_account,
3373 pool_amount.try_into().unwrap(),
3374 deposit_a,
3375 deposit_b,
3376 )
3377 .unwrap();
3378
3379 let swap_token_a =
3380 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
3381 assert_eq!(swap_token_a.amount, deposit_a + token_a_amount);
3382 let swap_token_b =
3383 gpl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap();
3384 assert_eq!(swap_token_b.amount, deposit_b + token_b_amount);
3385 let token_a = gpl_token::state::Account::unpack(&token_a_account.data).unwrap();
3386 assert_eq!(token_a.amount, 0);
3387 let token_b = gpl_token::state::Account::unpack(&token_b_account.data).unwrap();
3388 assert_eq!(token_b.amount, 0);
3389 let pool_account = gpl_token::state::Account::unpack(&pool_account.data).unwrap();
3390 let swap_pool_account =
3391 gpl_token::state::Account::unpack(&accounts.pool_token_account.data).unwrap();
3392 let pool_mint =
3393 gpl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap();
3394 assert_eq!(
3395 pool_mint.supply,
3396 pool_account.amount + swap_pool_account.amount
3397 );
3398 }
3399 }
3400
3401 #[test]
3402 fn test_withdraw() {
3403 let user_key = Pubkey::new_unique();
3404 let trade_fee_numerator = 1;
3405 let trade_fee_denominator = 2;
3406 let owner_trade_fee_numerator = 1;
3407 let owner_trade_fee_denominator = 10;
3408 let owner_withdraw_fee_numerator = 1;
3409 let owner_withdraw_fee_denominator = 5;
3410 let host_fee_numerator = 7;
3411 let host_fee_denominator = 100;
3412
3413 let fees = Fees {
3414 trade_fee_numerator,
3415 trade_fee_denominator,
3416 owner_trade_fee_numerator,
3417 owner_trade_fee_denominator,
3418 owner_withdraw_fee_numerator,
3419 owner_withdraw_fee_denominator,
3420 host_fee_numerator,
3421 host_fee_denominator,
3422 };
3423
3424 let token_a_amount = 1000;
3425 let token_b_amount = 2000;
3426 let curve_type = CurveType::ConstantProduct;
3427 let swap_curve = SwapCurve {
3428 curve_type,
3429 calculator: Box::new(ConstantProductCurve {}),
3430 };
3431
3432 let withdrawer_key = Pubkey::new_unique();
3433 let initial_a = token_a_amount / 10;
3434 let initial_b = token_b_amount / 10;
3435 let initial_pool = swap_curve.calculator.new_pool_supply() / 10;
3436 let withdraw_amount = initial_pool / 4;
3437 let minimum_token_a_amount = initial_a / 40;
3438 let minimum_token_b_amount = initial_b / 40;
3439
3440 let mut accounts =
3441 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
3442
3443 {
3445 let (
3446 token_a_key,
3447 mut token_a_account,
3448 token_b_key,
3449 mut token_b_account,
3450 pool_key,
3451 mut pool_account,
3452 ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, initial_a, initial_b, 0);
3453 assert_eq!(
3454 Err(ProgramError::UninitializedAccount),
3455 accounts.withdraw_all_token_types(
3456 &withdrawer_key,
3457 &pool_key,
3458 &mut pool_account,
3459 &token_a_key,
3460 &mut token_a_account,
3461 &token_b_key,
3462 &mut token_b_account,
3463 withdraw_amount.try_into().unwrap(),
3464 minimum_token_a_amount,
3465 minimum_token_b_amount,
3466 )
3467 );
3468 }
3469
3470 accounts.initialize_swap().unwrap();
3471
3472 {
3474 let (
3475 token_a_key,
3476 mut token_a_account,
3477 token_b_key,
3478 mut token_b_account,
3479 pool_key,
3480 mut pool_account,
3481 ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, initial_a, initial_b, 0);
3482 let old_swap_account = accounts.swap_account;
3483 let mut wrong_swap_account = old_swap_account.clone();
3484 wrong_swap_account.owner = gpl_token::id();
3485 accounts.swap_account = wrong_swap_account;
3486 assert_eq!(
3487 Err(ProgramError::IncorrectProgramId),
3488 accounts.withdraw_all_token_types(
3489 &withdrawer_key,
3490 &pool_key,
3491 &mut pool_account,
3492 &token_a_key,
3493 &mut token_a_account,
3494 &token_b_key,
3495 &mut token_b_account,
3496 withdraw_amount.try_into().unwrap(),
3497 minimum_token_a_amount,
3498 minimum_token_b_amount,
3499 )
3500 );
3501 accounts.swap_account = old_swap_account;
3502 }
3503
3504 {
3506 let (
3507 token_a_key,
3508 mut token_a_account,
3509 token_b_key,
3510 mut token_b_account,
3511 pool_key,
3512 mut pool_account,
3513 ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, initial_a, initial_b, 0);
3514 let old_authority = accounts.authority_key;
3515 let (bad_authority_key, _bump_seed) = Pubkey::find_program_address(
3516 &[&accounts.swap_key.to_bytes()[..]],
3517 &gpl_token::id(),
3518 );
3519 accounts.authority_key = bad_authority_key;
3520 assert_eq!(
3521 Err(SwapError::InvalidProgramAddress.into()),
3522 accounts.withdraw_all_token_types(
3523 &withdrawer_key,
3524 &pool_key,
3525 &mut pool_account,
3526 &token_a_key,
3527 &mut token_a_account,
3528 &token_b_key,
3529 &mut token_b_account,
3530 withdraw_amount.try_into().unwrap(),
3531 minimum_token_a_amount,
3532 minimum_token_b_amount,
3533 )
3534 );
3535 accounts.authority_key = old_authority;
3536 }
3537
3538 {
3540 let (
3541 token_a_key,
3542 mut token_a_account,
3543 token_b_key,
3544 mut token_b_account,
3545 pool_key,
3546 mut pool_account,
3547 ) = accounts.setup_token_accounts(
3548 &user_key,
3549 &withdrawer_key,
3550 initial_a,
3551 initial_b,
3552 to_u64(withdraw_amount).unwrap() / 2u64,
3553 );
3554 assert_eq!(
3555 Err(TokenError::InsufficientFunds.into()),
3556 accounts.withdraw_all_token_types(
3557 &withdrawer_key,
3558 &pool_key,
3559 &mut pool_account,
3560 &token_a_key,
3561 &mut token_a_account,
3562 &token_b_key,
3563 &mut token_b_account,
3564 withdraw_amount.try_into().unwrap(),
3565 minimum_token_a_amount / 2,
3566 minimum_token_b_amount / 2,
3567 )
3568 );
3569 }
3570
3571 {
3573 let (
3574 token_a_key,
3575 mut token_a_account,
3576 token_b_key,
3577 mut token_b_account,
3578 pool_key,
3579 mut pool_account,
3580 ) = accounts.setup_token_accounts(
3581 &user_key,
3582 &withdrawer_key,
3583 initial_a,
3584 initial_b,
3585 withdraw_amount.try_into().unwrap(),
3586 );
3587 assert_eq!(
3588 Err(TokenError::MintMismatch.into()),
3589 accounts.withdraw_all_token_types(
3590 &withdrawer_key,
3591 &pool_key,
3592 &mut pool_account,
3593 &token_b_key,
3594 &mut token_b_account,
3595 &token_a_key,
3596 &mut token_a_account,
3597 withdraw_amount.try_into().unwrap(),
3598 minimum_token_a_amount,
3599 minimum_token_b_amount,
3600 )
3601 );
3602 }
3603
3604 {
3606 let (
3607 token_a_key,
3608 mut token_a_account,
3609 token_b_key,
3610 mut token_b_account,
3611 _pool_key,
3612 _pool_account,
3613 ) = accounts.setup_token_accounts(
3614 &user_key,
3615 &withdrawer_key,
3616 initial_a,
3617 initial_b,
3618 withdraw_amount.try_into().unwrap(),
3619 );
3620 let (
3621 wrong_token_a_key,
3622 mut wrong_token_a_account,
3623 _token_b_key,
3624 _token_b_account,
3625 _pool_key,
3626 _pool_account,
3627 ) = accounts.setup_token_accounts(
3628 &user_key,
3629 &withdrawer_key,
3630 withdraw_amount.try_into().unwrap(),
3631 initial_b,
3632 withdraw_amount.try_into().unwrap(),
3633 );
3634 assert_eq!(
3635 Err(TokenError::MintMismatch.into()),
3636 accounts.withdraw_all_token_types(
3637 &withdrawer_key,
3638 &wrong_token_a_key,
3639 &mut wrong_token_a_account,
3640 &token_a_key,
3641 &mut token_a_account,
3642 &token_b_key,
3643 &mut token_b_account,
3644 withdraw_amount.try_into().unwrap(),
3645 minimum_token_a_amount,
3646 minimum_token_b_amount,
3647 )
3648 );
3649 }
3650
3651 {
3653 let (
3654 token_a_key,
3655 mut token_a_account,
3656 token_b_key,
3657 mut token_b_account,
3658 wrong_pool_key,
3659 wrong_pool_account,
3660 ) = accounts.setup_token_accounts(
3661 &user_key,
3662 &withdrawer_key,
3663 initial_a,
3664 initial_b,
3665 withdraw_amount.try_into().unwrap(),
3666 );
3667 let (
3668 _token_a_key,
3669 _token_a_account,
3670 _token_b_key,
3671 _token_b_account,
3672 pool_key,
3673 mut pool_account,
3674 ) = accounts.setup_token_accounts(
3675 &user_key,
3676 &withdrawer_key,
3677 initial_a,
3678 initial_b,
3679 withdraw_amount.try_into().unwrap(),
3680 );
3681 let old_pool_fee_account = accounts.pool_fee_account;
3682 let old_pool_fee_key = accounts.pool_fee_key;
3683 accounts.pool_fee_account = wrong_pool_account;
3684 accounts.pool_fee_key = wrong_pool_key;
3685 assert_eq!(
3686 Err(SwapError::IncorrectFeeAccount.into()),
3687 accounts.withdraw_all_token_types(
3688 &withdrawer_key,
3689 &pool_key,
3690 &mut pool_account,
3691 &token_a_key,
3692 &mut token_a_account,
3693 &token_b_key,
3694 &mut token_b_account,
3695 withdraw_amount.try_into().unwrap(),
3696 minimum_token_a_amount,
3697 minimum_token_b_amount,
3698 ),
3699 );
3700 accounts.pool_fee_account = old_pool_fee_account;
3701 accounts.pool_fee_key = old_pool_fee_key;
3702 }
3703
3704 {
3706 let (
3707 token_a_key,
3708 mut token_a_account,
3709 token_b_key,
3710 mut token_b_account,
3711 pool_key,
3712 mut pool_account,
3713 ) = accounts.setup_token_accounts(
3714 &user_key,
3715 &withdrawer_key,
3716 0,
3717 0,
3718 withdraw_amount.try_into().unwrap(),
3719 );
3720 let user_transfer_authority_key = Pubkey::new_unique();
3721 assert_eq!(
3722 Err(TokenError::OwnerMismatch.into()),
3723 do_process_instruction(
3724 withdraw_all_token_types(
3725 &SWAP_PROGRAM_ID,
3726 &gpl_token::id(),
3727 &accounts.swap_key,
3728 &accounts.authority_key,
3729 &user_transfer_authority_key,
3730 &accounts.pool_mint_key,
3731 &accounts.pool_fee_key,
3732 &pool_key,
3733 &accounts.token_a_key,
3734 &accounts.token_b_key,
3735 &token_a_key,
3736 &token_b_key,
3737 WithdrawAllTokenTypes {
3738 pool_token_amount: withdraw_amount.try_into().unwrap(),
3739 minimum_token_a_amount,
3740 minimum_token_b_amount,
3741 }
3742 )
3743 .unwrap(),
3744 vec![
3745 &mut accounts.swap_account,
3746 &mut Account::default(),
3747 &mut Account::default(),
3748 &mut accounts.pool_mint_account,
3749 &mut pool_account,
3750 &mut accounts.token_a_account,
3751 &mut accounts.token_b_account,
3752 &mut token_a_account,
3753 &mut token_b_account,
3754 &mut accounts.pool_fee_account,
3755 &mut Account::default(),
3756 ],
3757 )
3758 );
3759 }
3760
3761 {
3763 let (
3764 token_a_key,
3765 mut token_a_account,
3766 token_b_key,
3767 mut token_b_account,
3768 pool_key,
3769 mut pool_account,
3770 ) = accounts.setup_token_accounts(
3771 &user_key,
3772 &withdrawer_key,
3773 initial_a,
3774 initial_b,
3775 withdraw_amount.try_into().unwrap(),
3776 );
3777 let wrong_key = Pubkey::new_unique();
3778 assert_eq!(
3779 Err(SwapError::IncorrectTokenProgramId.into()),
3780 do_process_instruction(
3781 withdraw_all_token_types(
3782 &SWAP_PROGRAM_ID,
3783 &wrong_key,
3784 &accounts.swap_key,
3785 &accounts.authority_key,
3786 &accounts.authority_key,
3787 &accounts.pool_mint_key,
3788 &accounts.pool_fee_key,
3789 &pool_key,
3790 &accounts.token_a_key,
3791 &accounts.token_b_key,
3792 &token_a_key,
3793 &token_b_key,
3794 WithdrawAllTokenTypes {
3795 pool_token_amount: withdraw_amount.try_into().unwrap(),
3796 minimum_token_a_amount,
3797 minimum_token_b_amount,
3798 },
3799 )
3800 .unwrap(),
3801 vec![
3802 &mut accounts.swap_account,
3803 &mut Account::default(),
3804 &mut Account::default(),
3805 &mut accounts.pool_mint_account,
3806 &mut pool_account,
3807 &mut accounts.token_a_account,
3808 &mut accounts.token_b_account,
3809 &mut token_a_account,
3810 &mut token_b_account,
3811 &mut accounts.pool_fee_account,
3812 &mut Account::default(),
3813 ],
3814 )
3815 );
3816 }
3817
3818 {
3820 let (
3821 token_a_key,
3822 mut token_a_account,
3823 token_b_key,
3824 mut token_b_account,
3825 pool_key,
3826 mut pool_account,
3827 ) = accounts.setup_token_accounts(
3828 &user_key,
3829 &withdrawer_key,
3830 initial_a,
3831 initial_b,
3832 initial_pool.try_into().unwrap(),
3833 );
3834
3835 let old_a_key = accounts.token_a_key;
3836 let old_a_account = accounts.token_a_account;
3837
3838 accounts.token_a_key = token_a_key;
3839 accounts.token_a_account = token_a_account.clone();
3840
3841 assert_eq!(
3843 Err(SwapError::IncorrectSwapAccount.into()),
3844 accounts.withdraw_all_token_types(
3845 &withdrawer_key,
3846 &pool_key,
3847 &mut pool_account,
3848 &token_a_key,
3849 &mut token_a_account,
3850 &token_b_key,
3851 &mut token_b_account,
3852 withdraw_amount.try_into().unwrap(),
3853 minimum_token_a_amount,
3854 minimum_token_b_amount,
3855 )
3856 );
3857
3858 accounts.token_a_key = old_a_key;
3859 accounts.token_a_account = old_a_account;
3860
3861 let old_b_key = accounts.token_b_key;
3862 let old_b_account = accounts.token_b_account;
3863
3864 accounts.token_b_key = token_b_key;
3865 accounts.token_b_account = token_b_account.clone();
3866
3867 assert_eq!(
3869 Err(SwapError::IncorrectSwapAccount.into()),
3870 accounts.withdraw_all_token_types(
3871 &withdrawer_key,
3872 &pool_key,
3873 &mut pool_account,
3874 &token_a_key,
3875 &mut token_a_account,
3876 &token_b_key,
3877 &mut token_b_account,
3878 withdraw_amount.try_into().unwrap(),
3879 minimum_token_a_amount,
3880 minimum_token_b_amount,
3881 )
3882 );
3883
3884 accounts.token_b_key = old_b_key;
3885 accounts.token_b_account = old_b_account;
3886 }
3887
3888 {
3890 let (
3891 token_a_key,
3892 mut token_a_account,
3893 token_b_key,
3894 mut token_b_account,
3895 pool_key,
3896 mut pool_account,
3897 ) = accounts.setup_token_accounts(
3898 &user_key,
3899 &withdrawer_key,
3900 initial_a,
3901 initial_b,
3902 initial_pool.try_into().unwrap(),
3903 );
3904 let (pool_mint_key, pool_mint_account) =
3905 create_mint(&gpl_token::id(), &accounts.authority_key, None);
3906 let old_pool_key = accounts.pool_mint_key;
3907 let old_pool_account = accounts.pool_mint_account;
3908 accounts.pool_mint_key = pool_mint_key;
3909 accounts.pool_mint_account = pool_mint_account;
3910
3911 assert_eq!(
3912 Err(SwapError::IncorrectPoolMint.into()),
3913 accounts.withdraw_all_token_types(
3914 &withdrawer_key,
3915 &pool_key,
3916 &mut pool_account,
3917 &token_a_key,
3918 &mut token_a_account,
3919 &token_b_key,
3920 &mut token_b_account,
3921 withdraw_amount.try_into().unwrap(),
3922 minimum_token_a_amount,
3923 minimum_token_b_amount,
3924 )
3925 );
3926
3927 accounts.pool_mint_key = old_pool_key;
3928 accounts.pool_mint_account = old_pool_account;
3929 }
3930
3931 {
3933 let (
3934 token_a_key,
3935 mut token_a_account,
3936 token_b_key,
3937 mut token_b_account,
3938 pool_key,
3939 mut pool_account,
3940 ) = accounts.setup_token_accounts(
3941 &user_key,
3942 &withdrawer_key,
3943 initial_a,
3944 initial_b,
3945 initial_pool.try_into().unwrap(),
3946 );
3947 assert_eq!(
3948 Err(SwapError::ZeroTradingTokens.into()),
3949 accounts.withdraw_all_token_types(
3950 &withdrawer_key,
3951 &pool_key,
3952 &mut pool_account,
3953 &token_a_key,
3954 &mut token_a_account,
3955 &token_b_key,
3956 &mut token_b_account,
3957 1,
3958 0,
3959 0,
3960 )
3961 );
3962 }
3963
3964 {
3966 let (
3967 token_a_key,
3968 mut token_a_account,
3969 token_b_key,
3970 mut token_b_account,
3971 pool_key,
3972 mut pool_account,
3973 ) = accounts.setup_token_accounts(
3974 &user_key,
3975 &withdrawer_key,
3976 initial_a,
3977 initial_b,
3978 initial_pool.try_into().unwrap(),
3979 );
3980 assert_eq!(
3982 Err(SwapError::ExceededSlippage.into()),
3983 accounts.withdraw_all_token_types(
3984 &withdrawer_key,
3985 &pool_key,
3986 &mut pool_account,
3987 &token_a_key,
3988 &mut token_a_account,
3989 &token_b_key,
3990 &mut token_b_account,
3991 withdraw_amount.try_into().unwrap(),
3992 minimum_token_a_amount * 10,
3993 minimum_token_b_amount,
3994 )
3995 );
3996 assert_eq!(
3998 Err(SwapError::ExceededSlippage.into()),
3999 accounts.withdraw_all_token_types(
4000 &withdrawer_key,
4001 &pool_key,
4002 &mut pool_account,
4003 &token_a_key,
4004 &mut token_a_account,
4005 &token_b_key,
4006 &mut token_b_account,
4007 withdraw_amount.try_into().unwrap(),
4008 minimum_token_a_amount,
4009 minimum_token_b_amount * 10,
4010 )
4011 );
4012 }
4013
4014 {
4016 let (
4017 token_a_key,
4018 mut token_a_account,
4019 token_b_key,
4020 mut token_b_account,
4021 pool_key,
4022 mut pool_account,
4023 ) = accounts.setup_token_accounts(
4024 &user_key,
4025 &withdrawer_key,
4026 initial_a,
4027 initial_b,
4028 initial_pool.try_into().unwrap(),
4029 );
4030 let swap_token_a_key = accounts.token_a_key;
4031 let mut swap_token_a_account = accounts.get_token_account(&swap_token_a_key).clone();
4032 assert_eq!(
4033 Err(SwapError::InvalidInput.into()),
4034 accounts.withdraw_all_token_types(
4035 &withdrawer_key,
4036 &pool_key,
4037 &mut pool_account,
4038 &swap_token_a_key,
4039 &mut swap_token_a_account,
4040 &token_b_key,
4041 &mut token_b_account,
4042 withdraw_amount.try_into().unwrap(),
4043 minimum_token_a_amount,
4044 minimum_token_b_amount,
4045 )
4046 );
4047 let swap_token_b_key = accounts.token_b_key;
4048 let mut swap_token_b_account = accounts.get_token_account(&swap_token_b_key).clone();
4049 assert_eq!(
4050 Err(SwapError::InvalidInput.into()),
4051 accounts.withdraw_all_token_types(
4052 &withdrawer_key,
4053 &pool_key,
4054 &mut pool_account,
4055 &token_a_key,
4056 &mut token_a_account,
4057 &swap_token_b_key,
4058 &mut swap_token_b_account,
4059 withdraw_amount.try_into().unwrap(),
4060 minimum_token_a_amount,
4061 minimum_token_b_amount,
4062 )
4063 );
4064 }
4065
4066 {
4068 let (
4069 token_a_key,
4070 mut token_a_account,
4071 token_b_key,
4072 mut token_b_account,
4073 pool_key,
4074 mut pool_account,
4075 ) = accounts.setup_token_accounts(
4076 &user_key,
4077 &withdrawer_key,
4078 initial_a,
4079 initial_b,
4080 initial_pool.try_into().unwrap(),
4081 );
4082
4083 accounts
4084 .withdraw_all_token_types(
4085 &withdrawer_key,
4086 &pool_key,
4087 &mut pool_account,
4088 &token_a_key,
4089 &mut token_a_account,
4090 &token_b_key,
4091 &mut token_b_account,
4092 withdraw_amount.try_into().unwrap(),
4093 minimum_token_a_amount,
4094 minimum_token_b_amount,
4095 )
4096 .unwrap();
4097
4098 let swap_token_a =
4099 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
4100 let swap_token_b =
4101 gpl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap();
4102 let pool_mint =
4103 gpl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap();
4104 let withdraw_fee = accounts.fees.owner_withdraw_fee(withdraw_amount).unwrap();
4105 let results = accounts
4106 .swap_curve
4107 .calculator
4108 .pool_tokens_to_trading_tokens(
4109 withdraw_amount - withdraw_fee,
4110 pool_mint.supply.try_into().unwrap(),
4111 swap_token_a.amount.try_into().unwrap(),
4112 swap_token_b.amount.try_into().unwrap(),
4113 RoundDirection::Floor,
4114 )
4115 .unwrap();
4116 assert_eq!(
4117 swap_token_a.amount,
4118 token_a_amount - to_u64(results.token_a_amount).unwrap()
4119 );
4120 assert_eq!(
4121 swap_token_b.amount,
4122 token_b_amount - to_u64(results.token_b_amount).unwrap()
4123 );
4124 let token_a = gpl_token::state::Account::unpack(&token_a_account.data).unwrap();
4125 assert_eq!(
4126 token_a.amount,
4127 initial_a + to_u64(results.token_a_amount).unwrap()
4128 );
4129 let token_b = gpl_token::state::Account::unpack(&token_b_account.data).unwrap();
4130 assert_eq!(
4131 token_b.amount,
4132 initial_b + to_u64(results.token_b_amount).unwrap()
4133 );
4134 let pool_account = gpl_token::state::Account::unpack(&pool_account.data).unwrap();
4135 assert_eq!(
4136 pool_account.amount,
4137 to_u64(initial_pool - withdraw_amount).unwrap()
4138 );
4139 let fee_account =
4140 gpl_token::state::Account::unpack(&accounts.pool_fee_account.data).unwrap();
4141 assert_eq!(
4142 fee_account.amount,
4143 TryInto::<u64>::try_into(withdraw_fee).unwrap()
4144 );
4145 }
4146
4147 {
4149 let (
4150 token_a_key,
4151 mut token_a_account,
4152 token_b_key,
4153 mut token_b_account,
4154 _pool_key,
4155 mut _pool_account,
4156 ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, 0, 0, 0);
4157
4158 let pool_fee_key = accounts.pool_fee_key;
4159 let mut pool_fee_account = accounts.pool_fee_account.clone();
4160 let fee_account = gpl_token::state::Account::unpack(&pool_fee_account.data).unwrap();
4161 let pool_fee_amount = fee_account.amount;
4162
4163 accounts
4164 .withdraw_all_token_types(
4165 &user_key,
4166 &pool_fee_key,
4167 &mut pool_fee_account,
4168 &token_a_key,
4169 &mut token_a_account,
4170 &token_b_key,
4171 &mut token_b_account,
4172 pool_fee_amount,
4173 0,
4174 0,
4175 )
4176 .unwrap();
4177
4178 let swap_token_a =
4179 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
4180 let swap_token_b =
4181 gpl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap();
4182 let pool_mint =
4183 gpl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap();
4184 let results = accounts
4185 .swap_curve
4186 .calculator
4187 .pool_tokens_to_trading_tokens(
4188 pool_fee_amount.try_into().unwrap(),
4189 pool_mint.supply.try_into().unwrap(),
4190 swap_token_a.amount.try_into().unwrap(),
4191 swap_token_b.amount.try_into().unwrap(),
4192 RoundDirection::Floor,
4193 )
4194 .unwrap();
4195 let token_a = gpl_token::state::Account::unpack(&token_a_account.data).unwrap();
4196 assert_eq!(
4197 token_a.amount,
4198 TryInto::<u64>::try_into(results.token_a_amount).unwrap()
4199 );
4200 let token_b = gpl_token::state::Account::unpack(&token_b_account.data).unwrap();
4201 assert_eq!(
4202 token_b.amount,
4203 TryInto::<u64>::try_into(results.token_b_amount).unwrap()
4204 );
4205 }
4206 }
4207
4208 #[test]
4209 fn test_deposit_one_exact_in() {
4210 let user_key = Pubkey::new_unique();
4211 let depositor_key = Pubkey::new_unique();
4212 let trade_fee_numerator = 1;
4213 let trade_fee_denominator = 2;
4214 let owner_trade_fee_numerator = 1;
4215 let owner_trade_fee_denominator = 10;
4216 let owner_withdraw_fee_numerator = 1;
4217 let owner_withdraw_fee_denominator = 5;
4218 let host_fee_numerator = 20;
4219 let host_fee_denominator = 100;
4220
4221 let fees = Fees {
4222 trade_fee_numerator,
4223 trade_fee_denominator,
4224 owner_trade_fee_numerator,
4225 owner_trade_fee_denominator,
4226 owner_withdraw_fee_numerator,
4227 owner_withdraw_fee_denominator,
4228 host_fee_numerator,
4229 host_fee_denominator,
4230 };
4231
4232 let token_a_amount = 1000;
4233 let token_b_amount = 9000;
4234 let curve_type = CurveType::ConstantProduct;
4235 let swap_curve = SwapCurve {
4236 curve_type,
4237 calculator: Box::new(ConstantProductCurve {}),
4238 };
4239
4240 let mut accounts =
4241 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
4242
4243 let deposit_a = token_a_amount / 10;
4244 let deposit_b = token_b_amount / 10;
4245 let pool_amount = to_u64(INITIAL_SWAP_POOL_AMOUNT / 100).unwrap();
4246
4247 {
4249 let (
4250 token_a_key,
4251 mut token_a_account,
4252 _token_b_key,
4253 _token_b_account,
4254 pool_key,
4255 mut pool_account,
4256 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4257 assert_eq!(
4258 Err(ProgramError::UninitializedAccount),
4259 accounts.deposit_single_token_type_exact_amount_in(
4260 &depositor_key,
4261 &token_a_key,
4262 &mut token_a_account,
4263 &pool_key,
4264 &mut pool_account,
4265 deposit_a,
4266 pool_amount,
4267 )
4268 );
4269 }
4270
4271 accounts.initialize_swap().unwrap();
4272
4273 {
4275 let (
4276 token_a_key,
4277 mut token_a_account,
4278 _token_b_key,
4279 _token_b_account,
4280 pool_key,
4281 mut pool_account,
4282 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4283 let old_swap_account = accounts.swap_account;
4284 let mut wrong_swap_account = old_swap_account.clone();
4285 wrong_swap_account.owner = gpl_token::id();
4286 accounts.swap_account = wrong_swap_account;
4287 assert_eq!(
4288 Err(ProgramError::IncorrectProgramId),
4289 accounts.deposit_single_token_type_exact_amount_in(
4290 &depositor_key,
4291 &token_a_key,
4292 &mut token_a_account,
4293 &pool_key,
4294 &mut pool_account,
4295 deposit_a,
4296 pool_amount,
4297 )
4298 );
4299 accounts.swap_account = old_swap_account;
4300 }
4301
4302 {
4304 let (
4305 token_a_key,
4306 mut token_a_account,
4307 _token_b_key,
4308 _token_b_account,
4309 pool_key,
4310 mut pool_account,
4311 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4312 let old_authority = accounts.authority_key;
4313 let (bad_authority_key, _bump_seed) = Pubkey::find_program_address(
4314 &[&accounts.swap_key.to_bytes()[..]],
4315 &gpl_token::id(),
4316 );
4317 accounts.authority_key = bad_authority_key;
4318 assert_eq!(
4319 Err(SwapError::InvalidProgramAddress.into()),
4320 accounts.deposit_single_token_type_exact_amount_in(
4321 &depositor_key,
4322 &token_a_key,
4323 &mut token_a_account,
4324 &pool_key,
4325 &mut pool_account,
4326 deposit_a,
4327 pool_amount,
4328 )
4329 );
4330 accounts.authority_key = old_authority;
4331 }
4332
4333 {
4335 let (
4336 token_a_key,
4337 mut token_a_account,
4338 token_b_key,
4339 mut token_b_account,
4340 pool_key,
4341 mut pool_account,
4342 ) = accounts.setup_token_accounts(
4343 &user_key,
4344 &depositor_key,
4345 deposit_a / 2,
4346 deposit_b / 2,
4347 0,
4348 );
4349 assert_eq!(
4350 Err(TokenError::InsufficientFunds.into()),
4351 accounts.deposit_single_token_type_exact_amount_in(
4352 &depositor_key,
4353 &token_a_key,
4354 &mut token_a_account,
4355 &pool_key,
4356 &mut pool_account,
4357 deposit_a,
4358 0,
4359 )
4360 );
4361 assert_eq!(
4362 Err(TokenError::InsufficientFunds.into()),
4363 accounts.deposit_single_token_type_exact_amount_in(
4364 &depositor_key,
4365 &token_b_key,
4366 &mut token_b_account,
4367 &pool_key,
4368 &mut pool_account,
4369 deposit_b,
4370 0,
4371 )
4372 );
4373 }
4374
4375 {
4377 let (
4378 token_a_key,
4379 mut token_a_account,
4380 token_b_key,
4381 mut token_b_account,
4382 _pool_key,
4383 mut _pool_account,
4384 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4385 assert_eq!(
4386 Err(TokenError::MintMismatch.into()),
4387 accounts.deposit_single_token_type_exact_amount_in(
4388 &depositor_key,
4389 &token_a_key,
4390 &mut token_a_account,
4391 &token_b_key,
4392 &mut token_b_account,
4393 deposit_a,
4394 pool_amount,
4395 )
4396 );
4397 }
4398
4399 {
4401 let (
4402 token_a_key,
4403 mut token_a_account,
4404 _token_b_key,
4405 _token_b_account,
4406 pool_key,
4407 mut pool_account,
4408 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4409 let user_transfer_authority_key = Pubkey::new_unique();
4410 assert_eq!(
4411 Err(TokenError::OwnerMismatch.into()),
4412 do_process_instruction(
4413 deposit_single_token_type_exact_amount_in(
4414 &SWAP_PROGRAM_ID,
4415 &gpl_token::id(),
4416 &accounts.swap_key,
4417 &accounts.authority_key,
4418 &user_transfer_authority_key,
4419 &token_a_key,
4420 &accounts.token_a_key,
4421 &accounts.token_b_key,
4422 &accounts.pool_mint_key,
4423 &pool_key,
4424 DepositSingleTokenTypeExactAmountIn {
4425 source_token_amount: deposit_a,
4426 minimum_pool_token_amount: pool_amount,
4427 },
4428 )
4429 .unwrap(),
4430 vec![
4431 &mut accounts.swap_account,
4432 &mut Account::default(),
4433 &mut Account::default(),
4434 &mut token_a_account,
4435 &mut accounts.token_a_account,
4436 &mut accounts.token_b_account,
4437 &mut accounts.pool_mint_account,
4438 &mut pool_account,
4439 &mut Account::default(),
4440 ],
4441 )
4442 );
4443 }
4444
4445 {
4447 let (
4448 token_a_key,
4449 mut token_a_account,
4450 _token_b_key,
4451 _token_b_account,
4452 pool_key,
4453 mut pool_account,
4454 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4455 let wrong_key = Pubkey::new_unique();
4456 assert_eq!(
4457 Err(SwapError::IncorrectTokenProgramId.into()),
4458 do_process_instruction(
4459 deposit_single_token_type_exact_amount_in(
4460 &SWAP_PROGRAM_ID,
4461 &wrong_key,
4462 &accounts.swap_key,
4463 &accounts.authority_key,
4464 &accounts.authority_key,
4465 &token_a_key,
4466 &accounts.token_a_key,
4467 &accounts.token_b_key,
4468 &accounts.pool_mint_key,
4469 &pool_key,
4470 DepositSingleTokenTypeExactAmountIn {
4471 source_token_amount: deposit_a,
4472 minimum_pool_token_amount: pool_amount,
4473 },
4474 )
4475 .unwrap(),
4476 vec![
4477 &mut accounts.swap_account,
4478 &mut Account::default(),
4479 &mut Account::default(),
4480 &mut token_a_account,
4481 &mut accounts.token_a_account,
4482 &mut accounts.token_b_account,
4483 &mut accounts.pool_mint_account,
4484 &mut pool_account,
4485 &mut Account::default(),
4486 ],
4487 )
4488 );
4489 }
4490
4491 {
4493 let (
4494 token_a_key,
4495 mut token_a_account,
4496 token_b_key,
4497 token_b_account,
4498 pool_key,
4499 mut pool_account,
4500 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4501
4502 let old_a_key = accounts.token_a_key;
4503 let old_a_account = accounts.token_a_account;
4504
4505 accounts.token_a_key = token_a_key;
4506 accounts.token_a_account = token_a_account.clone();
4507
4508 assert_eq!(
4510 Err(SwapError::IncorrectSwapAccount.into()),
4511 accounts.deposit_single_token_type_exact_amount_in(
4512 &depositor_key,
4513 &token_a_key,
4514 &mut token_a_account,
4515 &pool_key,
4516 &mut pool_account,
4517 deposit_a,
4518 pool_amount,
4519 )
4520 );
4521
4522 accounts.token_a_key = old_a_key;
4523 accounts.token_a_account = old_a_account;
4524
4525 let old_b_key = accounts.token_b_key;
4526 let old_b_account = accounts.token_b_account;
4527
4528 accounts.token_b_key = token_b_key;
4529 accounts.token_b_account = token_b_account;
4530
4531 assert_eq!(
4533 Err(SwapError::IncorrectSwapAccount.into()),
4534 accounts.deposit_single_token_type_exact_amount_in(
4535 &depositor_key,
4536 &token_a_key,
4537 &mut token_a_account,
4538 &pool_key,
4539 &mut pool_account,
4540 deposit_a,
4541 pool_amount,
4542 )
4543 );
4544
4545 accounts.token_b_key = old_b_key;
4546 accounts.token_b_account = old_b_account;
4547 }
4548
4549 {
4551 let (
4552 token_a_key,
4553 mut token_a_account,
4554 _token_b_key,
4555 _token_b_account,
4556 pool_key,
4557 mut pool_account,
4558 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4559 let (pool_mint_key, pool_mint_account) =
4560 create_mint(&gpl_token::id(), &accounts.authority_key, None);
4561 let old_pool_key = accounts.pool_mint_key;
4562 let old_pool_account = accounts.pool_mint_account;
4563 accounts.pool_mint_key = pool_mint_key;
4564 accounts.pool_mint_account = pool_mint_account;
4565
4566 assert_eq!(
4567 Err(SwapError::IncorrectPoolMint.into()),
4568 accounts.deposit_single_token_type_exact_amount_in(
4569 &depositor_key,
4570 &token_a_key,
4571 &mut token_a_account,
4572 &pool_key,
4573 &mut pool_account,
4574 deposit_a,
4575 pool_amount,
4576 )
4577 );
4578
4579 accounts.pool_mint_key = old_pool_key;
4580 accounts.pool_mint_account = old_pool_account;
4581 }
4582
4583 {
4585 let (
4586 token_a_key,
4587 mut token_a_account,
4588 token_b_key,
4589 mut token_b_account,
4590 pool_key,
4591 mut pool_account,
4592 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4593 assert_eq!(
4595 Err(SwapError::ExceededSlippage.into()),
4596 accounts.deposit_single_token_type_exact_amount_in(
4597 &depositor_key,
4598 &token_a_key,
4599 &mut token_a_account,
4600 &pool_key,
4601 &mut pool_account,
4602 deposit_a / 10,
4603 pool_amount,
4604 )
4605 );
4606 assert_eq!(
4608 Err(SwapError::ExceededSlippage.into()),
4609 accounts.deposit_single_token_type_exact_amount_in(
4610 &depositor_key,
4611 &token_b_key,
4612 &mut token_b_account,
4613 &pool_key,
4614 &mut pool_account,
4615 deposit_b / 10,
4616 pool_amount,
4617 )
4618 );
4619 }
4620
4621 {
4623 let (
4624 _token_a_key,
4625 _token_a_account,
4626 _token_b_key,
4627 _token_b_account,
4628 pool_key,
4629 mut pool_account,
4630 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4631 let swap_token_a_key = accounts.token_a_key;
4632 let mut swap_token_a_account = accounts.get_token_account(&swap_token_a_key).clone();
4633 let swap_token_b_key = accounts.token_b_key;
4634 let mut swap_token_b_account = accounts.get_token_account(&swap_token_b_key).clone();
4635 let authority_key = accounts.authority_key;
4636 assert_eq!(
4637 Err(SwapError::InvalidInput.into()),
4638 accounts.deposit_single_token_type_exact_amount_in(
4639 &authority_key,
4640 &swap_token_a_key,
4641 &mut swap_token_a_account,
4642 &pool_key,
4643 &mut pool_account,
4644 deposit_a,
4645 pool_amount,
4646 )
4647 );
4648 assert_eq!(
4649 Err(SwapError::InvalidInput.into()),
4650 accounts.deposit_single_token_type_exact_amount_in(
4651 &authority_key,
4652 &swap_token_b_key,
4653 &mut swap_token_b_account,
4654 &pool_key,
4655 &mut pool_account,
4656 deposit_b,
4657 pool_amount,
4658 )
4659 );
4660 }
4661
4662 {
4664 let (
4665 token_a_key,
4666 mut token_a_account,
4667 token_b_key,
4668 mut token_b_account,
4669 pool_key,
4670 mut pool_account,
4671 ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
4672 accounts
4673 .deposit_single_token_type_exact_amount_in(
4674 &depositor_key,
4675 &token_a_key,
4676 &mut token_a_account,
4677 &pool_key,
4678 &mut pool_account,
4679 deposit_a,
4680 pool_amount,
4681 )
4682 .unwrap();
4683
4684 let swap_token_a =
4685 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
4686 assert_eq!(swap_token_a.amount, deposit_a + token_a_amount);
4687
4688 let token_a = gpl_token::state::Account::unpack(&token_a_account.data).unwrap();
4689 assert_eq!(token_a.amount, 0);
4690
4691 accounts
4692 .deposit_single_token_type_exact_amount_in(
4693 &depositor_key,
4694 &token_b_key,
4695 &mut token_b_account,
4696 &pool_key,
4697 &mut pool_account,
4698 deposit_b,
4699 pool_amount,
4700 )
4701 .unwrap();
4702 let swap_token_b =
4703 gpl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap();
4704 assert_eq!(swap_token_b.amount, deposit_b + token_b_amount);
4705
4706 let token_b = gpl_token::state::Account::unpack(&token_b_account.data).unwrap();
4707 assert_eq!(token_b.amount, 0);
4708
4709 let pool_account = gpl_token::state::Account::unpack(&pool_account.data).unwrap();
4710 let swap_pool_account =
4711 gpl_token::state::Account::unpack(&accounts.pool_token_account.data).unwrap();
4712 let pool_mint =
4713 gpl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap();
4714 assert_eq!(
4715 pool_mint.supply,
4716 pool_account.amount + swap_pool_account.amount
4717 );
4718 }
4719 }
4720
4721 #[test]
4722 fn test_withdraw_one_exact_out() {
4723 let user_key = Pubkey::new_unique();
4724 let trade_fee_numerator = 1;
4725 let trade_fee_denominator = 2;
4726 let owner_trade_fee_numerator = 1;
4727 let owner_trade_fee_denominator = 10;
4728 let owner_withdraw_fee_numerator = 1;
4729 let owner_withdraw_fee_denominator = 5;
4730 let host_fee_numerator = 7;
4731 let host_fee_denominator = 100;
4732
4733 let fees = Fees {
4734 trade_fee_numerator,
4735 trade_fee_denominator,
4736 owner_trade_fee_numerator,
4737 owner_trade_fee_denominator,
4738 owner_withdraw_fee_numerator,
4739 owner_withdraw_fee_denominator,
4740 host_fee_numerator,
4741 host_fee_denominator,
4742 };
4743
4744 let token_a_amount = 100_000;
4745 let token_b_amount = 200_000;
4746 let curve_type = CurveType::ConstantProduct;
4747 let swap_curve = SwapCurve {
4748 curve_type,
4749 calculator: Box::new(ConstantProductCurve {}),
4750 };
4751
4752 let withdrawer_key = Pubkey::new_unique();
4753 let initial_a = token_a_amount / 10;
4754 let initial_b = token_b_amount / 10;
4755 let initial_pool = swap_curve.calculator.new_pool_supply() / 10;
4756 let maximum_pool_token_amount = to_u64(initial_pool / 4).unwrap();
4757 let destination_a_amount = initial_a / 40;
4758 let destination_b_amount = initial_b / 40;
4759
4760 let mut accounts =
4761 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
4762
4763 {
4765 let (
4766 token_a_key,
4767 mut token_a_account,
4768 _token_b_key,
4769 _token_b_account,
4770 pool_key,
4771 mut pool_account,
4772 ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, initial_a, initial_b, 0);
4773 assert_eq!(
4774 Err(ProgramError::UninitializedAccount),
4775 accounts.withdraw_single_token_type_exact_amount_out(
4776 &withdrawer_key,
4777 &pool_key,
4778 &mut pool_account,
4779 &token_a_key,
4780 &mut token_a_account,
4781 destination_a_amount,
4782 maximum_pool_token_amount,
4783 )
4784 );
4785 }
4786
4787 accounts.initialize_swap().unwrap();
4788
4789 {
4791 let (
4792 token_a_key,
4793 mut token_a_account,
4794 _token_b_key,
4795 _token_b_account,
4796 pool_key,
4797 mut pool_account,
4798 ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, initial_a, initial_b, 0);
4799 let old_swap_account = accounts.swap_account;
4800 let mut wrong_swap_account = old_swap_account.clone();
4801 wrong_swap_account.owner = gpl_token::id();
4802 accounts.swap_account = wrong_swap_account;
4803 assert_eq!(
4804 Err(ProgramError::IncorrectProgramId),
4805 accounts.withdraw_single_token_type_exact_amount_out(
4806 &withdrawer_key,
4807 &pool_key,
4808 &mut pool_account,
4809 &token_a_key,
4810 &mut token_a_account,
4811 destination_a_amount,
4812 maximum_pool_token_amount,
4813 )
4814 );
4815 accounts.swap_account = old_swap_account;
4816 }
4817
4818 {
4820 let (
4821 _token_a_key,
4822 _token_a_account,
4823 token_b_key,
4824 mut token_b_account,
4825 pool_key,
4826 mut pool_account,
4827 ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, initial_a, initial_b, 0);
4828 let old_authority = accounts.authority_key;
4829 let (bad_authority_key, _bump_seed) = Pubkey::find_program_address(
4830 &[&accounts.swap_key.to_bytes()[..]],
4831 &gpl_token::id(),
4832 );
4833 accounts.authority_key = bad_authority_key;
4834 assert_eq!(
4835 Err(SwapError::InvalidProgramAddress.into()),
4836 accounts.withdraw_single_token_type_exact_amount_out(
4837 &withdrawer_key,
4838 &pool_key,
4839 &mut pool_account,
4840 &token_b_key,
4841 &mut token_b_account,
4842 destination_b_amount,
4843 maximum_pool_token_amount,
4844 )
4845 );
4846 accounts.authority_key = old_authority;
4847 }
4848
4849 {
4851 let (
4852 _token_a_key,
4853 _token_a_account,
4854 token_b_key,
4855 mut token_b_account,
4856 pool_key,
4857 mut pool_account,
4858 ) = accounts.setup_token_accounts(
4859 &user_key,
4860 &withdrawer_key,
4861 initial_a,
4862 initial_b,
4863 maximum_pool_token_amount / 1000,
4864 );
4865 assert_eq!(
4866 Err(TokenError::InsufficientFunds.into()),
4867 accounts.withdraw_single_token_type_exact_amount_out(
4868 &withdrawer_key,
4869 &pool_key,
4870 &mut pool_account,
4871 &token_b_key,
4872 &mut token_b_account,
4873 destination_b_amount,
4874 maximum_pool_token_amount,
4875 )
4876 );
4877 }
4878
4879 {
4881 let (
4882 token_a_key,
4883 mut token_a_account,
4884 token_b_key,
4885 mut token_b_account,
4886 _pool_key,
4887 _pool_account,
4888 ) = accounts.setup_token_accounts(
4889 &user_key,
4890 &withdrawer_key,
4891 maximum_pool_token_amount,
4892 initial_b,
4893 maximum_pool_token_amount,
4894 );
4895 assert_eq!(
4896 Err(TokenError::MintMismatch.into()),
4897 accounts.withdraw_single_token_type_exact_amount_out(
4898 &withdrawer_key,
4899 &token_a_key,
4900 &mut token_a_account,
4901 &token_b_key,
4902 &mut token_b_account,
4903 destination_b_amount,
4904 maximum_pool_token_amount,
4905 )
4906 );
4907 }
4908
4909 {
4911 let (
4912 token_a_key,
4913 mut token_a_account,
4914 _token_b_key,
4915 _token_b_account,
4916 wrong_pool_key,
4917 wrong_pool_account,
4918 ) = accounts.setup_token_accounts(
4919 &user_key,
4920 &withdrawer_key,
4921 initial_a,
4922 initial_b,
4923 maximum_pool_token_amount,
4924 );
4925 let (
4926 _token_a_key,
4927 _token_a_account,
4928 _token_b_key,
4929 _token_b_account,
4930 pool_key,
4931 mut pool_account,
4932 ) = accounts.setup_token_accounts(
4933 &user_key,
4934 &withdrawer_key,
4935 initial_a,
4936 initial_b,
4937 maximum_pool_token_amount,
4938 );
4939 let old_pool_fee_account = accounts.pool_fee_account;
4940 let old_pool_fee_key = accounts.pool_fee_key;
4941 accounts.pool_fee_account = wrong_pool_account;
4942 accounts.pool_fee_key = wrong_pool_key;
4943 assert_eq!(
4944 Err(SwapError::IncorrectFeeAccount.into()),
4945 accounts.withdraw_single_token_type_exact_amount_out(
4946 &withdrawer_key,
4947 &pool_key,
4948 &mut pool_account,
4949 &token_a_key,
4950 &mut token_a_account,
4951 destination_a_amount,
4952 maximum_pool_token_amount,
4953 )
4954 );
4955 accounts.pool_fee_account = old_pool_fee_account;
4956 accounts.pool_fee_key = old_pool_fee_key;
4957 }
4958
4959 {
4961 let (
4962 token_a_key,
4963 mut token_a_account,
4964 _token_b_key,
4965 _token_b_account,
4966 pool_key,
4967 mut pool_account,
4968 ) = accounts.setup_token_accounts(
4969 &user_key,
4970 &withdrawer_key,
4971 0,
4972 0,
4973 maximum_pool_token_amount,
4974 );
4975 let user_transfer_authority_key = Pubkey::new_unique();
4976 assert_eq!(
4977 Err(TokenError::OwnerMismatch.into()),
4978 do_process_instruction(
4979 withdraw_single_token_type_exact_amount_out(
4980 &SWAP_PROGRAM_ID,
4981 &gpl_token::id(),
4982 &accounts.swap_key,
4983 &accounts.authority_key,
4984 &user_transfer_authority_key,
4985 &accounts.pool_mint_key,
4986 &accounts.pool_fee_key,
4987 &pool_key,
4988 &accounts.token_a_key,
4989 &accounts.token_b_key,
4990 &token_a_key,
4991 WithdrawSingleTokenTypeExactAmountOut {
4992 destination_token_amount: destination_a_amount,
4993 maximum_pool_token_amount,
4994 }
4995 )
4996 .unwrap(),
4997 vec![
4998 &mut accounts.swap_account,
4999 &mut Account::default(),
5000 &mut Account::default(),
5001 &mut accounts.pool_mint_account,
5002 &mut pool_account,
5003 &mut accounts.token_a_account,
5004 &mut accounts.token_b_account,
5005 &mut token_a_account,
5006 &mut accounts.pool_fee_account,
5007 &mut Account::default(),
5008 ],
5009 )
5010 );
5011 }
5012
5013 {
5015 let (
5016 token_a_key,
5017 mut token_a_account,
5018 _token_b_key,
5019 _token_b_account,
5020 pool_key,
5021 mut pool_account,
5022 ) = accounts.setup_token_accounts(
5023 &user_key,
5024 &withdrawer_key,
5025 initial_a,
5026 initial_b,
5027 maximum_pool_token_amount,
5028 );
5029 let wrong_key = Pubkey::new_unique();
5030 assert_eq!(
5031 Err(SwapError::IncorrectTokenProgramId.into()),
5032 do_process_instruction(
5033 withdraw_single_token_type_exact_amount_out(
5034 &SWAP_PROGRAM_ID,
5035 &wrong_key,
5036 &accounts.swap_key,
5037 &accounts.authority_key,
5038 &accounts.authority_key,
5039 &accounts.pool_mint_key,
5040 &accounts.pool_fee_key,
5041 &pool_key,
5042 &accounts.token_a_key,
5043 &accounts.token_b_key,
5044 &token_a_key,
5045 WithdrawSingleTokenTypeExactAmountOut {
5046 destination_token_amount: destination_a_amount,
5047 maximum_pool_token_amount,
5048 }
5049 )
5050 .unwrap(),
5051 vec![
5052 &mut accounts.swap_account,
5053 &mut Account::default(),
5054 &mut Account::default(),
5055 &mut accounts.pool_mint_account,
5056 &mut pool_account,
5057 &mut accounts.token_a_account,
5058 &mut accounts.token_b_account,
5059 &mut token_a_account,
5060 &mut accounts.pool_fee_account,
5061 &mut Account::default(),
5062 ],
5063 )
5064 );
5065 }
5066
5067 {
5069 let (
5070 token_a_key,
5071 mut token_a_account,
5072 token_b_key,
5073 mut token_b_account,
5074 pool_key,
5075 mut pool_account,
5076 ) = accounts.setup_token_accounts(
5077 &user_key,
5078 &withdrawer_key,
5079 initial_a,
5080 initial_b,
5081 initial_pool.try_into().unwrap(),
5082 );
5083
5084 let old_a_key = accounts.token_a_key;
5085 let old_a_account = accounts.token_a_account;
5086
5087 accounts.token_a_key = token_a_key;
5088 accounts.token_a_account = token_a_account.clone();
5089
5090 assert_eq!(
5092 Err(SwapError::IncorrectSwapAccount.into()),
5093 accounts.withdraw_single_token_type_exact_amount_out(
5094 &withdrawer_key,
5095 &pool_key,
5096 &mut pool_account,
5097 &token_a_key,
5098 &mut token_a_account,
5099 destination_a_amount,
5100 maximum_pool_token_amount,
5101 )
5102 );
5103
5104 accounts.token_a_key = old_a_key;
5105 accounts.token_a_account = old_a_account;
5106
5107 let old_b_key = accounts.token_b_key;
5108 let old_b_account = accounts.token_b_account;
5109
5110 accounts.token_b_key = token_b_key;
5111 accounts.token_b_account = token_b_account.clone();
5112
5113 assert_eq!(
5115 Err(SwapError::IncorrectSwapAccount.into()),
5116 accounts.withdraw_single_token_type_exact_amount_out(
5117 &withdrawer_key,
5118 &pool_key,
5119 &mut pool_account,
5120 &token_b_key,
5121 &mut token_b_account,
5122 destination_b_amount,
5123 maximum_pool_token_amount,
5124 )
5125 );
5126
5127 accounts.token_b_key = old_b_key;
5128 accounts.token_b_account = old_b_account;
5129 }
5130
5131 {
5133 let (
5134 token_a_key,
5135 mut token_a_account,
5136 _token_b_key,
5137 _token_b_account,
5138 pool_key,
5139 mut pool_account,
5140 ) = accounts.setup_token_accounts(
5141 &user_key,
5142 &withdrawer_key,
5143 initial_a,
5144 initial_b,
5145 initial_pool.try_into().unwrap(),
5146 );
5147 let (pool_mint_key, pool_mint_account) =
5148 create_mint(&gpl_token::id(), &accounts.authority_key, None);
5149 let old_pool_key = accounts.pool_mint_key;
5150 let old_pool_account = accounts.pool_mint_account;
5151 accounts.pool_mint_key = pool_mint_key;
5152 accounts.pool_mint_account = pool_mint_account;
5153
5154 assert_eq!(
5155 Err(SwapError::IncorrectPoolMint.into()),
5156 accounts.withdraw_single_token_type_exact_amount_out(
5157 &withdrawer_key,
5158 &pool_key,
5159 &mut pool_account,
5160 &token_a_key,
5161 &mut token_a_account,
5162 destination_a_amount,
5163 maximum_pool_token_amount,
5164 )
5165 );
5166
5167 accounts.pool_mint_key = old_pool_key;
5168 accounts.pool_mint_account = old_pool_account;
5169 }
5170
5171 {
5173 let (
5174 token_a_key,
5175 mut token_a_account,
5176 token_b_key,
5177 mut token_b_account,
5178 pool_key,
5179 mut pool_account,
5180 ) = accounts.setup_token_accounts(
5181 &user_key,
5182 &withdrawer_key,
5183 initial_a,
5184 initial_b,
5185 maximum_pool_token_amount,
5186 );
5187
5188 assert_eq!(
5190 Err(SwapError::ExceededSlippage.into()),
5191 accounts.withdraw_single_token_type_exact_amount_out(
5192 &withdrawer_key,
5193 &pool_key,
5194 &mut pool_account,
5195 &token_a_key,
5196 &mut token_a_account,
5197 destination_a_amount,
5198 maximum_pool_token_amount / 1000,
5199 )
5200 );
5201 assert_eq!(
5202 Err(SwapError::ExceededSlippage.into()),
5203 accounts.withdraw_single_token_type_exact_amount_out(
5204 &withdrawer_key,
5205 &pool_key,
5206 &mut pool_account,
5207 &token_b_key,
5208 &mut token_b_account,
5209 destination_b_amount,
5210 maximum_pool_token_amount / 1000,
5211 )
5212 );
5213 }
5214
5215 {
5217 let (
5218 _token_a_key,
5219 _token_a_account,
5220 _token_b_key,
5221 _token_b_account,
5222 pool_key,
5223 mut pool_account,
5224 ) = accounts.setup_token_accounts(
5225 &user_key,
5226 &withdrawer_key,
5227 initial_a,
5228 initial_b,
5229 maximum_pool_token_amount,
5230 );
5231 let swap_token_a_key = accounts.token_a_key;
5232 let mut swap_token_a_account = accounts.get_token_account(&swap_token_a_key).clone();
5233 assert_eq!(
5234 Err(SwapError::InvalidInput.into()),
5235 accounts.withdraw_single_token_type_exact_amount_out(
5236 &withdrawer_key,
5237 &pool_key,
5238 &mut pool_account,
5239 &swap_token_a_key,
5240 &mut swap_token_a_account,
5241 destination_a_amount,
5242 maximum_pool_token_amount,
5243 )
5244 );
5245 let swap_token_b_key = accounts.token_b_key;
5246 let mut swap_token_b_account = accounts.get_token_account(&swap_token_b_key).clone();
5247 assert_eq!(
5248 Err(SwapError::InvalidInput.into()),
5249 accounts.withdraw_single_token_type_exact_amount_out(
5250 &withdrawer_key,
5251 &pool_key,
5252 &mut pool_account,
5253 &swap_token_b_key,
5254 &mut swap_token_b_account,
5255 destination_b_amount,
5256 maximum_pool_token_amount,
5257 )
5258 );
5259 }
5260
5261 {
5263 let (
5264 token_a_key,
5265 mut token_a_account,
5266 _token_b_key,
5267 _token_b_account,
5268 pool_key,
5269 mut pool_account,
5270 ) = accounts.setup_token_accounts(
5271 &user_key,
5272 &withdrawer_key,
5273 initial_a,
5274 initial_b,
5275 initial_pool.try_into().unwrap(),
5276 );
5277
5278 let swap_token_a =
5279 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
5280 let swap_token_b =
5281 gpl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap();
5282 let pool_mint =
5283 gpl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap();
5284
5285 let pool_token_amount = accounts
5286 .swap_curve
5287 .withdraw_single_token_type_exact_out(
5288 destination_a_amount.try_into().unwrap(),
5289 swap_token_a.amount.try_into().unwrap(),
5290 swap_token_b.amount.try_into().unwrap(),
5291 pool_mint.supply.try_into().unwrap(),
5292 TradeDirection::AtoB,
5293 &accounts.fees,
5294 )
5295 .unwrap();
5296 let withdraw_fee = accounts.fees.owner_withdraw_fee(pool_token_amount).unwrap();
5297
5298 accounts
5299 .withdraw_single_token_type_exact_amount_out(
5300 &withdrawer_key,
5301 &pool_key,
5302 &mut pool_account,
5303 &token_a_key,
5304 &mut token_a_account,
5305 destination_a_amount,
5306 maximum_pool_token_amount,
5307 )
5308 .unwrap();
5309
5310 let swap_token_a =
5311 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
5312
5313 assert_eq!(swap_token_a.amount, token_a_amount - destination_a_amount);
5314 let token_a = gpl_token::state::Account::unpack(&token_a_account.data).unwrap();
5315 assert_eq!(token_a.amount, initial_a + destination_a_amount);
5316
5317 let pool_account = gpl_token::state::Account::unpack(&pool_account.data).unwrap();
5318 assert_eq!(
5319 pool_account.amount,
5320 to_u64(initial_pool - pool_token_amount - withdraw_fee).unwrap()
5321 );
5322 let fee_account =
5323 gpl_token::state::Account::unpack(&accounts.pool_fee_account.data).unwrap();
5324 assert_eq!(fee_account.amount, to_u64(withdraw_fee).unwrap());
5325 }
5326
5327 {
5329 let (
5330 token_a_key,
5331 mut token_a_account,
5332 _token_b_key,
5333 _token_b_account,
5334 _pool_key,
5335 _pool_account,
5336 ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, initial_a, initial_b, 0);
5337
5338 let fee_a_amount = 2;
5339 let pool_fee_key = accounts.pool_fee_key;
5340 let mut pool_fee_account = accounts.pool_fee_account.clone();
5341 let fee_account = gpl_token::state::Account::unpack(&pool_fee_account.data).unwrap();
5342 let pool_fee_amount = fee_account.amount;
5343
5344 let swap_token_a =
5345 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
5346
5347 let token_a_amount = swap_token_a.amount;
5348 accounts
5349 .withdraw_single_token_type_exact_amount_out(
5350 &user_key,
5351 &pool_fee_key,
5352 &mut pool_fee_account,
5353 &token_a_key,
5354 &mut token_a_account,
5355 fee_a_amount,
5356 pool_fee_amount,
5357 )
5358 .unwrap();
5359
5360 let swap_token_a =
5361 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
5362
5363 assert_eq!(swap_token_a.amount, token_a_amount - fee_a_amount);
5364 let token_a = gpl_token::state::Account::unpack(&token_a_account.data).unwrap();
5365 assert_eq!(token_a.amount, initial_a + fee_a_amount);
5366 }
5367 }
5368
5369 fn check_valid_swap_curve(
5370 fees: Fees,
5371 curve_type: CurveType,
5372 calculator: Box<dyn CurveCalculator>,
5373 token_a_amount: u64,
5374 token_b_amount: u64,
5375 ) {
5376 let user_key = Pubkey::new_unique();
5377 let swapper_key = Pubkey::new_unique();
5378
5379 let swap_curve = SwapCurve {
5380 curve_type,
5381 calculator,
5382 };
5383
5384 let mut accounts = SwapAccountInfo::new(
5385 &user_key,
5386 fees.clone(),
5387 swap_curve.clone(),
5388 token_a_amount,
5389 token_b_amount,
5390 );
5391 let initial_a = token_a_amount / 5;
5392 let initial_b = token_b_amount / 5;
5393 accounts.initialize_swap().unwrap();
5394
5395 let swap_token_a_key = accounts.token_a_key;
5396 let swap_token_b_key = accounts.token_b_key;
5397
5398 let (
5399 token_a_key,
5400 mut token_a_account,
5401 token_b_key,
5402 mut token_b_account,
5403 _pool_key,
5404 _pool_account,
5405 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
5406 let a_to_b_amount = initial_a / 10;
5408 let minimum_token_b_amount = 0;
5409 let pool_mint = gpl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap();
5410 let initial_supply = pool_mint.supply;
5411 accounts
5412 .swap(
5413 &swapper_key,
5414 &token_a_key,
5415 &mut token_a_account,
5416 &swap_token_a_key,
5417 &swap_token_b_key,
5418 &token_b_key,
5419 &mut token_b_account,
5420 a_to_b_amount,
5421 minimum_token_b_amount,
5422 )
5423 .unwrap();
5424
5425 let results = swap_curve
5426 .swap(
5427 a_to_b_amount.try_into().unwrap(),
5428 token_a_amount.try_into().unwrap(),
5429 token_b_amount.try_into().unwrap(),
5430 TradeDirection::AtoB,
5431 &fees,
5432 )
5433 .unwrap();
5434
5435 let swap_token_a =
5436 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
5437 let token_a_amount = swap_token_a.amount;
5438 assert_eq!(
5439 token_a_amount,
5440 TryInto::<u64>::try_into(results.new_swap_source_amount).unwrap()
5441 );
5442 let token_a = gpl_token::state::Account::unpack(&token_a_account.data).unwrap();
5443 assert_eq!(token_a.amount, initial_a - a_to_b_amount);
5444
5445 let swap_token_b =
5446 gpl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap();
5447 let token_b_amount = swap_token_b.amount;
5448 assert_eq!(
5449 token_b_amount,
5450 TryInto::<u64>::try_into(results.new_swap_destination_amount).unwrap()
5451 );
5452 let token_b = gpl_token::state::Account::unpack(&token_b_account.data).unwrap();
5453 assert_eq!(
5454 token_b.amount,
5455 initial_b + to_u64(results.destination_amount_swapped).unwrap()
5456 );
5457
5458 let first_fee = swap_curve
5459 .withdraw_single_token_type_exact_out(
5460 results.owner_fee,
5461 token_a_amount.try_into().unwrap(),
5462 token_b_amount.try_into().unwrap(),
5463 initial_supply.try_into().unwrap(),
5464 TradeDirection::AtoB,
5465 &fees,
5466 )
5467 .unwrap();
5468 let fee_account =
5469 gpl_token::state::Account::unpack(&accounts.pool_fee_account.data).unwrap();
5470 assert_eq!(
5471 fee_account.amount,
5472 TryInto::<u64>::try_into(first_fee).unwrap()
5473 );
5474
5475 let first_swap_amount = results.destination_amount_swapped;
5476
5477 let pool_mint = gpl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap();
5479 let initial_supply = pool_mint.supply;
5480
5481 let b_to_a_amount = initial_b / 10;
5482 let minimum_a_amount = 0;
5483 accounts
5484 .swap(
5485 &swapper_key,
5486 &token_b_key,
5487 &mut token_b_account,
5488 &swap_token_b_key,
5489 &swap_token_a_key,
5490 &token_a_key,
5491 &mut token_a_account,
5492 b_to_a_amount,
5493 minimum_a_amount,
5494 )
5495 .unwrap();
5496
5497 let results = swap_curve
5498 .swap(
5499 b_to_a_amount.try_into().unwrap(),
5500 token_b_amount.try_into().unwrap(),
5501 token_a_amount.try_into().unwrap(),
5502 TradeDirection::BtoA,
5503 &fees,
5504 )
5505 .unwrap();
5506
5507 let swap_token_a =
5508 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
5509 let token_a_amount = swap_token_a.amount;
5510 assert_eq!(
5511 token_a_amount,
5512 TryInto::<u64>::try_into(results.new_swap_destination_amount).unwrap()
5513 );
5514 let token_a = gpl_token::state::Account::unpack(&token_a_account.data).unwrap();
5515 assert_eq!(
5516 token_a.amount,
5517 initial_a - a_to_b_amount + to_u64(results.destination_amount_swapped).unwrap()
5518 );
5519
5520 let swap_token_b =
5521 gpl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap();
5522 let token_b_amount = swap_token_b.amount;
5523 assert_eq!(
5524 token_b_amount,
5525 TryInto::<u64>::try_into(results.new_swap_source_amount).unwrap()
5526 );
5527 let token_b = gpl_token::state::Account::unpack(&token_b_account.data).unwrap();
5528 assert_eq!(
5529 token_b.amount,
5530 initial_b + to_u64(first_swap_amount).unwrap()
5531 - to_u64(results.source_amount_swapped).unwrap()
5532 );
5533
5534 let second_fee = swap_curve
5535 .withdraw_single_token_type_exact_out(
5536 results.owner_fee,
5537 token_a_amount.try_into().unwrap(),
5538 token_b_amount.try_into().unwrap(),
5539 initial_supply.try_into().unwrap(),
5540 TradeDirection::BtoA,
5541 &fees,
5542 )
5543 .unwrap();
5544 let fee_account =
5545 gpl_token::state::Account::unpack(&accounts.pool_fee_account.data).unwrap();
5546 assert_eq!(fee_account.amount, to_u64(first_fee + second_fee).unwrap());
5547 }
5548
5549 #[test]
5550 fn test_valid_swap_curves_all_fees() {
5551 let trade_fee_numerator = 1;
5553 let trade_fee_denominator = 10;
5554 let owner_trade_fee_numerator = 1;
5555 let owner_trade_fee_denominator = 30;
5556 let owner_withdraw_fee_numerator = 1;
5557 let owner_withdraw_fee_denominator = 30;
5558 let host_fee_numerator = 20;
5559 let host_fee_denominator = 100;
5560 let fees = Fees {
5561 trade_fee_numerator,
5562 trade_fee_denominator,
5563 owner_trade_fee_numerator,
5564 owner_trade_fee_denominator,
5565 owner_withdraw_fee_numerator,
5566 owner_withdraw_fee_denominator,
5567 host_fee_numerator,
5568 host_fee_denominator,
5569 };
5570
5571 let token_a_amount = 10_000_000_000;
5572 let token_b_amount = 50_000_000_000;
5573
5574 check_valid_swap_curve(
5575 fees.clone(),
5576 CurveType::ConstantProduct,
5577 Box::new(ConstantProductCurve {}),
5578 token_a_amount,
5579 token_b_amount,
5580 );
5581 let token_b_price = 1;
5582 check_valid_swap_curve(
5583 fees.clone(),
5584 CurveType::ConstantPrice,
5585 Box::new(ConstantPriceCurve { token_b_price }),
5586 token_a_amount,
5587 token_b_amount,
5588 );
5589 let token_b_offset = 10_000_000_000;
5590 check_valid_swap_curve(
5591 fees,
5592 CurveType::Offset,
5593 Box::new(OffsetCurve { token_b_offset }),
5594 token_a_amount,
5595 token_b_amount,
5596 );
5597 }
5598
5599 #[test]
5600 fn test_valid_swap_curves_trade_fee_only() {
5601 let trade_fee_numerator = 1;
5602 let trade_fee_denominator = 10;
5603 let owner_trade_fee_numerator = 0;
5604 let owner_trade_fee_denominator = 0;
5605 let owner_withdraw_fee_numerator = 0;
5606 let owner_withdraw_fee_denominator = 0;
5607 let host_fee_numerator = 0;
5608 let host_fee_denominator = 0;
5609 let fees = Fees {
5610 trade_fee_numerator,
5611 trade_fee_denominator,
5612 owner_trade_fee_numerator,
5613 owner_trade_fee_denominator,
5614 owner_withdraw_fee_numerator,
5615 owner_withdraw_fee_denominator,
5616 host_fee_numerator,
5617 host_fee_denominator,
5618 };
5619
5620 let token_a_amount = 10_000_000_000;
5621 let token_b_amount = 50_000_000_000;
5622
5623 check_valid_swap_curve(
5624 fees.clone(),
5625 CurveType::ConstantProduct,
5626 Box::new(ConstantProductCurve {}),
5627 token_a_amount,
5628 token_b_amount,
5629 );
5630 let token_b_price = 10_000;
5631 check_valid_swap_curve(
5632 fees.clone(),
5633 CurveType::ConstantPrice,
5634 Box::new(ConstantPriceCurve { token_b_price }),
5635 token_a_amount,
5636 token_b_amount / token_b_price,
5637 );
5638 let token_b_offset = 1;
5639 check_valid_swap_curve(
5640 fees,
5641 CurveType::Offset,
5642 Box::new(OffsetCurve { token_b_offset }),
5643 token_a_amount,
5644 token_b_amount,
5645 );
5646 }
5647
5648 #[test]
5649 fn test_valid_swap_with_fee_constraints() {
5650 let owner_key = Pubkey::new_unique();
5651
5652 let trade_fee_numerator = 1;
5653 let trade_fee_denominator = 10;
5654 let owner_trade_fee_numerator = 1;
5655 let owner_trade_fee_denominator = 30;
5656 let owner_withdraw_fee_numerator = 1;
5657 let owner_withdraw_fee_denominator = 30;
5658 let host_fee_numerator = 10;
5659 let host_fee_denominator = 100;
5660
5661 let token_a_amount = 1_000_000;
5662 let token_b_amount = 5_000_000;
5663
5664 let fees = Fees {
5665 trade_fee_numerator,
5666 trade_fee_denominator,
5667 owner_trade_fee_numerator,
5668 owner_trade_fee_denominator,
5669 owner_withdraw_fee_numerator,
5670 owner_withdraw_fee_denominator,
5671 host_fee_numerator,
5672 host_fee_denominator,
5673 };
5674
5675 let curve = ConstantProductCurve {};
5676 let swap_curve = SwapCurve {
5677 curve_type: CurveType::ConstantProduct,
5678 calculator: Box::new(curve),
5679 };
5680
5681 let owner_key_str = &owner_key.to_string();
5682 let valid_curve_types = &[CurveType::ConstantProduct];
5683 let constraints = Some(SwapConstraints {
5684 owner_key: owner_key_str,
5685 valid_curve_types,
5686 fees: &fees,
5687 });
5688 let mut accounts = SwapAccountInfo::new(
5689 &owner_key,
5690 fees.clone(),
5691 swap_curve,
5692 token_a_amount,
5693 token_b_amount,
5694 );
5695
5696 do_process_instruction_with_fee_constraints(
5698 initialize(
5699 &SWAP_PROGRAM_ID,
5700 &gpl_token::id(),
5701 &accounts.swap_key,
5702 &accounts.authority_key,
5703 &accounts.token_a_key,
5704 &accounts.token_b_key,
5705 &accounts.pool_mint_key,
5706 &accounts.pool_fee_key,
5707 &accounts.pool_token_key,
5708 accounts.fees.clone(),
5709 accounts.swap_curve.clone(),
5710 )
5711 .unwrap(),
5712 vec![
5713 &mut accounts.swap_account,
5714 &mut Account::default(),
5715 &mut accounts.token_a_account,
5716 &mut accounts.token_b_account,
5717 &mut accounts.pool_mint_account,
5718 &mut accounts.pool_fee_account,
5719 &mut accounts.pool_token_account,
5720 &mut Account::default(),
5721 ],
5722 &constraints,
5723 )
5724 .unwrap();
5725
5726 let authority_key = accounts.authority_key;
5727
5728 let (
5729 token_a_key,
5730 mut token_a_account,
5731 token_b_key,
5732 mut token_b_account,
5733 pool_key,
5734 mut pool_account,
5735 ) = accounts.setup_token_accounts(
5736 &owner_key,
5737 &authority_key,
5738 token_a_amount,
5739 token_b_amount,
5740 0,
5741 );
5742
5743 let amount_in = token_a_amount / 2;
5744 let minimum_amount_out = 0;
5745
5746 do_process_instruction_with_fee_constraints(
5748 swap(
5749 &SWAP_PROGRAM_ID,
5750 &gpl_token::id(),
5751 &accounts.swap_key,
5752 &accounts.authority_key,
5753 &accounts.authority_key,
5754 &token_a_key,
5755 &accounts.token_a_key,
5756 &accounts.token_b_key,
5757 &token_b_key,
5758 &accounts.pool_mint_key,
5759 &accounts.pool_fee_key,
5760 Some(&pool_key),
5761 Swap {
5762 amount_in,
5763 minimum_amount_out,
5764 },
5765 )
5766 .unwrap(),
5767 vec![
5768 &mut accounts.swap_account,
5769 &mut Account::default(),
5770 &mut Account::default(),
5771 &mut token_a_account,
5772 &mut accounts.token_a_account,
5773 &mut accounts.token_b_account,
5774 &mut token_b_account,
5775 &mut accounts.pool_mint_account,
5776 &mut accounts.pool_fee_account,
5777 &mut Account::default(),
5778 &mut pool_account,
5779 ],
5780 &constraints,
5781 )
5782 .unwrap();
5783
5784 let host_fee_account = gpl_token::state::Account::unpack(&pool_account.data).unwrap();
5786 let owner_fee_account =
5787 gpl_token::state::Account::unpack(&accounts.pool_fee_account.data).unwrap();
5788 let total_fee = owner_fee_account.amount * host_fee_denominator
5789 / (host_fee_denominator - host_fee_numerator);
5790 assert_eq!(
5791 total_fee,
5792 host_fee_account.amount + owner_fee_account.amount
5793 );
5794 }
5795
5796 #[test]
5797 fn test_invalid_swap() {
5798 let user_key = Pubkey::new_unique();
5799 let swapper_key = Pubkey::new_unique();
5800 let trade_fee_numerator = 1;
5801 let trade_fee_denominator = 4;
5802 let owner_trade_fee_numerator = 1;
5803 let owner_trade_fee_denominator = 10;
5804 let owner_withdraw_fee_numerator = 1;
5805 let owner_withdraw_fee_denominator = 5;
5806 let host_fee_numerator = 9;
5807 let host_fee_denominator = 100;
5808 let fees = Fees {
5809 trade_fee_numerator,
5810 trade_fee_denominator,
5811 owner_trade_fee_numerator,
5812 owner_trade_fee_denominator,
5813 owner_withdraw_fee_numerator,
5814 owner_withdraw_fee_denominator,
5815 host_fee_numerator,
5816 host_fee_denominator,
5817 };
5818
5819 let token_a_amount = 1000;
5820 let token_b_amount = 5000;
5821 let curve_type = CurveType::ConstantProduct;
5822 let swap_curve = SwapCurve {
5823 curve_type,
5824 calculator: Box::new(ConstantProductCurve {}),
5825 };
5826 let mut accounts =
5827 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
5828
5829 let initial_a = token_a_amount / 5;
5830 let initial_b = token_b_amount / 5;
5831 let minimum_token_b_amount = initial_b / 2;
5832
5833 let swap_token_a_key = accounts.token_a_key;
5834 let swap_token_b_key = accounts.token_b_key;
5835
5836 {
5838 let (
5839 token_a_key,
5840 mut token_a_account,
5841 token_b_key,
5842 mut token_b_account,
5843 _pool_key,
5844 _pool_account,
5845 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
5846 assert_eq!(
5847 Err(ProgramError::UninitializedAccount),
5848 accounts.swap(
5849 &swapper_key,
5850 &token_a_key,
5851 &mut token_a_account,
5852 &swap_token_a_key,
5853 &swap_token_b_key,
5854 &token_b_key,
5855 &mut token_b_account,
5856 initial_a,
5857 minimum_token_b_amount,
5858 )
5859 );
5860 }
5861
5862 accounts.initialize_swap().unwrap();
5863
5864 {
5866 let (
5867 token_a_key,
5868 mut token_a_account,
5869 token_b_key,
5870 mut token_b_account,
5871 _pool_key,
5872 _pool_account,
5873 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
5874 let old_swap_account = accounts.swap_account;
5875 let mut wrong_swap_account = old_swap_account.clone();
5876 wrong_swap_account.owner = gpl_token::id();
5877 accounts.swap_account = wrong_swap_account;
5878 assert_eq!(
5879 Err(ProgramError::IncorrectProgramId),
5880 accounts.swap(
5881 &swapper_key,
5882 &token_a_key,
5883 &mut token_a_account,
5884 &swap_token_a_key,
5885 &swap_token_b_key,
5886 &token_b_key,
5887 &mut token_b_account,
5888 initial_a,
5889 minimum_token_b_amount,
5890 )
5891 );
5892 accounts.swap_account = old_swap_account;
5893 }
5894
5895 {
5897 let (
5898 token_a_key,
5899 mut token_a_account,
5900 token_b_key,
5901 mut token_b_account,
5902 _pool_key,
5903 _pool_account,
5904 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
5905 let old_authority = accounts.authority_key;
5906 let (bad_authority_key, _bump_seed) = Pubkey::find_program_address(
5907 &[&accounts.swap_key.to_bytes()[..]],
5908 &gpl_token::id(),
5909 );
5910 accounts.authority_key = bad_authority_key;
5911 assert_eq!(
5912 Err(SwapError::InvalidProgramAddress.into()),
5913 accounts.swap(
5914 &swapper_key,
5915 &token_a_key,
5916 &mut token_a_account,
5917 &swap_token_a_key,
5918 &swap_token_b_key,
5919 &token_b_key,
5920 &mut token_b_account,
5921 initial_a,
5922 minimum_token_b_amount,
5923 )
5924 );
5925 accounts.authority_key = old_authority;
5926 }
5927
5928 {
5930 let (
5931 token_a_key,
5932 mut token_a_account,
5933 token_b_key,
5934 mut token_b_account,
5935 _pool_key,
5936 _pool_account,
5937 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
5938 let wrong_program_id = Pubkey::new_unique();
5939 assert_eq!(
5940 Err(SwapError::IncorrectTokenProgramId.into()),
5941 do_process_instruction(
5942 swap(
5943 &SWAP_PROGRAM_ID,
5944 &wrong_program_id,
5945 &accounts.swap_key,
5946 &accounts.authority_key,
5947 &accounts.authority_key,
5948 &token_a_key,
5949 &accounts.token_a_key,
5950 &accounts.token_b_key,
5951 &token_b_key,
5952 &accounts.pool_mint_key,
5953 &accounts.pool_fee_key,
5954 None,
5955 Swap {
5956 amount_in: initial_a,
5957 minimum_amount_out: minimum_token_b_amount,
5958 },
5959 )
5960 .unwrap(),
5961 vec![
5962 &mut accounts.swap_account,
5963 &mut Account::default(),
5964 &mut Account::default(),
5965 &mut token_a_account,
5966 &mut accounts.token_a_account,
5967 &mut accounts.token_b_account,
5968 &mut token_b_account,
5969 &mut accounts.pool_mint_account,
5970 &mut accounts.pool_fee_account,
5971 &mut Account::default(),
5972 ],
5973 ),
5974 );
5975 }
5976
5977 {
5979 let (
5980 token_a_key,
5981 mut token_a_account,
5982 token_b_key,
5983 mut token_b_account,
5984 _pool_key,
5985 _pool_account,
5986 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
5987 assert_eq!(
5988 Err(TokenError::InsufficientFunds.into()),
5989 accounts.swap(
5990 &swapper_key,
5991 &token_a_key,
5992 &mut token_a_account,
5993 &swap_token_a_key,
5994 &swap_token_b_key,
5995 &token_b_key,
5996 &mut token_b_account,
5997 initial_a * 2,
5998 minimum_token_b_amount * 2,
5999 )
6000 );
6001 }
6002
6003 {
6005 let (
6006 token_a_key,
6007 mut token_a_account,
6008 token_b_key,
6009 mut token_b_account,
6010 _pool_key,
6011 _pool_account,
6012 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6013 let user_transfer_key = Pubkey::new_unique();
6014 assert_eq!(
6015 Err(SwapError::IncorrectSwapAccount.into()),
6016 do_process_instruction(
6017 swap(
6018 &SWAP_PROGRAM_ID,
6019 &gpl_token::id(),
6020 &accounts.swap_key,
6021 &accounts.authority_key,
6022 &user_transfer_key,
6023 &token_a_key,
6024 &token_a_key,
6025 &token_b_key,
6026 &token_b_key,
6027 &accounts.pool_mint_key,
6028 &accounts.pool_fee_key,
6029 None,
6030 Swap {
6031 amount_in: initial_a,
6032 minimum_amount_out: minimum_token_b_amount,
6033 },
6034 )
6035 .unwrap(),
6036 vec![
6037 &mut accounts.swap_account,
6038 &mut Account::default(),
6039 &mut Account::default(),
6040 &mut token_a_account.clone(),
6041 &mut token_a_account,
6042 &mut token_b_account.clone(),
6043 &mut token_b_account,
6044 &mut accounts.pool_mint_account,
6045 &mut accounts.pool_fee_account,
6046 &mut Account::default(),
6047 ],
6048 ),
6049 );
6050 }
6051
6052 {
6054 let (
6055 token_a_key,
6056 mut token_a_account,
6057 token_b_key,
6058 mut token_b_account,
6059 _pool_key,
6060 _pool_account,
6061 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6062 assert_eq!(
6063 Err(TokenError::MintMismatch.into()),
6064 accounts.swap(
6065 &swapper_key,
6066 &token_b_key,
6067 &mut token_b_account,
6068 &swap_token_a_key,
6069 &swap_token_b_key,
6070 &token_a_key,
6071 &mut token_a_account,
6072 initial_a,
6073 minimum_token_b_amount,
6074 )
6075 );
6076 }
6077
6078 {
6080 let (
6081 token_a_key,
6082 mut token_a_account,
6083 _token_b_key,
6084 _token_b_account,
6085 _pool_key,
6086 _pool_account,
6087 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6088 assert_eq!(
6089 Err(SwapError::InvalidInput.into()),
6090 accounts.swap(
6091 &swapper_key,
6092 &token_a_key,
6093 &mut token_a_account.clone(),
6094 &swap_token_a_key,
6095 &swap_token_a_key,
6096 &token_a_key,
6097 &mut token_a_account,
6098 initial_a,
6099 minimum_token_b_amount,
6100 )
6101 );
6102 }
6103
6104 {
6106 let (
6107 token_a_key,
6108 mut token_a_account,
6109 token_b_key,
6110 mut token_b_account,
6111 _pool_key,
6112 _pool_account,
6113 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6114 let (pool_mint_key, pool_mint_account) =
6115 create_mint(&gpl_token::id(), &accounts.authority_key, None);
6116 let old_pool_key = accounts.pool_mint_key;
6117 let old_pool_account = accounts.pool_mint_account;
6118 accounts.pool_mint_key = pool_mint_key;
6119 accounts.pool_mint_account = pool_mint_account;
6120
6121 assert_eq!(
6122 Err(SwapError::IncorrectPoolMint.into()),
6123 accounts.swap(
6124 &swapper_key,
6125 &token_a_key,
6126 &mut token_a_account,
6127 &swap_token_a_key,
6128 &swap_token_b_key,
6129 &token_b_key,
6130 &mut token_b_account,
6131 initial_a,
6132 minimum_token_b_amount,
6133 )
6134 );
6135
6136 accounts.pool_mint_key = old_pool_key;
6137 accounts.pool_mint_account = old_pool_account;
6138 }
6139
6140 {
6142 let (
6143 token_a_key,
6144 mut token_a_account,
6145 token_b_key,
6146 mut token_b_account,
6147 wrong_pool_key,
6148 wrong_pool_account,
6149 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6150 let old_pool_fee_account = accounts.pool_fee_account;
6151 let old_pool_fee_key = accounts.pool_fee_key;
6152 accounts.pool_fee_account = wrong_pool_account;
6153 accounts.pool_fee_key = wrong_pool_key;
6154 assert_eq!(
6155 Err(SwapError::IncorrectFeeAccount.into()),
6156 accounts.swap(
6157 &swapper_key,
6158 &token_a_key,
6159 &mut token_a_account,
6160 &swap_token_a_key,
6161 &swap_token_b_key,
6162 &token_b_key,
6163 &mut token_b_account,
6164 initial_a,
6165 minimum_token_b_amount,
6166 )
6167 );
6168 accounts.pool_fee_account = old_pool_fee_account;
6169 accounts.pool_fee_key = old_pool_fee_key;
6170 }
6171
6172 {
6174 let (
6175 token_a_key,
6176 mut token_a_account,
6177 token_b_key,
6178 mut token_b_account,
6179 _pool_key,
6180 _pool_account,
6181 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6182 let user_transfer_key = Pubkey::new_unique();
6183 assert_eq!(
6184 Err(TokenError::OwnerMismatch.into()),
6185 do_process_instruction(
6186 swap(
6187 &SWAP_PROGRAM_ID,
6188 &gpl_token::id(),
6189 &accounts.swap_key,
6190 &accounts.authority_key,
6191 &user_transfer_key,
6192 &token_a_key,
6193 &accounts.token_a_key,
6194 &accounts.token_b_key,
6195 &token_b_key,
6196 &accounts.pool_mint_key,
6197 &accounts.pool_fee_key,
6198 None,
6199 Swap {
6200 amount_in: initial_a,
6201 minimum_amount_out: minimum_token_b_amount,
6202 },
6203 )
6204 .unwrap(),
6205 vec![
6206 &mut accounts.swap_account,
6207 &mut Account::default(),
6208 &mut Account::default(),
6209 &mut token_a_account,
6210 &mut accounts.token_a_account,
6211 &mut accounts.token_b_account,
6212 &mut token_b_account,
6213 &mut accounts.pool_mint_account,
6214 &mut accounts.pool_fee_account,
6215 &mut Account::default(),
6216 ],
6217 ),
6218 );
6219 }
6220
6221 {
6223 let (
6224 token_a_key,
6225 mut token_a_account,
6226 token_b_key,
6227 mut token_b_account,
6228 _pool_key,
6229 _pool_account,
6230 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6231 assert_eq!(
6232 Err(SwapError::ZeroTradingTokens.into()),
6233 accounts.swap(
6234 &swapper_key,
6235 &token_b_key,
6236 &mut token_b_account,
6237 &swap_token_b_key,
6238 &swap_token_a_key,
6239 &token_a_key,
6240 &mut token_a_account,
6241 1,
6242 1,
6243 )
6244 );
6245 }
6246
6247 {
6249 let (
6250 token_a_key,
6251 mut token_a_account,
6252 token_b_key,
6253 mut token_b_account,
6254 _pool_key,
6255 _pool_account,
6256 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6257 assert_eq!(
6258 Err(SwapError::ExceededSlippage.into()),
6259 accounts.swap(
6260 &swapper_key,
6261 &token_a_key,
6262 &mut token_a_account,
6263 &swap_token_a_key,
6264 &swap_token_b_key,
6265 &token_b_key,
6266 &mut token_b_account,
6267 initial_a,
6268 minimum_token_b_amount * 2,
6269 )
6270 );
6271 }
6272
6273 {
6275 let (
6276 token_a_key,
6277 mut token_a_account,
6278 token_b_key,
6279 mut token_b_account,
6280 _pool_key,
6281 _pool_account,
6282 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6283 let mut swap_token_a_account = accounts.get_token_account(&swap_token_a_key).clone();
6284 let authority_key = accounts.authority_key;
6285 assert_eq!(
6286 Err(SwapError::InvalidInput.into()),
6287 accounts.swap(
6288 &authority_key,
6289 &swap_token_a_key,
6290 &mut swap_token_a_account,
6291 &swap_token_a_key,
6292 &swap_token_b_key,
6293 &token_b_key,
6294 &mut token_b_account,
6295 initial_a,
6296 minimum_token_b_amount,
6297 )
6298 );
6299 let mut swap_token_b_account = accounts.get_token_account(&swap_token_b_key).clone();
6300 assert_eq!(
6301 Err(SwapError::InvalidInput.into()),
6302 accounts.swap(
6303 &swapper_key,
6304 &token_a_key,
6305 &mut token_a_account,
6306 &swap_token_a_key,
6307 &swap_token_b_key,
6308 &swap_token_b_key,
6309 &mut swap_token_b_account,
6310 initial_a,
6311 minimum_token_b_amount,
6312 )
6313 );
6314 }
6315
6316 {
6318 let authority_key = accounts.authority_key;
6319 let (
6320 token_a_key,
6321 mut token_a_account,
6322 token_b_key,
6323 mut token_b_account,
6324 _pool_key,
6325 _pool_account,
6326 ) = accounts.setup_token_accounts(&user_key, &authority_key, initial_a, initial_b, 0);
6327 let owner_key = &swapper_key.to_string();
6328 let fees = Fees {
6329 trade_fee_numerator,
6330 trade_fee_denominator,
6331 owner_trade_fee_numerator,
6332 owner_trade_fee_denominator,
6333 owner_withdraw_fee_numerator,
6334 owner_withdraw_fee_denominator,
6335 host_fee_numerator,
6336 host_fee_denominator,
6337 };
6338 let constraints = Some(SwapConstraints {
6339 owner_key,
6340 valid_curve_types: &[],
6341 fees: &fees,
6342 });
6343 do_process_instruction_with_fee_constraints(
6344 swap(
6345 &SWAP_PROGRAM_ID,
6346 &gpl_token::id(),
6347 &accounts.swap_key,
6348 &accounts.authority_key,
6349 &accounts.authority_key,
6350 &token_a_key,
6351 &accounts.token_a_key,
6352 &accounts.token_b_key,
6353 &token_b_key,
6354 &accounts.pool_mint_key,
6355 &accounts.pool_fee_key,
6356 None,
6357 Swap {
6358 amount_in: initial_a,
6359 minimum_amount_out: minimum_token_b_amount,
6360 },
6361 )
6362 .unwrap(),
6363 vec![
6364 &mut accounts.swap_account,
6365 &mut Account::default(),
6366 &mut Account::default(),
6367 &mut token_a_account,
6368 &mut accounts.token_a_account,
6369 &mut accounts.token_b_account,
6370 &mut token_b_account,
6371 &mut accounts.pool_mint_account,
6372 &mut accounts.pool_fee_account,
6373 &mut Account::default(),
6374 ],
6375 &constraints,
6376 )
6377 .unwrap();
6378 }
6379
6380 {
6382 let authority_key = accounts.authority_key;
6383 let (
6384 token_a_key,
6385 mut token_a_account,
6386 token_b_key,
6387 mut token_b_account,
6388 _pool_key,
6389 _pool_account,
6390 ) = accounts.setup_token_accounts(&user_key, &authority_key, initial_a, initial_b, 0);
6391 let (
6392 bad_token_a_key,
6393 mut bad_token_a_account,
6394 _token_b_key,
6395 mut _token_b_account,
6396 _pool_key,
6397 _pool_account,
6398 ) = accounts.setup_token_accounts(&user_key, &authority_key, initial_a, initial_b, 0);
6399 let owner_key = &swapper_key.to_string();
6400 let fees = Fees {
6401 trade_fee_numerator,
6402 trade_fee_denominator,
6403 owner_trade_fee_numerator,
6404 owner_trade_fee_denominator,
6405 owner_withdraw_fee_numerator,
6406 owner_withdraw_fee_denominator,
6407 host_fee_numerator,
6408 host_fee_denominator,
6409 };
6410 let constraints = Some(SwapConstraints {
6411 owner_key,
6412 valid_curve_types: &[],
6413 fees: &fees,
6414 });
6415 assert_eq!(
6416 Err(SwapError::IncorrectPoolMint.into()),
6417 do_process_instruction_with_fee_constraints(
6418 swap(
6419 &SWAP_PROGRAM_ID,
6420 &gpl_token::id(),
6421 &accounts.swap_key,
6422 &accounts.authority_key,
6423 &accounts.authority_key,
6424 &token_a_key,
6425 &accounts.token_a_key,
6426 &accounts.token_b_key,
6427 &token_b_key,
6428 &accounts.pool_mint_key,
6429 &accounts.pool_fee_key,
6430 Some(&bad_token_a_key),
6431 Swap {
6432 amount_in: initial_a,
6433 minimum_amount_out: 0,
6434 },
6435 )
6436 .unwrap(),
6437 vec![
6438 &mut accounts.swap_account,
6439 &mut Account::default(),
6440 &mut Account::default(),
6441 &mut token_a_account,
6442 &mut accounts.token_a_account,
6443 &mut accounts.token_b_account,
6444 &mut token_b_account,
6445 &mut accounts.pool_mint_account,
6446 &mut accounts.pool_fee_account,
6447 &mut Account::default(),
6448 &mut bad_token_a_account,
6449 ],
6450 &constraints,
6451 ),
6452 );
6453 }
6454 }
6455
6456 #[test]
6457 fn test_overdraw_offset_curve() {
6458 let trade_fee_numerator = 1;
6459 let trade_fee_denominator = 10;
6460 let owner_trade_fee_numerator = 1;
6461 let owner_trade_fee_denominator = 30;
6462 let owner_withdraw_fee_numerator = 1;
6463 let owner_withdraw_fee_denominator = 30;
6464 let host_fee_numerator = 10;
6465 let host_fee_denominator = 100;
6466
6467 let token_a_amount = 1_000_000_000;
6468 let token_b_amount = 0;
6469 let fees = Fees {
6470 trade_fee_numerator,
6471 trade_fee_denominator,
6472 owner_trade_fee_numerator,
6473 owner_trade_fee_denominator,
6474 owner_withdraw_fee_numerator,
6475 owner_withdraw_fee_denominator,
6476 host_fee_numerator,
6477 host_fee_denominator,
6478 };
6479
6480 let token_b_offset = 2_000_000;
6481 let swap_curve = SwapCurve {
6482 curve_type: CurveType::Offset,
6483 calculator: Box::new(OffsetCurve { token_b_offset }),
6484 };
6485 let user_key = Pubkey::new_unique();
6486 let swapper_key = Pubkey::new_unique();
6487
6488 let mut accounts =
6489 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
6490
6491 accounts.initialize_swap().unwrap();
6492
6493 let swap_token_a_key = accounts.token_a_key;
6494 let swap_token_b_key = accounts.token_b_key;
6495 let initial_a = 500_000;
6496 let initial_b = 1_000;
6497
6498 let (
6499 token_a_key,
6500 mut token_a_account,
6501 token_b_key,
6502 mut token_b_account,
6503 _pool_key,
6504 _pool_account,
6505 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6506
6507 let a_to_b_amount = initial_a;
6509 let minimum_token_b_amount = 0;
6510
6511 assert_eq!(
6512 Err(SwapError::ZeroTradingTokens.into()),
6513 accounts.swap(
6514 &swapper_key,
6515 &token_a_key,
6516 &mut token_a_account,
6517 &swap_token_a_key,
6518 &swap_token_b_key,
6519 &token_b_key,
6520 &mut token_b_account,
6521 a_to_b_amount,
6522 minimum_token_b_amount,
6523 )
6524 );
6525
6526 let b_to_a_amount = initial_b;
6528 let minimum_token_a_amount = 0;
6529 accounts
6530 .swap(
6531 &swapper_key,
6532 &token_b_key,
6533 &mut token_b_account,
6534 &swap_token_b_key,
6535 &swap_token_a_key,
6536 &token_a_key,
6537 &mut token_a_account,
6538 b_to_a_amount,
6539 minimum_token_a_amount,
6540 )
6541 .unwrap();
6542
6543 accounts
6545 .swap(
6546 &swapper_key,
6547 &token_a_key,
6548 &mut token_a_account,
6549 &swap_token_a_key,
6550 &swap_token_b_key,
6551 &token_b_key,
6552 &mut token_b_account,
6553 a_to_b_amount,
6554 minimum_token_b_amount,
6555 )
6556 .unwrap();
6557
6558 assert_eq!(
6560 Err(SwapError::ZeroTradingTokens.into()),
6561 accounts.swap(
6562 &swapper_key,
6563 &token_a_key,
6564 &mut token_a_account,
6565 &swap_token_a_key,
6566 &swap_token_b_key,
6567 &token_b_key,
6568 &mut token_b_account,
6569 a_to_b_amount,
6570 minimum_token_b_amount,
6571 )
6572 );
6573
6574 {
6577 let initial_a = 100;
6578 let initial_b = 100;
6579 let pool_amount = 100;
6580 let (
6581 token_a_key,
6582 mut token_a_account,
6583 token_b_key,
6584 mut token_b_account,
6585 pool_key,
6586 mut pool_account,
6587 ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
6588 assert_eq!(
6589 Err(SwapError::UnsupportedCurveOperation.into()),
6590 accounts.deposit_all_token_types(
6591 &swapper_key,
6592 &token_a_key,
6593 &mut token_a_account,
6594 &token_b_key,
6595 &mut token_b_account,
6596 &pool_key,
6597 &mut pool_account,
6598 pool_amount,
6599 initial_a,
6600 initial_b,
6601 )
6602 );
6603 }
6604 }
6605
6606 #[test]
6607 fn test_withdraw_all_offset_curve() {
6608 let trade_fee_numerator = 1;
6609 let trade_fee_denominator = 10;
6610 let owner_trade_fee_numerator = 1;
6611 let owner_trade_fee_denominator = 30;
6612 let owner_withdraw_fee_numerator = 0;
6613 let owner_withdraw_fee_denominator = 30;
6614 let host_fee_numerator = 10;
6615 let host_fee_denominator = 100;
6616
6617 let token_a_amount = 1_000_000_000;
6618 let token_b_amount = 10;
6619 let fees = Fees {
6620 trade_fee_numerator,
6621 trade_fee_denominator,
6622 owner_trade_fee_numerator,
6623 owner_trade_fee_denominator,
6624 owner_withdraw_fee_numerator,
6625 owner_withdraw_fee_denominator,
6626 host_fee_numerator,
6627 host_fee_denominator,
6628 };
6629
6630 let token_b_offset = 2_000_000;
6631 let swap_curve = SwapCurve {
6632 curve_type: CurveType::Offset,
6633 calculator: Box::new(OffsetCurve { token_b_offset }),
6634 };
6635 let total_pool = swap_curve.calculator.new_pool_supply();
6636 let user_key = Pubkey::new_unique();
6637 let withdrawer_key = Pubkey::new_unique();
6638
6639 let mut accounts =
6640 SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount);
6641
6642 accounts.initialize_swap().unwrap();
6643
6644 let (
6645 token_a_key,
6646 mut token_a_account,
6647 token_b_key,
6648 mut token_b_account,
6649 _pool_key,
6650 _pool_account,
6651 ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, 0, 0, 0);
6652
6653 let pool_key = accounts.pool_token_key;
6654 let mut pool_account = accounts.pool_token_account.clone();
6655
6656 accounts
6661 .withdraw_all_token_types(
6662 &user_key,
6663 &pool_key,
6664 &mut pool_account,
6665 &token_a_key,
6666 &mut token_a_account,
6667 &token_b_key,
6668 &mut token_b_account,
6669 total_pool.try_into().unwrap(),
6670 0,
6671 0,
6672 )
6673 .unwrap();
6674
6675 let token_a = gpl_token::state::Account::unpack(&token_a_account.data).unwrap();
6676 assert_eq!(token_a.amount, token_a_amount);
6677 let token_b = gpl_token::state::Account::unpack(&token_b_account.data).unwrap();
6678 assert_eq!(token_b.amount, token_b_amount);
6679 let swap_token_a =
6680 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
6681 assert_eq!(swap_token_a.amount, 0);
6682 let swap_token_b =
6683 gpl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap();
6684 assert_eq!(swap_token_b.amount, 0);
6685 }
6686
6687 #[test]
6688 fn test_withdraw_all_constant_price_curve() {
6689 let trade_fee_numerator = 1;
6690 let trade_fee_denominator = 10;
6691 let owner_trade_fee_numerator = 1;
6692 let owner_trade_fee_denominator = 30;
6693 let owner_withdraw_fee_numerator = 0;
6694 let owner_withdraw_fee_denominator = 30;
6695 let host_fee_numerator = 10;
6696 let host_fee_denominator = 100;
6697
6698 let swap_token_a_amount = 1_000_000_000;
6702 let swap_token_b_amount = 1_000;
6703 let token_b_price = 2_000_000;
6704 let fees = Fees {
6705 trade_fee_numerator,
6706 trade_fee_denominator,
6707 owner_trade_fee_numerator,
6708 owner_trade_fee_denominator,
6709 owner_withdraw_fee_numerator,
6710 owner_withdraw_fee_denominator,
6711 host_fee_numerator,
6712 host_fee_denominator,
6713 };
6714
6715 let swap_curve = SwapCurve {
6716 curve_type: CurveType::ConstantPrice,
6717 calculator: Box::new(ConstantPriceCurve { token_b_price }),
6718 };
6719 let total_pool = swap_curve.calculator.new_pool_supply();
6720 let user_key = Pubkey::new_unique();
6721 let withdrawer_key = Pubkey::new_unique();
6722
6723 let mut accounts = SwapAccountInfo::new(
6724 &user_key,
6725 fees,
6726 swap_curve,
6727 swap_token_a_amount,
6728 swap_token_b_amount,
6729 );
6730
6731 accounts.initialize_swap().unwrap();
6732
6733 let (
6734 token_a_key,
6735 mut token_a_account,
6736 token_b_key,
6737 mut token_b_account,
6738 _pool_key,
6739 _pool_account,
6740 ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, 0, 0, 0);
6741
6742 let pool_key = accounts.pool_token_key;
6743 let mut pool_account = accounts.pool_token_account.clone();
6744
6745 assert_eq!(
6750 Err(SwapError::ExceededSlippage.into()),
6751 accounts.withdraw_all_token_types(
6752 &user_key,
6753 &pool_key,
6754 &mut pool_account,
6755 &token_a_key,
6756 &mut token_a_account,
6757 &token_b_key,
6758 &mut token_b_account,
6759 total_pool.try_into().unwrap(),
6760 swap_token_a_amount,
6761 swap_token_b_amount,
6762 )
6763 );
6764
6765 accounts
6766 .withdraw_all_token_types(
6767 &user_key,
6768 &pool_key,
6769 &mut pool_account,
6770 &token_a_key,
6771 &mut token_a_account,
6772 &token_b_key,
6773 &mut token_b_account,
6774 total_pool.try_into().unwrap(),
6775 0,
6776 0,
6777 )
6778 .unwrap();
6779
6780 let token_a = gpl_token::state::Account::unpack(&token_a_account.data).unwrap();
6781 assert_eq!(token_a.amount, swap_token_a_amount);
6782 let token_b = gpl_token::state::Account::unpack(&token_b_account.data).unwrap();
6783 assert_eq!(token_b.amount, 750);
6784 let swap_token_a =
6785 gpl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap();
6786 assert_eq!(swap_token_a.amount, 0);
6787 let swap_token_b =
6788 gpl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap();
6789 assert_eq!(swap_token_b.amount, 250);
6790
6791 let token_b_amount = 10;
6793 let token_a_amount = token_b_amount * token_b_price;
6794 let (
6795 token_a_key,
6796 mut token_a_account,
6797 token_b_key,
6798 mut token_b_account,
6799 pool_key,
6800 mut pool_account,
6801 ) = accounts.setup_token_accounts(
6802 &user_key,
6803 &withdrawer_key,
6804 token_a_amount,
6805 token_b_amount,
6806 0,
6807 );
6808
6809 assert_eq!(
6810 Err(SwapError::ExceededSlippage.into()),
6811 accounts.deposit_all_token_types(
6812 &withdrawer_key,
6813 &token_a_key,
6814 &mut token_a_account,
6815 &token_b_key,
6816 &mut token_b_account,
6817 &pool_key,
6818 &mut pool_account,
6819 1, token_a_amount,
6821 token_b_amount,
6822 )
6823 );
6824
6825 let token_b_amount = 125;
6827 let token_a_amount = token_b_amount * token_b_price;
6828 let (
6829 token_a_key,
6830 mut token_a_account,
6831 token_b_key,
6832 mut token_b_account,
6833 pool_key,
6834 mut pool_account,
6835 ) = accounts.setup_token_accounts(
6836 &user_key,
6837 &withdrawer_key,
6838 token_a_amount,
6839 token_b_amount,
6840 0,
6841 );
6842
6843 accounts
6844 .deposit_all_token_types(
6845 &withdrawer_key,
6846 &token_a_key,
6847 &mut token_a_account,
6848 &token_b_key,
6849 &mut token_b_account,
6850 &pool_key,
6851 &mut pool_account,
6852 1, token_a_amount,
6854 token_b_amount,
6855 )
6856 .unwrap();
6857 }
6858}