1use borsh::BorshSerialize;
2use solana_program::account_info::AccountInfo;
3use solana_program::entrypoint::ProgramResult;
4use solana_program::instruction::{AccountMeta, Instruction};
5use solana_program::program_error::ProgramError;
6use solana_program::pubkey::Pubkey;
7
8pub use delegation_sdk_attribute_delegate::delegate;
9
10use crate::consts::BUFFER;
12use crate::types::DelegateAccountArgs;
13use crate::utils::{close_pda, create_pda, seeds_with_bump};
14pub mod consts;
15pub mod types;
16pub mod utils;
17
18pub fn id() -> Pubkey {
19 consts::DELEGATION_PROGRAM_ID
20}
21
22#[allow(clippy::too_many_arguments)]
24#[inline(always)]
25pub fn delegate_account<'a, 'info>(
26 payer: &'a AccountInfo<'info>,
27 pda: &'a AccountInfo<'info>,
28 owner_program: &'a AccountInfo<'info>,
29 buffer: &'a AccountInfo<'info>,
30 delegation_record: &'a AccountInfo<'info>,
31 delegation_metadata: &'a AccountInfo<'info>,
32 delegation_program: &'a AccountInfo<'info>,
33 system_program: &'a AccountInfo<'info>,
34 pda_seeds: &[&[u8]],
35 valid_until: i64,
36 commit_frequency_ms: u32,
37) -> ProgramResult {
38 let buffer_seeds: &[&[u8]] = &[BUFFER, pda.key.as_ref()];
39
40 let (_, delegate_account_bump) = Pubkey::find_program_address(pda_seeds, owner_program.key);
41
42 let (_, buffer_pda_bump) = Pubkey::find_program_address(buffer_seeds, owner_program.key);
43
44 let delegate_account_bump_slice: &[u8] = &[delegate_account_bump];
46 let pda_signer_seeds: &[&[&[u8]]] =
47 &[&*seeds_with_bump(pda_seeds, delegate_account_bump_slice)];
48
49 let buffer_bump_slice: &[u8] = &[buffer_pda_bump];
51 let buffer_signer_seeds: &[&[&[u8]]] = &[&*seeds_with_bump(buffer_seeds, buffer_bump_slice)];
52
53 let data_len = pda.data_len();
54
55 create_pda(
57 buffer,
58 owner_program.key,
59 data_len,
60 buffer_signer_seeds,
61 system_program,
62 payer,
63 )?;
64
65 let mut buffer_data = buffer.try_borrow_mut_data()?;
67 let new_data = pda.try_borrow_data()?.to_vec().clone();
68 (*buffer_data).copy_from_slice(&new_data);
69 drop(buffer_data);
70
71 close_pda(pda, payer)?;
73
74 create_pda(
76 pda,
77 delegation_program.key,
78 data_len,
79 pda_signer_seeds,
80 system_program,
81 payer,
82 )?;
83
84 let seeds_vec: Vec<Vec<u8>> = pda_seeds.iter().map(|&slice| slice.to_vec()).collect();
85
86 let delegation_args = DelegateAccountArgs {
87 valid_until,
88 commit_frequency_ms,
89 seeds: seeds_vec,
90 };
91
92 cpi_delegate(
93 payer,
94 pda,
95 owner_program,
96 buffer,
97 delegation_record,
98 delegation_metadata,
99 system_program,
100 pda_signer_seeds,
101 delegation_args,
102 )?;
103
104 close_pda(buffer, payer)?;
105 Ok(())
106}
107
108#[inline(always)]
110pub fn undelegate_account<'a, 'info>(
111 delegated_account: &'a AccountInfo<'info>,
112 owner_program: &Pubkey,
113 buffer: &'a AccountInfo<'info>,
114 payer: &'a AccountInfo<'info>,
115 system_program: &'a AccountInfo<'info>,
116 account_signer_seeds: Vec<Vec<u8>>,
117) -> ProgramResult {
118 if !buffer.is_signer {
119 return Err(ProgramError::MissingRequiredSignature);
120 }
121
122 let account_seeds: Vec<&[u8]> = account_signer_seeds.iter().map(|v| v.as_slice()).collect();
123
124 let (_, account_bump) = Pubkey::find_program_address(account_seeds.as_ref(), owner_program);
125
126 let account_bump_slice: &[u8] = &[account_bump];
128 let account_signer_seeds: &[&[&[u8]]] = &[&*seeds_with_bump(
129 account_seeds.as_ref(),
130 account_bump_slice,
131 )];
132
133 create_pda(
135 &delegated_account,
136 owner_program,
137 buffer.data_len(),
138 account_signer_seeds,
139 &system_program,
140 &payer,
141 )?;
142
143 let mut data = delegated_account.try_borrow_mut_data()?;
144 let buffer_data = buffer.try_borrow_data()?;
145 (*data).copy_from_slice(&buffer_data);
146 Ok(())
147}
148
149#[allow(clippy::too_many_arguments)]
151#[inline(always)]
152pub fn cpi_delegate<'a, 'info>(
153 payer: &'a AccountInfo<'info>,
154 delegate_account: &'a AccountInfo<'info>,
155 owner_program: &'a AccountInfo<'info>,
156 buffer: &'a AccountInfo<'info>,
157 delegation_record: &'a AccountInfo<'info>,
158 delegation_metadata: &'a AccountInfo<'info>,
159 system_program: &'a AccountInfo<'info>,
160 signers_seeds: &[&[&[u8]]],
161 args: DelegateAccountArgs,
162) -> ProgramResult {
163 let mut data: Vec<u8> = vec![0u8; 8];
164 let serialized_seeds = args.try_to_vec()?;
165 data.extend_from_slice(&serialized_seeds);
166
167 let delegation_instruction = Instruction {
168 program_id: id(),
169 accounts: vec![
170 AccountMeta::new(*payer.key, true),
171 AccountMeta::new(*delegate_account.key, true),
172 AccountMeta::new_readonly(*owner_program.key, false),
173 AccountMeta::new(*buffer.key, false),
174 AccountMeta::new(*delegation_record.key, false),
175 AccountMeta::new(*delegation_metadata.key, false),
176 AccountMeta::new_readonly(*system_program.key, false),
177 ],
178 data,
179 };
180
181 solana_program::program::invoke_signed(
182 &delegation_instruction,
183 &[
184 payer.clone(),
185 delegate_account.clone(),
186 owner_program.clone(),
187 buffer.clone(),
188 delegation_record.clone(),
189 delegation_metadata.clone(),
190 system_program.clone(),
191 ],
192 signers_seeds,
193 )
194}
195
196#[inline(always)]
198pub fn allow_undelegation<'a, 'info>(
199 delegated_account: &'a AccountInfo<'info>,
200 delegation_record: &'a AccountInfo<'info>,
201 delegation_metedata: &'a AccountInfo<'info>,
202 buffer: &'a AccountInfo<'info>,
203 delegation_program: &'a AccountInfo<'info>,
204 owner_program: &Pubkey,
205) -> ProgramResult {
206 let buffer_seeds: &[&[u8]] = &[BUFFER, delegated_account.key.as_ref()];
207 let (_, buffer_pda_bump) = Pubkey::find_program_address(buffer_seeds, owner_program);
208 let buffer_bump_slice: &[u8] = &[buffer_pda_bump];
209 let buffer_signer_seeds: &[&[&[u8]]] = &[&*seeds_with_bump(buffer_seeds, buffer_bump_slice)];
210
211 let allow_undelegation_instruction = Instruction {
212 program_id: *delegation_program.key,
213 accounts: vec![
214 AccountMeta::new_readonly(*delegated_account.key, false),
215 AccountMeta::new_readonly(*delegation_record.key, false),
216 AccountMeta::new(*delegation_metedata.key, false),
217 AccountMeta::new_readonly(*buffer.key, true),
218 ],
219 data: vec![0x4, 0, 0, 0, 0, 0, 0, 0],
220 };
221
222 solana_program::program::invoke_signed(
223 &allow_undelegation_instruction,
224 &[
225 delegated_account.clone(),
226 delegation_record.clone(),
227 delegation_metedata.clone(),
228 buffer.clone(),
229 ],
230 buffer_signer_seeds,
231 )
232}
233
234#[inline(always)]
236pub fn trigger_commit<'a, 'info>(
237 payer: &'a AccountInfo<'info>,
238 delegated_account: &'a AccountInfo<'info>,
239 magic_program: &'a AccountInfo<'info>,
240) -> ProgramResult {
241 let allow_undelegation_instruction = Instruction {
242 program_id: *magic_program.key,
243 accounts: vec![
244 AccountMeta::new_readonly(*payer.key, true),
245 AccountMeta::new_readonly(*delegated_account.key, false),
246 ],
247 data: vec![0x1, 0, 0, 0],
248 };
249
250 solana_program::program::invoke(
251 &allow_undelegation_instruction,
252 &[payer.clone(), delegated_account.clone()],
253 )
254}