Procházet zdrojové kódy

`feat` : add token-2022 core ixs and state (#190)

* add token-2022 core ixs and state

* chore : resolve comments and refactor

* improv : add `#[inline(always)]` for all invoke_signed methods

* chore : fix docs and cleanup
Nagaprasad V R před 3 měsíci
rodič
revize
55ecb47a4f
48 změnil soubory, kde provedl 1804 přidání a 3 odebrání
  1. 8 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 15 0
      programs/token-2022/Cargo.toml
  4. 59 0
      programs/token-2022/README.md
  5. 69 0
      programs/token-2022/src/instructions/approve.rs
  6. 78 0
      programs/token-2022/src/instructions/approve_checked.rs
  7. 69 0
      programs/token-2022/src/instructions/burn.rs
  8. 73 0
      programs/token-2022/src/instructions/burn_checked.rs
  9. 53 0
      programs/token-2022/src/instructions/close_account.rs
  10. 53 0
      programs/token-2022/src/instructions/freeze_account.rs
  11. 57 0
      programs/token-2022/src/instructions/initialize_account.rs
  12. 69 0
      programs/token-2022/src/instructions/initialize_account_2.rs
  13. 61 0
      programs/token-2022/src/instructions/initialize_account_3.rs
  14. 82 0
      programs/token-2022/src/instructions/initialize_mint.rs
  15. 76 0
      programs/token-2022/src/instructions/initialize_mint_2.rs
  16. 69 0
      programs/token-2022/src/instructions/mint_to.rs
  17. 74 0
      programs/token-2022/src/instructions/mint_to_checked.rs
  18. 39 0
      programs/token-2022/src/instructions/mod.rs
  19. 45 0
      programs/token-2022/src/instructions/revoke.rs
  20. 85 0
      programs/token-2022/src/instructions/set_authority.rs
  21. 41 0
      programs/token-2022/src/instructions/sync_native.rs
  22. 53 0
      programs/token-2022/src/instructions/thaw_account.rs
  23. 65 0
      programs/token-2022/src/instructions/transfer.rs
  24. 78 0
      programs/token-2022/src/instructions/transfer_checked.rs
  25. 17 0
      programs/token-2022/src/lib.rs
  26. 36 0
      programs/token-2022/src/state/account_state.rs
  27. 150 0
      programs/token-2022/src/state/mint.rs
  28. 7 0
      programs/token-2022/src/state/mod.rs
  29. 203 0
      programs/token-2022/src/state/token.rs
  30. 1 0
      programs/token/src/instructions/approve.rs
  31. 1 0
      programs/token/src/instructions/approve_checked.rs
  32. 1 0
      programs/token/src/instructions/burn.rs
  33. 1 0
      programs/token/src/instructions/burn_checked.rs
  34. 1 0
      programs/token/src/instructions/close_account.rs
  35. 1 0
      programs/token/src/instructions/freeze_account.rs
  36. 1 0
      programs/token/src/instructions/initialize_account.rs
  37. 1 0
      programs/token/src/instructions/initialize_account_2.rs
  38. 1 0
      programs/token/src/instructions/initialize_account_3.rs
  39. 1 0
      programs/token/src/instructions/initialize_mint.rs
  40. 1 0
      programs/token/src/instructions/initialize_mint_2.rs
  41. 1 0
      programs/token/src/instructions/mint_to.rs
  42. 1 0
      programs/token/src/instructions/mint_to_checked.rs
  43. 1 0
      programs/token/src/instructions/revoke.rs
  44. 1 3
      programs/token/src/instructions/set_authority.rs
  45. 1 0
      programs/token/src/instructions/sync_native.rs
  46. 1 0
      programs/token/src/instructions/thaw_account.rs
  47. 1 0
      programs/token/src/instructions/transfer.rs
  48. 1 0
      programs/token/src/instructions/transfer_checked.rs

+ 8 - 0
Cargo.lock

@@ -93,6 +93,14 @@ dependencies = [
  "pinocchio-pubkey",
 ]
 
+[[package]]
+name = "pinocchio-token-2022"
+version = "0.1.0"
+dependencies = [
+ "pinocchio",
+ "pinocchio-pubkey",
+]
+
 [[package]]
 name = "proc-macro2"
 version = "1.0.89"

+ 1 - 0
Cargo.toml

@@ -5,6 +5,7 @@ members = [
     "programs/memo",
     "programs/system",
     "programs/token",
+    "programs/token-2022",
     "sdk/log/crate",
     "sdk/log/macro",
     "sdk/pinocchio",

+ 15 - 0
programs/token-2022/Cargo.toml

@@ -0,0 +1,15 @@
+[package]
+name = "pinocchio-token-2022"
+description = "Pinocchio helpers to invoke Token-2022 program instructions"
+version = "0.1.0"
+edition = { workspace = true }
+license = { workspace = true }
+readme = "./README.md"
+repository = { workspace = true }
+
+[lib]
+crate-type = ["rlib"]
+
+[dependencies]
+pinocchio = { workspace = true }
+pinocchio-pubkey = { workspace = true }

+ 59 - 0
programs/token-2022/README.md

@@ -0,0 +1,59 @@
+<p align="center">
+ <img alt="pinocchio-token-2022" src="https://github.com/user-attachments/assets/4048fe96-9096-4441-85c3-5deffeb089a6" height="100"/>
+</p>
+<h3 align="center">
+  <code>pinocchio-token-2022</code>
+</h3>
+<p align="center">
+  <a href="https://crates.io/crates/pinocchio-token-2022"><img src="https://img.shields.io/crates/v/pinocchio-token-2022?logo=rust" /></a>
+  <a href="https://docs.rs/pinocchio-token-2022"><img src="https://img.shields.io/docsrs/pinocchio-token-2022?logo=docsdotrs" /></a>
+</p>
+
+## Overview
+
+This crate contains [`pinocchio`](https://crates.io/crates/pinocchio) helpers to perform cross-program invocations (CPIs) for SPL Token-2022 instructions.
+
+Each instruction defines a `struct` with the accounts and parameters required. Once all values are set, you can call directly `invoke` or `invoke_signed` to perform the CPI.
+
+Instruction that are common to both SPL Token and SPL Token-2022 programs expect the program address, so they can be used to invoke either token program.
+
+This is a `no_std` crate.
+
+> **Note:** The API defined in this crate is subject to change.
+
+## Examples
+
+Initializing a mint account:
+
+```rust
+// This example assumes that the instruction receives a writable `mint`
+// account; `authority` is a `Pubkey`.
+// The SPL Token program is being invoked.
+InitializeMint {
+    mint,
+    rent_sysvar,
+    decimals: 9,
+    mint_authority: authority,
+    freeze_authority: Some(authority),
+    token_program: Pubkey::from_str("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
+}.invoke()?;
+```
+
+Performing a transfer of tokens:
+
+```rust
+// This example assumes that the instruction receives writable `from` and `to`
+// accounts, and a signer `authority` account.
+// The SPL Token-2022 is being invoked.
+Transfer {
+    from,
+    to,
+    authority,
+    amount: 10,
+    token_program: Pubkey::from_str("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb")
+}.invoke()?;
+```
+
+## License
+
+The code is licensed under the [Apache License Version 2.0](../LICENSE)

+ 69 - 0
programs/token-2022/src/instructions/approve.rs

@@ -0,0 +1,69 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Approves a delegate.
+///
+/// ### Accounts:
+///   0. `[WRITE]` The token account.
+///   1. `[]` The delegate.
+///   2. `[SIGNER]` The source account owner.
+pub struct Approve<'a, 'b> {
+    /// Source Account.
+    pub source: &'a AccountInfo,
+    /// Delegate Account
+    pub delegate: &'a AccountInfo,
+    /// Source Owner Account
+    pub authority: &'a AccountInfo,
+    /// Amount
+    pub amount: u64,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl Approve<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // Account metadata
+        let account_metas: [AccountMeta; 3] = [
+            AccountMeta::writable(self.source.key()),
+            AccountMeta::readonly(self.delegate.key()),
+            AccountMeta::readonly_signer(self.authority.key()),
+        ];
+
+        // Instruction data
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1..9]: amount (8 bytes, u64)
+        let mut instruction_data = [UNINIT_BYTE; 9];
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[4]);
+        // Set amount as u64 at offset [1..9]
+        write_bytes(&mut instruction_data[1..], &self.amount.to_le_bytes());
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 9) },
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.source, self.delegate, self.authority],
+            signers,
+        )
+    }
+}

