gmsol_store/instructions/migration/
referral_code.rs1use anchor_lang::prelude::*;
2
3use crate::{
4 internal,
5 states::{user::ReferralCodeBytes, Store},
6};
7
8#[account(zero_copy)]
10#[cfg_attr(feature = "debug", derive(Debug))]
11pub struct ReferralCode {
12 pub bump: u8,
14 pub code: ReferralCodeBytes,
16 pub store: Pubkey,
18 pub owner: Pubkey,
20}
21
22#[derive(Accounts)]
24pub struct MigrateReferralCode<'info> {
25 #[account(mut)]
27 pub authority: Signer<'info>,
28 pub store: AccountLoader<'info, Store>,
30 pub system: Program<'info, System>,
32}
33
34impl<'info> internal::Authentication<'info> for MigrateReferralCode<'info> {
35 fn authority(&self) -> &Signer<'info> {
36 &self.authority
37 }
38
39 fn store(&self) -> &AccountLoader<'info, Store> {
40 &self.store
41 }
42}
43
44#[cfg(feature = "migration")]
45pub(crate) use migration::unchecked_migrate_referral_code;
46
47#[cfg(feature = "migration")]
48mod migration {
49 use anchor_lang::system_program;
50 use gmsol_utils::InitSpace;
51
52 use crate::{
53 states::{user::ReferralCodeV2, Seed},
54 CoreError,
55 };
56
57 use super::*;
58
59 pub(crate) fn unchecked_migrate_referral_code<'info>(
63 ctx: Context<'_, '_, 'info, 'info, MigrateReferralCode<'info>>,
64 ) -> Result<()> {
65 let code = &ctx.remaining_accounts[0];
66 let data = ctx.accounts.validate_and_clone(code)?;
67 ctx.accounts.initialize_code_v2_unchecked(&data, code)?;
68 Ok(())
69 }
70
71 impl<'info> MigrateReferralCode<'info> {
72 fn validate_and_clone(&self, code: &'info AccountInfo<'info>) -> Result<ReferralCode> {
73 let loader = AccountLoader::<ReferralCode>::try_from(code)?;
74 let pubkey = loader.key();
75 let store = self.store.key();
76 let code = loader.load()?;
77
78 require_keys_eq!(code.store, store, CoreError::StoreMismatched);
80
81 let expected_pubkey = Pubkey::create_program_address(
83 &[
84 ReferralCodeV2::SEED,
85 store.as_ref(),
86 &code.code,
87 &[code.bump],
88 ],
89 &crate::ID,
90 )
91 .map_err(|_| error!(CoreError::InvalidArgument))?;
92 require_keys_eq!(expected_pubkey, pubkey, ErrorCode::ConstraintSeeds);
93
94 Ok(*code)
95 }
96
97 fn uninitialize_code_and_realloc(&self, account: &AccountInfo<'info>) -> Result<()> {
98 let rent = Rent::get()?;
99
100 account.try_borrow_mut_data()?.fill(0);
101
102 let space = 8 + ReferralCodeV2::INIT_SPACE;
103 let required_lamports = rent
104 .minimum_balance(space)
105 .max(1)
106 .saturating_sub(account.lamports());
107
108 if required_lamports > 0 {
109 system_program::transfer(
110 CpiContext::new(
111 self.system.to_account_info(),
112 system_program::Transfer {
113 from: self.authority.to_account_info(),
114 to: account.clone(),
115 },
116 ),
117 required_lamports,
118 )?;
119 }
120
121 account.realloc(space, false)?;
122 Ok(())
123 }
124
125 fn initialize_code_v2_unchecked(
128 &self,
129 data: &ReferralCode,
130 code: &'info AccountInfo<'info>,
131 ) -> Result<()> {
132 self.uninitialize_code_and_realloc(code)?;
133 let referral_code_v2 =
134 AccountLoader::<ReferralCodeV2>::try_from_unchecked(&crate::ID, code)?;
135 referral_code_v2
136 .load_init()?
137 .init(data.bump, data.code, &data.store, &data.owner);
138 referral_code_v2.exit(&crate::ID)?;
139 Ok(())
140 }
141 }
142}