solana_program/address_lookup_table/instruction.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
use {
crate::{
address_lookup_table::program::id,
clock::Slot,
instruction::{AccountMeta, Instruction},
pubkey::Pubkey,
system_program,
},
serde::{Deserialize, Serialize},
};
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum ProgramInstruction {
/// Create an address lookup table
///
/// # Account references
/// 0. `[WRITE]` Uninitialized address lookup table account
/// 1. `[SIGNER]` Account used to derive and control the new address lookup table.
/// 2. `[SIGNER, WRITE]` Account that will fund the new address lookup table.
/// 3. `[]` System program for CPI.
CreateLookupTable {
/// A recent slot must be used in the derivation path
/// for each initialized table. When closing table accounts,
/// the initialization slot must no longer be "recent" to prevent
/// address tables from being recreated with reordered or
/// otherwise malicious addresses.
recent_slot: Slot,
/// Address tables are always initialized at program-derived
/// addresses using the funding address, recent blockhash, and
/// the user-passed `bump_seed`.
bump_seed: u8,
},
/// Permanently freeze an address lookup table, making it immutable.
///
/// # Account references
/// 0. `[WRITE]` Address lookup table account to freeze
/// 1. `[SIGNER]` Current authority
FreezeLookupTable,
/// Extend an address lookup table with new addresses. Funding account and
/// system program account references are only required if the lookup table
/// account requires additional lamports to cover the rent-exempt balance
/// after being extended.
///
/// # Account references
/// 0. `[WRITE]` Address lookup table account to extend
/// 1. `[SIGNER]` Current authority
/// 2. `[SIGNER, WRITE, OPTIONAL]` Account that will fund the table reallocation
/// 3. `[OPTIONAL]` System program for CPI.
ExtendLookupTable { new_addresses: Vec<Pubkey> },
/// Deactivate an address lookup table, making it unusable and
/// eligible for closure after a short period of time.
///
/// # Account references
/// 0. `[WRITE]` Address lookup table account to deactivate
/// 1. `[SIGNER]` Current authority
DeactivateLookupTable,
/// Close an address lookup table account
///
/// # Account references
/// 0. `[WRITE]` Address lookup table account to close
/// 1. `[SIGNER]` Current authority
/// 2. `[WRITE]` Recipient of closed account lamports
CloseLookupTable,
}
/// Derives the address of an address table account from a wallet address and a recent block's slot.
pub fn derive_lookup_table_address(
authority_address: &Pubkey,
recent_block_slot: Slot,
) -> (Pubkey, u8) {
Pubkey::find_program_address(
&[authority_address.as_ref(), &recent_block_slot.to_le_bytes()],
&id(),
)
}
/// Constructs an instruction to create a table account and returns
/// the instruction and the table account's derived address.
fn create_lookup_table_common(
authority_address: Pubkey,
payer_address: Pubkey,
recent_slot: Slot,
authority_is_signer: bool,
) -> (Instruction, Pubkey) {
let (lookup_table_address, bump_seed) =
derive_lookup_table_address(&authority_address, recent_slot);
let instruction = Instruction::new_with_bincode(
id(),
&ProgramInstruction::CreateLookupTable {
recent_slot,
bump_seed,
},
vec![
AccountMeta::new(lookup_table_address, false),
AccountMeta::new_readonly(authority_address, authority_is_signer),
AccountMeta::new(payer_address, true),
AccountMeta::new_readonly(system_program::id(), false),
],
);
(instruction, lookup_table_address)
}
/// Constructs an instruction to create a table account and returns
/// the instruction and the table account's derived address.
///
/// # Note
///
/// This instruction requires the authority to be a signer but
/// in v1.12 the address lookup table program will no longer require
/// the authority to sign the transaction.
pub fn create_lookup_table_signed(
authority_address: Pubkey,
payer_address: Pubkey,
recent_slot: Slot,
) -> (Instruction, Pubkey) {
create_lookup_table_common(authority_address, payer_address, recent_slot, true)
}
/// Constructs an instruction to create a table account and returns
/// the instruction and the table account's derived address.
///
/// # Note
///
/// This instruction doesn't require the authority to be a signer but
/// until v1.12 the address lookup table program still requires the
/// authority to sign the transaction.
pub fn create_lookup_table(
authority_address: Pubkey,
payer_address: Pubkey,
recent_slot: Slot,
) -> (Instruction, Pubkey) {
create_lookup_table_common(authority_address, payer_address, recent_slot, false)
}
/// Constructs an instruction that freezes an address lookup
/// table so that it can never be closed or extended again. Empty
/// lookup tables cannot be frozen.
pub fn freeze_lookup_table(lookup_table_address: Pubkey, authority_address: Pubkey) -> Instruction {
Instruction::new_with_bincode(
id(),
&ProgramInstruction::FreezeLookupTable,
vec![
AccountMeta::new(lookup_table_address, false),
AccountMeta::new_readonly(authority_address, true),
],
)
}
/// Constructs an instruction which extends an address lookup
/// table account with new addresses.
pub fn extend_lookup_table(
lookup_table_address: Pubkey,
authority_address: Pubkey,
payer_address: Option<Pubkey>,
new_addresses: Vec<Pubkey>,
) -> Instruction {
let mut accounts = vec![
AccountMeta::new(lookup_table_address, false),
AccountMeta::new_readonly(authority_address, true),
];
if let Some(payer_address) = payer_address {
accounts.extend([
AccountMeta::new(payer_address, true),
AccountMeta::new_readonly(system_program::id(), false),
]);
}
Instruction::new_with_bincode(
id(),
&ProgramInstruction::ExtendLookupTable { new_addresses },
accounts,
)
}
/// Constructs an instruction that deactivates an address lookup
/// table so that it cannot be extended again and will be unusable
/// and eligible for closure after a short amount of time.
pub fn deactivate_lookup_table(
lookup_table_address: Pubkey,
authority_address: Pubkey,
) -> Instruction {
Instruction::new_with_bincode(
id(),
&ProgramInstruction::DeactivateLookupTable,
vec![
AccountMeta::new(lookup_table_address, false),
AccountMeta::new_readonly(authority_address, true),
],
)
}
/// Returns an instruction that closes an address lookup table
/// account. The account will be deallocated and the lamports
/// will be drained to the recipient address.
pub fn close_lookup_table(
lookup_table_address: Pubkey,
authority_address: Pubkey,
recipient_address: Pubkey,
) -> Instruction {
Instruction::new_with_bincode(
id(),
&ProgramInstruction::CloseLookupTable,
vec![
AccountMeta::new(lookup_table_address, false),
AccountMeta::new_readonly(authority_address, true),
AccountMeta::new(recipient_address, false),
],
)
}