+ 78 - 0
programs/token-2022/src/instructions/approve_checked.rs

@@ -0,0 +1,78 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Approves a delegate.
+///
+/// ### Accounts:
+///   0. `[WRITE]` The source account.
+///   1. `[]` The token mint.
+///   2. `[]` The delegate.
+///   3. `[SIGNER]` The source account owner.
+pub struct ApproveChecked<'a, 'b> {
+    /// Source Account.
+    pub source: &'a AccountInfo,
+    /// Mint Account.
+    pub mint: &'a AccountInfo,
+    /// Delegate Account.
+    pub delegate: &'a AccountInfo,
+    /// Source Owner Account.
+    pub authority: &'a AccountInfo,
+    /// Amount.
+    pub amount: u64,
+    /// Decimals.
+    pub decimals: u8,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl ApproveChecked<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // Account metadata
+        let account_metas: [AccountMeta; 4] = [
+            AccountMeta::writable(self.source.key()),
+            AccountMeta::readonly(self.mint.key()),
+            AccountMeta::readonly(self.delegate.key()),
+            AccountMeta::readonly_signer(self.authority.key()),
+        ];
+
+        // Instruction data
+        // -  [0]  : instruction discriminator (1 byte, u8)
+        // -  [1..9]: amount (8 bytes, u64)
+        // -  [9]   : decimals (1 byte, u8)
+        let mut instruction_data = [UNINIT_BYTE; 10];
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[13]);
+        // Set amount as u64 at offset [1..9]
+        write_bytes(&mut instruction_data[1..9], &self.amount.to_le_bytes());
+        // Set decimals as u8 at offset [9]
+        write_bytes(&mut instruction_data[9..], &[self.decimals]);
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 10) },
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.source, self.mint, self.delegate, self.authority],
+            signers,
+        )
+    }
+}

+ 69 - 0
programs/token-2022/src/instructions/burn.rs

@@ -0,0 +1,69 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Burns tokens by removing them from an account.
+///
+/// ### Accounts:
+///   0. `[WRITE]` The account to burn from.
+///   1. `[WRITE]` The token mint.
+///   2. `[SIGNER]` The account's owner/delegate.
+pub struct Burn<'a, 'b> {
+    /// Source of the Burn Account
+    pub account: &'a AccountInfo,
+    /// Mint Account
+    pub mint: &'a AccountInfo,
+    /// Owner of the Token Account
+    pub authority: &'a AccountInfo,
+    /// Amount
+    pub amount: u64,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl Burn<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // Account metadata
+        let account_metas: [AccountMeta; 3] = [
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::writable(self.mint.key()),
+            AccountMeta::readonly_signer(self.authority.key()),
+        ];
+
+        // Instruction data
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1..9]: amount (8 bytes, u64)
+        let mut instruction_data = [UNINIT_BYTE; 9];
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[8]);
+        // Set amount as u64 at offset [1..9]
+        write_bytes(&mut instruction_data[1..], &self.amount.to_le_bytes());
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 9) },
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.account, self.mint, self.authority],
+            signers,
+        )
+    }
+}

+ 73 - 0
programs/token-2022/src/instructions/burn_checked.rs

@@ -0,0 +1,73 @@
+use core::slice::from_raw_parts;
+
+use crate::{write_bytes, UNINIT_BYTE};
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+/// Burns tokens by removing them from an account.
+///
+/// ### Accounts:
+///   0. `[WRITE]` The account to burn from.
+///   1. `[WRITE]` The token mint.
+///   2. `[SIGNER]` The account's owner/delegate.
+pub struct BurnChecked<'a, 'b> {
+    /// Source of the Burn Account
+    pub account: &'a AccountInfo,
+    /// Mint Account
+    pub mint: &'a AccountInfo,
+    /// Owner of the Token Account
+    pub authority: &'a AccountInfo,
+    /// Amount
+    pub amount: u64,
+    /// Decimals
+    pub decimals: u8,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl BurnChecked<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // Account metadata
+        let account_metas: [AccountMeta; 3] = [
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::writable(self.mint.key()),
+            AccountMeta::readonly_signer(self.authority.key()),
+        ];
+
+        // Instruction data
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1..9]: amount (8 bytes, u64)
+        // -  [9]: decimals (1 byte, u8)
+        let mut instruction_data = [UNINIT_BYTE; 10];
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[15]);
+        // Set amount as u64 at offset [1..9]
+        write_bytes(&mut instruction_data[1..9], &self.amount.to_le_bytes());
+        // Set decimals as u8 at offset [9]
+        write_bytes(&mut instruction_data[9..], &[self.decimals]);
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 10) },
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.account, self.mint, self.authority],
+            signers,
+        )
+    }
+}

