-
Notifications
You must be signed in to change notification settings - Fork 165
feat : add token-2022 core ixs and state
#190
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
febo
merged 4 commits into
anza-xyz:main
from
Nagaprasadvr:feat-add-token-2022-core-state-and-ixs
Aug 9, 2025
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 { | ||
Nagaprasadvr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // 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, | ||
| ) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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, | ||
| ) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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, | ||
| ) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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, | ||
| ) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.