Skip to main content

sendfun_sdk/launchpad/
migrate.rs

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}