diff --git a/lang/src/address_lookup_table_program.rs b/lang/src/address_lookup_table_program.rs new file mode 100644 index 0000000000..79090e36bf --- /dev/null +++ b/lang/src/address_lookup_table_program.rs @@ -0,0 +1,64 @@ +use crate::prelude::*; +use crate::solana_program::address_lookup_table; +use solana_program::address_lookup_table::state::AddressLookupTable as SolanaAddressLookupTable; +use solana_program::pubkey::Pubkey; +use std::ops::{Deref, DerefMut}; + +#[derive(Debug, Clone)] +pub struct AddressLookupTable; +impl anchor_lang::Id for AddressLookupTable { + fn id() -> Pubkey { + address_lookup_table::program::ID + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct AddressLookupTableAccount<'info>(SolanaAddressLookupTable<'info>); + +impl AccountSerialize for AddressLookupTableAccount<'_> {} + +impl<'info> AccountDeserialize for AddressLookupTableAccount<'info> { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result { + // Deserialize into the temporary struct + let table = SolanaAddressLookupTable::deserialize(buf) + .map_err(|_| ProgramError::InvalidAccountData)?; + + // Construct a new AddressLookupTable with a lifetime tied to 'info + let new_table = SolanaAddressLookupTable { + meta: table.meta, + addresses: std::borrow::Cow::Owned(table.addresses.into_owned()), + }; + + Ok(Self(new_table)) + } +} + +impl<'info> Deref for AddressLookupTableAccount<'info> { + type Target = SolanaAddressLookupTable<'info>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'info> DerefMut for AddressLookupTableAccount<'info> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Owner for AddressLookupTableAccount<'_> { + fn owner() -> Pubkey { + address_lookup_table::program::ID + } +} + + #[cfg(feature = "idl-build")] + mod idl_build { + use super::*; + + impl crate::IdlBuild for AddressLookupTableAccount<'_> {} + impl crate::Discriminator for AddressLookupTableAccount<'_> { + const DISCRIMINATOR: &'static [u8] = &[]; + } + } diff --git a/lang/src/lib.rs b/lang/src/lib.rs index dd4d3b64b8..ed66e8a821 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -45,10 +45,12 @@ pub mod event; pub mod idl; pub mod system_program; mod vec; +mod address_lookup_table_program; #[cfg(feature = "lazy-account")] mod lazy; +pub use crate::address_lookup_table_program::*; pub use crate::bpf_upgradeable_state::*; pub use anchor_attribute_access_control::access_control; pub use anchor_attribute_account::{account, declare_id, pubkey, zero_copy}; @@ -402,6 +404,7 @@ impl Key for Pubkey { /// All programs should include it via `anchor_lang::prelude::*;`. pub mod prelude { pub use super::{ + address_lookup_table_program::{AddressLookupTable, AddressLookupTableAccount}, access_control, account, accounts::account::Account, accounts::account_loader::AccountLoader, accounts::interface::Interface, accounts::interface_account::InterfaceAccount, accounts::program::Program, diff --git a/tests/address-lookup-table-program/Anchor.toml b/tests/address-lookup-table-program/Anchor.toml new file mode 100644 index 0000000000..05c0441427 --- /dev/null +++ b/tests/address-lookup-table-program/Anchor.toml @@ -0,0 +1,9 @@ +[programs.localnet] +bpf_upgradeable_state = "Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e" + +[provider] +cluster = "localnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/tests/address-lookup-table-program/Cargo.toml b/tests/address-lookup-table-program/Cargo.toml new file mode 100644 index 0000000000..97d6280542 --- /dev/null +++ b/tests/address-lookup-table-program/Cargo.toml @@ -0,0 +1,8 @@ +[workspace] +members = [ + "programs/*" +] +resolver = "2" + +[profile.release] +overflow-checks = true diff --git a/tests/address-lookup-table-program/address_lookup_table_state-keypair.json b/tests/address-lookup-table-program/address_lookup_table_state-keypair.json new file mode 100644 index 0000000000..ae39fe9564 --- /dev/null +++ b/tests/address-lookup-table-program/address_lookup_table_state-keypair.json @@ -0,0 +1 @@ +[114,99,192,17,48,208,90,184,231,46,220,91,47,115,132,253,218,163,228,101,8,121,220,138,41,140,176,127,254,91,51,28,176,244,174,182,223,57,57,125,117,201,31,213,9,39,207,212,100,173,88,252,61,235,89,156,53,86,4,90,16,251,191,219] \ No newline at end of file diff --git a/tests/address-lookup-table-program/migrations/deploy.ts b/tests/address-lookup-table-program/migrations/deploy.ts new file mode 100644 index 0000000000..82fb175fa2 --- /dev/null +++ b/tests/address-lookup-table-program/migrations/deploy.ts @@ -0,0 +1,12 @@ +// Migrations are an early feature. Currently, they're nothing more than this +// single deploy script that's invoked from the CLI, injecting a provider +// configured from the workspace's Anchor.toml. + +const anchor = require("@coral-xyz/anchor"); + +module.exports = async function (provider) { + // Configure client to use the provider. + anchor.setProvider(provider); + + // Add your deploy script here. +}; diff --git a/tests/address-lookup-table-program/package.json b/tests/address-lookup-table-program/package.json new file mode 100644 index 0000000000..d3416e5955 --- /dev/null +++ b/tests/address-lookup-table-program/package.json @@ -0,0 +1,16 @@ +{ + "name": "address-lookup-table", + "version": "0.24.0", + "license": "(MIT OR Apache-2.0)", + "homepage": "https://github.com/coral-xyz/anchor#readme", + "bugs": { + "url": "https://github.com/coral-xyz/anchor/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/coral-xyz/anchor.git" + }, + "engines": { + "node": ">=17" + } +} diff --git a/tests/address-lookup-table-program/program_with_different_programdata.json b/tests/address-lookup-table-program/program_with_different_programdata.json new file mode 100644 index 0000000000..8825b0f8e9 --- /dev/null +++ b/tests/address-lookup-table-program/program_with_different_programdata.json @@ -0,0 +1 @@ +[86,234,116,86,82,140,116,250,254,32,75,217,35,39,9,238,39,98,242,254,25,216,201,66,1,239,93,12,81,19,34,108,219,67,158,98,245,234,81,126,228,157,205,206,130,5,14,54,1,21,88,246,128,124,240,93,157,49,102,19,253,19,205,178] \ No newline at end of file diff --git a/tests/address-lookup-table-program/programs/address-lookup-table-program/Cargo.toml b/tests/address-lookup-table-program/programs/address-lookup-table-program/Cargo.toml new file mode 100644 index 0000000000..8cf288cff4 --- /dev/null +++ b/tests/address-lookup-table-program/programs/address-lookup-table-program/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "address-lookup-table-program" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "address_lookup_table_program" + +[features] +no-entrypoint = [] +no-idl = [] +cpi = ["no-entrypoint"] +default = [] +idl-build = ["anchor-lang/idl-build"] + +[dependencies] +anchor-lang = { path = "../../../../lang" } diff --git a/tests/address-lookup-table-program/programs/address-lookup-table-program/Xargo.toml b/tests/address-lookup-table-program/programs/address-lookup-table-program/Xargo.toml new file mode 100644 index 0000000000..475fb71ed1 --- /dev/null +++ b/tests/address-lookup-table-program/programs/address-lookup-table-program/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/tests/address-lookup-table-program/programs/address-lookup-table-program/src/lib.rs b/tests/address-lookup-table-program/programs/address-lookup-table-program/src/lib.rs new file mode 100644 index 0000000000..185abea65f --- /dev/null +++ b/tests/address-lookup-table-program/programs/address-lookup-table-program/src/lib.rs @@ -0,0 +1,30 @@ +use anchor_lang::prelude::*; + +use crate::program::AddressLookupTableTest; + +declare_id!("Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e"); + +#[program] +pub mod address_lookup_table_test { + use super::*; + + pub fn test_read( + ctx: Context, + ) -> Result<()> { + Ok(()) + } +} + +#[error_code] +pub enum CustomError { + InvalidProgramDataAddress, + AccountNotProgram, +} + +#[derive(Accounts)] +pub struct Test<'info> { + #[account(mut)] + pub authority: Signer<'info>, + pub table: Account<'info, AddressLookupTable>, + pub lut_program: Program<'info, AddressLookupTableProgram>, +} diff --git a/tests/address-lookup-table-program/tests/address-lookup-table.ts b/tests/address-lookup-table-program/tests/address-lookup-table.ts new file mode 100644 index 0000000000..a948a30f7a --- /dev/null +++ b/tests/address-lookup-table-program/tests/address-lookup-table.ts @@ -0,0 +1,31 @@ +import * as anchor from "@coral-xyz/anchor"; +import { AnchorError, Program } from "@coral-xyz/anchor"; +import { PublicKey } from "@solana/web3.js"; +import { assert } from "chai"; +import { + AddressLookupTable, + AddressLookupTableProgram, +} from "../target/types/address_lookup_table_program"; + +describe("address_lookup_table_program", () => { + const provider = anchor.AnchorProvider.env(); + // Configure the client to use the local cluster. + anchor.setProvider(provider); + + const program = anchor.workspace + .AddressLookupTableProgram as Program; + const lutProgramAddress = new anchor.web3.PublicKey( + "AddressLookupTab1e1111111111111111111111111" + ); + + it("Test loads", async () => { + const tx = await program.rpc.test({ + accounts: { + authority: provider.wallet.publicKey, + lutProgram: lutProgramAddress, + table: lutProgramAddress, // Just a dummy value. fix + }, + signers: [settings], + }); + }); +}); diff --git a/tests/address-lookup-table-program/tsconfig.json b/tests/address-lookup-table-program/tsconfig.json new file mode 100644 index 0000000000..b3b6656d38 --- /dev/null +++ b/tests/address-lookup-table-program/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true, + "skipLibCheck": true + } +}