use solana_pubkey::Pubkey;
use crate::{
get_associated_token_address, get_board_address, get_epoch_vault_address, get_event_authority_address,
get_one_btc_vault_address, get_satrush_config_address, get_treasury_address, SLOT_HASHES_ID, SYSTEM_PROGRAM_ID,
TOKEN_PROGRAM_ID,
};
pub fn get_lookup_table_entries(usd_mint: Pubkey, btc_mint: Pubkey, swap_program: Pubkey) -> Vec<Pubkey> {
let board = get_board_address().0;
let epoch_vault = get_epoch_vault_address().0;
let one_btc_vault = get_one_btc_vault_address().0;
let treasury = get_treasury_address().0;
vec![
get_satrush_config_address().0,
board,
get_associated_token_address(&board, &usd_mint),
get_associated_token_address(&board, &btc_mint),
epoch_vault,
get_associated_token_address(&epoch_vault, &usd_mint),
one_btc_vault,
get_associated_token_address(&one_btc_vault, &usd_mint),
treasury,
get_associated_token_address(&treasury, &usd_mint),
usd_mint,
btc_mint,
SLOT_HASHES_ID,
TOKEN_PROGRAM_ID,
SYSTEM_PROGRAM_ID,
get_event_authority_address().0,
swap_program,
]
}
pub fn decode_address_lookup_table(
address: Pubkey,
data: &[u8],
) -> Result<solana_message::AddressLookupTableAccount, std::io::Error> {
let table = solana_address_lookup_table_interface::state::AddressLookupTable::deserialize(data)
.map_err(|e| std::io::Error::other(format!("account {address} is not an address lookup table: {e:?}")))?;
Ok(solana_message::AddressLookupTableAccount {
key: address,
addresses: table.addresses.to_vec(),
})
}
#[cfg(feature = "fetch")]
pub fn fetch_address_lookup_table(
rpc: &solana_rpc_client::rpc_client::RpcClient,
address: &Pubkey,
) -> Result<solana_message::AddressLookupTableAccount, std::io::Error> {
let account = rpc
.get_account(address)
.map_err(|e| std::io::Error::other(format!("lookup table {address} not found: {e}")))?;
decode_address_lookup_table(*address, &account.data)
}
#[cfg(test)]
mod tests {
use super::*;
use solana_address_lookup_table_interface::state::{AddressLookupTable, LookupTableMeta};
use std::borrow::Cow;
use std::collections::HashSet;
#[test]
fn entries_are_unique_and_keep_signers_and_program_ids_static() {
let entries = get_lookup_table_entries(Pubkey::new_unique(), Pubkey::new_unique(), Pubkey::new_unique());
let unique: HashSet<_> = entries.iter().collect();
assert_eq!(unique.len(), entries.len(), "duplicate entries waste table slots");
assert_eq!(entries.len(), 17);
assert!(!entries.contains(&crate::SATRUSH_ID));
assert!(!entries.contains(&crate::get_round_address(0).0));
}
#[test]
fn decodes_a_serialized_lookup_table() {
let address = Pubkey::new_unique();
let stored = vec![Pubkey::new_unique(), Pubkey::new_unique()];
let data = AddressLookupTable {
meta: LookupTableMeta::default(),
addresses: Cow::Owned(stored.clone()),
}
.serialize_for_tests()
.unwrap();
let decoded = decode_address_lookup_table(address, &data).unwrap();
assert_eq!(decoded.key, address);
assert_eq!(decoded.addresses, stored);
}
#[test]
fn rejects_non_lookup_table_data() {
assert!(decode_address_lookup_table(Pubkey::new_unique(), &[0u8; 8]).is_err());
}
}