gmsol_sdk/client/ops/
alt.rs

1use 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
17/// Address Lookup Table operations.
18pub trait AddressLookupTableOps<C> {
19    /// Fetch address lookup table with the given config.
20    fn alt_with_config(
21        &self,
22        address: &Pubkey,
23        config: RpcAccountInfoConfig,
24    ) -> impl Future<Output = crate::Result<WithSlot<Option<AddressLookupTableAccount>>>>;
25
26    /// Fetch address lookup table.
27    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    /// Create a [`TransactionBuilder`] to create address lookup table.
46    fn create_alt(&self) -> impl Future<Output = crate::Result<(TransactionBuilder<C>, Pubkey)>>;
47
48    /// Create a [`BundleBuilder`] to extend the given address lookup table with new addresses.
49    fn extend_alt(
50        &self,
51        alt: &Pubkey,
52        new_addresses: Vec<Pubkey>,
53        chunk_size: Option<usize>,
54    ) -> crate::Result<BundleBuilder<C>>;
55    /// Create a [`TransactionBuilder`] to deactivate the given address lookup table
56    fn deactivate_alt(&self, alt: &Pubkey) -> TransactionBuilder<C>;
57
58    /// Create a [`TransactionBuilder`] to close the given address lookup table
59    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}