Sfoglia il codice sorgente

Add interface crate

febo 11 mesi fa
parent
commit
2adf089ef0

+ 12 - 0
interface/Cargo.toml

@@ -0,0 +1,12 @@
+[package]
+name = "token-interface"
+version = "0.0.0"
+edition = "2021"
+readme = "./README.md"
+license-file = "../LICENSE"
+publish = false
+
+[dependencies]
+bytemuck = { version="1.18.0", features=["derive"] }
+pinocchio = "0.6"
+pinocchio-pubkey = "0.2"

+ 0 - 0
p-token/src/error.rs → interface/src/error.rs


+ 518 - 0
interface/src/instruction.rs

@@ -0,0 +1,518 @@
+//! Instruction types
+
+use pinocchio::{program_error::ProgramError, pubkey::Pubkey};
+
+use crate::{error::TokenError, state::PodCOption};
+
+/// Instructions supported by the token program.
+#[repr(C)]
+#[derive(Clone, Debug, PartialEq)]
+pub enum TokenInstruction<'a> {
+    /// Initializes a new mint and optionally deposits all the newly minted
+    /// tokens in an account.
+    ///
+    /// The `InitializeMint` instruction requires no signers and MUST be
+    /// included within the same Transaction as the system program's
+    /// `CreateAccount` instruction that creates the account being initialized.
+    /// Otherwise another party can acquire ownership of the uninitialized
+    /// account.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[writable]` The mint to initialize.
+    ///   1. `[]` Rent sysvar
+    InitializeMint {
+        /// Number of base 10 digits to the right of the decimal place.
+        decimals: u8,
+        /// The authority/multisignature to mint tokens.
+        mint_authority: Pubkey,
+        /// The freeze authority/multisignature of the mint.
+        freeze_authority: PodCOption<Pubkey>,
+    },
+
+    /// Initializes a new account to hold tokens.  If this account is associated
+    /// with the native mint then the token balance of the initialized account
+    /// will be equal to the amount of SOL in the account. If this account is
+    /// associated with another mint, that mint must be initialized before this
+    /// command can succeed.
+    ///
+    /// The `InitializeAccount` instruction requires no signers and MUST be
+    /// included within the same Transaction as the system program's
+    /// `CreateAccount` instruction that creates the account being initialized.
+    /// Otherwise another party can acquire ownership of the uninitialized
+    /// account.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[writable]`  The account to initialize.
+    ///   1. `[]` The mint this account will be associated with.
+    ///   2. `[]` The new account's owner/multisignature.
+    ///   3. `[]` Rent sysvar
+    InitializeAccount,
+
+    /// Initializes a multisignature account with N provided signers.
+    ///
+    /// Multisignature accounts can used in place of any single owner/delegate
+    /// accounts in any token instruction that require an owner/delegate to be
+    /// present.  The variant field represents the number of signers (M)
+    /// required to validate this multisignature account.
+    ///
+    /// The `InitializeMultisig` instruction requires no signers and MUST be
+    /// included within the same Transaction as the system program's
+    /// `CreateAccount` instruction that creates the account being initialized.
+    /// Otherwise another party can acquire ownership of the uninitialized
+    /// account.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[writable]` The multisignature account to initialize.
+    ///   1. `[]` Rent sysvar
+    ///   2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <=
+    ///      11.
+    InitializeMultisig {
+        /// The number of signers (M) required to validate this multisignature
+        /// account.
+        m: u8,
+    },
+
+    /// Transfers tokens from one account to another either directly or via a
+    /// delegate.  If this account is associated with the native mint then equal
+    /// amounts of SOL and Tokens will be transferred to the destination
+    /// account.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single owner/delegate
+    ///   0. `[writable]` The source account.
+    ///   1. `[writable]` The destination account.
+    ///   2. `[signer]` The source account's owner/delegate.
+    ///
+    ///   * Multisignature owner/delegate
+    ///   0. `[writable]` The source account.
+    ///   1. `[writable]` The destination account.
+    ///   2. `[]` The source account's multisignature owner/delegate.
+    ///   3. ..3+M `[signer]` M signer accounts.
+    Transfer {
+        /// The amount of tokens to transfer.
+        amount: u64,
+    },
+
+    /// Approves a delegate.  A delegate is given the authority over tokens on
+    /// behalf of the source account's owner.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single owner
+    ///   0. `[writable]` The source account.
+    ///   1. `[]` The delegate.
+    ///   2. `[signer]` The source account owner.
+    ///
+    ///   * Multisignature owner
+    ///   0. `[writable]` The source account.
+    ///   1. `[]` The delegate.
+    ///   2. `[]` The source account's multisignature owner.
+    ///   3. ..3+M `[signer]` M signer accounts
+    Approve {
+        /// The amount of tokens the delegate is approved for.
+        amount: u64,
+    },
+
+    /// Revokes the delegate's authority.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single owner
+    ///   0. `[writable]` The source account.
+    ///   1. `[signer]` The source account owner.
+    ///
+    ///   * Multisignature owner
+    ///   0. `[writable]` The source account.
+    ///   1. `[]` The source account's multisignature owner.
+    ///   2. ..2+M `[signer]` M signer accounts
+    Revoke,
+
+    /// Sets a new authority of a mint or account.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single authority
+    ///   0. `[writable]` The mint or account to change the authority of.
+    ///   1. `[signer]` The current authority of the mint or account.
+    ///
+    ///   * Multisignature authority
+    ///   0. `[writable]` The mint or account to change the authority of.
+    ///   1. `[]` The mint's or account's current multisignature authority.
+    ///   2. ..2+M `[signer]` M signer accounts
+    SetAuthority {
+        /// The type of authority to update.
+        authority_type: AuthorityType,
+        /// The new authority
+        new_authority: PodCOption<Pubkey>,
+    },
+
+    /// Mints new tokens to an account.  The native mint does not support
+    /// minting.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single authority
+    ///   0. `[writable]` The mint.
+    ///   1. `[writable]` The account to mint tokens to.
+    ///   2. `[signer]` The mint's minting authority.
+    ///
+    ///   * Multisignature authority
+    ///   0. `[writable]` The mint.
+    ///   1. `[writable]` The account to mint tokens to.
+    ///   2. `[]` The mint's multisignature mint-tokens authority.
+    ///   3. ..3+M `[signer]` M signer accounts.
+    MintTo {
+        /// The amount of new tokens to mint.
+        amount: u64,
+    },
+
+    /// Burns tokens by removing them from an account.  `Burn` does not support
+    /// accounts associated with the native mint, use `CloseAccount` instead.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single owner/delegate
+    ///   0. `[writable]` The account to burn from.
+    ///   1. `[writable]` The token mint.
+    ///   2. `[signer]` The account's owner/delegate.
+    ///
+    ///   * Multisignature owner/delegate
+    ///   0. `[writable]` The account to burn from.
+    ///   1. `[writable]` The token mint.
+    ///   2. `[]` The account's multisignature owner/delegate.
+    ///   3. ..3+M `[signer]` M signer accounts.
+    Burn {
+        /// The amount of tokens to burn.
+        amount: u64,
+    },
+
+    /// Close an account by transferring all its SOL to the destination account.
+    /// Non-native accounts may only be closed if its token amount is zero.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single owner
+    ///   0. `[writable]` The account to close.
+    ///   1. `[writable]` The destination account.
+    ///   2. `[signer]` The account's owner.
+    ///
+    ///   * Multisignature owner
+    ///   0. `[writable]` The account to close.
+    ///   1. `[writable]` The destination account.
+    ///   2. `[]` The account's multisignature owner.
+    ///   3. ..3+M `[signer]` M signer accounts.
+    CloseAccount,
+
+    /// Freeze an Initialized account using the Mint's freeze_authority (if
+    /// set).
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single owner
+    ///   0. `[writable]` The account to freeze.
+    ///   1. `[]` The token mint.
+    ///   2. `[signer]` The mint freeze authority.
+    ///
+    ///   * Multisignature owner
+    ///   0. `[writable]` The account to freeze.
+    ///   1. `[]` The token mint.
+    ///   2. `[]` The mint's multisignature freeze authority.
+    ///   3. ..3+M `[signer]` M signer accounts.
+    FreezeAccount,
+
+    /// Thaw a Frozen account using the Mint's freeze_authority (if set).
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single owner
+    ///   0. `[writable]` The account to freeze.
+    ///   1. `[]` The token mint.
+    ///   2. `[signer]` The mint freeze authority.
+    ///
+    ///   * Multisignature owner
+    ///   0. `[writable]` The account to freeze.
+    ///   1. `[]` The token mint.
+    ///   2. `[]` The mint's multisignature freeze authority.
+    ///   3. ..3+M `[signer]` M signer accounts.
+    ThawAccount,
+
+    /// Transfers tokens from one account to another either directly or via a
+    /// delegate.  If this account is associated with the native mint then equal
+    /// amounts of SOL and Tokens will be transferred to the destination
+    /// account.
+    ///
+    /// This instruction differs from Transfer in that the token mint and
+    /// decimals value is checked by the caller.  This may be useful when
+    /// creating transactions offline or within a hardware wallet.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single owner/delegate
+    ///   0. `[writable]` The source account.
+    ///   1. `[]` The token mint.
+    ///   2. `[writable]` The destination account.
+    ///   3. `[signer]` The source account's owner/delegate.
+    ///
+    ///   * Multisignature owner/delegate
+    ///   0. `[writable]` The source account.
+    ///   1. `[]` The token mint.
+    ///   2. `[writable]` The destination account.
+    ///   3. `[]` The source account's multisignature owner/delegate.
+    ///   4. ..4+M `[signer]` M signer accounts.
+    TransferChecked {
+        /// The amount of tokens to transfer.
+        amount: u64,
+        /// Expected number of base 10 digits to the right of the decimal place.
+        decimals: u8,
+    },
+
+    /// Approves a delegate.  A delegate is given the authority over tokens on
+    /// behalf of the source account's owner.
+    ///
+    /// This instruction differs from Approve in that the token mint and
+    /// decimals value is checked by the caller.  This may be useful when
+    /// creating transactions offline or within a hardware wallet.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single owner
+    ///   0. `[writable]` The source account.
+    ///   1. `[]` The token mint.
+    ///   2. `[]` The delegate.
+    ///   3. `[signer]` The source account owner.
+    ///
+    ///   * Multisignature owner
+    ///   0. `[writable]` The source account.
+    ///   1. `[]` The token mint.
+    ///   2. `[]` The delegate.
+    ///   3. `[]` The source account's multisignature owner.
+    ///   4. ..4+M `[signer]` M signer accounts
+    ApproveChecked {
+        /// The amount of tokens the delegate is approved for.
+        amount: u64,
+        /// Expected number of base 10 digits to the right of the decimal place.
+        decimals: u8,
+    },
+
+    /// Mints new tokens to an account.  The native mint does not support
+    /// minting.
+    ///
+    /// This instruction differs from MintTo in that the decimals value is
+    /// checked by the caller.  This may be useful when creating transactions
+    /// offline or within a hardware wallet.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single authority
+    ///   0. `[writable]` The mint.
+    ///   1. `[writable]` The account to mint tokens to.
+    ///   2. `[signer]` The mint's minting authority.
+    ///
+    ///   * Multisignature authority
+    ///   0. `[writable]` The mint.
+    ///   1. `[writable]` The account to mint tokens to.
+    ///   2. `[]` The mint's multisignature mint-tokens authority.
+    ///   3. ..3+M `[signer]` M signer accounts.
+    MintToChecked {
+        /// The amount of new tokens to mint.
+        amount: u64,
+        /// Expected number of base 10 digits to the right of the decimal place.
+        decimals: u8,
+    },
+
+    /// Burns tokens by removing them from an account.  `BurnChecked` does not
+    /// support accounts associated with the native mint, use `CloseAccount`
+    /// instead.
+    ///
+    /// This instruction differs from Burn in that the decimals value is checked
+    /// by the caller. This may be useful when creating transactions offline or
+    /// within a hardware wallet.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   * Single owner/delegate
+    ///   0. `[writable]` The account to burn from.
+    ///   1. `[writable]` The token mint.
+    ///   2. `[signer]` The account's owner/delegate.
+    ///
+    ///   * Multisignature owner/delegate
+    ///   0. `[writable]` The account to burn from.
+    ///   1. `[writable]` The token mint.
+    ///   2. `[]` The account's multisignature owner/delegate.
+    ///   3. ..3+M `[signer]` M signer accounts.
+    BurnChecked {
+        /// The amount of tokens to burn.
+        amount: u64,
+        /// Expected number of base 10 digits to the right of the decimal place.
+        decimals: u8,
+    },
+
+    /// Like InitializeAccount, but the owner pubkey is passed via instruction
+    /// data rather than the accounts list. This variant may be preferable
+    /// when using Cross Program Invocation from an instruction that does
+    /// not need the owner's `AccountInfo` otherwise.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[writable]`  The account to initialize.
+    ///   1. `[]` The mint this account will be associated with.
+    ///   3. `[]` Rent sysvar
+    InitializeAccount2 {
+        /// The new account's owner/multisignature.
+        owner: Pubkey,
+    },
+
+    /// Given a wrapped / native token account (a token account containing SOL)
+    /// updates its amount field based on the account's underlying `lamports`.
+    /// This is useful if a non-wrapped SOL account uses
+    /// `system_instruction::transfer` to move lamports to a wrapped token
+    /// account, and needs to have its token `amount` field updated.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[writable]`  The native token account to sync with its underlying
+    ///      lamports.
+    SyncNative,
+
+    /// Like InitializeAccount2, but does not require the Rent sysvar to be
+    /// provided
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[writable]`  The account to initialize.
+    ///   1. `[]` The mint this account will be associated with.
+    InitializeAccount3 {
+        /// The new account's owner/multisignature.
+        owner: Pubkey,
+    },
+
+    /// Like InitializeMultisig, but does not require the Rent sysvar to be
+    /// provided
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[writable]` The multisignature account to initialize.
+    ///   1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <=
+    ///      11.
+    InitializeMultisig2 {
+        /// The number of signers (M) required to validate this multisignature
+        /// account.
+        m: u8,
+    },
+
+    /// Like [`InitializeMint`], but does not require the Rent sysvar to be
+    /// provided
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[writable]` The mint to initialize.
+    InitializeMint2 {
+        /// Number of base 10 digits to the right of the decimal place.
+        decimals: u8,
+        /// The authority/multisignature to mint tokens.
+        mint_authority: Pubkey,
+        /// The freeze authority/multisignature of the mint.
+        freeze_authority: PodCOption<Pubkey>,
+    },
+
+    /// Gets the required size of an account for the given mint as a
+    /// little-endian `u64`.
+    ///
+    /// Return data can be fetched using `sol_get_return_data` and deserializing
+    /// the return data as a little-endian `u64`.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[]` The mint to calculate for
+    GetAccountDataSize, // typically, there's also data, but this program ignores it
+
+    /// Initialize the Immutable Owner extension for the given token account
+    ///
+    /// Fails if the account has already been initialized, so must be called
+    /// before `InitializeAccount`.
+    ///
+    /// No-ops in this version of the program, but is included for compatibility
+    /// with the Associated Token Account program.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[writable]`  The account to initialize.
+    ///
+    /// Data expected by this instruction:
+    ///   None
+    InitializeImmutableOwner,
+
+    /// Convert an Amount of tokens to a UiAmount `string`, using the given
+    /// mint. In this version of the program, the mint can only specify the
+    /// number of decimals.
+    ///
+    /// Fails on an invalid mint.
+    ///
+    /// Return data can be fetched using `sol_get_return_data` and deserialized
+    /// with `String::from_utf8`.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[]` The mint to calculate for
+    AmountToUiAmount {
+        /// The amount of tokens to reformat.
+        amount: u64,
+    },
+
+    /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using
+    /// the given mint. In this version of the program, the mint can only
+    /// specify the number of decimals.
+    ///
+    /// Return data can be fetched using `sol_get_return_data` and deserializing
+    /// the return data as a little-endian `u64`.
+    ///
+    /// Accounts expected by this instruction:
+    ///
+    ///   0. `[]` The mint to calculate for
+    UiAmountToAmount {
+        /// The ui_amount of tokens to reformat.
+        ui_amount: &'a str,
+    },
+    // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the
+    // latter remains a superset of this instruction set. New variants also need to be added to
+    // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility
+}
+
+/// Specifies the authority type for SetAuthority instructions
+#[repr(u8)]
+#[derive(Clone, Debug, PartialEq)]
+pub enum AuthorityType {
+    /// Authority to mint new tokens
+    MintTokens,
+    /// Authority to freeze any account associated with the Mint
+    FreezeAccount,
+    /// Owner of a given token account
+    AccountOwner,
+    /// Authority to close a token account
+    CloseAccount,
+}
+
+impl AuthorityType {
+    fn into(&self) -> u8 {
+        match self {
+            AuthorityType::MintTokens => 0,
+            AuthorityType::FreezeAccount => 1,
+            AuthorityType::AccountOwner => 2,
+            AuthorityType::CloseAccount => 3,
+        }
+    }
+
+    fn from(index: u8) -> Result<Self, ProgramError> {
+        match index {
+            0 => Ok(AuthorityType::MintTokens),
+            1 => Ok(AuthorityType::FreezeAccount),
+            2 => Ok(AuthorityType::AccountOwner),
+            3 => Ok(AuthorityType::CloseAccount),
+            _ => Err(TokenError::InvalidInstruction.into()),
+        }
+    }
+}