+ 53 - 0
programs/token-2022/src/instructions/close_account.rs

@@ -0,0 +1,53 @@
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+/// Close an account by transferring all its SOL to the destination account.
+///
+/// ### Accounts:
+///   0. `[WRITE]` The account to close.
+///   1. `[WRITE]` The destination account.
+///   2. `[SIGNER]` The account's owner.
+pub struct CloseAccount<'a, 'b> {
+    /// Token Account.
+    pub account: &'a AccountInfo,
+    /// Destination Account
+    pub destination: &'a AccountInfo,
+    /// Owner Account
+    pub authority: &'a AccountInfo,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl CloseAccount<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 3] = [
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::writable(self.destination.key()),
+            AccountMeta::readonly_signer(self.authority.key()),
+        ];
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: &[9],
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.account, self.destination, self.authority],
+            signers,
+        )
+    }
+}

+ 53 - 0
programs/token-2022/src/instructions/freeze_account.rs

@@ -0,0 +1,53 @@
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+/// Freeze an Initialized account using the Mint's freeze authority
+///
+/// ### Accounts:
+///   0. `[WRITE]` The account to freeze.
+///   1. `[]` The token mint.
+///   2. `[SIGNER]` The mint freeze authority.
+pub struct FreezeAccount<'a, 'b> {
+    /// Token Account to freeze.
+    pub account: &'a AccountInfo,
+    /// Mint Account.
+    pub mint: &'a AccountInfo,
+    /// Mint Freeze Authority Account
+    pub freeze_authority: &'a AccountInfo,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl FreezeAccount<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 3] = [
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::readonly(self.mint.key()),
+            AccountMeta::readonly_signer(self.freeze_authority.key()),
+        ];
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: &[10],
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.account, self.mint, self.freeze_authority],
+            signers,
+        )
+    }
+}

+ 57 - 0
programs/token-2022/src/instructions/initialize_account.rs

@@ -0,0 +1,57 @@
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+/// Initialize a new Token Account.
+///
+/// ### Accounts:
+///   0. `[WRITE]`  The account to initialize.
+///   1. `[]` The mint this account will be associated with.
+///   2. `[]` The new account's owner/multi-signature.
+///   3. `[]` Rent sysvar
+pub struct InitializeAccount<'a, 'b> {
+    /// New Account.
+    pub account: &'a AccountInfo,
+    /// Mint Account.
+    pub mint: &'a AccountInfo,
+    /// Owner of the new Account.
+    pub owner: &'a AccountInfo,
+    /// Rent Sysvar Account
+    pub rent_sysvar: &'a AccountInfo,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl InitializeAccount<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 4] = [
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::readonly(self.mint.key()),
+            AccountMeta::readonly(self.owner.key()),
+            AccountMeta::readonly(self.rent_sysvar.key()),
+        ];
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: &[1],
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.account, self.mint, self.owner, self.rent_sysvar],
+            signers,
+        )
+    }
+}

+ 69 - 0
programs/token-2022/src/instructions/initialize_account_2.rs

@@ -0,0 +1,69 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Initialize a new Token Account.
+///
+/// ### Accounts:
+///   0. `[WRITE]`  The account to initialize.
+///   1. `[]` The mint this account will be associated with.
+///   3. `[]` Rent sysvar
+pub struct InitializeAccount2<'a, 'b> {
+    /// New Account.
+    pub account: &'a AccountInfo,
+    /// Mint Account.
+    pub mint: &'a AccountInfo,
+    /// Rent Sysvar Account
+    pub rent_sysvar: &'a AccountInfo,
+    /// Owner of the new Account.
+    pub owner: &'a Pubkey,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl InitializeAccount2<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 3] = [
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::readonly(self.mint.key()),
+            AccountMeta::readonly(self.rent_sysvar.key()),
+        ];
+
+        // instruction data
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1..33]: owner (32 bytes, Pubkey)
+        let mut instruction_data = [UNINIT_BYTE; 33];
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[16]);
+        // Set owner as [u8; 32] at offset [1..33]
+        write_bytes(&mut instruction_data[1..], self.owner);
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 33) },
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.account, self.mint, self.rent_sysvar],
+            signers,
+        )
+    }
+}

+ 61 - 0
programs/token-2022/src/instructions/initialize_account_3.rs

@@ -0,0 +1,61 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Initialize a new Token Account.
+///
+/// ### Accounts:
+///   0. `[WRITE]`  The account to initialize.
+///   1. `[]` The mint this account will be associated with.
+pub struct InitializeAccount3<'a, 'b> {
+    /// New Account.
+    pub account: &'a AccountInfo,
+    /// Mint Account.
+    pub mint: &'a AccountInfo,
+    /// Owner of the new Account.
+    pub owner: &'a Pubkey,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl InitializeAccount3<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 2] = [
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::readonly(self.mint.key()),
+        ];
+
+        // instruction data
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1..33]: owner (32 bytes, Pubkey)
+        let mut instruction_data = [UNINIT_BYTE; 33];
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[18]);
+        // Set owner as [u8; 32] at offset [1..33]
+        write_bytes(&mut instruction_data[1..], self.owner);
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 33) },
+        };
+
+        invoke_signed(&instruction, &[self.account, self.mint], signers)
+    }
+}

+ 82 - 0
programs/token-2022/src/instructions/initialize_mint.rs

