Skip to content

p-token: Add format and lint scripts #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,44 @@ jobs:
- name: Lint
run: pnpm programs:lint

format_and_lint_interface:
name: Format & Lint Interface
runs-on: ubuntu-latest
steps:
- name: Git Checkout
uses: actions/checkout@v4

- name: Setup Environment
uses: ./.github/actions/setup
with:
clippy: true
rustfmt: true

- name: Format
run: pnpm interface:format

- name: Lint
run: pnpm interface:lint

format_and_lint_ptoken:
name: Format & Lint p-token
runs-on: ubuntu-latest
steps:
- name: Git Checkout
uses: actions/checkout@v4

- name: Setup Environment
uses: ./.github/actions/setup
with:
clippy: true
rustfmt: true

- name: Format
run: pnpm p-token:format

- name: Lint
run: pnpm p-token:lint

audit_rust:
name: Audit Rust
runs-on: ubuntu-latest
Expand Down Expand Up @@ -154,6 +192,7 @@ jobs:
build_ptoken:
name: Build p-token
runs-on: ubuntu-latest
needs: [format_and_lint_interface, format_and_lint_ptoken]
steps:
- name: Git Checkout
uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ edition = "2021"
level = "warn"
check-cfg = [
'cfg(target_os, values("solana"))',
'cfg(feature, values("frozen-abi", "no-entrypoint"))',
'cfg(feature, values("custom-alloc", "custom-panic", "frozen-abi", "no-entrypoint"))',
]