+ 4 - 0
interface/src/lib.rs

@@ -0,0 +1,4 @@
+pub mod error;
+pub mod instruction;
+pub mod native_mint;
+pub mod state;

+ 1 - 2
p-token/src/native_mint.rs → interface/src/native_mint.rs

@@ -6,8 +6,7 @@ use pinocchio::pubkey::Pubkey;
 pub const DECIMALS: u8 = 9;
 
 // The Mint for native SOL Token accounts
-pub const ID: Pubkey =
-    pinocchio_pubkey::declare_pubkey!("So11111111111111111111111111111111111111112");
+pub const ID: Pubkey = pinocchio_pubkey::pubkey!("So11111111111111111111111111111111111111112");
 
 #[inline(always)]
 pub fn is_native_mint(mint: &Pubkey) -> bool {

+ 0 - 0
p-token/src/state/account.rs → interface/src/state/account.rs


+ 0 - 0
p-token/src/state/mint.rs → interface/src/state/mint.rs


+ 18 - 1
p-token/src/state/mod.rs → interface/src/state/mod.rs

@@ -36,10 +36,14 @@ impl<T: Default + PartialEq + Pod + Sized> From<Option<T>> for PodCOption<T> {
 }
 
 impl<T: Default + PartialEq + Pod + Sized> PodCOption<T> {
+    pub const NONE: [u8; 4] = [0, 0, 0, 0];
+
+    pub const SOME: [u8; 4] = [1, 0, 0, 0];
+
     /// Returns `true` if the option is a `None` value.
     #[inline]
     pub fn is_none(&self) -> bool {
-        self.tag == [0, 0, 0, 0]
+        self.tag == Self::NONE
     }
 
     /// Returns `true` if the option is a `Some` value.
@@ -77,6 +81,19 @@ impl<T: Default + PartialEq + Pod + Sized> PodCOption<T> {
             Some(&mut self.value)
         }
     }
+
+    #[inline]
+    pub fn set(&mut self, value: T) {
+        self.tag = Self::SOME;
+        self.value = value;
+    }
+
+    #[inline]
+    pub fn clear(&mut self) {
+        self.tag = Self::NONE;
+        // we don't need to zero the value since the tag
+        // indicates it is a `None` value
+    }
 }
 
 /// ## Safety

