diff --git a/Cargo.lock b/Cargo.lock index 5184e76..577e357 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3180,6 +3180,7 @@ dependencies = [ "log", "rustc_version", "serde", + "shank", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-program", @@ -3433,6 +3434,52 @@ dependencies = [ "keccak", ] +[[package]] +name = "shank" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d894855493d4ce613b25550fe1ed1c62d0af5486b984579ba55e3f8c9631d5" +dependencies = [ + "shank_macro", +] + +[[package]] +name = "shank_macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9bf2645f8eebde043da69200195058e7b59806705104f908a31d05ca82844ce" +dependencies = [ + "proc-macro2", + "quote", + "shank_macro_impl", + "shank_render", + "syn 1.0.109", +] + +[[package]] +name = "shank_macro_impl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d0593f48acb0a722906416b1f6b8926f6571eb9af16d566a7c65427f269f50" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + +[[package]] +name = "shank_render" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121175ba61809189f888dc5822ebfd30fa0d91e1e1f61d25a4d40b0847b3075e" +dependencies = [ + "proc-macro2", + "quote", + "shank_macro_impl", +] + [[package]] name = "sharded-slab" version = "0.1.7" diff --git a/program/Cargo.toml b/program/Cargo.toml index e85eb35..6e09165 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,6 +18,7 @@ bincode = "1.3.3" bytemuck = "1.14.1" log = "0.4.20" serde = { version = "1.0.193", features = ["derive"] } +shank = "0.4.2" solana-frozen-abi = "1.18.2" solana-frozen-abi-macro = "1.18.2" solana-program = "1.18.2" diff --git a/program/address_lookup_table.json b/program/address_lookup_table.json new file mode 100644 index 0000000..fbf1e57 --- /dev/null +++ b/program/address_lookup_table.json @@ -0,0 +1,228 @@ +{ + "version": "0.1.0", + "name": "address_lookup_table", + "instructions": [ + { + "name": "CreateLookupTable", + "accounts": [ + { + "name": "lookupTable", + "isMut": true, + "isSigner": false, + "docs": [ + "Uninitialized address lookup table account (seeds: [authority, recent_slot])" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Account used to derive and control the new address lookup table" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "System program for CPI" + ] + } + ], + "args": [ + { + "name": "recentSlot", + "type": { + "defined": "Slot" + } + }, + { + "name": "bumpSeed", + "type": "u8" + } + ], + "discriminant": { + "type": "u8", + "value": 0 + } + }, + { + "name": "FreezeLookupTable", + "accounts": [ + { + "name": "lookupTable", + "isMut": true, + "isSigner": false, + "docs": [ + "Address lookup table account to freeze (seeds: [authority, recent_slot])" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Current authority" + ] + } + ], + "args": [], + "discriminant": { + "type": "u8", + "value": 1 + } + }, + { + "name": "ExtendLookupTable", + "accounts": [ + { + "name": "lookupTable", + "isMut": true, + "isSigner": false, + "docs": [ + "Address lookup table account to extend (seeds: [authority, recent_slot])" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Current authority" + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true, + "isOptional": true, + "docs": [ + "Account that will fund the table reallocation" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "System program for CPI" + ] + } + ], + "args": [ + { + "name": "newAddresses", + "type": { + "vec": "publicKey" + } + } + ], + "discriminant": { + "type": "u8", + "value": 2 + } + }, + { + "name": "DeactivateLookupTable", + "accounts": [ + { + "name": "lookupTable", + "isMut": true, + "isSigner": false, + "docs": [ + "Address lookup table account to deactivate (seeds: [authority, recent_slot])" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Current authority" + ] + } + ], + "args": [], + "discriminant": { + "type": "u8", + "value": 3 + } + }, + { + "name": "CloseLookupTable", + "accounts": [ + { + "name": "lookupTable", + "isMut": true, + "isSigner": false, + "docs": [ + "Address lookup table account to close (seeds: [authority, recent_slot])" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Current authority" + ] + }, + { + "name": "recipient", + "isMut": true, + "isSigner": false, + "docs": [ + "Recipient of closed account lamports" + ] + } + ], + "args": [], + "discriminant": { + "type": "u8", + "value": 4 + } + } + ], + "accounts": [ + { + "name": "LookupTableMeta", + "type": { + "kind": "struct", + "fields": [ + { + "name": "deactivationSlot", + "type": { + "defined": "Slot" + } + }, + { + "name": "lastExtendedSlot", + "type": { + "defined": "Slot" + } + }, + { + "name": "lastExtendedSlotStartIndex", + "type": "u8" + }, + { + "name": "authority", + "type": { + "option": "publicKey" + } + }, + { + "name": "padding", + "type": "u16" + } + ] + } + } + ], + "metadata": { + "origin": "shank", + "address": "AaoNx79M6YE3DcXfrRN4nmBcQvQPqdpowi6uEESuJdnm" + } +} \ No newline at end of file diff --git a/program/src/instruction.rs b/program/src/instruction.rs index b7443d1..b5a9eb1 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -2,6 +2,7 @@ use { serde::{Deserialize, Serialize}, + shank::{ShankContext, ShankInstruction}, solana_program::{ clock::Slot, instruction::{AccountMeta, Instruction}, @@ -10,7 +11,7 @@ use { }, }; -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, ShankContext, ShankInstruction)] pub enum AddressLookupTableInstruction { /// Create an address lookup table /// @@ -21,6 +22,19 @@ pub enum AddressLookupTableInstruction { /// 2. `[SIGNER, WRITE]` Account that will fund the new address lookup /// table. /// 3. `[]` System program for CPI. + #[account( + 0, + writable, + name = "lookup_table", + desc = "Uninitialized address lookup table account (seeds: [authority, recent_slot])" + )] + #[account( + 1, + signer, + name = "authority", + desc = "Account used to derive and control the new address lookup table" + )] + #[account(2, name = "system_program", desc = "System program for CPI")] CreateLookupTable { /// A recent slot must be used in the derivation path /// for each initialized table. When closing table accounts, @@ -39,6 +53,13 @@ pub enum AddressLookupTableInstruction { /// # Account references /// 0. `[WRITE]` Address lookup table account to freeze /// 1. `[SIGNER]` Current authority + #[account( + 0, + writable, + name = "lookup_table", + desc = "Address lookup table account to freeze (seeds: [authority, recent_slot])" + )] + #[account(1, signer, name = "authority", desc = "Current authority")] FreezeLookupTable, /// Extend an address lookup table with new addresses. Funding account and @@ -52,6 +73,22 @@ pub enum AddressLookupTableInstruction { /// 2. `[SIGNER, WRITE, OPTIONAL]` Account that will fund the table /// reallocation /// 3. `[OPTIONAL]` System program for CPI. + #[account( + 0, + writable, + name = "lookup_table", + desc = "Address lookup table account to extend (seeds: [authority, recent_slot])" + )] + #[account(1, signer, name = "authority", desc = "Current authority")] + #[account( + 2, + signer, + writable, + optional, + name = "payer", + desc = "Account that will fund the table reallocation" + )] + #[account(3, optional, name = "system_program", desc = "System program for CPI")] ExtendLookupTable { new_addresses: Vec }, /// Deactivate an address lookup table, making it unusable and @@ -60,6 +97,13 @@ pub enum AddressLookupTableInstruction { /// # Account references /// 0. `[WRITE]` Address lookup table account to deactivate /// 1. `[SIGNER]` Current authority + #[account( + 0, + writable, + name = "lookup_table", + desc = "Address lookup table account to deactivate (seeds: [authority, recent_slot])" + )] + #[account(1, signer, name = "authority", desc = "Current authority")] DeactivateLookupTable, /// Close an address lookup table account @@ -68,6 +112,19 @@ pub enum AddressLookupTableInstruction { /// 0. `[WRITE]` Address lookup table account to close /// 1. `[SIGNER]` Current authority /// 2. `[WRITE]` Recipient of closed account lamports + #[account( + 0, + writable, + name = "lookup_table", + desc = "Address lookup table account to close (seeds: [authority, recent_slot])" + )] + #[account(1, signer, name = "authority", desc = "Current authority")] + #[account( + 2, + writable, + name = "recipient", + desc = "Recipient of closed account lamports" + )] CloseLookupTable, } @@ -191,3 +248,9 @@ pub fn close_lookup_table( ], ) } + +#[test] +fn test_joe() { + let (instruction, _) = create_lookup_table(Pubkey::new_unique(), Pubkey::new_unique(), 0); + println!("Instruction data: {:?}", instruction.data); +} diff --git a/program/src/state.rs b/program/src/state.rs index e86e616..ce59f11 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -1,6 +1,7 @@ use { crate::error::AddressLookupError, serde::{Deserialize, Serialize}, + shank::ShankAccount, solana_frozen_abi_macro::{AbiEnumVisitor, AbiExample}, solana_program::{ clock::Slot, program_error::ProgramError, pubkey::Pubkey, slot_hashes::MAX_ENTRIES, @@ -41,7 +42,12 @@ pub enum LookupTableStatus { } /// Address lookup table metadata -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)] +#[rustfmt::skip] +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample, ShankAccount)] +#[seeds( + authority("Account used to derive and control the new address lookup table", Pubkey), + recent_slot("A recent block-producing slot", u64), +)] pub struct LookupTableMeta { // [Core BPF]: TODO: `Clock` instead of `SlotHashes`. /// Lookup tables cannot be closed until the deactivation slot is