withdraw_liquidity.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. use spl_math::uint::U256;
  2. use steel::*;
  3. use token_swap_api::prelude::*;
  4. pub fn process_withdraw_liquidity(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
  5. // Load accounts.
  6. let [payer_info, depositor_info, pool_info, pool_authority_info, mint_liquidity_info, mint_a_info, mint_b_info, pool_account_a_info, pool_account_b_info, depositor_account_liquidity_info, depositor_account_a_info, depositor_account_b_info, token_program, system_program, associated_token_program] =
  7. accounts
  8. else {
  9. return Err(ProgramError::NotEnoughAccountKeys);
  10. };
  11. let args = WithdrawLiquidity::try_from_bytes(data)?;
  12. let amount = u64::from_le_bytes(args.amount);
  13. // Check payer account is signer and program is the correct program.
  14. payer_info.is_signer()?;
  15. token_program.is_program(&spl_token::ID)?;
  16. system_program.is_program(&system_program::ID)?;
  17. associated_token_program.is_program(&ASSOCIATED_TOKEN_PROGRAM_ID)?;
  18. // check if depositor is signer
  19. depositor_info.is_signer()?;
  20. // Verify mint_a and mint_b is a mint account.
  21. let _mint_a = mint_a_info.as_mint()?;
  22. let _mint_b = mint_b_info.as_mint()?;
  23. // validate pool account
  24. if pool_info.data_is_empty() {
  25. return Err(TokenSwapError::AccountIsNotExisted.into());
  26. }
  27. validate_pool_account(pool_info, *mint_a_info.key, *mint_b_info.key)?;
  28. let pool_info_data = pool_info.as_account_mut::<Pool>(&token_swap_api::ID)?;
  29. // validate pool authority
  30. validate_pool_authority(
  31. pool_info_data,
  32. pool_authority_info,
  33. *mint_a_info.key,
  34. *mint_b_info.key,
  35. )?;
  36. // validate mint liquidity
  37. validate_mint_liquidity(
  38. pool_info_data,
  39. mint_liquidity_info,
  40. *mint_a_info.key,
  41. *mint_b_info.key,
  42. )?;
  43. // // validate pool_account_a_info, pool_account_b_info
  44. let pool_account_a = pool_account_a_info
  45. .is_writable()?
  46. .as_associated_token_account(pool_authority_info.key, mint_a_info.key)?;
  47. let pool_account_b = pool_account_b_info
  48. .is_writable()?
  49. .as_associated_token_account(pool_authority_info.key, mint_b_info.key)?;
  50. // validate depositor_account_a_info and depositor_account_b_info
  51. let _depositor_account_a = depositor_account_a_info
  52. .is_writable()?
  53. .as_associated_token_account(depositor_info.key, mint_a_info.key)?;
  54. let _depositor_account_b = depositor_account_b_info
  55. .is_writable()?
  56. .as_associated_token_account(depositor_info.key, mint_b_info.key)?;
  57. let pool_authority_seeds = &[
  58. pool_info_data.amm.as_ref(),
  59. pool_info_data.mint_a.as_ref(),
  60. pool_info_data.mint_b.as_ref(),
  61. AUTHORITY_SEED,
  62. ];
  63. // Transfer tokens from the pool
  64. let mint_liquidity = mint_liquidity_info.as_mint()?;
  65. let amount_a = U256::from(amount)
  66. .checked_mul(U256::from(pool_account_a.amount))
  67. .unwrap()
  68. .checked_div(U256::from(mint_liquidity.supply + MINIMUM_LIQUIDITY))
  69. .unwrap()
  70. .as_u64();
  71. transfer_signed_with_bump(
  72. pool_authority_info,
  73. pool_account_a_info,
  74. depositor_account_a_info,
  75. token_program,
  76. amount_a,
  77. pool_authority_seeds,
  78. pool_info_data.pool_authority_bump,
  79. )?;
  80. let amount_b = U256::from(amount)
  81. .checked_mul(U256::from(pool_account_b.amount))
  82. .unwrap()
  83. .checked_div(U256::from(mint_liquidity.supply + MINIMUM_LIQUIDITY))
  84. .unwrap()
  85. .as_u64();
  86. transfer_signed_with_bump(
  87. pool_authority_info,
  88. pool_account_b_info,
  89. depositor_account_b_info,
  90. token_program,
  91. amount_b,
  92. pool_authority_seeds,
  93. pool_info_data.pool_authority_bump,
  94. )?;
  95. // Burn the liquidity tokens
  96. // It will fail if the amount is invalid
  97. burn(
  98. depositor_account_liquidity_info,
  99. mint_liquidity_info,
  100. depositor_info,
  101. token_program,
  102. amount,
  103. )?;
  104. Ok(())
  105. }