@@ -0,0 +1,82 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Initialize a new mint.
+///
+/// ### Accounts:
+///   0. `[WRITABLE]` Mint account
+///   1. `[]` Rent sysvar
+pub struct InitializeMint<'a, 'b> {
+    /// Mint Account.
+    pub mint: &'a AccountInfo,
+    /// Rent sysvar Account.
+    pub rent_sysvar: &'a AccountInfo,
+    /// Decimals.
+    pub decimals: u8,
+    /// Mint Authority.
+    pub mint_authority: &'a Pubkey,
+    /// Freeze Authority.
+    pub freeze_authority: Option<&'a Pubkey>,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl InitializeMint<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // Account metadata
+        let account_metas: [AccountMeta; 2] = [
+            AccountMeta::writable(self.mint.key()),
+            AccountMeta::readonly(self.rent_sysvar.key()),
+        ];
+
+        // Instruction data layout:
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1]: decimals (1 byte, u8)
+        // -  [2..34]: mint_authority (32 bytes, Pubkey)
+        // -  [34]: freeze_authority presence flag (1 byte, u8)
+        // -  [35..67]: freeze_authority (optional, 32 bytes, Pubkey)
+        let mut instruction_data = [UNINIT_BYTE; 67];
+        let mut length = instruction_data.len();
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[0]);
+        // Set decimals as u8 at offset [1]
+        write_bytes(&mut instruction_data[1..2], &[self.decimals]);
+        // Set mint_authority as Pubkey at offset [2..34]
+        write_bytes(&mut instruction_data[2..34], self.mint_authority);
+
+        if let Some(freeze_auth) = self.freeze_authority {
+            // Set Option = `true` & freeze_authority at offset [34..67]
+            write_bytes(&mut instruction_data[34..35], &[1]);
+            write_bytes(&mut instruction_data[35..], freeze_auth);
+        } else {
+            // Set Option = `false`
+            write_bytes(&mut instruction_data[34..35], &[0]);
+            // Adjust length if no freeze authority
+            length = 35;
+        }
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, length) },
+        };
+
+        invoke_signed(&instruction, &[self.mint, self.rent_sysvar], signers)
+    }
+}

+ 76 - 0
programs/token-2022/src/instructions/initialize_mint_2.rs

@@ -0,0 +1,76 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Initialize a new mint.
+///
+/// ### Accounts:
+///   0. `[WRITABLE]` Mint account
+pub struct InitializeMint2<'a, 'b> {
+    /// Mint Account.
+    pub mint: &'a AccountInfo,
+    /// Decimals.
+    pub decimals: u8,
+    /// Mint Authority.
+    pub mint_authority: &'a Pubkey,
+    /// Freeze Authority.
+    pub freeze_authority: Option<&'a Pubkey>,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl InitializeMint2<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // Account metadata
+        let account_metas: [AccountMeta; 1] = [AccountMeta::writable(self.mint.key())];
+
+        // Instruction data layout:
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1]: decimals (1 byte, u8)
+        // -  [2..34]: mint_authority (32 bytes, Pubkey)
+        // -  [34]: freeze_authority presence flag (1 byte, u8)
+        // -  [35..67]: freeze_authority (optional, 32 bytes, Pubkey)
+        let mut instruction_data = [UNINIT_BYTE; 67];
+        let mut length = instruction_data.len();
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[20]);
+        // Set decimals as u8 at offset [1]
+        write_bytes(&mut instruction_data[1..2], &[self.decimals]);
+        // Set mint_authority as Pubkey at offset [2..34]
+        write_bytes(&mut instruction_data[2..34], self.mint_authority);
+
+        if let Some(freeze_auth) = self.freeze_authority {
+            // Set Option = `true` & freeze_authority at offset [34..67]
+            write_bytes(&mut instruction_data[34..35], &[1]);
+            write_bytes(&mut instruction_data[35..], freeze_auth);
+        } else {
+            // Set Option = `false`
+            write_bytes(&mut instruction_data[34..35], &[0]);
+            // Adjust length if no freeze authority
+            length = 35;
+        }
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, length) },
+        };
+
+        invoke_signed(&instruction, &[self.mint], signers)
+    }
+}

+ 69 - 0
programs/token-2022/src/instructions/mint_to.rs

@@ -0,0 +1,69 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Mints new tokens to an account.
+///
+/// ### Accounts:
+///   0. `[WRITE]` The mint.
+///   1. `[WRITE]` The account to mint tokens to.
+///   2. `[SIGNER]` The mint's minting authority.
+pub struct MintTo<'a, 'b> {
+    /// Mint Account.
+    pub mint: &'a AccountInfo,
+    /// Token Account.
+    pub account: &'a AccountInfo,
+    /// Mint Authority
+    pub mint_authority: &'a AccountInfo,
+    /// Amount
+    pub amount: u64,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl MintTo<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 3] = [
+            AccountMeta::writable(self.mint.key()),
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::readonly_signer(self.mint_authority.key()),
+        ];
+
+        // Instruction data layout:
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1..9]: amount (8 bytes, u64)
+        let mut instruction_data = [UNINIT_BYTE; 9];
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[7]);
+        // Set amount as u64 at offset [1..9]
+        write_bytes(&mut instruction_data[1..9], &self.amount.to_le_bytes());
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 9) },
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.mint, self.account, self.mint_authority],
+            signers,
+        )
+    }
+}

+ 74 - 0
programs/token-2022/src/instructions/mint_to_checked.rs

@@ -0,0 +1,74 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Mints new tokens to an account.
+///
+/// ### Accounts:
+///   0. `[WRITE]` The mint.
+///   1. `[WRITE]` The account to mint tokens to.
+///   2. `[SIGNER]` The mint's minting authority.
+pub struct MintToChecked<'a, 'b> {
+    /// Mint Account.
+    pub mint: &'a AccountInfo,
+    /// Token Account.
+    pub account: &'a AccountInfo,
+    /// Mint Authority
+    pub mint_authority: &'a AccountInfo,
+    /// Amount
+    pub amount: u64,
+    /// Decimals
+    pub decimals: u8,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl MintToChecked<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 3] = [
+            AccountMeta::writable(self.mint.key()),
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::readonly_signer(self.mint_authority.key()),
+        ];
+
+        // Instruction data layout:
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1..9]: amount (8 bytes, u64)
+        // -  [9]: decimals (1 byte, u8)
+        let mut instruction_data = [UNINIT_BYTE; 10];
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[14]);
+        // Set amount as u64 at offset [1..9]
+        write_bytes(&mut instruction_data[1..9], &self.amount.to_le_bytes());
+        // Set decimals as u8 at offset [9]
+        write_bytes(&mut instruction_data[9..], &[self.decimals]);
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 10) },
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.mint, self.account, self.mint_authority],
+            signers,
+        )
+    }
+}

+ 39 - 0
programs/token-2022/src/instructions/mod.rs

