gmsol_sdk/client/ops/
alt.rs1use std::{future::Future, ops::Deref};
2
3use gmsol_solana_utils::{
4 bundle_builder::BundleBuilder, transaction_builder::TransactionBuilder, utils::WithSlot,
5};
6use solana_account_decoder::UiAccountEncoding;
7use solana_client::rpc_config::RpcAccountInfoConfig;
8use solana_sdk::{
9 account::ReadableAccount,
10 address_lookup_table::{self, state::AddressLookupTable, AddressLookupTableAccount},
11 pubkey::Pubkey,
12 signer::Signer,
13};
14
15use crate::client::accounts::get_account_with_context;
16
17pub trait AddressLookupTableOps<C> {
19 fn alt_with_config(
21 &self,
22 address: &Pubkey,
23 config: RpcAccountInfoConfig,
24 ) -> impl Future<Output = crate::Result<WithSlot<Option<AddressLookupTableAccount>>>>;
25
26 fn alt(
28 &self,
29 address: &Pubkey,
30 ) -> impl Future<Output = crate::Result<Option<AddressLookupTableAccount>>> {
31 async {
32 Ok(self
33 .alt_with_config(
34 address,
35 RpcAccountInfoConfig {
36 encoding: Some(UiAccountEncoding::Base64),
37 ..Default::default()
38 },
39 )
40 .await?
41 .into_value())
42 }
43 }
44
45 fn create_alt(&self) -> impl Future<Output = crate::Result<(TransactionBuilder<C>, Pubkey)>>;
47
48 fn extend_alt(
50 &self,
51 alt: &Pubkey,
52 new_addresses: Vec<Pubkey>,
53 chunk_size: Option<usize>,
54 ) -> crate::Result<BundleBuilder<C>>;
55 fn deactivate_alt(&self, alt: &Pubkey) -> TransactionBuilder<C>;
57
58 fn close_alt(&self, alt: &Pubkey) -> TransactionBuilder<C>;
60}
61
62impl<C: Deref<Target = impl Signer> + Clone> AddressLookupTableOps<C> for crate::Client<C> {
63 async fn alt_with_config(
64 &self,
65 address: &Pubkey,
66 config: RpcAccountInfoConfig,
67 ) -> crate::Result<WithSlot<Option<AddressLookupTableAccount>>> {
68 let client = self.store_program().rpc();
69 let account: WithSlot<_> = get_account_with_context(&client, address, config).await?;
70 account
71 .map(|a| {
72 a.map(|account| {
73 let table = AddressLookupTable::deserialize(account.data())
74 .map_err(crate::Error::custom)?;
75 Ok(AddressLookupTableAccount {
76 key: *address,
77 addresses: table.addresses.iter().copied().collect(),
78 })
79 })
80 .transpose()
81 })
82 .transpose()
83 }
84
85 async fn create_alt(&self) -> crate::Result<(TransactionBuilder<C>, Pubkey)> {
86 let slot = self.get_slot(None).await?;
87 let payer = self.payer();
88 let (ix, address) =
89 address_lookup_table::instruction::create_lookup_table(payer, payer, slot);
90 let rpc = self
91 .store_transaction()
92 .program(address_lookup_table::program::ID)
93 .pre_instruction(ix, false);
94
95 Ok((rpc, address))
96 }
97
98 fn extend_alt(
99 &self,
100 alt: &Pubkey,
101 new_addresses: Vec<Pubkey>,
102 chunk_size: Option<usize>,
103 ) -> crate::Result<BundleBuilder<C>> {
104 let mut tx = self.bundle();
105 let payer = self.payer();
106
107 let chunk_size = chunk_size.unwrap_or(10);
108 for new_addresses in new_addresses.chunks(chunk_size) {
109 let ix = address_lookup_table::instruction::extend_lookup_table(
110 *alt,
111 payer,
112 Some(payer),
113 new_addresses.to_owned(),
114 );
115 let rpc = self
116 .store_transaction()
117 .program(address_lookup_table::program::ID)
118 .pre_instruction(ix, false);
119 tx.try_push(rpc).map_err(|(_, err)| err)?;
120 }
121 Ok(tx)
122 }
123
124 fn deactivate_alt(&self, alt: &Pubkey) -> TransactionBuilder<C> {
125 let payer = self.payer();
126 let ix = address_lookup_table::instruction::deactivate_lookup_table(*alt, payer);
127 self.store_transaction()
128 .program(address_lookup_table::program::ID)
129 .pre_instruction(ix, false)
130 }
131
132 fn close_alt(&self, alt: &Pubkey) -> TransactionBuilder<C> {
133 let payer = self.payer();
134 let ix = address_lookup_table::instruction::close_lookup_table(*alt, payer, payer);
135 self.store_transaction()
136 .program(address_lookup_table::program::ID)
137 .pre_instruction(ix, false)
138 }
139}