[workspace.metadata.cli]
Expand Down
66 changes: 40 additions & 26 deletions interface/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ pub enum TokenInstruction {
///
/// 0. `[writable]` The multisignature account to initialize.
/// 1. `[]` Rent sysvar.
/// 2. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= N <= 11`.
/// 2. `..+N` `[signer]` The signer accounts, must equal to N where `1 <=
/// N <= 11`.
///
/// Data expected by this instruction:
///
/// - `u8` The number of signers (M) required to validate this multisignature account.
/// - `u8` The number of signers (M) required to validate this
/// multisignature account.
InitializeMultisig,

/// Transfers tokens from one account to another either directly or via a
Expand Down Expand Up @@ -268,7 +270,8 @@ pub enum TokenInstruction {
/// Data expected by this instruction:
///
/// - `u64` The amount of tokens to transfer.
/// - `u8` Expected number of base 10 digits to the right of the decimal place.
/// - `u8` Expected number of base 10 digits to the right of the decimal
/// place.
TransferChecked,

/// Approves a delegate. A delegate is given the authority over tokens on
Expand Down Expand Up @@ -296,7 +299,8 @@ pub enum TokenInstruction {
/// Data expected by this instruction:
///
/// - `u64` The amount of tokens the delegate is approved for.
/// - `u8` Expected number of base 10 digits to the right of the decimal place.
/// - `u8` Expected number of base 10 digits to the right of the decimal
/// place.
ApproveChecked,

/// Mints new tokens to an account. The native mint does not support
Expand All @@ -322,7 +326,8 @@ pub enum TokenInstruction {
/// Data expected by this instruction:
///
/// - `u64` The amount of new tokens to mint.
/// - `u8` Expected number of base 10 digits to the right of the decimal place.
/// - `u8` Expected number of base 10 digits to the right of the decimal
/// place.
MintToChecked,

/// Burns tokens by removing them from an account. [`BurnChecked`] does not
Expand All @@ -349,13 +354,14 @@ pub enum TokenInstruction {
/// Data expected by this instruction:
///
/// - `u64` The amount of tokens to burn.
/// - `u8` Expected number of base 10 digits to the right of the decimal place.
/// - `u8` Expected number of base 10 digits to the right of the decimal
/// place.
BurnChecked,

/// 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.
/// 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:
///
Expand Down Expand Up @@ -399,11 +405,13 @@ pub enum TokenInstruction {
/// Accounts expected by this instruction:
///
/// 0. `[writable]` The multisignature account to initialize.
/// 1. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= N <= 11`.
/// 1. `..+N` `[signer]` The signer accounts, must equal to N where `1 <=
/// N <= 11`.
///
/// Data expected by this instruction:
///
/// - `u8` The number of signers (M) required to validate this multisignature account.
/// - `u8` The number of signers (M) required to validate this
/// multisignature account.
InitializeMultisig2,

/// Like [`InitializeMint`], but does not require the Rent sysvar to be
Expand Down Expand Up @@ -462,9 +470,9 @@ pub enum TokenInstruction {
/// - `u64` The amount of tokens to reformat.
AmountToUiAmount,

/// 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.
/// 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`.
Expand All @@ -490,22 +498,26 @@ pub enum TokenInstruction {
/// 3. `..+M` `[signer]` M signer accounts.
WithdrawExcessLamports = 38,

/// Executes a batch of instructions. The instructions to be executed are specified
/// in sequence on the instruction data. Each instruction provides:
/// Executes a batch of instructions. The instructions to be executed are
/// specified in sequence on the instruction data. Each instruction
/// provides:
/// - `u8`: number of accounts
/// - `u8`: instruction data length (includes the discriminator)
/// - `u8`: instruction discriminator
/// - `[u8]`: instruction data
///
/// Accounts follow a similar pattern, where accounts for each instruction are
/// specified in sequence. Therefore, the number of accounts expected by this
/// instruction is variable, i.e., it depends on the instructions provided.
/// Accounts follow a similar pattern, where accounts for each instruction
/// are specified in sequence. Therefore, the number of accounts
/// expected by this instruction is variable, i.e., it depends on the
/// instructions provided.
///
/// Both the number of accounts and instruction data length are used to identify
/// the slice of accounts and instruction data for each instruction.
/// Both the number of accounts and instruction data length are used to
/// identify the slice of accounts and instruction data for each
/// instruction.
///
/// Note that it is not sound to have a `batch` instruction that contains other
/// `batch` instruction; an error will be raised when this is detected.
/// Note that it is not sound to have a `batch` instruction that contains
/// other `batch` instruction; an error will be raised when this is
/// detected.
Batch = 255,
// 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
Expand Down Expand Up @@ -554,8 +566,10 @@ impl TryFrom<u8> for AuthorityType {

#[cfg(test)]
mod tests {
use super::{AuthorityType, TokenInstruction};
use strum::IntoEnumIterator;
use {
super::{AuthorityType, TokenInstruction},
strum::IntoEnumIterator,
};

#[test]
fn test_token_instruction_from_u8_exhaustive() {
Expand Down
7 changes: 4 additions & 3 deletions interface/src/state/account.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use pinocchio::pubkey::Pubkey;

use super::{account_state::AccountState, COption, Initializable, Transmutable};
use {
super::{account_state::AccountState, COption, Initializable, Transmutable},
pinocchio::pubkey::Pubkey,
};

/// Incinerator address.
pub const INCINERATOR_ID: Pubkey =
Expand Down
7 changes: 4 additions & 3 deletions interface/src/state/mint.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use pinocchio::pubkey::Pubkey;

use super::{COption, Initializable, Transmutable};
use {
super::{COption, Initializable, Transmutable},
pinocchio::pubkey::Pubkey,
};

/// Internal representation of a mint data.
#[repr(C)]
Expand Down
5 changes: 3 additions & 2 deletions interface/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ pub type COption<T> = ([u8; 4], T);

/// Marker trait for types that can be cast from a raw pointer.
///
/// It is up to the type implementing this trait to guarantee that the cast is safe,
/// i.e., the fields of the type are well aligned and there are no padding bytes.
/// It is up to the type implementing this trait to guarantee that the cast is
/// safe, i.e., the fields of the type are well aligned and there are no padding
/// bytes.
pub trait Transmutable {
/// The length of the type.
///
Expand Down
10 changes: 6 additions & 4 deletions interface/src/state/multisig.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use pinocchio::pubkey::Pubkey;

use super::{Initializable, Transmutable};
use {
super::{Initializable, Transmutable},
pinocchio::pubkey::Pubkey,
};

/// Minimum number of multisignature signers (min N)
pub const MIN_SIGNERS: u8 = 1;
Expand All @@ -25,7 +26,8 @@ pub struct Multisig {
}

impl Multisig {
/// Utility function that checks index is between [`MIN_SIGNERS`] and [`MAX_SIGNERS`].
/// Utility function that checks index is between [`MIN_SIGNERS`] and
/// [`MAX_SIGNERS`].
pub fn is_valid_signer_index(index: u8) -> bool {
(MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
}
Expand Down
3 changes: 3 additions & 0 deletions p-token/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ solana-sdk = "2.1"
spl-token = { version="^4", features=["no-entrypoint"] }
spl-token-2022 = { version="^7", features=["no-entrypoint"] }
test-case = "3.3.1"

[lints]
workspace = true
48 changes: 26 additions & 22 deletions p-token/src/entrypoint.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use pinocchio::{
account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint,
program_error::ProgramError, pubkey::Pubkey, ProgramResult,
use {
crate::processor::*,
pinocchio::{
account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint,
program_error::ProgramError, pubkey::Pubkey, ProgramResult,
},
};

use crate::processor::*;

program_entrypoint!(process_instruction);
// Do not allocate memory.
no_allocator!();
Expand All @@ -13,10 +14,11 @@ default_panic_handler!();

/// Process an instruction.
///
/// In the first stage, the entrypoint checks the discriminator of the instruction data
/// to determine whether the instruction is a "batch" instruction or a "regular" instruction.
/// This avoids nesting of "batch" instructions, since it is not sound to have a "batch"
/// instruction inside another "batch" instruction.
/// In the first stage, the entrypoint checks the discriminator of the
/// instruction data to determine whether the instruction is a "batch"
/// instruction or a "regular" instruction. This avoids nesting of "batch"
/// instructions, since it is not sound to have a "batch" instruction inside
/// another "batch" instruction.
#[inline(always)]
pub fn process_instruction(
_program_id: &Pubkey,
Expand All @@ -40,20 +42,21 @@ pub fn process_instruction(

/// Process a "regular" instruction.
///
/// The processor of the token program is divided into two parts to reduce the overhead
/// of having a large `match` statement. The first part of the processor handles the
/// most common instructions, while the second part handles the remaining instructions.
/// The processor of the token program is divided into two parts to reduce the
/// overhead of having a large `match` statement. The first part of the
/// processor handles the most common instructions, while the second part
/// handles the remaining instructions.
///
/// The rationale is to reduce the overhead of making multiple comparisons for popular
/// instructions.
/// The rationale is to reduce the overhead of making multiple comparisons for
/// popular instructions.
///
/// Instructions on the first part of the inner processor:
///
/// - `0`: `InitializeMint`
/// - `1`: `InitializeAccount`
/// - `3`: `Transfer`
/// - `7`: `MintTo`
/// - `9`: `CloseAccount`
/// - `0`: `InitializeMint`
/// - `1`: `InitializeAccount`
/// - `3`: `Transfer`
/// - `7`: `MintTo`
/// - `9`: `CloseAccount`
/// - `16`: `InitializeAccount2`
/// - `18`: `InitializeAccount3`
/// - `20`: `InitializeMint2`
Expand Down Expand Up @@ -129,9 +132,10 @@ pub(crate) fn inner_process_instruction(

/// Process a remaining "regular" instruction.
///
/// This function is called by the [`inner_process_instruction`] function if the discriminator
/// does not match any of the common instructions. This function is used to reduce the
/// overhead of having a large `match` statement in the [`inner_process_instruction`] function.
/// This function is called by the [`inner_process_instruction`] function if the
/// discriminator does not match any of the common instructions. This function
/// is used to reduce the overhead of having a large `match` statement in the
/// [`inner_process_instruction`] function.
fn inner_process_remaining_instruction(
accounts: &[AccountInfo],
instruction_data: &[u8],
Expand Down
22 changes: 12 additions & 10 deletions p-token/src/processor/amount_to_ui_amount.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use core::str::from_utf8_unchecked;
use pinocchio::{
account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult,
use {
super::{check_account_owner, MAX_FORMATTED_DIGITS},
core::str::from_utf8_unchecked,
pinocchio::{
account_info::AccountInfo, program::set_return_data, program_error::ProgramError,
ProgramResult,
},
pinocchio_log::logger::{Argument, Logger},
spl_token_interface::{
error::TokenError,
state::{load, mint::Mint},
},
};
use pinocchio_log::logger::{Argument, Logger};
use spl_token_interface::{
error::TokenError,
state::{load, mint::Mint},
};

use super::{check_account_owner, MAX_FORMATTED_DIGITS};

#[inline(always)]
pub fn process_amount_to_ui_amount(
Expand Down
7 changes: 4 additions & 3 deletions p-token/src/processor/approve.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult};

use super::shared;
use {
super::shared,
pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult},
};

#[inline(always)]
pub fn process_approve(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult {
Expand Down
7 changes: 4 additions & 3 deletions p-token/src/processor/approve_checked.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult};

use super::shared;
use {
super::shared,
pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult},
};

#[inline(always)]
pub fn process_approve_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult {
Expand Down
Loading