@@ -0,0 +1,39 @@
+mod approve;
+mod approve_checked;
+mod burn;
+mod burn_checked;
+mod close_account;
+mod freeze_account;
+mod initialize_account;
+mod initialize_account_2;
+mod initialize_account_3;
+mod initialize_mint;
+mod initialize_mint_2;
+mod mint_to;
+mod mint_to_checked;
+mod revoke;
+mod set_authority;
+mod sync_native;
+mod thaw_account;
+mod transfer;
+mod transfer_checked;
+
+pub use approve::*;
+pub use approve_checked::*;
+pub use burn::*;
+pub use burn_checked::*;
+pub use close_account::*;
+pub use freeze_account::*;
+pub use initialize_account::*;
+pub use initialize_account_2::*;
+pub use initialize_account_3::*;
+pub use initialize_mint::*;
+pub use initialize_mint_2::*;
+pub use mint_to::*;
+pub use mint_to_checked::*;
+pub use revoke::*;
+pub use set_authority::*;
+pub use sync_native::*;
+pub use thaw_account::*;
+pub use transfer::*;
+pub use transfer_checked::*;

+ 45 - 0
programs/token-2022/src/instructions/revoke.rs

@@ -0,0 +1,45 @@
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+/// Revokes the delegate's authority.
+///
+/// ### Accounts:
+///   0. `[WRITE]` The source account.
+///   1. `[SIGNER]` The source account owner.
+pub struct Revoke<'a, 'b> {
+    /// Source Account.
+    pub source: &'a AccountInfo,
+    ///  Source Owner Account.
+    pub authority: &'a AccountInfo,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl Revoke<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 2] = [
+            AccountMeta::writable(self.source.key()),
+            AccountMeta::readonly_signer(self.authority.key()),
+        ];
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: &[5],
+        };
+
+        invoke_signed(&instruction, &[self.source, self.authority], signers)
+    }
+}

+ 85 - 0
programs/token-2022/src/instructions/set_authority.rs

@@ -0,0 +1,85 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+#[repr(u8)]
+#[derive(Clone, Copy)]
+pub enum AuthorityType {
+    MintTokens = 0,
+    FreezeAccount = 1,
+    AccountOwner = 2,
+    CloseAccount = 3,
+}
+
+/// Sets a new authority of a mint or account.
+///
+/// ### Accounts:
+///   0. `[WRITE]` The mint or account to change the authority of.
+///   1. `[SIGNER]` The current authority of the mint or account.
+pub struct SetAuthority<'a, 'b> {
+    /// Account (Mint or Token)
+    pub account: &'a AccountInfo,
+    /// Authority of the Account.
+    pub authority: &'a AccountInfo,
+    /// The type of authority to update.
+    pub authority_type: AuthorityType,
+    /// The new authority
+    pub new_authority: Option<&'a Pubkey>,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl SetAuthority<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 2] = [
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::readonly_signer(self.authority.key()),
+        ];
+
+        // instruction data
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1]: authority_type (1 byte, u8)
+        // -  [2]: new_authority presence flag (1 byte, AuthorityType)
+        // -  [3..35] new_authority (optional, 32 bytes, Pubkey)
+        let mut instruction_data = [UNINIT_BYTE; 35];
+        let mut length = instruction_data.len();
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[6]);
+        // Set authority_type as u8 at offset [1]
+        write_bytes(&mut instruction_data[1..2], &[self.authority_type as u8]);
+
+        if let Some(new_authority) = self.new_authority {
+            // Set new_authority as [u8; 32] at offset [2..35]
+            write_bytes(&mut instruction_data[2..3], &[1]);
+            write_bytes(&mut instruction_data[3..], new_authority);
+        } else {
+            write_bytes(&mut instruction_data[2..3], &[0]);
+            // Adjust length if no new authority
+            length = 3;
+        }
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, length) },
+        };
+
+        invoke_signed(&instruction, &[self.account, self.authority], signers)
+    }
+}

+ 41 - 0
programs/token-2022/src/instructions/sync_native.rs

@@ -0,0 +1,41 @@
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+/// Given a native token account updates its amount field based
+/// on the account's underlying `lamports`.
+///
+/// ### Accounts:
+///   0. `[WRITE]`  The native token account to sync with its underlying
+///      lamports.
+pub struct SyncNative<'a, 'b> {
+    /// Native Token Account
+    pub native_token: &'a AccountInfo,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl SyncNative<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 1] = [AccountMeta::writable(self.native_token.key())];
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: &[17],
+        };
+
+        invoke_signed(&instruction, &[self.native_token], signers)
+    }
+}

+ 53 - 0
programs/token-2022/src/instructions/thaw_account.rs

@@ -0,0 +1,53 @@
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+/// Thaw a Frozen account using the Mint's freeze authority
+///
+/// ### Accounts:
+///   0. `[WRITE]` The account to thaw.
+///   1. `[]` The token mint.
+///   2. `[SIGNER]` The mint freeze authority.
+pub struct ThawAccount<'a, 'b> {
+    /// Token Account to thaw.
+    pub account: &'a AccountInfo,
+    /// Mint Account.
+    pub mint: &'a AccountInfo,
+    /// Mint Freeze Authority Account
+    pub freeze_authority: &'a AccountInfo,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl ThawAccount<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 3] = [
+            AccountMeta::writable(self.account.key()),
+            AccountMeta::readonly(self.mint.key()),
+            AccountMeta::readonly_signer(self.freeze_authority.key()),
+        ];
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: &[11],
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.account, self.mint, self.freeze_authority],
+            signers,
+        )
+    }
+}

+ 65 - 0
programs/token-2022/src/instructions/transfer.rs

@@ -0,0 +1,65 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Transfer Tokens from one Token Account to another.
+///
+/// ### Accounts:
+///   0. `[WRITE]` Sender account
+///   1. `[WRITE]` Recipient account
+///   2. `[SIGNER]` Authority account
+pub struct Transfer<'a, 'b> {
+    /// Sender account.
+    pub from: &'a AccountInfo,
+    /// Recipient account.
+    pub to: &'a AccountInfo,
+    /// Authority account.
+    pub authority: &'a AccountInfo,
+    /// Amount of micro-tokens to transfer.
+    pub amount: u64,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl Transfer<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 3] = [
+            AccountMeta::writable(self.from.key()),
+            AccountMeta::writable(self.to.key()),
+            AccountMeta::readonly_signer(self.authority.key()),
+        ];
+
+        // Instruction data layout:
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1..9]: amount (8 bytes, u64)
+        let mut instruction_data = [UNINIT_BYTE; 9];
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[3]);
+        // Set amount as u64 at offset [1..9]
+        write_bytes(&mut instruction_data[1..9], &self.amount.to_le_bytes());
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 9) },
+        };
+
+        invoke_signed(&instruction, &[self.from, self.to, self.authority], signers)
+    }
+}

+ 78 - 0
programs/token-2022/src/instructions/transfer_checked.rs

