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:
parent
c2da3dbd48
commit
c00adbe3a7
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue