2020-08-14 14:13:35 -07:00
|
|
|
//! Instruction types
|
|
|
|
|
2020-08-25 13:24:11 -07:00
|
|
|
use crate::{error::TokenError, option::COption};
|
2020-08-14 14:13:35 -07:00
|
|
|
use solana_sdk::{
|
|
|
|
instruction::{AccountMeta, Instruction},
|
|
|
|
program_error::ProgramError,
|
|
|
|
pubkey::Pubkey,
|
2020-08-26 23:29:54 -07:00
|
|
|
sysvar,
|
2020-08-14 14:13:35 -07:00
|
|
|
};
|
|
|
|
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.
|
2020-08-26 23:29:54 -07:00
|
|
|
/// 1. `[]` Rent sysvar
|
2020-08-14 14:13:35 -07:00
|
|
|
///
|
|
|
|
InitializeMint {
|
|
|
|
/// Number of base 10 digits to the right of the decimal place.
|
|
|
|
decimals: u8,
|
2020-08-26 22:58:42 -07:00
|
|
|
/// The authority/multisignature to mint tokens.
|
|
|
|
mint_authority: Pubkey,
|
2020-08-25 13:24:11 -07:00
|
|
|
/// The freeze authority/multisignature of the mint.
|
|
|
|
freeze_authority: COption<Pubkey>,
|
2020-08-14 14:13:35 -07:00
|
|
|
},
|
2020-08-27 14:22:03 -07:00
|
|
|
/// 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.
|
2020-08-14 14:13:35 -07:00
|
|
|
///
|
|
|
|
/// 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.
|
2020-08-26 23:29:54 -07:00
|
|
|
/// 3. `[]` Rent sysvar
|
2020-08-14 14:13:35 -07:00
|
|
|
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.
|
2020-08-27 12:06:23 -07:00
|
|
|
/// 1. `[]` Rent sysvar
|
|
|
|
/// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11.
|
2020-08-14 14:13:35 -07:00
|
|
|
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,
|
2020-08-25 13:24:11 -07:00
|
|
|
/// Sets a new authority of a mint or account.
|
2020-08-14 14:13:35 -07:00
|
|
|
///
|
|
|
|
/// Accounts expected by this instruction:
|
|
|
|
///
|
2020-08-25 13:24:11 -07:00
|
|
|
/// * Single authority
|
|
|
|
/// 0. `[writable]` The mint or account to change the authority of.
|
|
|
|
/// 1. `[signer]` The current authority of the mint or account.
|
2020-08-14 14:13:35 -07:00
|
|
|
///
|
2020-08-25 13:24:11 -07:00
|
|
|
/// * Multisignature authority
|
|
|
|
/// 0. `[writable]` The mint or account to change the authority of.
|
|
|
|
/// 1. `[]` The mint's or account's multisignature authority.
|
2020-08-27 12:06:23 -07:00
|
|
|
/// 2. ..2+M '[signer]' M signer accounts
|
2020-08-25 13:24:11 -07:00
|
|
|
SetAuthority {
|
|
|
|
/// The type of authority to update.
|
|
|
|
authority_type: AuthorityType,
|
|
|
|
/// The new authority
|
|
|
|
new_authority: COption<Pubkey>,
|
|
|
|
},
|
2020-08-14 14:13:35 -07:00
|
|
|
/// Mints new tokens to an account. The native mint does not support minting.
|
|
|
|
///
|
|
|
|
/// Accounts expected by this instruction:
|
|
|
|
///
|
2020-08-25 13:24:11 -07:00
|
|
|
/// * Single authority
|
2020-08-14 14:13:35 -07:00
|
|
|
/// 0. `[writable]` The mint.
|
|
|
|
/// 1. `[writable]` The account to mint tokens to.
|
2020-08-25 13:24:11 -07:00
|
|
|
/// 2. `[signer]` The mint's minting authority.
|
2020-08-14 14:13:35 -07:00
|
|
|
///
|
2020-08-25 13:24:11 -07:00
|
|
|
/// * Multisignature authority
|
2020-08-14 14:13:35 -07:00
|
|
|
/// 0. `[writable]` The mint.
|
|
|
|
/// 1. `[writable]` The account to mint tokens to.
|
2020-08-25 13:24:11 -07:00
|
|
|
/// 2. `[]` The mint's multisignature mint-tokens authority.
|
2020-08-14 14:13:35 -07:00
|
|
|
/// 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.
|
2020-08-27 12:06:23 -07:00
|
|
|
/// 1. '[writable]' The token mint.
|
|
|
|
/// 2. `[signer]` The account's owner/delegate.
|
2020-08-14 14:13:35 -07:00
|
|
|
///
|
|
|
|
/// * Multisignature owner/delegate
|
|
|
|
/// 0. `[writable]` The account to burn from.
|
2020-08-27 12:06:23 -07:00
|
|
|
/// 1. '[writable]' The token mint.
|
|
|
|
/// 2. `[]` The account's multisignature owner/delegate.
|
|
|
|
/// 3. ..3+M '[signer]' M signer accounts.
|
2020-08-14 14:13:35 -07:00
|
|
|
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,
|
2020-08-25 13:24:11 -07:00
|
|
|
/// 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,
|
2020-08-14 14:13:35 -07:00
|
|
|
}
|
|
|
|
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 => {
|
2020-08-26 22:58:42 -07:00
|
|
|
if input.len() < size_of::<u8>() + size_of::<Pubkey>() + size_of::<bool>() {
|
2020-08-14 14:13:35 -07:00
|
|
|
return Err(TokenError::InvalidInstruction.into());
|
|
|
|
}
|
2020-08-25 13:24:11 -07:00
|
|
|
let mut input_len = 0;
|
|
|
|
input_len += size_of::<u8>();
|
|
|
|
|
|
|
|
let decimals = unsafe { *(&input[input_len] as *const u8) };
|
|
|
|
input_len += size_of::<u8>();
|
|
|
|
|
2020-08-26 22:58:42 -07:00
|
|
|
let mint_authority = unsafe { *(&input[input_len] as *const u8 as *const Pubkey) };
|
|
|
|
input_len += size_of::<Pubkey>();
|
|
|
|
|
2020-08-25 13:24:11 -07:00
|
|
|
let freeze_authority = COption::unpack_or(
|
|
|
|
input,
|
|
|
|
&mut input_len,
|
|
|
|
Into::<ProgramError>::into(TokenError::InvalidInstruction),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Self::InitializeMint {
|
|
|
|
mint_authority,
|
|
|
|
freeze_authority,
|
|
|
|
decimals,
|
|
|
|
}
|
2020-08-14 14:13:35 -07:00
|
|
|
}
|
|
|
|
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,
|
2020-08-25 13:24:11 -07:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
2020-08-14 14:13:35 -07:00
|
|
|
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,
|
2020-08-25 13:24:11 -07:00
|
|
|
10 => Self::FreezeAccount,
|
|
|
|
11 => Self::ThawAccount,
|
2020-08-14 14:13:35 -07:00
|
|
|
_ => 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 {
|
2020-08-25 13:24:11 -07:00
|
|
|
Self::InitializeMint {
|
|
|
|
mint_authority,
|
|
|
|
freeze_authority,
|
|
|
|
decimals,
|
|
|
|
} => {
|
2020-08-14 14:13:35 -07:00
|
|
|
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>();
|
2020-08-25 13:24:11 -07:00
|
|
|
|
2020-08-26 22:58:42 -07:00
|
|
|
#[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>();
|
|
|
|
|
2020-08-25 13:24:11 -07:00
|
|
|
freeze_authority.pack(&mut output, &mut output_len);
|
2020-08-14 14:13:35 -07:00
|
|
|
}
|
|
|
|
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>();
|
|
|
|
}
|
2020-08-25 13:24:11 -07:00
|
|
|
Self::SetAuthority {
|
|
|
|
authority_type,
|
|
|
|
new_authority,
|
|
|
|
} => {
|
2020-08-14 14:13:35 -07:00
|
|
|
output[output_len] = 6;
|
|
|
|
output_len += size_of::<u8>();
|
2020-08-25 13:24:11 -07:00
|
|
|
|
|
|
|
output[output_len] = authority_type.into();
|
|
|
|
output_len += size_of::<u8>();
|
|
|
|
|
|
|
|
new_authority.pack(&mut output, &mut output_len);
|
2020-08-14 14:13:35 -07:00
|
|
|
}
|
|
|
|
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>();
|
|
|
|
}
|
2020-08-25 13:24:11 -07:00
|
|
|
Self::FreezeAccount => {
|
|
|
|
output[output_len] = 10;
|
|
|
|
output_len += size_of::<u8>();
|
|
|
|
}
|
|
|
|
Self::ThawAccount => {
|
|
|
|
output[output_len] = 11;
|
|
|
|
output_len += size_of::<u8>();
|
|
|
|
}
|
2020-08-14 14:13:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
output.truncate(output_len);
|
|
|
|
Ok(output)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-25 13:24:11 -07:00
|
|
|
/// 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,
|
2020-08-25 20:36:35 -07:00
|
|
|
/// Authority to close a token account
|
|
|
|
CloseAccount,
|
2020-08-25 13:24:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AuthorityType {
|
|
|
|
fn into(&self) -> u8 {
|
|
|
|
match self {
|
|
|
|
AuthorityType::MintTokens => 0,
|
|
|
|
AuthorityType::FreezeAccount => 1,
|
|
|
|
AuthorityType::AccountHolder => 2,
|
2020-08-25 20:36:35 -07:00
|
|
|
AuthorityType::CloseAccount => 3,
|
2020-08-25 13:24:11 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from(index: u8) -> Result<Self, ProgramError> {
|
|
|
|
match index {
|
|
|
|
0 => Ok(AuthorityType::MintTokens),
|
|
|
|
1 => Ok(AuthorityType::FreezeAccount),
|
|
|
|
2 => Ok(AuthorityType::AccountHolder),
|
2020-08-25 20:36:35 -07:00
|
|
|
3 => Ok(AuthorityType::CloseAccount),
|
2020-08-25 13:24:11 -07:00
|
|
|
_ => Err(TokenError::InvalidInstruction.into()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-14 14:13:35 -07:00
|
|
|
/// Creates a 'InitializeMint' instruction.
|
|
|
|
pub fn initialize_mint(
|
|
|
|
token_program_id: &Pubkey,
|
|
|
|
mint_pubkey: &Pubkey,
|
2020-08-26 17:27:44 -07:00
|
|
|
mint_authority_pubkey: &Pubkey,
|
2020-08-25 13:24:11 -07:00
|
|
|
freeze_authority_pubkey: Option<&Pubkey>,
|
2020-08-14 14:13:35 -07:00
|
|
|
decimals: u8,
|
|
|
|
) -> Result<Instruction, ProgramError> {
|
2020-08-25 13:24:11 -07:00
|
|
|
let freeze_authority = freeze_authority_pubkey.cloned().into();
|
|
|
|
let data = TokenInstruction::InitializeMint {
|
2020-08-26 22:58:42 -07:00
|
|
|
mint_authority: *mint_authority_pubkey,
|
2020-08-25 13:24:11 -07:00
|
|
|
freeze_authority,
|
|
|
|
decimals,
|
|
|
|
}
|
|
|
|
.pack()?;
|
2020-08-14 14:13:35 -07:00
|
|
|
|
2020-08-26 23:29:54 -07:00
|
|
|
let accounts = vec![
|
|
|
|
AccountMeta::new(*mint_pubkey, false),
|
|
|
|
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
|
|
|
];
|
2020-08-14 14:13:35 -07:00
|
|
|
|
|
|
|
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),
|
2020-08-26 23:29:54 -07:00
|
|
|
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
2020-08-14 14:13:35 -07:00
|
|
|
];
|
|
|
|
|
|
|
|
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()?;
|
|
|
|
|
2020-08-26 23:29:54 -07:00
|
|
|
let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
|
2020-08-14 14:13:35 -07:00
|
|
|
accounts.push(AccountMeta::new(*multisig_pubkey, false));
|
2020-08-26 23:29:54 -07:00
|
|
|
accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
|
2020-08-14 14:13:35 -07:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-08-25 13:24:11 -07:00
|
|
|
/// Creates a `SetAuthority` instruction.
|
|
|
|
pub fn set_authority(
|
2020-08-14 14:13:35 -07:00
|
|
|
token_program_id: &Pubkey,
|
|
|
|
owned_pubkey: &Pubkey,
|
2020-08-25 13:24:11 -07:00
|
|
|
new_authority_pubkey: Option<&Pubkey>,
|
|
|
|
authority_type: AuthorityType,
|
2020-08-14 14:13:35 -07:00
|
|
|
owner_pubkey: &Pubkey,
|
|
|
|
signer_pubkeys: &[&Pubkey],
|
|
|
|
) -> Result<Instruction, ProgramError> {
|
2020-08-25 13:24:11 -07:00
|
|
|
let new_authority = new_authority_pubkey.cloned().into();
|
|
|
|
let data = TokenInstruction::SetAuthority {
|
|
|
|
authority_type,
|
|
|
|
new_authority,
|
|
|
|
}
|
|
|
|
.pack()?;
|
2020-08-14 14:13:35 -07:00
|
|
|
|
|
|
|
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,
|
2020-08-27 12:06:23 -07:00
|
|
|
mint_pubkey: &Pubkey,
|
2020-08-14 14:13:35 -07:00
|
|
|
authority_pubkey: &Pubkey,
|
|
|
|
signer_pubkeys: &[&Pubkey],
|
|
|
|
amount: u64,
|
|
|
|
) -> Result<Instruction, ProgramError> {
|
|
|
|
let data = TokenInstruction::Burn { amount }.pack()?;
|
|
|
|
|
2020-08-27 12:06:23 -07:00
|
|
|
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
|
2020-08-14 14:13:35 -07:00
|
|
|
accounts.push(AccountMeta::new(*account_pubkey, false));
|
2020-08-27 12:06:23 -07:00
|
|
|
accounts.push(AccountMeta::new(*mint_pubkey, false));
|
2020-08-14 14:13:35 -07:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-08-25 13:24:11 -07:00
|
|
|
/// 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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-08-14 14:13:35 -07:00
|
|
|
/// 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,
|
2020-08-26 22:58:42 -07:00
|
|
|
mint_authority: Pubkey::new(&[1u8; 32]),
|
2020-08-25 13:24:11 -07:00
|
|
|
freeze_authority: COption::None,
|
2020-08-14 14:13:35 -07:00
|
|
|
};
|
|
|
|
let packed = check.pack().unwrap();
|
2020-08-26 22:58:42 -07:00
|
|
|
let mut expect = Vec::from([0u8, 2]);
|
|
|
|
expect.extend_from_slice(&[1u8; 32]);
|
|
|
|
expect.extend_from_slice(&[0]);
|
2020-08-25 13:24:11 -07:00
|
|
|
assert_eq!(packed, expect);
|
|
|
|
let unpacked = TokenInstruction::unpack(&expect).unwrap();
|
|
|
|
assert_eq!(unpacked, check);
|
|
|
|
|
|
|
|
let check = TokenInstruction::InitializeMint {
|
|
|
|
decimals: 2,
|
2020-08-26 22:58:42 -07:00
|
|
|
mint_authority: Pubkey::new(&[2u8; 32]),
|
2020-08-25 13:24:11 -07:00
|
|
|
freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
|
|
|
|
};
|
|
|
|
let packed = check.pack().unwrap();
|
2020-08-26 17:27:44 -07:00
|
|
|
let mut expect = vec![0u8, 2];
|
2020-08-25 13:24:11 -07:00
|
|
|
expect.extend_from_slice(&[2u8; 32]);
|
|
|
|
expect.extend_from_slice(&[1]);
|
|
|
|
expect.extend_from_slice(&[3u8; 32]);
|
2020-08-14 14:13:35 -07:00
|
|
|
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);
|
|
|
|
|
2020-08-25 13:24:11 -07:00
|
|
|
let check = TokenInstruction::SetAuthority {
|
|
|
|
authority_type: AuthorityType::FreezeAccount,
|
|
|
|
new_authority: COption::Some(Pubkey::new(&[4u8; 32])),
|
|
|
|
};
|
2020-08-14 14:13:35 -07:00
|
|
|
let packed = check.pack().unwrap();
|
2020-08-25 13:24:11 -07:00
|
|
|
let mut expect = Vec::from([6u8, 1]);
|
|
|
|
expect.extend_from_slice(&[1]);
|
|
|
|
expect.extend_from_slice(&[4u8; 32]);
|
2020-08-14 14:13:35 -07:00
|
|
|
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);
|
2020-08-25 13:24:11 -07:00
|
|
|
|
|
|
|
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);
|
2020-08-14 14:13:35 -07:00
|
|
|
}
|
|
|
|
}
|