@@ -0,0 +1,78 @@
+use core::slice::from_raw_parts;
+
+use pinocchio::{
+    account_info::AccountInfo,
+    instruction::{AccountMeta, Instruction, Signer},
+    program::invoke_signed,
+    pubkey::Pubkey,
+    ProgramResult,
+};
+
+use crate::{write_bytes, UNINIT_BYTE};
+
+/// Transfer Tokens from one Token Account to another.
+///
+/// ### Accounts:
+///   0. `[WRITE]` The source account.
+///   1. `[]` The token mint.
+///   2. `[WRITE]` The destination account.
+///   3. `[SIGNER]` The source account's owner/delegate.
+pub struct TransferChecked<'a, 'b> {
+    /// Sender account.
+    pub from: &'a AccountInfo,
+    /// Mint Account
+    pub mint: &'a AccountInfo,
+    /// Recipient account.
+    pub to: &'a AccountInfo,
+    /// Authority account.
+    pub authority: &'a AccountInfo,
+    /// Amount of micro-tokens to transfer.
+    pub amount: u64,
+    /// Decimal for the Token
+    pub decimals: u8,
+    /// Token Program
+    pub token_program: &'b Pubkey,
+}
+
+impl TransferChecked<'_, '_> {
+    #[inline(always)]
+    pub fn invoke(&self) -> ProgramResult {
+        self.invoke_signed(&[])
+    }
+
+    #[inline(always)]
+    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
+        // account metadata
+        let account_metas: [AccountMeta; 4] = [
+            AccountMeta::writable(self.from.key()),
+            AccountMeta::readonly(self.mint.key()),
+            AccountMeta::writable(self.to.key()),
+            AccountMeta::readonly_signer(self.authority.key()),
+        ];
+
+        // Instruction data layout:
+        // -  [0]: instruction discriminator (1 byte, u8)
+        // -  [1..9]: amount (8 bytes, u64)
+        // -  [9]: decimals (1 byte, u8)
+        let mut instruction_data = [UNINIT_BYTE; 10];
+
+        // Set discriminator as u8 at offset [0]
+        write_bytes(&mut instruction_data, &[12]);
+        // Set amount as u64 at offset [1..9]
+        write_bytes(&mut instruction_data[1..9], &self.amount.to_le_bytes());
+        // Set decimals as u8 at offset [9]
+        write_bytes(&mut instruction_data[9..], &[self.decimals]);
+
+        let instruction = Instruction {
+            program_id: self.token_program,
+            accounts: &account_metas,
+            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 10) },
+        };
+
+        invoke_signed(
+            &instruction,
+            &[self.from, self.mint, self.to, self.authority],
+            signers,
+        )
+    }
+}

+ 17 - 0
programs/token-2022/src/lib.rs

@@ -0,0 +1,17 @@
+#![no_std]
+
+pub mod instructions;
+pub mod state;
+
+pinocchio_pubkey::declare_id!("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb");
+
+use core::mem::MaybeUninit;
+
+const UNINIT_BYTE: MaybeUninit<u8> = MaybeUninit::<u8>::uninit();
+
+#[inline(always)]
+fn write_bytes(destination: &mut [MaybeUninit<u8>], source: &[u8]) {
+    for (d, s) in destination.iter_mut().zip(source.iter()) {
+        d.write(*s);
+    }
+}

+ 36 - 0
programs/token-2022/src/state/account_state.rs

@@ -0,0 +1,36 @@
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum AccountState {
+    /// Account is not yet initialized
+    Uninitialized,
+
+    /// Account is initialized; the account owner and/or delegate may perform
+    /// permitted operations on this account
+    Initialized,
+
+    /// Account has been frozen by the mint freeze authority. Neither the
+    /// account owner nor the delegate are able to perform operations on
+    /// this account.
+    Frozen,
+}
+
+impl From<u8> for AccountState {
+    fn from(value: u8) -> Self {
+        match value {
+            0 => AccountState::Uninitialized,
+            1 => AccountState::Initialized,
+            2 => AccountState::Frozen,
+            _ => panic!("invalid account state value: {value}"),
+        }
+    }
+}
+
+impl From<AccountState> for u8 {
+    fn from(value: AccountState) -> Self {
+        match value {
+            AccountState::Uninitialized => 0,
+            AccountState::Initialized => 1,
+            AccountState::Frozen => 2,
+        }
+    }
+}

+ 150 - 0
programs/token-2022/src/state/mint.rs

