1use crate::constants::{
2 ATA_PROGRAM_ID, DEX_PROGRAM_ID, LAUNCHPAD_PROGRAM_ID, NEXUS_PROGRAM_ID,
3 SYSTEM_PROGRAM_ID, TOKEN_2022_PROGRAM_ID,
4};
5use solana_address::Address;
6
7#[derive(Clone, Debug)]
8pub struct BuildMigrateParams<'a> {
9 pub caller: &'a Address,
10 pub base_mint: &'a Address,
11 pub quote_mint: &'a Address,
12 pub quote_token_program: &'a Address,
13}
14
15#[must_use]
16pub fn build_migrate_instruction(
17 p: &BuildMigrateParams<'_>,
18) -> solana_instruction::Instruction {
19 let base_mint = p.base_mint;
20 let quote_mint = p.quote_mint;
21
22 let (bonding_curve, _) =
23 super::pda::find_bonding_curve_pda(base_mint, quote_mint);
24 let (base_vault, _) = crate::utils::find_associated_token_pda(
25 &bonding_curve,
26 base_mint,
27 &TOKEN_2022_PROGRAM_ID,
28 );
29 let (quote_vault, _) = crate::utils::find_associated_token_pda(
30 &bonding_curve,
31 quote_mint,
32 p.quote_token_program,
33 );
34 let (creator_fee_config, _) =
35 super::pda::find_creator_fee_config_pda(base_mint, quote_mint);
36
37 let (pool, _) = crate::dex::pda::find_pool_pda(base_mint, quote_mint);
38 let (lp_mint, _) = crate::dex::pda::find_lp_mint_pda(base_mint, quote_mint);
39 let (pool_base_vault, _) = crate::utils::find_associated_token_pda(
40 &pool,
41 base_mint,
42 &TOKEN_2022_PROGRAM_ID,
43 );
44 let (pool_quote_vault, _) = crate::utils::find_associated_token_pda(
45 &pool,
46 quote_mint,
47 p.quote_token_program,
48 );
49 let (pool_lp_account, _) = crate::utils::find_associated_token_pda(
50 &pool,
51 &lp_mint,
52 &TOKEN_2022_PROGRAM_ID,
53 );
54 let (dex_creator_fee_config, _) =
55 crate::dex::pda::find_creator_fee_config_pda(base_mint, quote_mint);
56
57 let migrate = super::instructions::Migrate {
58 caller: *p.caller,
59 bonding_curve,
60 base_mint: *base_mint,
61 quote_mint: *quote_mint,
62 base_vault,
63 quote_vault,
64 dex_program: DEX_PROGRAM_ID,
65 migration_authority: super::pda::MIGRATION_AUTHORITY_ADDRESS,
66 pool,
67 lp_mint,
68 pool_base_vault,
69 pool_quote_vault,
70 pool_lp_account,
71 dex_event_authority: crate::dex::pda::EVENT_AUTHORITY_ADDRESS,
72 nexus_program: NEXUS_PROGRAM_ID,
73 creator_fee_config,
74 base_token_program: TOKEN_2022_PROGRAM_ID,
75 quote_token_program: *p.quote_token_program,
76 associated_token_program: ATA_PROGRAM_ID,
77 system_program: SYSTEM_PROGRAM_ID,
78 event_authority: super::pda::EVENT_AUTHORITY_ADDRESS,
79 program: LAUNCHPAD_PROGRAM_ID,
80 dex_creator_fee_config,
81 };
82 migrate.instruction()
83}
84
85#[cfg(test)]
86mod tests {
87 use solana_address::Address;
88
89 use super::{BuildMigrateParams, build_migrate_instruction};
90 use crate::constants::{
91 DEX_PROGRAM_ID, LAUNCHPAD_PROGRAM_ID, TOKEN_PROGRAM_ID, WSOL_MINT,
92 };
93
94 const CREATOR_FEE_CONFIG_INDEX: usize = 15;
95 const DEX_CREATOR_FEE_CONFIG_INDEX: usize = 22;
96
97 const BASE_MINT: Address = Address::new_from_array([2u8; 32]);
98
99 fn migrate() -> solana_instruction::Instruction {
100 let caller = Address::new_from_array([1u8; 32]);
101 build_migrate_instruction(&BuildMigrateParams {
102 caller: &caller,
103 base_mint: &BASE_MINT,
104 quote_mint: &WSOL_MINT,
105 quote_token_program: &TOKEN_PROGRAM_ID,
106 })
107 }
108
109 fn creator_fee_config_pda(program: &Address) -> Address {
110 Address::find_program_address(
111 &[
112 b"creator_fee_config",
113 BASE_MINT.as_ref(),
114 WSOL_MINT.as_ref(),
115 ],
116 program,
117 )
118 .0
119 }
120
121 #[test]
122 fn the_creator_fee_config_slot_is_the_curves_pda() {
123 let ix = migrate();
124
125 assert_eq!(ix.accounts.len(), 23);
126 let slot = &ix.accounts[CREATOR_FEE_CONFIG_INDEX];
127 assert_eq!(slot.pubkey, creator_fee_config_pda(&LAUNCHPAD_PROGRAM_ID));
128 assert_eq!(
129 slot.pubkey,
130 solana_address::address!(
131 "BMrF9UWCQwk4bYq9nYsfLWFCVx6UhgLXrxJCABENvd19"
132 ),
133 );
134 assert!(!slot.is_signer);
135 assert!(slot.is_writable);
136 }
137
138 #[test]
139 fn the_last_slot_is_the_pools_creator_fee_config_pda() {
140 let ix = migrate();
141
142 let slot = &ix.accounts[DEX_CREATOR_FEE_CONFIG_INDEX];
143 assert_eq!(slot.pubkey, creator_fee_config_pda(&DEX_PROGRAM_ID));
144 assert_eq!(
145 slot.pubkey,
146 solana_address::address!(
147 "DBtuuqp2KVdSJG6ffEd3NiLwhuBwybSXANx7YtjUsG6w"
148 ),
149 );
150 assert!(!slot.is_signer);
151 assert!(slot.is_writable);
152 }
153
154 #[test]
155 fn the_curves_and_the_pools_slots_differ() {
156 let ix = migrate();
157
158 assert_ne!(
159 ix.accounts[CREATOR_FEE_CONFIG_INDEX].pubkey,
160 ix.accounts[DEX_CREATOR_FEE_CONFIG_INDEX].pubkey,
161 );
162 }
163}