Add capability to freeze token Accounts (#297)

* Add freeze elements to state structs

* Add can_freeze paramter to InitializeMint instruction, and plumb

* Add fixed_supply parameter to InitializeMint

* Convert to SetAuthority instruction

* Add frozen restrictions

* Add FreezeAccount instruction

* Make FreezeAccount into toggle

* Add parameter to make freezing explicit

* Pass mint owner, freeze_authority as parameters

* Rename ToggleFreeze

* Make AuthorityType more explicit

* Rename mint owner => mint_authority

* Add Account::is_frozen method

* C header updates

* s/is_initialized/state for Account

* Minting nit

* Add helpers to clean up AuthorityType packing

* Split FreezeAccount into 2 instructions

* Pass new_authority as parameter not account

* More C header updates

* Use new COption helpers

* Use boolean for toggle fn
This commit is contained in:
Tyera Eulberg 2020-08-25 14:24:11 -06:00 committed by GitHub
parent c2da3dbd48
commit c00adbe3a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1283 additions and 209 deletions

View File

@ -21,6 +21,85 @@
*/
#define Token_MIN_SIGNERS 1
/**
* Account state.
*/
enum Token_AccountState
#ifdef __cplusplus
: uint8_t
#endif // __cplusplus
{
/**
* Account is not yet initialized
*/
Token_AccountState_Uninitialized,
/**
* Account is initialized; the account owner and/or delegate may perform permitted operations
* on this account
*/
Token_AccountState_Initialized,
/**
* Account has been frozen by the mint freeze authority. Neither the account owner nor
* the delegate are able to perform operations on this account.
*/
Token_AccountState_Frozen,
};
#ifndef __cplusplus
typedef uint8_t Token_AccountState;
#endif // __cplusplus
/**
* Specifies the authority type for SetAuthority instructions
*/
enum Token_AuthorityType
#ifdef __cplusplus
: uint8_t
#endif // __cplusplus
{
/**
* Authority to mint new tokens
*/
Token_AuthorityType_MintTokens,
/**
* Authority to freeze any account associated with the Mint
*/
Token_AuthorityType_FreezeAccount,
/**
* Holder of a given token account
*/
Token_AuthorityType_AccountHolder,
};
#ifndef __cplusplus
typedef uint8_t Token_AuthorityType;
#endif // __cplusplus
typedef uint8_t Token_Pubkey[32];
/**
* A C representation of Rust's `std::option::Option`
*/
typedef enum Token_COption_Pubkey_Tag {
/**
* No value
*/
Token_COption_Pubkey_None_Pubkey,
/**
* Some value `T`
*/
Token_COption_Pubkey_Some_Pubkey,
} Token_COption_Pubkey_Tag;
typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey {
Token_Pubkey _0;
} Token_COption_Pubkey_Token_Some_Body_Pubkey;
typedef struct Token_COption_Pubkey {
Token_COption_Pubkey_Tag tag;
union {
Token_COption_Pubkey_Token_Some_Body_Pubkey some;
};
} Token_COption_Pubkey;
/**
* Instructions supported by the token program.
*/
@ -35,11 +114,7 @@ typedef enum Token_TokenInstruction_Tag {
* Accounts expected by this instruction:
*
* 0. `[writable]` The mint to initialize.
* 1.
* * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens.
* * If supply is zero: `[]` The owner/multisignature of the mint.
* 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if
* present then further minting is supported.
* 1. If supply is non-zero: `[writable]` The account to hold all the newly minted tokens.
*
*/
Token_TokenInstruction_InitializeMint,
@ -127,36 +202,34 @@ typedef enum Token_TokenInstruction_Tag {
*/
Token_TokenInstruction_Revoke,
/**
* Sets a new owner of a mint or account.
* Sets a new authority of a mint or account.
*
* Accounts expected by this instruction:
*
* * Single owner
* 0. `[writable]` The mint or account to change the owner of.
* 1. `[]` The new owner/delegate/multisignature.
* 2. `[signer]` The owner of the mint or account.
* * Single authority
* 0. `[writable]` The mint or account to change the authority of.
* 1. `[signer]` The current authority of the mint or account.
*
* * Multisignature owner
* 0. `[writable]` The mint or account to change the owner of.
* 1. `[]` The new owner/delegate/multisignature.
* 2. `[]` The mint's or account's multisignature owner.
* * Multisignature authority
* 0. `[writable]` The mint or account to change the authority of.
* 1. `[]` The mint's or account's multisignature authority.
* 3. ..3+M '[signer]' M signer accounts
*/
Token_TokenInstruction_SetOwner,
Token_TokenInstruction_SetAuthority,
/**
* Mints new tokens to an account. The native mint does not support minting.
*
* Accounts expected by this instruction:
*
* * Single owner
* * Single authority
* 0. `[writable]` The mint.
* 1. `[writable]` The account to mint tokens to.
* 2. `[signer]` The mint's owner.
* 2. `[signer]` The mint's minting authority.
*
* * Multisignature owner
* * Multisignature authority
* 0. `[writable]` The mint.
* 1. `[writable]` The account to mint tokens to.
* 2. `[]` The mint's multisignature owner.
* 2. `[]` The mint's multisignature mint-tokens authority.
* 3. ..3+M '[signer]' M signer accounts.
*/
Token_TokenInstruction_MintTo,
@ -194,6 +267,40 @@ typedef enum Token_TokenInstruction_Tag {
* 3. ..3+M '[signer]' M signer accounts.
*/
Token_TokenInstruction_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.
*/
Token_TokenInstruction_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.
*/
Token_TokenInstruction_ThawAccount,
} Token_TokenInstruction_Tag;
typedef struct Token_TokenInstruction_Token_InitializeMint_Body {
@ -205,6 +312,15 @@ typedef struct Token_TokenInstruction_Token_InitializeMint_Body {
* Number of base 10 digits to the right of the decimal place.
*/
uint8_t decimals;
/**
* The authority/multisignature to mint tokens, if supply is non-zero. If present,
* further minting is supported.
*/
Token_COption_Pubkey mint_authority;
/**
* The freeze authority/multisignature of the mint.
*/
Token_COption_Pubkey freeze_authority;
} Token_TokenInstruction_Token_InitializeMint_Body;
typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body {
@ -228,6 +344,17 @@ typedef struct Token_TokenInstruction_Token_Approve_Body {
uint64_t amount;
} Token_TokenInstruction_Token_Approve_Body;
typedef struct Token_TokenInstruction_Token_SetAuthority_Body {
/**
* The type of authority to update.
*/
Token_AuthorityType authority_type;
/**
* The new authority
*/
Token_COption_Pubkey new_authority;
} Token_TokenInstruction_Token_SetAuthority_Body;
typedef struct Token_TokenInstruction_Token_MintTo_Body {
/**
* The amount of new tokens to mint.
@ -249,48 +376,22 @@ typedef struct Token_TokenInstruction {
Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig;
Token_TokenInstruction_Token_Transfer_Body transfer;
Token_TokenInstruction_Token_Approve_Body approve;
Token_TokenInstruction_Token_SetAuthority_Body set_authority;
Token_TokenInstruction_Token_MintTo_Body mint_to;
Token_TokenInstruction_Token_Burn_Body burn;
};
} Token_TokenInstruction;
typedef uint8_t Token_Pubkey[32];
/**
* A C representation of Rust's `std::option::Option`
*/
typedef enum Token_COption_Pubkey_Tag {
/**
* No value
*/
Token_COption_Pubkey_None_Pubkey,
/**
* Some value `T`
*/
Token_COption_Pubkey_Some_Pubkey,
} Token_COption_Pubkey_Tag;
typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey {
Token_Pubkey _0;
} Token_COption_Pubkey_Token_Some_Body_Pubkey;
typedef struct Token_COption_Pubkey {
Token_COption_Pubkey_Tag tag;
union {
Token_COption_Pubkey_Token_Some_Body_Pubkey some;
};
} Token_COption_Pubkey;
/**
* Mint data.
*/
typedef struct Token_Mint {
/**
* Optional owner, used to mint new tokens. The owner may only
* be provided during mint creation. If no owner is present then the mint
* has a fixed supply and no further tokens may be minted.
* Optional authority used to mint new tokens. The mint authority may only be provided during
* mint creation. If no mint authority is present then the mint has a fixed supply and no
* further tokens may be minted.
*/
Token_COption_Pubkey owner;
Token_COption_Pubkey mint_authority;
/**
* Number of base 10 digits to the right of the decimal place.
*/
@ -299,6 +400,10 @@ typedef struct Token_Mint {
* Is `true` if this structure has been initialized
*/
bool is_initialized;
/**
* Optional authority to freeze token accounts.
*/
Token_COption_Pubkey freeze_authority;
} Token_Mint;
/**
@ -323,9 +428,9 @@ typedef struct Token_Account {
*/
Token_COption_Pubkey delegate;
/**
* Is `true` if this structure has been initialized
* The account's state
*/
bool is_initialized;
Token_AccountState state;
/**
* Is this a native token
*/

View File

@ -43,9 +43,21 @@ pub enum TokenError {
/// Invalid instruction
#[error("Invalid instruction")]
InvalidInstruction,
/// State is invalid for requested operation.
#[error("State is invalid for requested operation")]
InvalidState,
/// Operation overflowed
#[error("Operation overflowed")]
Overflow,
/// Account does not support specified authority type.
#[error("Account does not support specified authority type")]
AuthorityTypeNotSupported,
/// This token mint cannot freeze accounts.
#[error("This token mint cannot freeze accounts")]
MintCannotFreeze,
/// Account is frozen; all account operations will fail
#[error("Account is frozen")]
AccountFrozen,
}
impl From<TokenError> for ProgramError {
fn from(e: TokenError) -> Self {

View File

@ -1,6 +1,6 @@
//! Instruction types
use crate::error::TokenError;
use crate::{error::TokenError, option::COption};
use solana_sdk::{
instruction::{AccountMeta, Instruction},
program_error::ProgramError,
@ -26,17 +26,18 @@ pub enum TokenInstruction {
/// Accounts expected by this instruction:
///
/// 0. `[writable]` The mint to initialize.
/// 1.
/// * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens.
/// * If supply is zero: `[]` The owner/multisignature of the mint.
/// 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if
/// present then further minting is supported.
/// 1. If supply is non-zero: `[writable]` The account to hold all the newly minted tokens.
///
InitializeMint {
/// Initial amount of tokens to mint.
amount: u64,
/// Number of base 10 digits to the right of the decimal place.
decimals: u8,
/// The authority/multisignature to mint tokens, if supply is non-zero. If present,
/// further minting is supported.
mint_authority: COption<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.
@ -121,34 +122,37 @@ pub enum TokenInstruction {
/// 1. '[]' The source account's multisignature owner.
/// 2. ..2+M '[signer]' M signer accounts
Revoke,
/// Sets a new owner of a mint or account.
/// Sets a new authority of a mint or account.
///
/// Accounts expected by this instruction:
///
/// * Single owner
/// 0. `[writable]` The mint or account to change the owner of.
/// 1. `[]` The new owner/delegate/multisignature.
/// 2. `[signer]` The owner of the mint or account.
/// * Single authority
/// 0. `[writable]` The mint or account to change the authority of.
/// 1. `[signer]` The current authority of the mint or account.
///
/// * Multisignature owner
/// 0. `[writable]` The mint or account to change the owner of.
/// 1. `[]` The new owner/delegate/multisignature.
/// 2. `[]` The mint's or account's multisignature owner.
/// * Multisignature authority
/// 0. `[writable]` The mint or account to change the authority of.
/// 1. `[]` The mint's or account's multisignature authority.
/// 3. ..3+M '[signer]' M signer accounts
SetOwner,
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 owner
/// * Single authority
/// 0. `[writable]` The mint.
/// 1. `[writable]` The account to mint tokens to.
/// 2. `[signer]` The mint's owner.
/// 2. `[signer]` The mint's minting authority.
///
/// * Multisignature owner
/// * Multisignature authority
/// 0. `[writable]` The mint.
/// 1. `[writable]` The account to mint tokens to.
/// 2. `[]` The mint's multisignature owner.
/// 2. `[]` The mint's multisignature mint-tokens authority.
/// 3. ..3+M '[signer]' M signer accounts.
MintTo {
/// The amount of new tokens to mint.
@ -187,6 +191,36 @@ pub enum TokenInstruction {
/// 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,
}
impl TokenInstruction {
/// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html).
@ -196,14 +230,37 @@ impl TokenInstruction {
}
Ok(match input[0] {
0 => {
if input.len() < size_of::<u8>() + size_of::<u64>() + size_of::<u8>() {
if input.len()
< size_of::<u8>() + size_of::<u64>() + size_of::<u8>() + size_of::<bool>()
{
return Err(TokenError::InvalidInstruction.into());
}
let mut input_len = 0;
input_len += size_of::<u8>();
#[allow(clippy::cast_ptr_alignment)]
let amount = unsafe { *(&input[size_of::<u8>()] as *const u8 as *const u64) };
let decimals =
unsafe { *(&input[size_of::<u8>() + size_of::<u64>()] as *const u8) };
Self::InitializeMint { amount, decimals }
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) };
input_len += size_of::<u8>();
let mint_authority = COption::unpack_or(
input,
&mut input_len,
Into::<ProgramError>::into(TokenError::InvalidInstruction),
)?;
let freeze_authority = COption::unpack_or(
input,
&mut input_len,
Into::<ProgramError>::into(TokenError::InvalidInstruction),
)?;
Self::InitializeMint {
mint_authority,
freeze_authority,
amount,
decimals,
}
}
1 => Self::InitializeAccount,
2 => {
@ -231,7 +288,26 @@ impl TokenInstruction {
Self::Approve { amount }
}
5 => Self::Revoke,
6 => Self::SetOwner,
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());
@ -249,6 +325,8 @@ impl TokenInstruction {
Self::Burn { amount }
}
9 => Self::CloseAccount,
10 => Self::FreezeAccount,
11 => Self::ThawAccount,
_ => return Err(TokenError::InvalidInstruction.into()),
})
}
@ -258,7 +336,12 @@ impl TokenInstruction {
let mut output = vec![0u8; size_of::<TokenInstruction>()];
let mut output_len = 0;
match self {
Self::InitializeMint { amount, decimals } => {
Self::InitializeMint {
mint_authority,
freeze_authority,
amount,
decimals,
} => {
output[output_len] = 0;
output_len += size_of::<u8>();
@ -270,6 +353,9 @@ impl TokenInstruction {
let value = unsafe { &mut *(&mut output[output_len] as *mut u8) };
*value = *decimals;
output_len += size_of::<u8>();
mint_authority.pack(&mut output, &mut output_len);
freeze_authority.pack(&mut output, &mut output_len);
}
Self::InitializeAccount => {
output[output_len] = 1;
@ -306,9 +392,17 @@ impl TokenInstruction {
output[output_len] = 5;
output_len += size_of::<u8>();
}
Self::SetOwner => {
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;
@ -332,6 +426,14 @@ impl TokenInstruction {
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>();
}
}
output.truncate(output_len);
@ -339,16 +441,56 @@ impl TokenInstruction {
}
}
/// 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,
}
impl AuthorityType {
fn into(&self) -> u8 {
match self {
AuthorityType::MintTokens => 0,
AuthorityType::FreezeAccount => 1,
AuthorityType::AccountHolder => 2,
}
}
fn from(index: u8) -> Result<Self, ProgramError> {
match index {
0 => Ok(AuthorityType::MintTokens),
1 => Ok(AuthorityType::FreezeAccount),
2 => Ok(AuthorityType::AccountHolder),
_ => Err(TokenError::InvalidInstruction.into()),
}
}
}
/// Creates a 'InitializeMint' instruction.
pub fn initialize_mint(
token_program_id: &Pubkey,
mint_pubkey: &Pubkey,
account_pubkey: Option<&Pubkey>,
owner_pubkey: Option<&Pubkey>,
mint_authority_pubkey: Option<&Pubkey>,
freeze_authority_pubkey: Option<&Pubkey>,
amount: u64,
decimals: u8,
) -> Result<Instruction, ProgramError> {
let data = TokenInstruction::InitializeMint { amount, decimals }.pack()?;
let mint_authority = mint_authority_pubkey.cloned().into();
let freeze_authority = freeze_authority_pubkey.cloned().into();
let data = TokenInstruction::InitializeMint {
mint_authority,
freeze_authority,
amount,
decimals,
}
.pack()?;
let mut accounts = vec![AccountMeta::new(*mint_pubkey, false)];
if amount != 0 {
@ -359,14 +501,6 @@ pub fn initialize_mint(
}
}
}
match owner_pubkey {
Some(pubkey) => accounts.push(AccountMeta::new_readonly(*pubkey, false)),
None => {
if amount == 0 {
return Err(TokenError::OwnerRequiredIfNoInitialSupply.into());
}
}
}
Ok(Instruction {
program_id: *token_program_id,
@ -509,19 +643,24 @@ pub fn revoke(
})
}
/// Creates a `SetOwner` instruction.
pub fn set_owner(
/// Creates a `SetAuthority` instruction.
pub fn set_authority(
token_program_id: &Pubkey,
owned_pubkey: &Pubkey,
new_owner_pubkey: &Pubkey,
new_authority_pubkey: Option<&Pubkey>,
authority_type: AuthorityType,
owner_pubkey: &Pubkey,
signer_pubkeys: &[&Pubkey],
) -> Result<Instruction, ProgramError> {
let data = TokenInstruction::SetOwner.pack()?;
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(*new_owner_pubkey, false));
accounts.push(AccountMeta::new_readonly(
*owner_pubkey,
signer_pubkeys.is_empty(),
@ -621,6 +760,62 @@ pub fn close_account(
})
}
/// 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,
})
}
/// 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)
@ -635,9 +830,27 @@ mod test {
let check = TokenInstruction::InitializeMint {
amount: 1,
decimals: 2,
mint_authority: COption::None,
freeze_authority: COption::None,
};
let packed = check.pack().unwrap();
let expect = Vec::from([0u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
let expect = Vec::from([0u8, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]);
assert_eq!(packed, expect);
let unpacked = TokenInstruction::unpack(&expect).unwrap();
assert_eq!(unpacked, check);
let check = TokenInstruction::InitializeMint {
amount: 1,
decimals: 2,
mint_authority: COption::Some(Pubkey::new(&[2u8; 32])),
freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
};
let packed = check.pack().unwrap();
let mut expect = vec![0u8, 1, 0, 0, 0, 0, 0, 0, 0, 2];
expect.extend_from_slice(&[1]);
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);
@ -677,9 +890,14 @@ mod test {
let unpacked = TokenInstruction::unpack(&expect).unwrap();
assert_eq!(unpacked, check);
let check = TokenInstruction::SetOwner;
let check = TokenInstruction::SetAuthority {
authority_type: AuthorityType::FreezeAccount,
new_authority: COption::Some(Pubkey::new(&[4u8; 32])),
};
let packed = check.pack().unwrap();
let expect = Vec::from([6u8]);
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);
@ -704,5 +922,19 @@ mod test {
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);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -8,14 +8,16 @@ use std::mem::size_of;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Mint {
/// Optional owner, used to mint new tokens. The owner may only
/// be provided during mint creation. If no owner is present then the mint
/// has a fixed supply and no further tokens may be minted.
pub owner: COption<Pubkey>,
/// Optional authority used to mint new tokens. The mint authority may only be provided during
/// mint creation. If no mint authority is present then the mint has a fixed supply and no
/// further tokens may be minted.
pub mint_authority: COption<Pubkey>,
/// Number of base 10 digits to the right of the decimal place.
pub decimals: u8,
/// Is `true` if this structure has been initialized
pub is_initialized: bool,
/// Optional authority to freeze token accounts.
pub freeze_authority: COption<Pubkey>,
}
impl IsInitialized for Mint {
fn is_initialized(&self) -> bool {
@ -36,16 +38,42 @@ pub struct Account {
/// If `delegate` is `Some` then `delegated_amount` represents
/// the amount authorized by the delegate
pub delegate: COption<Pubkey>,
/// Is `true` if this structure has been initialized
pub is_initialized: bool,
/// The account's state
pub state: AccountState,
/// Is this a native token
pub is_native: bool,
/// The amount delegated
pub delegated_amount: u64,
}
impl Account {
/// Checks if account is frozen
pub fn is_frozen(&self) -> bool {
self.state == AccountState::Frozen
}
}
impl IsInitialized for Account {
fn is_initialized(&self) -> bool {
self.is_initialized
self.state != AccountState::Uninitialized
}
}
/// Account state.
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AccountState {
/// Account is not yet initialized
Uninitialized,
/// Account is initialized; the account owner and/or delegate may perform permitted operations
/// on this account
Initialized,
/// Account has been frozen by the mint freeze authority. Neither the account owner nor
/// the delegate are able to perform operations on this account.
Frozen,
}
impl Default for AccountState {
fn default() -> Self {
AccountState::Uninitialized
}
}