@@ -0,0 +1,150 @@
+use pinocchio::{
+    account_info::{AccountInfo, Ref},
+    program_error::ProgramError,
+    pubkey::Pubkey,
+};
+
+use crate::ID;
+
+/// Mint data.
+#[repr(C)]
+pub struct Mint {
+    /// Indicates whether the mint authority is present or not.
+    mint_authority_flag: [u8; 4],
+
+    /// Optional authority used to mint new tokens. The mint authority may only
+    /// be provided during mint creation. If no mint authority is present
+    /// then the mint has a fixed supply and no further tokens may be
+    /// minted.
+    mint_authority: Pubkey,
+
+    /// Total supply of tokens.
+    supply: [u8; 8],
+
+    /// Number of base 10 digits to the right of the decimal place.
+    decimals: u8,
+
+    /// Is `true` if this structure has been initialized.
+    is_initialized: u8,
+
+    /// Indicates whether the freeze authority is present or not.
+    freeze_authority_flag: [u8; 4],
+
+    /// Optional authority to freeze token accounts.
+    freeze_authority: Pubkey,
+}
+
+impl Mint {
+    /// The length of the `Mint` account data.
+    pub const BASE_LEN: usize = core::mem::size_of::<Mint>();
+
+    /// Return a `Mint` from the given account info.
+    ///
+    /// This method performs owner and length validation on `AccountInfo`, safe borrowing
+    /// the account data.
+    #[inline]
+    pub fn from_account_info(account_info: &AccountInfo) -> Result<Ref<Mint>, ProgramError> {
+        if account_info.data_len() < Self::BASE_LEN {
+            return Err(ProgramError::InvalidAccountData);
+        }
+        if !account_info.is_owned_by(&ID) {
+            return Err(ProgramError::InvalidAccountOwner);
+        }
+        Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe {
+            Self::from_bytes_unchecked(data)
+        }))
+    }
+
+    /// Return a `Mint` from the given account info.
+    ///
+    /// This method performs owner and length validation on `AccountInfo`, but does not
+    /// perform the borrow check.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that it is safe to borrow the account data (e.g., there are
+    /// no mutable borrows of the account data).
+    #[inline]
+    pub unsafe fn from_account_info_unchecked(
+        account_info: &AccountInfo,
+    ) -> Result<&Self, ProgramError> {
+        if account_info.data_len() < Self::BASE_LEN {
+            return Err(ProgramError::InvalidAccountData);
+        }
+        if account_info.owner() != &ID {
+            return Err(ProgramError::InvalidAccountOwner);
+        }
+        Ok(Self::from_bytes_unchecked(
+            account_info.borrow_data_unchecked(),
+        ))
+    }
+
+    /// Return a `Mint` from the given bytes.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `bytes` contains a valid representation of `Mint`, and
+    /// it is properly aligned to be interpreted as an instance of `Mint`.
+    /// At the moment `Mint` has an alignment of 1 byte.
+    /// This method does not perform a length validation.
+    #[inline(always)]
+    pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
+        &*(bytes[..Self::BASE_LEN].as_ptr() as *const Mint)
+    }
+
+    #[inline(always)]
+    pub fn has_mint_authority(&self) -> bool {
+        self.mint_authority_flag[0] == 1
+    }
+
+    pub fn mint_authority(&self) -> Option<&Pubkey> {
+        if self.has_mint_authority() {
+            Some(self.mint_authority_unchecked())
+        } else {
+            None
+        }
+    }
+
+    /// Return the mint authority.
+    ///
+    /// This method should be used when the caller knows that the mint will have a mint
+    /// authority set since it skips the `Option` check.
+    #[inline(always)]
+    pub fn mint_authority_unchecked(&self) -> &Pubkey {
+        &self.mint_authority
+    }
+
+    pub fn supply(&self) -> u64 {
+        u64::from_le_bytes(self.supply)
+    }
+
+    pub fn decimals(&self) -> u8 {
+        self.decimals
+    }
+
+    pub fn is_initialized(&self) -> bool {
+        self.is_initialized == 1
+    }
+
+    #[inline(always)]
+    pub fn has_freeze_authority(&self) -> bool {
+        self.freeze_authority_flag[0] == 1
+    }
+
+    pub fn freeze_authority(&self) -> Option<&Pubkey> {
+        if self.has_freeze_authority() {
+            Some(self.freeze_authority_unchecked())
+        } else {
+            None
+        }
+    }
+
+    /// Return the freeze authority.
+    ///
+    /// This method should be used when the caller knows that the mint will have a freeze
+    /// authority set since it skips the `Option` check.
+    #[inline(always)]
+    pub fn freeze_authority_unchecked(&self) -> &Pubkey {
+        &self.freeze_authority
+    }
+}

+ 7 - 0
programs/token-2022/src/state/mod.rs

@@ -0,0 +1,7 @@
+mod account_state;
+mod mint;
+mod token;
+
+pub use account_state::*;
+pub use mint::*;
+pub use token::*;

+ 203 - 0
programs/token-2022/src/state/token.rs

@@ -0,0 +1,203 @@
+use super::AccountState;
+use pinocchio::{
+    account_info::{AccountInfo, Ref},
+    program_error::ProgramError,
+    pubkey::Pubkey,
+};
+
+use crate::ID;
+
+/// Token account data.
+#[repr(C)]
+pub struct TokenAccount {
+    /// The mint associated with this account
+    mint: Pubkey,
+
+    /// The owner of this account.
+    owner: Pubkey,
+
+    /// The amount of tokens this account holds.
+    amount: [u8; 8],
+
+    /// Indicates whether the delegate is present or not.
+    delegate_flag: [u8; 4],
+
+    /// If `delegate` is `Some` then `delegated_amount` represents
+    /// the amount authorized by the delegate.
+    delegate: Pubkey,
+
+    /// The account's state.
+    state: u8,
+
+    /// Indicates whether this account represents a native token or not.
+    is_native: [u8; 4],
+
+    /// When `is_native.is_some()` is `true`, this is a native token, and the
+    /// value logs the rent-exempt reserve. An Account is required to be rent-exempt,
+    /// so the value is used by the Processor to ensure that wrapped SOL
+    /// accounts do not drop below this threshold.
+    native_amount: [u8; 8],
+
+    /// The amount delegated.
+    delegated_amount: [u8; 8],
+
+    /// Indicates whether the close authority is present or not.
+    close_authority_flag: [u8; 4],
+
+    /// Optional authority to close the account.
+    close_authority: Pubkey,
+}
+
+impl TokenAccount {
+    pub const BASE_LEN: usize = core::mem::size_of::<TokenAccount>();
+
+    /// Return a `TokenAccount` from the given account info.
+    ///
+    /// This method performs owner and length validation on `AccountInfo`, safe borrowing
+    /// the account data.
+    #[inline]
+    pub fn from_account_info(
+        account_info: &AccountInfo,
+    ) -> Result<Ref<TokenAccount>, ProgramError> {
+        if account_info.data_len() < Self::BASE_LEN {
+            return Err(ProgramError::InvalidAccountData);
+        }
+        if !account_info.is_owned_by(&ID) {
+            return Err(ProgramError::InvalidAccountData);
+        }
+        Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe {
+            Self::from_bytes_unchecked(data)
+        }))
+    }
+
+    /// Return a `TokenAccount` from the given account info.
+    ///
+    /// This method performs owner and length validation on `AccountInfo`, but does not
+    /// perform the borrow check.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that it is safe to borrow the account data (e.g., there are
+    /// no mutable borrows of the account data).
+    #[inline]
+    pub unsafe fn from_account_info_unchecked(
+        account_info: &AccountInfo,
+    ) -> Result<&TokenAccount, ProgramError> {
+        if account_info.data_len() < Self::BASE_LEN {
+            return Err(ProgramError::InvalidAccountData);
+        }
+        if account_info.owner() != &ID {
+            return Err(ProgramError::InvalidAccountData);
+        }
+        Ok(Self::from_bytes_unchecked(
+            account_info.borrow_data_unchecked(),
+        ))
+    }
+
+    /// Return a `TokenAccount` from the given bytes.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `bytes` contains a valid representation of `TokenAccount`, and
+    /// it is properly aligned to be interpreted as an instance of `TokenAccount`.
+    /// At the moment `TokenAccount` has an alignment of 1 byte.
+    /// This method does not perform a length validation.
+    #[inline(always)]
+    pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
+        &*(bytes[..Self::BASE_LEN].as_ptr() as *const TokenAccount)
+    }
+
+    pub fn mint(&self) -> &Pubkey {
+        &self.mint
+    }
+
+    pub fn owner(&self) -> &Pubkey {
+        &self.owner
+    }
+
+    pub fn amount(&self) -> u64 {
+        u64::from_le_bytes(self.amount)
+    }
+
+    #[inline(always)]
+    pub fn has_delegate(&self) -> bool {
+        self.delegate_flag[0] == 1
+    }
+
+    pub fn delegate(&self) -> Option<&Pubkey> {
+        if self.has_delegate() {
+            Some(self.delegate_unchecked())
+        } else {
+            None
+        }
+    }
+
+    /// Use this when you know the account will have a delegate and want to skip the `Option` check.
+    #[inline(always)]
+    pub fn delegate_unchecked(&self) -> &Pubkey {
+        &self.delegate
+    }
+
+    #[inline(always)]
+    pub fn state(&self) -> AccountState {
+        self.state.into()
+    }
+
+    #[inline(always)]
+    pub fn is_native(&self) -> bool {
+        self.is_native[0] == 1
+    }
+
+    pub fn native_amount(&self) -> Option<u64> {
+        if self.is_native() {
+            Some(self.native_amount_unchecked())
+        } else {
+            None
+        }
+    }
+
+    /// Return the native amount.
+    ///
+    /// This method should be used when the caller knows that the token is native since it
+    /// skips the `Option` check.
+    #[inline(always)]
+    pub fn native_amount_unchecked(&self) -> u64 {
+        u64::from_le_bytes(self.native_amount)
+    }
+
+    pub fn delegated_amount(&self) -> u64 {
+        u64::from_le_bytes(self.delegated_amount)
+    }
+
+    #[inline(always)]
+    pub fn has_close_authority(&self) -> bool {
+        self.close_authority_flag[0] == 1
+    }
+
+    pub fn close_authority(&self) -> Option<&Pubkey> {
+        if self.has_close_authority() {
+            Some(self.close_authority_unchecked())
+        } else {
+            None
+        }
+    }
+
+    /// Return the close authority.
+    ///
+    /// This method should be used when the caller knows that the token will have a close
+    /// authority set since it skips the `Option` check.
+    #[inline(always)]
+    pub fn close_authority_unchecked(&self) -> &Pubkey {
+        &self.close_authority
+    }
+
+    #[inline(always)]
+    pub fn is_initialized(&self) -> bool {
+        self.state != AccountState::Uninitialized as u8
+    }
+
+    #[inline(always)]
+    pub fn is_frozen(&self) -> bool {
+        self.state == AccountState::Frozen as u8
+    }
+}

