1#![doc = include_str!("../README.md")]
2
3pub mod dex;
4pub mod launchpad;
5pub mod nexus;
6
7pub mod constants;
8pub mod math;
9pub mod transfer_fee;
10
11pub mod utils;
12
13#[cfg(test)]
14mod tests {
15
16 mod pda_tests {
17 use solana_address::address;
18
19 #[test]
20 fn launchpad_bonding_curve_pda() {
21 let base = address!("So11111111111111111111111111111111111111112");
22 let quote = address!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
23 let (addr1, _) =
24 crate::launchpad::pda::find_bonding_curve_pda(&base, "e);
25 let (addr2, _) =
26 crate::launchpad::pda::find_bonding_curve_pda(&base, "e);
27 assert_eq!(addr1, addr2);
28 let (addr3, _) =
29 crate::launchpad::pda::find_bonding_curve_pda("e, &base);
30 assert_ne!(addr1, addr3);
31 }
32
33 #[test]
34 fn dex_pool_and_lp_mint_pdas_differ() {
35 let base = address!("So11111111111111111111111111111111111111112");
36 let quote = address!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
37 let (pool, _) = crate::dex::pda::find_pool_pda(&base, "e);
38 let (lp, _) = crate::dex::pda::find_lp_mint_pda(&base, "e);
39 assert_ne!(pool, lp);
40 }
41
42 #[test]
43 fn nexus_staking_pdas() {
44 let user = address!("11111111111111111111111111111112");
45 let staking_mint =
46 address!("So11111111111111111111111111111111111111112");
47 let reward_mint =
48 address!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
49
50 let (pos, _) = crate::nexus::pda::find_user_stake_position_pda(
51 &user,
52 &staking_mint,
53 );
54 let (debt, _) = crate::nexus::pda::find_user_reward_debt_pda(
55 &user,
56 &staking_mint,
57 &reward_mint,
58 );
59 assert_ne!(pos, debt);
60 }
61
62 #[test]
63 fn nexus_creator_fee_config_pda() {
64 let quote = address!("So11111111111111111111111111111111111111112");
65 let (addr1, _) =
66 crate::nexus::pda::find_creator_fee_config_pda_from_id(
67 "wallet",
68 "SomeCreator",
69 "e,
70 );
71 let (addr2, _) =
72 crate::nexus::pda::find_creator_fee_config_pda_from_id(
73 "twitter",
74 "SomeCreator",
75 "e,
76 );
77 assert_ne!(addr1, addr2);
78 }
79
80 #[test]
81 fn event_authority_pdas_differ_per_program() {
82 let (lp, _) = crate::launchpad::pda::find_event_authority_pda();
83 let (dex, _) = crate::dex::pda::find_event_authority_pda();
84 let (nexus, _) = crate::nexus::pda::find_event_authority_pda();
85 assert_ne!(lp, dex);
86 assert_ne!(dex, nexus);
87 assert_ne!(lp, nexus);
88 }
89 }
90
91 mod generated_constants {
92 use solana_address::Address;
93
94 struct PdaCheck<'a> {
95 label: &'a str,
96 address: Address,
97 bump: u8,
98 seeds: &'a [&'a [u8]],
99 program_id: Address,
100 }
101
102 #[track_caller]
103 fn assert_pda(check: PdaCheck<'_>) {
104 let (derived, derived_bump) =
105 Address::find_program_address(check.seeds, &check.program_id);
106 assert_eq!(check.address, derived, "{}: address", check.label);
107 assert_eq!(check.bump, derived_bump, "{}: bump", check.label);
108 }
109
110 #[test]
111 fn launchpad_pda_constants_match_derivation() {
112 use crate::launchpad::generated::SEND_LAUNCHPAD_ID as ID;
113 use crate::launchpad::pda::{
114 EVENT_AUTHORITY_ADDRESS, EVENT_AUTHORITY_BUMP,
115 EVENT_AUTHORITY_SEED, GLOBAL_CONFIG_ADDRESS,
116 GLOBAL_CONFIG_BUMP, GLOBAL_CONFIG_SEED,
117 MIGRATION_AUTHORITY_ADDRESS, MIGRATION_AUTHORITY_BUMP,
118 MIGRATION_AUTHORITY_SEED,
119 };
120
121 assert_pda(PdaCheck {
122 label: "launchpad global_config",
123 address: GLOBAL_CONFIG_ADDRESS,
124 bump: GLOBAL_CONFIG_BUMP,
125 seeds: &[GLOBAL_CONFIG_SEED],
126 program_id: ID,
127 });
128 assert_pda(PdaCheck {
129 label: "launchpad event_authority",
130 address: EVENT_AUTHORITY_ADDRESS,
131 bump: EVENT_AUTHORITY_BUMP,
132 seeds: &[EVENT_AUTHORITY_SEED],
133 program_id: ID,
134 });
135 assert_pda(PdaCheck {
136 label: "launchpad migration_authority",
137 address: MIGRATION_AUTHORITY_ADDRESS,
138 bump: MIGRATION_AUTHORITY_BUMP,
139 seeds: &[MIGRATION_AUTHORITY_SEED],
140 program_id: ID,
141 });
142 }
143
144 #[test]
145 fn dex_pda_constants_match_derivation() {
146 use crate::dex::generated::SEND_DEX_ID as ID;
147 use crate::dex::pda::{
148 EVENT_AUTHORITY_ADDRESS, EVENT_AUTHORITY_BUMP,
149 EVENT_AUTHORITY_SEED, GLOBAL_CONFIG_ADDRESS,
150 GLOBAL_CONFIG_BUMP, GLOBAL_CONFIG_SEED,
151 };
152
153 assert_pda(PdaCheck {
154 label: "dex global_config",
155 address: GLOBAL_CONFIG_ADDRESS,
156 bump: GLOBAL_CONFIG_BUMP,
157 seeds: &[GLOBAL_CONFIG_SEED],
158 program_id: ID,
159 });
160 assert_pda(PdaCheck {
161 label: "dex event_authority",
162 address: EVENT_AUTHORITY_ADDRESS,
163 bump: EVENT_AUTHORITY_BUMP,
164 seeds: &[EVENT_AUTHORITY_SEED],
165 program_id: ID,
166 });
167 }
168
169 #[test]
170 fn nexus_pda_constants_match_derivation() {
171 use crate::nexus::generated::SEND_NEXUS_ID as ID;
172 use crate::nexus::pda::{
173 ALT_REGISTRY_ADDRESS, ALT_REGISTRY_BUMP, ALT_REGISTRY_SEED,
174 EVENT_AUTHORITY_ADDRESS, EVENT_AUTHORITY_BUMP,
175 EVENT_AUTHORITY_SEED, GLOBAL_CONFIG_ADDRESS,
176 GLOBAL_CONFIG_BUMP, GLOBAL_CONFIG_SEED, STAKING_CONFIG_ADDRESS,
177 STAKING_CONFIG_BUMP, STAKING_CONFIG_SEED,
178 };
179
180 assert_pda(PdaCheck {
181 label: "nexus global_config",
182 address: GLOBAL_CONFIG_ADDRESS,
183 bump: GLOBAL_CONFIG_BUMP,
184 seeds: &[GLOBAL_CONFIG_SEED],
185 program_id: ID,
186 });
187 assert_pda(PdaCheck {
188 label: "nexus staking_config",
189 address: STAKING_CONFIG_ADDRESS,
190 bump: STAKING_CONFIG_BUMP,
191 seeds: &[STAKING_CONFIG_SEED],
192 program_id: ID,
193 });
194 assert_pda(PdaCheck {
195 label: "nexus event_authority",
196 address: EVENT_AUTHORITY_ADDRESS,
197 bump: EVENT_AUTHORITY_BUMP,
198 seeds: &[EVENT_AUTHORITY_SEED],
199 program_id: ID,
200 });
201 assert_pda(PdaCheck {
202 label: "nexus alt_registry",
203 address: ALT_REGISTRY_ADDRESS,
204 bump: ALT_REGISTRY_BUMP,
205 seeds: &[ALT_REGISTRY_SEED],
206 program_id: ID,
207 });
208 let platform =
211 crate::constants::find_platform_address(b"sendfun").0;
212 assert_eq!(
213 crate::nexus::pda::find_default_partner_pda(&platform),
214 crate::nexus::pda::find_partner_config_pda(
215 &platform,
216 &crate::constants::DEFAULT_PARTNER,
217 ),
218 );
219 assert_ne!(
220 crate::nexus::pda::find_default_partner_pda(&platform).0,
221 crate::nexus::pda::find_default_partner_pda(
222 &crate::constants::find_platform_address(b"acme").0
223 )
224 .0,
225 );
226 assert_eq!(
227 crate::nexus::pda::find_default_fee_preset_pda(&platform),
228 crate::nexus::pda::find_fee_preset_pda(&platform, 0),
229 );
230 assert_ne!(
233 crate::nexus::pda::find_default_fee_preset_pda(&platform).0,
234 crate::nexus::pda::find_default_fee_preset_pda(
235 &crate::constants::find_platform_address(b"acme").0
236 )
237 .0,
238 );
239 assert_eq!(
240 crate::nexus::pda::find_default_partner_metadata_pda(&platform),
241 crate::nexus::pda::find_partner_metadata_pda(
242 &platform,
243 &crate::constants::DEFAULT_PARTNER,
244 ),
245 );
246 assert_ne!(
248 crate::nexus::pda::find_default_partner_metadata_pda(&platform)
249 .0,
250 crate::nexus::pda::find_default_partner_metadata_pda(
251 &crate::constants::find_platform_address(b"acme").0
252 )
253 .0,
254 );
255 }
256
257 #[test]
260 fn sendfun_default_partner_addresses_are_pinned() {
261 use crate::constants::{DEFAULT_PARTNER, find_platform_address};
262 use solana_address::address;
263
264 let platform = find_platform_address(b"sendfun").0;
265 assert_eq!(
266 platform,
267 address!("2PJedAsa7pCnScks2XM3U4o2nPaTvvBmi2553VcCnGWB"),
268 "sendfun platform"
269 );
270
271 assert_eq!(
272 crate::nexus::pda::find_partner_config_pda(
273 &platform,
274 &DEFAULT_PARTNER
275 )
276 .0,
277 address!("B77P3Hvj9xLi4tcFtyjNcf6NjhkQrfJvLkz3nVZnBzec"),
278 "default partner config"
279 );
280 assert_eq!(
281 crate::nexus::pda::find_fee_preset_pda(&platform, 0).0,
282 address!("DTWXzPHfg7vjnhwhE7rxhdPZPGGFjuqD1excog3xmKTx"),
283 "default fee preset 0"
284 );
285 assert_eq!(
286 crate::nexus::pda::find_partner_metadata_pda(
287 &platform,
288 &DEFAULT_PARTNER
289 )
290 .0,
291 address!("8WqZvqH4B1LtcfxZHeAdYWCYvwfMaUkQvJqZsw4fmii5"),
292 "default partner metadata"
293 );
294 }
295 }
296
297 #[test]
298 fn nexus_find_creator_fee_config_pda_from_id_matches_hash_derivation() {
299 use solana_address::address;
300 let quote = address!("So11111111111111111111111111111111111111112");
301 let creator_hash =
302 crate::utils::creator_hash_from_id("wallet", "SomeCreator");
303 let (addr1, bump1) =
304 crate::nexus::pda::find_creator_fee_config_pda_from_id(
305 "wallet",
306 "SomeCreator",
307 "e,
308 );
309 let (addr2, bump2) = crate::nexus::pda::find_creator_fee_config_pda(
310 &creator_hash,
311 "e,
312 );
313 assert_eq!(addr1, addr2);
314 assert_eq!(bump1, bump2);
315 }
316
317 #[test]
318 fn bonding_curve_status_values() {
319 assert_eq!(
320 crate::launchpad::types::BondingCurveStatus::Funding as u8,
321 0
322 );
323 assert_eq!(
324 crate::launchpad::types::BondingCurveStatus::Completed as u8,
325 1
326 );
327 assert_eq!(
328 crate::launchpad::types::BondingCurveStatus::Migrated as u8,
329 2
330 );
331 assert_eq!(
332 crate::launchpad::types::BondingCurveStatus::Paused as u8,
333 3
334 );
335 }
336
337 #[test]
338 fn pool_status_values() {
339 assert_eq!(crate::dex::types::PoolStatus::Active as u8, 0);
340 assert_eq!(crate::dex::types::PoolStatus::Paused as u8, 1);
341 }
342
343 #[test]
344 fn launchpad_fees_total() {
345 let fees = crate::nexus::types::LaunchpadFees {
346 creation_fee_cents: 0,
347 protocol_fee_bps: 100,
348 creator_fee_bps: 50,
349 fee_decay_seconds: 0,
350 fee_decay_start_bps: 0,
351 };
352 assert_eq!(fees.total_fee_bps(), Some(150));
353 }
354
355 #[test]
356 fn dex_fees_total() {
357 let fees = crate::nexus::types::DexFees {
358 creation_fee_cents: 0,
359 protocol_fee_bps: 80,
360 lp_fee_bps: 30,
361 creator_fee_bps: 40,
362 fee_decay_seconds: 0,
363 fee_decay_start_bps: 0,
364 };
365 assert_eq!(fees.total_fee_bps(), Some(150));
366 }
367}