+ 0 - 0
p-token/src/state/multisignature.rs → interface/src/state/multisignature.rs


+ 3 - 2
p-token/Cargo.toml

@@ -18,8 +18,9 @@ test-sbf = []
 
 [dependencies]
 bytemuck = { version="1.18.0", features=["derive"] }
-pinocchio = "0.2"
-pinocchio-pubkey = "0.1"
+pinocchio = "0.6"
+pinocchio-pubkey = "0.2"
+token-interface = { version = "^0", path = "../interface" }
 
 [dev-dependencies]
 assert_matches = "1.5.0"

+ 2 - 2
p-token/src/entrypoint.rs

@@ -1,6 +1,6 @@
 use pinocchio::{
-    account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, program_error::ProgramError,
-    pubkey::Pubkey,
+    account_info::AccountInfo, entrypoint, program_error::ProgramError, pubkey::Pubkey,
+    ProgramResult,
 };
 
 use crate::processor::{

+ 0 - 3
p-token/src/lib.rs

@@ -1,9 +1,6 @@
 //! A lighter Token program for SVM.
 
 mod entrypoint;
-pub mod error;
-pub mod native_mint;
 mod processor;
-pub mod state;
 
 pinocchio_pubkey::declare_id!("TokenLight111111111111111111111111111111111");

+ 28 - 46
p-token/src/processor/initialize_account.rs

@@ -1,16 +1,12 @@
-use std::mem::size_of;
-
-use bytemuck::{Pod, Zeroable};
 use pinocchio::{
     account_info::AccountInfo,
-    entrypoint::ProgramResult,
-    get_account_info,
     program_error::ProgramError,
-    pubkey::{self, Pubkey},
+    pubkey::Pubkey,
     sysvars::{rent::Rent, Sysvar},
+    ProgramResult,
 };
-
-use crate::{
+use std::mem::size_of;
+use token_interface::{
     error::TokenError,
     native_mint::is_native_mint,
     state::{
@@ -25,36 +21,30 @@ use super::check_account_owner;
 pub fn process_initialize_account(
     program_id: &Pubkey,
     accounts: &[AccountInfo],
-    args: Option<&InitializeAccount>,
+    owner: Option<&Pubkey>,
     _rent_sysvar_account: bool,
 ) -> ProgramResult {
-    let [new_account_info, mint_info, _remaning @ ..] = accounts else {
-        return Err(ProgramError::NotEnoughAccountKeys);
-    };
-
-    let owner = if let Some(InitializeAccount { owner }) = args {
-        owner
+    let (new_account_info, mint_info, owner) = if let Some(owner) = owner {
+        let [new_account_info, mint_info, _remaning @ ..] = accounts else {
+            return Err(ProgramError::NotEnoughAccountKeys);
+        };
+        (new_account_info, mint_info, owner)
     } else {
-        get_account_info!(accounts, 2).key()
+        let [new_account_info, mint_info, owner_info, _remaning @ ..] = accounts else {
+            return Err(ProgramError::NotEnoughAccountKeys);
+        };
+        (new_account_info, mint_info, owner_info.key())
     };
 
-    // FEBO: ~408 CU can be saved by removing the rent check (is_exempt seems to
-    // be very expensive).
-    //
-    // The transaction will naturally fail if the account is not rent exempt with
-    // a TransactionError::InsufficientFundsForRent error.
-    /*
+    /* TODO: Implement rent exemption
     let rent = Rent::get()?;
 
-    if !rent.is_exempt(
-        unsafe { *new_account_info.unchecked_borrow_lamports() },
-        size_of::<Account>(),
-    ) {
-        return Err(Token::NotRentExempt);
+    if !rent.is_exempt_scaled(new_account_info.lamports(), size_of::<Account>()) {
+        return Err(TokenError::NotRentExempt.into());
     }
     */
 
-    let account_data = unsafe { new_account_info.unchecked_borrow_mut_data() };
+    let account_data = unsafe { new_account_info.borrow_mut_data_unchecked() };
     let account = bytemuck::try_from_bytes_mut::<Account>(account_data)
         .map_err(|_error| ProgramError::InvalidAccountData)?;
 
@@ -67,19 +57,19 @@ pub fn process_initialize_account(
     if !is_native_mint {
         check_account_owner(program_id, mint_info)?;
 
-        let mint_data = unsafe { mint_info.unchecked_borrow_data() };
-        let mint = bytemuck::from_bytes::<Mint>(mint_data);
+        let mint_data = unsafe { mint_info.borrow_data_unchecked() };
+        let mint = bytemuck::try_from_bytes::<Mint>(mint_data)
+            .map_err(|_error| ProgramError::InvalidAccountData)?;
 
-        let initialized: bool = mint.is_initialized.into();
-        if !initialized {
+        if !bool::from(mint.is_initialized) {
             return Err(TokenError::InvalidMint.into());
         }
     }
 
-    pubkey::copy(&mut account.mint, mint_info.key());
-    pubkey::copy(&mut account.owner, owner);
-    account.close_authority = PodCOption::from(None);
-    account.delegate = PodCOption::from(None);
+    account.mint = *mint_info.key();
+    account.owner = *owner;
+    account.close_authority.clear();
+    account.delegate.clear();
     account.delegated_amount = 0u64.to_le_bytes();
     account.state = AccountState::Initialized as u8;
 
@@ -90,23 +80,15 @@ pub fn process_initialize_account(
         account.is_native = PodCOption::from(Some(rent_exempt_reserve.to_le_bytes()));
         unsafe {
             account.amount = new_account_info
-                .unchecked_borrow_lamports()
+                .borrow_lamports_unchecked()
                 .checked_sub(rent_exempt_reserve)
                 .ok_or(TokenError::Overflow)?
                 .to_le_bytes()
         }
     } else {
-        account.is_native = PodCOption::from(None);
+        account.is_native.clear();
         account.amount = 0u64.to_le_bytes();
     };
 
     Ok(())
 }
-
-/// Instruction data for the `InitializeAccount` instruction.
-#[repr(C)]
-#[derive(Clone, Copy, Default, Pod, Zeroable)]
-pub struct InitializeAccount {
-    /// The new account's owner/multisignature.
-    pub owner: Pubkey,
-}

+ 16 - 18
p-token/src/processor/initialize_mint.rs

@@ -1,14 +1,12 @@
-use std::mem::size_of;
-
 use bytemuck::{Pod, Zeroable};
 use pinocchio::{
     account_info::AccountInfo,
-    entrypoint::ProgramResult,
     program_error::ProgramError,
     pubkey::{Pubkey, PUBKEY_BYTES},
+    ProgramResult,
 };
-
-use crate::{
+use std::mem::size_of;
+use token_interface::{
     error::TokenError,
     state::{mint::Mint, PodCOption},
 };
@@ -18,33 +16,32 @@ pub fn process_initialize_mint(
     args: &InitializeMint,
     _rent_sysvar_account: bool,
 ) -> ProgramResult {
+    // Validate the mint account.
+
     let [mint_info, _remaining @ ..] = accounts else {
         return Err(ProgramError::NotEnoughAccountKeys);
     };
 
-    let mint_data = &mut mint_info.try_borrow_mut_data()?;
-    let mint = bytemuck::from_bytes_mut::<Mint>(mint_data);
+    let mint_data = unsafe { mint_info.borrow_mut_data_unchecked() };
+    let mint = bytemuck::try_from_bytes_mut::<Mint>(mint_data)
+        .map_err(|_error| ProgramError::InvalidAccountData)?;
 
     if mint.is_initialized.into() {
         return Err(TokenError::AlreadyInUse.into());
     }
 
-    // FEBO: ~408 CU can be saved by removing the rent check (is_exempt seems to
-    // be very expensive).
-    //
-    // The transaction will naturally fail if the account is not rent exempt with
-    // a TransactionError::InsufficientFundsForRent error.
-    /*
+    // Check rent-exempt status of the mint account.
+
+    /* TODO: Implement rent exemption
     let rent = Rent::get()?;
 
-    if !rent.is_exempt(
-        unsafe { *mint_info.unchecked_borrow_lamports() },
-        size_of::<Mint>(),
-    ) {
-        return Err(TokenError::NotRentExempt);
+    if !rent.is_exempt_scaled(mint_info.lamports(), size_of::<Mint>()) {
+        return Err(TokenError::NotRentExempt.into());
     }
     */
 
+    // Initialize the mint.
+
     mint.mint_authority = PodCOption::from(Some(args.data.mint_authority));
     mint.decimals = args.data.decimals;
     mint.is_initialized = true.into();
@@ -90,6 +87,7 @@ impl<'a> InitializeMint<'a> {
     }
 }
 
+/// Base information for the mint.
 #[repr(C)]
 #[derive(Clone, Copy, Default, Pod, Zeroable)]
 pub struct MintData {

+ 8 - 8
p-token/src/processor/mint_to.rs

@@ -1,9 +1,7 @@
 use pinocchio::{
-    account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
-    pubkey::Pubkey,
+    account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult,
 };
-
-use crate::{
+use token_interface::{
     error::TokenError,
     native_mint::is_native_mint,
     state::{account::Account, mint::Mint},
@@ -23,8 +21,9 @@ pub fn process_mint_to(
 
     // destination account
 
-    let account_data = unsafe { destination_account_info.unchecked_borrow_mut_data() };
-    let destination_account = bytemuck::from_bytes_mut::<Account>(account_data);
+    let account_data = unsafe { destination_account_info.borrow_mut_data_unchecked() };
+    let destination_account = bytemuck::try_from_bytes_mut::<Account>(account_data)
+        .map_err(|_error| ProgramError::InvalidAccountData)?;
 
     if destination_account.is_frozen() {
         return Err(TokenError::AccountFrozen.into());
@@ -38,8 +37,9 @@ pub fn process_mint_to(
         return Err(TokenError::MintMismatch.into());
     }
 
-    let mint_data = unsafe { mint_info.unchecked_borrow_mut_data() };
-    let mint = bytemuck::from_bytes_mut::<Mint>(mint_data);
+    let mint_data = unsafe { mint_info.borrow_mut_data_unchecked() };
+    let mint = bytemuck::try_from_bytes_mut::<Mint>(mint_data)
+        .map_err(|_error| ProgramError::InvalidAccountData)?;
 
     if let Some(expected_decimals) = expected_decimals {
         if expected_decimals != mint.decimals {

+ 3 - 7
p-token/src/processor/mod.rs

@@ -1,11 +1,7 @@
 use pinocchio::{
-    account_info::AccountInfo,
-    entrypoint::ProgramResult,
-    program_error::ProgramError,
-    pubkey::{self, Pubkey},
+    account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult,
 };
-
-use crate::{
+use token_interface::{
     error::TokenError,
     state::multisignature::{Multisig, MAX_SIGNERS},
 };
@@ -46,7 +42,7 @@ pub fn validate_owner(
 
         for signer in signers.iter() {
             for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() {
-                if pubkey::compare(key, signer.key()) && !matched[position] {
+                if key == signer.key() && !matched[position] {
                     if !signer.is_signer() {
                         return Err(ProgramError::MissingRequiredSignature);
                     }

+ 8 - 8
p-token/src/processor/transfer.rs

@@ -1,9 +1,7 @@
 use pinocchio::{
-    account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
-    pubkey::Pubkey,
+    account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult,
 };
-
-use crate::{
+use token_interface::{
     error::TokenError,
     native_mint::is_native_mint,
     state::{account::Account, mint::Mint, PodCOption},
@@ -56,11 +54,13 @@ pub fn process_transfer(
 
     // Validates source and destination accounts.
 
-    let source_account_data = unsafe { source_account_info.unchecked_borrow_mut_data() };
-    let source_account = bytemuck::from_bytes_mut::<Account>(source_account_data);
+    let source_account_data = unsafe { source_account_info.borrow_mut_data_unchecked() };
+    let source_account = bytemuck::try_from_bytes_mut::<Account>(source_account_data)
+        .map_err(|_error| ProgramError::InvalidAccountData)?;
 
-    let destination_account_data = unsafe { destination_account_info.unchecked_borrow_mut_data() };
-    let destination_account = bytemuck::from_bytes_mut::<Account>(destination_account_data);
+    let destination_account_data = unsafe { destination_account_info.borrow_mut_data_unchecked() };
+    let destination_account = bytemuck::try_from_bytes_mut::<Account>(destination_account_data)
+        .map_err(|_error| ProgramError::InvalidAccountData)?;
 
     if source_account.is_frozen() || destination_account.is_frozen() {
         return Err(TokenError::AccountFrozen.into());

+ 1 - 1
p-token/tests/initialize_mint.rs

@@ -11,7 +11,7 @@ use solana_sdk::{
     system_instruction,
     transaction::Transaction,
 };
-use token_program::state::mint::Mint;
+use token_interface::state::mint::Mint;
 
 #[test_case::test_case(spl_token::ID ; "spl-token")]
 #[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "token-light")]

+ 1 - 1
p-token/tests/setup/mint.rs

@@ -5,7 +5,7 @@ use solana_sdk::{
     program_error::ProgramError, pubkey::Pubkey, signature::Keypair, signer::Signer,
     system_instruction, transaction::Transaction,
 };
-use token_program::state::mint::Mint;
+use token_interface::state::mint::Mint;
 
 pub async fn initialize(
     context: &mut ProgramTestContext,