1use crate::types::DelegateAccountArgs;
2use crate::utils::{close_pda_with_system_transfer, create_pda, seeds_with_bump};
3use borsh::BorshSerialize;
4use dlp::delegate_buffer_seeds_from_delegated_account;
5
6use crate::solana_compat::solana::{
7 invoke_signed, sol_memset, system_instruction, AccountInfo, AccountMeta, Instruction,
8 ProgramError, ProgramResult, Pubkey,
9};
10
11pub const DELEGATION_PROGRAM_ID: Pubkey =
12 Pubkey::new_from_array(dlp::consts::DELEGATION_PROGRAM_ID.to_bytes());
13
14pub struct DelegateAccounts<'a, 'info> {
15 pub payer: &'a AccountInfo<'info>,
16 pub pda: &'a AccountInfo<'info>,
17 pub owner_program: &'a AccountInfo<'info>,
18 pub buffer: &'a AccountInfo<'info>,
19 pub delegation_record: &'a AccountInfo<'info>,
20 pub delegation_metadata: &'a AccountInfo<'info>,
21 pub delegation_program: &'a AccountInfo<'info>,
22 pub system_program: &'a AccountInfo<'info>,
23}
24
25pub struct DelegateConfig {
26 pub commit_frequency_ms: u32,
27 pub validator: Option<Pubkey>,
28}
29
30impl Default for DelegateConfig {
31 fn default() -> Self {
32 DelegateConfig {
33 commit_frequency_ms: DelegateAccountArgs::default().commit_frequency_ms,
34 validator: DelegateAccountArgs::default().validator,
35 }
36 }
37}
38
39#[allow(clippy::needless_lifetimes)]
40pub fn delegate_account<'a, 'info>(
41 accounts: DelegateAccounts<'a, 'info>,
42 pda_seeds: &[&[u8]],
43 config: DelegateConfig,
44) -> ProgramResult {
45 let buffer_seeds: &[&[u8]] = delegate_buffer_seeds_from_delegated_account!(accounts.pda.key);
46
47 let (_, delegate_account_bump) =
48 Pubkey::find_program_address(pda_seeds, accounts.owner_program.key);
49
50 let (_, buffer_pda_bump) =
51 Pubkey::find_program_address(buffer_seeds, accounts.owner_program.key);
52
53 let delegate_account_bump_slice: &[u8] = &[delegate_account_bump];
55 let pda_signer_seeds: &[&[&[u8]]] =
56 &[&*seeds_with_bump(pda_seeds, delegate_account_bump_slice)];
57
58 let buffer_bump_slice: &[u8] = &[buffer_pda_bump];
60 let buffer_signer_seeds: &[&[&[u8]]] = &[&*seeds_with_bump(buffer_seeds, buffer_bump_slice)];
61
62 let data_len = accounts.pda.data_len();
63
64 create_pda(
66 accounts.buffer,
67 accounts.owner_program.key,
68 data_len,
69 buffer_signer_seeds,
70 accounts.system_program,
71 accounts.payer,
72 false,
73 )?;
74
75 {
77 let pda_ro = accounts.pda.try_borrow_data()?;
78 let mut buf = accounts.buffer.try_borrow_mut_data()?;
79 buf.copy_from_slice(&pda_ro);
80 }
81
82 {
84 let mut pda_mut = accounts.pda.try_borrow_mut_data()?;
85 #[allow(unused_unsafe)]
86 unsafe {
87 sol_memset(&mut pda_mut, 0, data_len)
88 };
89 }
90
91 if accounts.pda.owner != accounts.system_program.key {
93 accounts.pda.assign(accounts.system_program.key);
94 }
95 if accounts.pda.owner != accounts.delegation_program.key {
96 invoke_signed(
97 &system_instruction::assign(accounts.pda.key, accounts.delegation_program.key),
98 &[accounts.pda.clone(), accounts.system_program.clone()],
99 pda_signer_seeds,
100 )?;
101 }
102
103 let seeds_vec: Vec<Vec<u8>> = pda_seeds.iter().map(|&slice| slice.to_vec()).collect();
104
105 let delegation_args = DelegateAccountArgs {
106 commit_frequency_ms: config.commit_frequency_ms,
107 seeds: seeds_vec,
108 validator: config.validator,
109 };
110
111 cpi_delegate(
112 accounts.payer,
113 accounts.pda,
114 accounts.owner_program,
115 accounts.buffer,
116 accounts.delegation_record,
117 accounts.delegation_metadata,
118 accounts.system_program,
119 pda_signer_seeds,
120 delegation_args,
121 )?;
122
123 close_pda_with_system_transfer(
124 accounts.buffer,
125 buffer_signer_seeds,
126 accounts.payer,
127 accounts.system_program,
128 )?;
129 Ok(())
130}
131
132pub fn undelegate_account<'a, 'info>(
134 delegated_account: &'a AccountInfo<'info>,
135 owner_program: &Pubkey,
136 buffer: &'a AccountInfo<'info>,
137 payer: &'a AccountInfo<'info>,
138 system_program: &'a AccountInfo<'info>,
139 account_signer_seeds: Vec<Vec<u8>>,
140) -> ProgramResult {
141 if !buffer.is_signer {
142 return Err(ProgramError::MissingRequiredSignature);
143 }
144 if buffer.owner != &DELEGATION_PROGRAM_ID {
145 return Err(ProgramError::InvalidAccountOwner);
146 }
147
148 let account_seeds: Vec<&[u8]> = account_signer_seeds.iter().map(|v| v.as_slice()).collect();
149
150 let (_, account_bump) = Pubkey::find_program_address(account_seeds.as_ref(), owner_program);
151
152 let account_bump_slice: &[u8] = &[account_bump];
154 let account_signer_seeds: &[&[&[u8]]] = &[&*seeds_with_bump(
155 account_seeds.as_ref(),
156 account_bump_slice,
157 )];
158
159 create_pda(
161 delegated_account,
162 owner_program,
163 buffer.data_len(),
164 account_signer_seeds,
165 system_program,
166 payer,
167 true,
168 )?;
169
170 let mut data = delegated_account.try_borrow_mut_data()?;
171 let buffer_data = buffer.try_borrow_data()?;
172 (*data).copy_from_slice(&buffer_data);
173 Ok(())
174}
175
176#[allow(clippy::too_many_arguments)]
178pub fn cpi_delegate<'a, 'info>(
179 payer: &'a AccountInfo<'info>,
180 delegate_account: &'a AccountInfo<'info>,
181 owner_program: &'a AccountInfo<'info>,
182 buffer: &'a AccountInfo<'info>,
183 delegation_record: &'a AccountInfo<'info>,
184 delegation_metadata: &'a AccountInfo<'info>,
185 system_program: &'a AccountInfo<'info>,
186 signers_seeds: &[&[&[u8]]],
187 args: DelegateAccountArgs,
188) -> ProgramResult {
189 let mut data: Vec<u8> = vec![0u8; 8];
190 args.serialize(&mut data)?;
191
192 let delegation_instruction = Instruction {
193 program_id: crate::id().to_bytes().into(),
194 accounts: vec![
195 AccountMeta::new(payer.key.to_bytes().into(), true),
196 AccountMeta::new(delegate_account.key.to_bytes().into(), true),
197 AccountMeta::new_readonly(owner_program.key.to_bytes().into(), false),
198 AccountMeta::new(buffer.key.to_bytes().into(), false),
199 AccountMeta::new(delegation_record.key.to_bytes().into(), false),
200 AccountMeta::new(delegation_metadata.key.to_bytes().into(), false),
201 AccountMeta::new_readonly(system_program.key.to_bytes().into(), false),
202 ],
203 data,
204 };
205
206 invoke_signed(
207 &delegation_instruction,
208 &[
209 payer.clone(),
210 delegate_account.clone(),
211 owner_program.clone(),
212 buffer.clone(),
213 delegation_record.clone(),
214 delegation_metadata.clone(),
215 system_program.clone(),
216 ],
217 signers_seeds,
218 )
219}