1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315 |
- //! Instruction types
- use crate::{error::TokenError, option::COption};
- use solana_sdk::{
- instruction::{AccountMeta, Instruction},
- program_error::ProgramError,
- pubkey::Pubkey,
- sysvar,
- };
- use std::mem::size_of;
- /// Minimum number of multisignature signers (min N)
- pub const MIN_SIGNERS: usize = 1;
- /// Maximum number of multisignature signers (max N)
- pub const MAX_SIGNERS: usize = 11;
- /// Instructions supported by the token program.
- #[repr(C)]
- #[derive(Clone, Debug, PartialEq)]
- pub enum TokenInstruction {
- /// 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 `CreateInstruction` 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: COption<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 `CreateInstruction` 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 `CreateInstruction` 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 multisignature authority.
- /// 2. ..2+M '[signer]' M signer accounts
- SetAuthority {
- /// The type of authority to update.
- authority_type: AuthorityType,
- /// The new authority
- new_authority: COption<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
- /// asserted 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.
- Transfer2 {
- /// 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 asserted
- /// 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
- Approve2 {
- /// 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 asserted 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.
- MintTo2 {
- /// 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. `Burn2` does not support accounts
- /// associated with the native mint, use `CloseAccount` instead.
- ///
- /// This instruction differs from Burn in that the decimals value is asserted 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.
- Burn2 {
- /// The amount of tokens to burn.
- amount: u64,
- /// Expected number of base 10 digits to the right of the decimal place.
- decimals: u8,
- },
- }
- impl TokenInstruction {
- /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html).
- pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
- if input.len() < size_of::<u8>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- Ok(match input[0] {
- 0 => {
- if input.len() < size_of::<u8>() + size_of::<Pubkey>() + size_of::<bool>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- let mut input_len = 0;
- input_len += size_of::<u8>();
- let decimals = unsafe { *(&input[input_len] as *const u8) };
- input_len += size_of::<u8>();
- let mint_authority = unsafe { *(&input[input_len] as *const u8 as *const Pubkey) };
- input_len += size_of::<Pubkey>();
- let freeze_authority = COption::unpack_or(
- input,
- &mut input_len,
- Into::<ProgramError>::into(TokenError::InvalidInstruction),
- )?;
- Self::InitializeMint {
- mint_authority,
- freeze_authority,
- decimals,
- }
- }
- 1 => Self::InitializeAccount,
- 2 => {
- if input.len() < size_of::<u8>() + size_of::<u8>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- #[allow(clippy::cast_ptr_alignment)]
- let m = unsafe { *(&input[1] as *const u8) };
- Self::InitializeMultisig { m }
- }
- 3 => {
- if input.len() < size_of::<u8>() + size_of::<u64>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- #[allow(clippy::cast_ptr_alignment)]
- let amount = unsafe { *(&input[size_of::<u8>()] as *const u8 as *const u64) };
- Self::Transfer { amount }
- }
- 4 => {
- if input.len() < size_of::<u8>() + size_of::<u64>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- #[allow(clippy::cast_ptr_alignment)]
- let amount = unsafe { *(&input[size_of::<u8>()] as *const u8 as *const u64) };
- Self::Approve { amount }
- }
- 5 => Self::Revoke,
- 6 => {
- if input.len() < size_of::<u8>() + size_of::<u8>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- let mut input_len = 0;
- input_len += size_of::<u8>();
- let authority_type = AuthorityType::from(input[1])?;
- input_len += size_of::<u8>();
- let new_authority = COption::unpack_or(
- input,
- &mut input_len,
- Into::<ProgramError>::into(TokenError::InvalidInstruction),
- )?;
- Self::SetAuthority {
- authority_type,
- new_authority,
- }
- }
- 7 => {
- if input.len() < size_of::<u8>() + size_of::<u64>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- #[allow(clippy::cast_ptr_alignment)]
- let amount = unsafe { *(&input[size_of::<u8>()] as *const u8 as *const u64) };
- Self::MintTo { amount }
- }
- 8 => {
- if input.len() < size_of::<u8>() + size_of::<u64>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- #[allow(clippy::cast_ptr_alignment)]
- let amount = unsafe { *(&input[size_of::<u8>()] as *const u8 as *const u64) };
- Self::Burn { amount }
- }
- 9 => Self::CloseAccount,
- 10 => Self::FreezeAccount,
- 11 => Self::ThawAccount,
- 12 => {
- if input.len() < size_of::<u8>() + size_of::<u64>() + size_of::<u8>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- let mut input_len = 0;
- input_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) };
- input_len += size_of::<u64>();
- let decimals = unsafe { *(&input[input_len] as *const u8) };
- Self::Transfer2 { amount, decimals }
- }
- 13 => {
- if input.len() < size_of::<u8>() + size_of::<u64>() + size_of::<u8>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- let mut input_len = 0;
- input_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) };
- input_len += size_of::<u64>();
- let decimals = unsafe { *(&input[input_len] as *const u8) };
- Self::Approve2 { amount, decimals }
- }
- 14 => {
- if input.len() < size_of::<u8>() + size_of::<u64>() + size_of::<u8>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- let mut input_len = 0;
- input_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) };
- input_len += size_of::<u64>();
- let decimals = unsafe { *(&input[input_len] as *const u8) };
- Self::MintTo2 { amount, decimals }
- }
- 15 => {
- if input.len() < size_of::<u8>() + size_of::<u64>() + size_of::<u8>() {
- return Err(TokenError::InvalidInstruction.into());
- }
- let mut input_len = 0;
- input_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) };
- input_len += size_of::<u64>();
- let decimals = unsafe { *(&input[input_len] as *const u8) };
- Self::Burn2 { amount, decimals }
- }
- _ => return Err(TokenError::InvalidInstruction.into()),
- })
- }
- /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer.
- pub fn pack(&self) -> Result<Vec<u8>, ProgramError> {
- let mut output = vec![0u8; size_of::<TokenInstruction>()];
- let mut output_len = 0;
- match self {
- Self::InitializeMint {
- mint_authority,
- freeze_authority,
- decimals,
- } => {
- output[output_len] = 0;
- output_len += size_of::<u8>();
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8) };
- *value = *decimals;
- output_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut Pubkey) };
- *value = *mint_authority;
- output_len += size_of::<Pubkey>();
- freeze_authority.pack(&mut output, &mut output_len);
- }
- Self::InitializeAccount => {
- output[output_len] = 1;
- output_len += size_of::<u8>();
- }
- Self::InitializeMultisig { m } => {
- output[output_len] = 2;
- output_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u8) };
- *value = *m;
- output_len += size_of::<u8>();
- }
- Self::Transfer { amount } => {
- output[output_len] = 3;
- output_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
- *value = *amount;
- output_len += size_of::<u64>();
- }
- Self::Approve { amount } => {
- output[output_len] = 4;
- output_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
- *value = *amount;
- output_len += size_of::<u64>();
- }
- Self::Revoke => {
- output[output_len] = 5;
- output_len += size_of::<u8>();
- }
- Self::SetAuthority {
- authority_type,
- new_authority,
- } => {
- output[output_len] = 6;
- output_len += size_of::<u8>();
- output[output_len] = authority_type.into();
- output_len += size_of::<u8>();
- new_authority.pack(&mut output, &mut output_len);
- }
- Self::MintTo { amount } => {
- output[output_len] = 7;
- output_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
- *value = *amount;
- output_len += size_of::<u64>();
- }
- Self::Burn { amount } => {
- output[output_len] = 8;
- output_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
- *value = *amount;
- output_len += size_of::<u64>();
- }
- Self::CloseAccount => {
- output[output_len] = 9;
- output_len += size_of::<u8>();
- }
- Self::FreezeAccount => {
- output[output_len] = 10;
- output_len += size_of::<u8>();
- }
- Self::ThawAccount => {
- output[output_len] = 11;
- output_len += size_of::<u8>();
- }
- Self::Transfer2 { amount, decimals } => {
- output[output_len] = 12;
- output_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
- *value = *amount;
- output_len += size_of::<u64>();
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8) };
- *value = *decimals;
- output_len += size_of::<u8>();
- }
- Self::Approve2 { amount, decimals } => {
- output[output_len] = 13;
- output_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
- *value = *amount;
- output_len += size_of::<u64>();
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8) };
- *value = *decimals;
- output_len += size_of::<u8>();
- }
- Self::MintTo2 { amount, decimals } => {
- output[output_len] = 14;
- output_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
- *value = *amount;
- output_len += size_of::<u64>();
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8) };
- *value = *decimals;
- output_len += size_of::<u8>();
- }
- Self::Burn2 { amount, decimals } => {
- output[output_len] = 15;
- output_len += size_of::<u8>();
- #[allow(clippy::cast_ptr_alignment)]
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
- *value = *amount;
- output_len += size_of::<u64>();
- let value = unsafe { &mut *(&mut output[output_len] as *mut u8) };
- *value = *decimals;
- output_len += size_of::<u8>();
- }
- }
- output.truncate(output_len);
- Ok(output)
- }
- }
- /// 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,
- /// Holder of a given token account
- AccountHolder,
- /// Authority to close a token account
- CloseAccount,
- }
- impl AuthorityType {
- fn into(&self) -> u8 {
- match self {
- AuthorityType::MintTokens => 0,
- AuthorityType::FreezeAccount => 1,
- AuthorityType::AccountHolder => 2,
- AuthorityType::CloseAccount => 3,
- }
- }
- fn from(index: u8) -> Result<Self, ProgramError> {
- match index {
- 0 => Ok(AuthorityType::MintTokens),
- 1 => Ok(AuthorityType::FreezeAccount),
- 2 => Ok(AuthorityType::AccountHolder),
- 3 => Ok(AuthorityType::CloseAccount),
- _ => Err(TokenError::InvalidInstruction.into()),
- }
- }
- }
- /// Creates a 'InitializeMint' instruction.
- pub fn initialize_mint(
- token_program_id: &Pubkey,
- mint_pubkey: &Pubkey,
- mint_authority_pubkey: &Pubkey,
- freeze_authority_pubkey: Option<&Pubkey>,
- decimals: u8,
- ) -> Result<Instruction, ProgramError> {
- let freeze_authority = freeze_authority_pubkey.cloned().into();
- let data = TokenInstruction::InitializeMint {
- mint_authority: *mint_authority_pubkey,
- freeze_authority,
- decimals,
- }
- .pack()?;
- let accounts = vec![
- AccountMeta::new(*mint_pubkey, false),
- AccountMeta::new_readonly(sysvar::rent::id(), false),
- ];
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `InitializeAccount` instruction.
- pub fn initialize_account(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::InitializeAccount.pack()?;
- let accounts = vec![
- AccountMeta::new(*account_pubkey, false),
- AccountMeta::new_readonly(*mint_pubkey, false),
- AccountMeta::new_readonly(*owner_pubkey, false),
- AccountMeta::new_readonly(sysvar::rent::id(), false),
- ];
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `InitializeMultisig` instruction.
- pub fn initialize_multisig(
- token_program_id: &Pubkey,
- multisig_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- m: u8,
- ) -> Result<Instruction, ProgramError> {
- if !is_valid_signer_index(m as usize)
- || !is_valid_signer_index(signer_pubkeys.len())
- || m as usize > signer_pubkeys.len()
- {
- return Err(ProgramError::MissingRequiredSignature);
- }
- let data = TokenInstruction::InitializeMultisig { m }.pack()?;
- let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*multisig_pubkey, false));
- accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `Transfer` instruction.
- pub fn transfer(
- token_program_id: &Pubkey,
- source_pubkey: &Pubkey,
- destination_pubkey: &Pubkey,
- authority_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::Transfer { amount }.pack()?;
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*source_pubkey, false));
- accounts.push(AccountMeta::new(*destination_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *authority_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates an `Approve` instruction.
- pub fn approve(
- token_program_id: &Pubkey,
- source_pubkey: &Pubkey,
- delegate_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::Approve { amount }.pack()?;
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*source_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `Revoke` instruction.
- pub fn revoke(
- token_program_id: &Pubkey,
- source_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::Revoke.pack()?;
- let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
- accounts.push(AccountMeta::new_readonly(*source_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `SetAuthority` instruction.
- pub fn set_authority(
- token_program_id: &Pubkey,
- owned_pubkey: &Pubkey,
- new_authority_pubkey: Option<&Pubkey>,
- authority_type: AuthorityType,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- ) -> Result<Instruction, ProgramError> {
- let new_authority = new_authority_pubkey.cloned().into();
- let data = TokenInstruction::SetAuthority {
- authority_type,
- new_authority,
- }
- .pack()?;
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*owned_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `MintTo` instruction.
- pub fn mint_to(
- token_program_id: &Pubkey,
- mint_pubkey: &Pubkey,
- account_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::MintTo { amount }.pack()?;
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*mint_pubkey, false));
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `Burn` instruction.
- pub fn burn(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- authority_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::Burn { amount }.pack()?;
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new(*mint_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *authority_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `CloseAccount` instruction.
- pub fn close_account(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- destination_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::CloseAccount.pack()?;
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new(*destination_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `FreezeAccount` instruction.
- pub fn freeze_account(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::FreezeAccount.pack()?;
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `ThawAccount` instruction.
- pub fn thaw_account(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::ThawAccount.pack()?;
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `Transfer2` instruction.
- #[allow(clippy::too_many_arguments)]
- pub fn transfer2(
- token_program_id: &Pubkey,
- source_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- destination_pubkey: &Pubkey,
- authority_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- decimals: u8,
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::Transfer2 { amount, decimals }.pack()?;
- let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*source_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
- accounts.push(AccountMeta::new(*destination_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *authority_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates an `Approve2` instruction.
- #[allow(clippy::too_many_arguments)]
- pub fn approve2(
- token_program_id: &Pubkey,
- source_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- delegate_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- decimals: u8,
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::Approve2 { amount, decimals }.pack()?;
- let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*source_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `MintTo2` instruction.
- pub fn mint_to2(
- token_program_id: &Pubkey,
- mint_pubkey: &Pubkey,
- account_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- decimals: u8,
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::MintTo2 { amount, decimals }.pack()?;
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*mint_pubkey, false));
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `Burn2` instruction.
- pub fn burn2(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- authority_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- decimals: u8,
- ) -> Result<Instruction, ProgramError> {
- let data = TokenInstruction::Burn2 { amount, decimals }.pack()?;
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new(*mint_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *authority_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS
- pub fn is_valid_signer_index(index: usize) -> bool {
- !(index < MIN_SIGNERS || index > MAX_SIGNERS)
- }
- #[cfg(test)]
- mod test {
- use super::*;
- #[test]
- fn test_instruction_packing() {
- let check = TokenInstruction::InitializeMint {
- decimals: 2,
- mint_authority: Pubkey::new(&[1u8; 32]),
- freeze_authority: COption::None,
- };
- let packed = check.pack().unwrap();
- let mut expect = Vec::from([0u8, 2]);
- expect.extend_from_slice(&[1u8; 32]);
- expect.extend_from_slice(&[0]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::InitializeMint {
- decimals: 2,
- mint_authority: Pubkey::new(&[2u8; 32]),
- freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
- };
- let packed = check.pack().unwrap();
- let mut expect = vec![0u8, 2];
- expect.extend_from_slice(&[2u8; 32]);
- expect.extend_from_slice(&[1]);
- expect.extend_from_slice(&[3u8; 32]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::InitializeAccount;
- let packed = check.pack().unwrap();
- let expect = Vec::from([1u8]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::InitializeMultisig { m: 1 };
- let packed = check.pack().unwrap();
- let expect = Vec::from([2u8, 1]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Transfer { amount: 1 };
- let packed = check.pack().unwrap();
- let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Approve { amount: 1 };
- let packed = check.pack().unwrap();
- let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Revoke;
- let packed = check.pack().unwrap();
- let expect = Vec::from([5u8]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::SetAuthority {
- authority_type: AuthorityType::FreezeAccount,
- new_authority: COption::Some(Pubkey::new(&[4u8; 32])),
- };
- let packed = check.pack().unwrap();
- let mut expect = Vec::from([6u8, 1]);
- expect.extend_from_slice(&[1]);
- expect.extend_from_slice(&[4u8; 32]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::MintTo { amount: 1 };
- let packed = check.pack().unwrap();
- let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Burn { amount: 1 };
- let packed = check.pack().unwrap();
- let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::CloseAccount;
- let packed = check.pack().unwrap();
- let expect = Vec::from([9u8]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::FreezeAccount;
- let packed = check.pack().unwrap();
- let expect = Vec::from([10u8]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::ThawAccount;
- let packed = check.pack().unwrap();
- let expect = Vec::from([11u8]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Transfer2 {
- amount: 1,
- decimals: 2,
- };
- let packed = check.pack().unwrap();
- let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Approve2 {
- amount: 1,
- decimals: 2,
- };
- let packed = check.pack().unwrap();
- let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::MintTo2 {
- amount: 1,
- decimals: 2,
- };
- let packed = check.pack().unwrap();
- let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Burn2 {
- amount: 1,
- decimals: 2,
- };
- let packed = check.pack().unwrap();
- let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- }
- }
|