From ff223eba8e230a5ca86e0f88f8752c1f33e89962 Mon Sep 17 00:00:00 2001 From: burhankhaja Date: Fri, 14 Nov 2025 17:14:59 +0000 Subject: [PATCH] token-2022: Add permanent delegate extension Co-authored-by: M. Daeva --- .../instructions/initialize.rs | 68 +++++++++++++++++++ .../permanent_delegate/instructions/mod.rs | 3 + .../extensions/permanent_delegate/mod.rs | 5 ++ .../extensions/permanent_delegate/state.rs | 17 +++++ 4 files changed, 93 insertions(+) create mode 100644 programs/token-2022/src/instructions/extensions/permanent_delegate/instructions/initialize.rs create mode 100644 programs/token-2022/src/instructions/extensions/permanent_delegate/instructions/mod.rs create mode 100644 programs/token-2022/src/instructions/extensions/permanent_delegate/mod.rs create mode 100644 programs/token-2022/src/instructions/extensions/permanent_delegate/state.rs diff --git a/programs/token-2022/src/instructions/extensions/permanent_delegate/instructions/initialize.rs b/programs/token-2022/src/instructions/extensions/permanent_delegate/instructions/initialize.rs new file mode 100644 index 00000000..3bdafae7 --- /dev/null +++ b/programs/token-2022/src/instructions/extensions/permanent_delegate/instructions/initialize.rs @@ -0,0 +1,68 @@ +use { + crate::instructions::extensions::{ + permanent_delegate::state::offset_permanent_delegate_initialize as OFFSET, + ExtensionDiscriminator, + }, + pinocchio::{ + account_info::AccountInfo, + cpi::invoke, + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + ProgramResult, + }, +}; + +/// Initialize the permanent delegate on a new mint. +/// +/// Fails if the mint has already been initialized, so must be called before +/// `InitializeMint`. +/// +/// The mint must have exactly enough space allocated for the base mint (82 +/// bytes), plus 83 bytes of padding, 1 byte reserved for the account type, +/// then space required for this extension, plus any others. +/// +/// Accounts expected by this instruction: +/// +/// 0. `[writable]` The mint to initialize. +/// +/// Data expected by this instruction: +/// Pubkey for the permanent delegate +pub struct InitializePermanentDelegate<'a, 'b> { + /// The mint to initialize the permanent delegate + pub mint: &'a AccountInfo, + /// The public key for the account that can close the mint + pub delegate: &'b Pubkey, + /// Token Program + pub token_program: &'b Pubkey, +} + +impl InitializePermanentDelegate<'_, '_> { + #[inline(always)] + pub fn invoke(&self) -> ProgramResult { + let account_metas = [AccountMeta::writable(self.mint.key())]; + + let mut buffer = [0u8; OFFSET::END as usize]; + let data = initialize_instruction_data(&mut buffer, &self.delegate); + + let instruction = Instruction { + program_id: self.token_program, + accounts: &account_metas, + data, + }; + + invoke(&instruction, &[self.mint]) + } +} + +#[inline(always)] +fn initialize_instruction_data<'a>(buffer: &'a mut [u8], delegate: &Pubkey) -> &'a [u8] { + let offset = OFFSET::START as usize; + + // Set discriminator + buffer[..offset].copy_from_slice(&[ExtensionDiscriminator::PermanentDelegate as u8]); + + // Set delegate + buffer[offset..offset + OFFSET::PERMANENT_DELEGATE_PUBKEY as usize].copy_from_slice(delegate); + + buffer +} diff --git a/programs/token-2022/src/instructions/extensions/permanent_delegate/instructions/mod.rs b/programs/token-2022/src/instructions/extensions/permanent_delegate/instructions/mod.rs new file mode 100644 index 00000000..52d32669 --- /dev/null +++ b/programs/token-2022/src/instructions/extensions/permanent_delegate/instructions/mod.rs @@ -0,0 +1,3 @@ +mod initialize; + +pub use initialize::*; diff --git a/programs/token-2022/src/instructions/extensions/permanent_delegate/mod.rs b/programs/token-2022/src/instructions/extensions/permanent_delegate/mod.rs new file mode 100644 index 00000000..ec1f45c6 --- /dev/null +++ b/programs/token-2022/src/instructions/extensions/permanent_delegate/mod.rs @@ -0,0 +1,5 @@ +pub mod instructions; +pub mod state; + +pub use instructions::*; +pub use state::*; diff --git a/programs/token-2022/src/instructions/extensions/permanent_delegate/state.rs b/programs/token-2022/src/instructions/extensions/permanent_delegate/state.rs new file mode 100644 index 00000000..964782a7 --- /dev/null +++ b/programs/token-2022/src/instructions/extensions/permanent_delegate/state.rs @@ -0,0 +1,17 @@ +use pinocchio::pubkey::Pubkey; + +/// Instruction data layout: +/// - [0] : Extension discriminator (1 byte) +/// - [1..33] : permanent delegate pubkey (32 bytes) +pub mod offset_permanent_delegate_initialize { + pub const START: u8 = 1; + pub const PERMANENT_DELEGATE_PUBKEY: u8 = 32; + pub const END: u8 = START + PERMANENT_DELEGATE_PUBKEY; +} + +/// Permanent delegate extension data for mints. +#[repr(C)] +pub struct PermanentDelegate { + /// Optional permanent delegate for transferring or burning tokens + delegate: Pubkey, +}