+ 1 - 0
programs/token/src/instructions/approve.rs

@@ -32,6 +32,7 @@ impl Approve<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // Account metadata
         let account_metas: [AccountMeta; 3] = [

+ 1 - 0
programs/token/src/instructions/approve_checked.rs

@@ -37,6 +37,7 @@ impl ApproveChecked<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // Account metadata
         let account_metas: [AccountMeta; 4] = [

+ 1 - 0
programs/token/src/instructions/burn.rs

@@ -32,6 +32,7 @@ impl Burn<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // Account metadata
         let account_metas: [AccountMeta; 3] = [

+ 1 - 0
programs/token/src/instructions/burn_checked.rs

@@ -33,6 +33,7 @@ impl BurnChecked<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // Account metadata
         let account_metas: [AccountMeta; 3] = [

+ 1 - 0
programs/token/src/instructions/close_account.rs

@@ -26,6 +26,7 @@ impl CloseAccount<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 3] = [

+ 1 - 0
programs/token/src/instructions/freeze_account.rs

@@ -26,6 +26,7 @@ impl FreezeAccount<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 3] = [

+ 1 - 0
programs/token/src/instructions/initialize_account.rs

@@ -29,6 +29,7 @@ impl InitializeAccount<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 4] = [

+ 1 - 0
programs/token/src/instructions/initialize_account_2.rs

@@ -33,6 +33,7 @@ impl InitializeAccount2<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 3] = [

+ 1 - 0
programs/token/src/instructions/initialize_account_3.rs

@@ -30,6 +30,7 @@ impl InitializeAccount3<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 2] = [

+ 1 - 0
programs/token/src/instructions/initialize_mint.rs

@@ -34,6 +34,7 @@ impl InitializeMint<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // Account metadata
         let account_metas: [AccountMeta; 2] = [

+ 1 - 0
programs/token/src/instructions/initialize_mint_2.rs

@@ -31,6 +31,7 @@ impl InitializeMint2<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // Account metadata
         let account_metas: [AccountMeta; 1] = [AccountMeta::writable(self.mint.key())];

+ 1 - 0
programs/token/src/instructions/mint_to.rs

@@ -32,6 +32,7 @@ impl MintTo<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 3] = [

+ 1 - 0
programs/token/src/instructions/mint_to_checked.rs

@@ -34,6 +34,7 @@ impl MintToChecked<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 3] = [

+ 1 - 0
programs/token/src/instructions/revoke.rs

@@ -23,6 +23,7 @@ impl Revoke<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 2] = [

+ 1 - 3
programs/token/src/instructions/set_authority.rs

@@ -27,13 +27,10 @@ pub enum AuthorityType {
 pub struct SetAuthority<'a> {
     /// Account (Mint or Token)
     pub account: &'a AccountInfo,
-
     /// Authority of the Account.
     pub authority: &'a AccountInfo,
-
     /// The type of authority to update.
     pub authority_type: AuthorityType,
-
     /// The new authority
     pub new_authority: Option<&'a Pubkey>,
 }
@@ -44,6 +41,7 @@ impl SetAuthority<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 2] = [

+ 1 - 0
programs/token/src/instructions/sync_native.rs

@@ -22,6 +22,7 @@ impl SyncNative<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 1] = [AccountMeta::writable(self.native_token.key())];

+ 1 - 0
programs/token/src/instructions/thaw_account.rs

@@ -26,6 +26,7 @@ impl ThawAccount<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 3] = [

+ 1 - 0
programs/token/src/instructions/transfer.rs

@@ -32,6 +32,7 @@ impl Transfer<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 3] = [

+ 1 - 0
programs/token/src/instructions/transfer_checked.rs

@@ -37,6 +37,7 @@ impl TransferChecked<'_> {
         self.invoke_signed(&[])
     }
 
+    #[inline(always)]
     pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
         // account metadata
         let account_metas: [AccountMeta; 4] = [