gmsol/
idl.rs

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
10/// IDL operations.
11pub trait IdlOps<C> {
12    /// Create IDL account.
13    fn create_idl_account(
14        &self,
15        program_id: &Pubkey,
16        data_len: u64,
17    ) -> crate::Result<TransactionBuilder<C>>;
18
19    /// Resize buffer/account.
20    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    /// Set IDL buffer.
28    fn set_idl_buffer(
29        &self,
30        program_id: &Pubkey,
31        buffer: &Pubkey,
32    ) -> crate::Result<TransactionBuilder<C>>;
33
34    /// Set IDL authority.
35    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    /// Close IDL buffer/account.
43    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}