1use std::ops::Deref;
2
3use anchor_client::anchor_lang::{
4 idl::{IdlAccount, IdlInstruction, IDL_IX_TAG},
5 AnchorSerialize,
6};
7use gmsol_solana_utils::transaction_builder::TransactionBuilder;
8use solana_sdk::{instruction::AccountMeta, pubkey::Pubkey, signer::Signer};
9
10pub trait IdlOps<C> {
12 fn create_idl_account(
14 &self,
15 program_id: &Pubkey,
16 data_len: u64,
17 ) -> crate::Result<TransactionBuilder<C>>;
18
19 fn resize_idl_account(
21 &self,
22 program_id: &Pubkey,
23 account: Option<&Pubkey>,
24 data_len: u64,
25 ) -> crate::Result<TransactionBuilder<C>>;
26
27 fn set_idl_buffer(
29 &self,
30 program_id: &Pubkey,
31 buffer: &Pubkey,
32 ) -> crate::Result<TransactionBuilder<C>>;
33
34 fn set_idl_authority(
36 &self,
37 program_id: &Pubkey,
38 account: Option<&Pubkey>,
39 new_authority: &Pubkey,
40 ) -> crate::Result<TransactionBuilder<C>>;
41
42 fn close_idl_account(
44 &self,
45 program_id: &Pubkey,
46 account: Option<&Pubkey>,
47 sol_destination: Option<&Pubkey>,
48 ) -> crate::Result<TransactionBuilder<C>>;
49}
50
51fn serialize_idl_ix(ix: IdlInstruction) -> crate::Result<Vec<u8>> {
52 let mut data = IDL_IX_TAG.to_le_bytes().to_vec();
53 data.append(&mut ix.try_to_vec()?);
54 Ok(data)
55}
56
57impl<C: Deref<Target = impl Signer> + Clone> IdlOps<C> for crate::Client<C> {
58 fn create_idl_account(
59 &self,
60 program_id: &Pubkey,
61 data_len: u64,
62 ) -> crate::Result<TransactionBuilder<C>> {
63 let idl_address = IdlAccount::address(program_id);
64 let program_signer = Pubkey::find_program_address(&[], program_id).0;
65
66 let tx = self
67 .store_transaction()
68 .program(*program_id)
69 .accounts(vec![
70 AccountMeta::new_readonly(self.payer(), true),
71 AccountMeta::new(idl_address, false),
72 AccountMeta::new_readonly(program_signer, false),
73 AccountMeta::new_readonly(solana_sdk::system_program::ID, false),
74 AccountMeta::new_readonly(*program_id, false),
75 ])
76 .args(serialize_idl_ix(IdlInstruction::Create { data_len })?);
77
78 Ok(tx)
79 }
80
81 fn resize_idl_account(
82 &self,
83 program_id: &Pubkey,
84 account: Option<&Pubkey>,
85 data_len: u64,
86 ) -> crate::Result<TransactionBuilder<C>> {
87 let account = account
88 .copied()
89 .unwrap_or_else(|| IdlAccount::address(program_id));
90
91 let tx = self
92 .store_transaction()
93 .program(*program_id)
94 .accounts(vec![
95 AccountMeta::new(account, false),
96 AccountMeta::new_readonly(self.payer(), true),
97 AccountMeta::new_readonly(solana_sdk::system_program::ID, false),
98 ])
99 .args(serialize_idl_ix(IdlInstruction::Resize { data_len })?);
100
101 Ok(tx)
102 }
103
104 fn set_idl_buffer(
105 &self,
106 program_id: &Pubkey,
107 buffer: &Pubkey,
108 ) -> crate::Result<TransactionBuilder<C>> {
109 let idl_address = IdlAccount::address(program_id);
110 let tx = self
111 .store_transaction()
112 .program(*program_id)
113 .accounts(vec![
114 AccountMeta::new(*buffer, false),
115 AccountMeta::new(idl_address, false),
116 AccountMeta::new(self.payer(), true),
117 ])
118 .args(serialize_idl_ix(IdlInstruction::SetBuffer)?);
119
120 Ok(tx)
121 }
122
123 fn set_idl_authority(
124 &self,
125 program_id: &Pubkey,
126 account: Option<&Pubkey>,
127 new_authority: &Pubkey,
128 ) -> crate::Result<TransactionBuilder<C>> {
129 let idl_address = account
130 .copied()
131 .unwrap_or_else(|| IdlAccount::address(program_id));
132
133 let tx = self
134 .store_transaction()
135 .program(*program_id)
136 .accounts(vec![
137 AccountMeta::new(idl_address, false),
138 AccountMeta::new_readonly(self.payer(), true),
139 ])
140 .args(serialize_idl_ix(IdlInstruction::SetAuthority {
141 new_authority: *new_authority,
142 })?);
143
144 Ok(tx)
145 }
146
147 fn close_idl_account(
148 &self,
149 program_id: &Pubkey,
150 account: Option<&Pubkey>,
151 sol_destination: Option<&Pubkey>,
152 ) -> crate::Result<TransactionBuilder<C>> {
153 let idl_address = account
154 .copied()
155 .unwrap_or_else(|| IdlAccount::address(program_id));
156
157 let sol_destination = sol_destination.copied().unwrap_or_else(|| self.payer());
158 let tx = self
159 .store_transaction()
160 .program(*program_id)
161 .accounts(vec![
162 AccountMeta::new(idl_address, false),
163 AccountMeta::new(self.payer(), true),
164 AccountMeta::new(sol_destination, false),
165 ])
166 .args(serialize_idl_ix(IdlInstruction::Close)?);
167 Ok(tx)
168 }
169}