Remove token 1.0
This commit is contained in:
parent
ea52428475
commit
20b6ee04a3
|
@ -1,34 +0,0 @@
|
|||
|
||||
# Note: This crate must be built using do.sh
|
||||
|
||||
[package]
|
||||
name = "spl-token"
|
||||
version = "1.0.8"
|
||||
description = "Solana Program Library Token"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana-program-library"
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
exclude = ["js/**"]
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
skip-no-mangle = ["solana-sdk/skip-no-mangle"]
|
||||
program = ["solana-sdk/program"]
|
||||
default = ["solana-sdk/default"]
|
||||
|
||||
[dependencies]
|
||||
num-derive = "0.3"
|
||||
num-traits = "0.2"
|
||||
remove_dir_all = "=0.5.0"
|
||||
solana-sdk = { version = "1.3.4", default-features = false, optional = true }
|
||||
thiserror = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "0.7.0"}
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "=0.14.2"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
|
@ -1,2 +0,0 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -1,65 +0,0 @@
|
|||
extern crate cbindgen;
|
||||
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-env-changed=SPL_CBINDGEN");
|
||||
println!("cargo:rerun-if-changed=inc/token.h");
|
||||
if std::path::Path::new("inc/token.h").exists() && env::var("SPL_CBINDGEN").is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
println!("cargo:warning=Generating inc/token.h");
|
||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
let config = cbindgen::Config {
|
||||
header: Some("/* Autogenerated SPL Token program C Bindings */".to_string()),
|
||||
after_includes: Some(format!(
|
||||
"{}{}{}",
|
||||
format!(
|
||||
"\n#define TOKEN_MAJOR_VERSION {}",
|
||||
env!("CARGO_PKG_VERSION_MAJOR")
|
||||
),
|
||||
format!(
|
||||
"\n#define TOKEN_MINOR_VERSION {}",
|
||||
env!("CARGO_PKG_VERSION_MINOR")
|
||||
),
|
||||
format!(
|
||||
"\n#define TOKEN_PATCH_VERSION {}",
|
||||
env!("CARGO_PKG_VERSION_PATCH")
|
||||
)
|
||||
)),
|
||||
language: cbindgen::Language::C,
|
||||
line_length: 80,
|
||||
style: cbindgen::Style::Both,
|
||||
tab_width: 4,
|
||||
cpp_compat: true,
|
||||
pragma_once: true,
|
||||
enumeration: cbindgen::EnumConfig {
|
||||
prefix_with_name: true,
|
||||
..cbindgen::EnumConfig::default()
|
||||
},
|
||||
export: cbindgen::ExportConfig {
|
||||
prefix: Some("Token_".to_string()),
|
||||
include: vec![
|
||||
"TokenInstruction".to_string(),
|
||||
"Mint".to_string(),
|
||||
"Account".to_string(),
|
||||
"Multisig".to_string(),
|
||||
],
|
||||
exclude: vec!["DECIMALS".to_string()],
|
||||
..cbindgen::ExportConfig::default()
|
||||
},
|
||||
parse: cbindgen::ParseConfig {
|
||||
parse_deps: true,
|
||||
include: Some(vec!["solana-sdk".to_string()]),
|
||||
..cbindgen::ParseConfig::default()
|
||||
},
|
||||
..cbindgen::Config::default()
|
||||
};
|
||||
cbindgen::Builder::new()
|
||||
.with_crate(crate_dir)
|
||||
.with_config(config)
|
||||
.generate()
|
||||
.unwrap()
|
||||
.write_to_file("inc/token.h");
|
||||
}
|
|
@ -1,359 +0,0 @@
|
|||
/* Autogenerated SPL Token program C Bindings */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TOKEN_MAJOR_VERSION 1
|
||||
#define TOKEN_MINOR_VERSION 0
|
||||
#define TOKEN_PATCH_VERSION 8
|
||||
|
||||
/**
|
||||
* Maximum number of multisignature signers (max N)
|
||||
*/
|
||||
#define Token_MAX_SIGNERS 11
|
||||
|
||||
/**
|
||||
* Minimum number of multisignature signers (min N)
|
||||
*/
|
||||
#define Token_MIN_SIGNERS 1
|
||||
|
||||
/**
|
||||
* Instructions supported by the token program.
|
||||
*/
|
||||
typedef enum Token_TokenInstruction_Tag {
|
||||
/**
|
||||
* Initializes a new mint and optionally deposits all the newly minted tokens in an account.
|
||||
*
|
||||
* The `InitializeMint` instruction requires no signers and MUST be included within
|
||||
* the same Transaction as the system program's `CreateInstruction` that creates the account
|
||||
* being initialized. Otherwise another party can acquire ownership of the uninitialized account.
|
||||
*
|
||||
* Accounts expected by this instruction:
|
||||
*
|
||||
* 0. `[writable]` The mint to initialize.
|
||||
* 1.
|
||||
* * 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.
|
||||
*
|
||||
*/
|
||||
Token_TokenInstruction_InitializeMint,
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
Token_TokenInstruction_InitializeAccount,
|
||||
/**
|
||||
* Initializes a multisignature account with N provided signers.
|
||||
*
|
||||
* Multisignature accounts can used in place of any single owner/delegate accounts in any
|
||||
* token instruction that require an owner/delegate to be present. The variant field represents the
|
||||
* number of signers (M) required to validate this multisignature account.
|
||||
*
|
||||
* The `InitializeMultisig` instruction requires no signers and MUST be included within
|
||||
* the same Transaction as the system program's `CreateInstruction` that creates the account
|
||||
* being initialized. Otherwise another party can acquire ownership of the uninitialized account.
|
||||
*
|
||||
* Accounts expected by this instruction:
|
||||
*
|
||||
* 0. `[writable]` The multisignature account to initialize.
|
||||
* 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11.
|
||||
*/
|
||||
Token_TokenInstruction_InitializeMultisig,
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
Token_TokenInstruction_Transfer,
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
Token_TokenInstruction_Approve,
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
Token_TokenInstruction_Revoke,
|
||||
/**
|
||||
* Sets a new owner 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.
|
||||
*
|
||||
* * 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.
|
||||
* 3. ..3+M '[signer]' M signer accounts
|
||||
*/
|
||||
Token_TokenInstruction_SetOwner,
|
||||
/**
|
||||
* Mints new tokens to an account. The native mint does not support minting.
|
||||
*
|
||||
* Accounts expected by this instruction:
|
||||
*
|
||||
* * Single owner
|
||||
* 0. `[writable]` The mint.
|
||||
* 1. `[writable]` The account to mint tokens to.
|
||||
* 2. `[signer]` The mint's owner.
|
||||
*
|
||||
* * Multisignature owner
|
||||
* 0. `[writable]` The mint.
|
||||
* 1. `[writable]` The account to mint tokens to.
|
||||
* 2. `[]` The mint's multisignature owner.
|
||||
* 3. ..3+M '[signer]' M signer accounts.
|
||||
*/
|
||||
Token_TokenInstruction_MintTo,
|
||||
/**
|
||||
* Burns tokens by removing them from an account. `Burn` does not support accounts
|
||||
* associated with the native mint, use `CloseAccount` instead.
|
||||
*
|
||||
* Accounts expected by this instruction:
|
||||
*
|
||||
* * Single owner/delegate
|
||||
* 0. `[writable]` The account to burn from.
|
||||
* 1. `[signer]` The account's owner/delegate.
|
||||
*
|
||||
* * Multisignature owner/delegate
|
||||
* 0. `[writable]` The account to burn from.
|
||||
* 1. `[]` The account's multisignature owner/delegate.
|
||||
* 2. ..2+M '[signer]' M signer accounts.
|
||||
*/
|
||||
Token_TokenInstruction_Burn,
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
Token_TokenInstruction_CloseAccount,
|
||||
} Token_TokenInstruction_Tag;
|
||||
|
||||
typedef struct Token_TokenInstruction_Token_InitializeMint_Body {
|
||||
/**
|
||||
* Initial amount of tokens to mint.
|
||||
*/
|
||||
uint64_t amount;
|
||||
/**
|
||||
* Number of base 10 digits to the right of the decimal place.
|
||||
*/
|
||||
uint8_t decimals;
|
||||
} Token_TokenInstruction_Token_InitializeMint_Body;
|
||||
|
||||
typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body {
|
||||
/**
|
||||
* The number of signers (M) required to validate this multisignature account.
|
||||
*/
|
||||
uint8_t m;
|
||||
} Token_TokenInstruction_Token_InitializeMultisig_Body;
|
||||
|
||||
typedef struct Token_TokenInstruction_Token_Transfer_Body {
|
||||
/**
|
||||
* The amount of tokens to transfer.
|
||||
*/
|
||||
uint64_t amount;
|
||||
} Token_TokenInstruction_Token_Transfer_Body;
|
||||
|
||||
typedef struct Token_TokenInstruction_Token_Approve_Body {
|
||||
/**
|
||||
* The amount of tokens the delegate is approved for.
|
||||
*/
|
||||
uint64_t amount;
|
||||
} Token_TokenInstruction_Token_Approve_Body;
|
||||
|
||||
typedef struct Token_TokenInstruction_Token_MintTo_Body {
|
||||
/**
|
||||
* The amount of new tokens to mint.
|
||||
*/
|
||||
uint64_t amount;
|
||||
} Token_TokenInstruction_Token_MintTo_Body;
|
||||
|
||||
typedef struct Token_TokenInstruction_Token_Burn_Body {
|
||||
/**
|
||||
* The amount of tokens to burn.
|
||||
*/
|
||||
uint64_t amount;
|
||||
} Token_TokenInstruction_Token_Burn_Body;
|
||||
|
||||
typedef struct Token_TokenInstruction {
|
||||
Token_TokenInstruction_Tag tag;
|
||||
union {
|
||||
Token_TokenInstruction_Token_InitializeMint_Body initialize_mint;
|
||||
Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig;
|
||||
Token_TokenInstruction_Token_Transfer_Body transfer;
|
||||
Token_TokenInstruction_Token_Approve_Body approve;
|
||||
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.
|
||||
*/
|
||||
Token_COption_Pubkey owner;
|
||||
/**
|
||||
* Number of base 10 digits to the right of the decimal place.
|
||||
*/
|
||||
uint8_t decimals;
|
||||
/**
|
||||
* Is `true` if this structure has been initialized
|
||||
*/
|
||||
bool is_initialized;
|
||||
} Token_Mint;
|
||||
|
||||
/**
|
||||
* Account data.
|
||||
*/
|
||||
typedef struct Token_Account {
|
||||
/**
|
||||
* The mint associated with this account
|
||||
*/
|
||||
Token_Pubkey mint;
|
||||
/**
|
||||
* The owner of this account.
|
||||
*/
|
||||
Token_Pubkey owner;
|
||||
/**
|
||||
* The amount of tokens this account holds.
|
||||
*/
|
||||
uint64_t amount;
|
||||
/**
|
||||
* If `delegate` is `Some` then `delegated_amount` represents
|
||||
* the amount authorized by the delegate
|
||||
*/
|
||||
Token_COption_Pubkey delegate;
|
||||
/**
|
||||
* Is `true` if this structure has been initialized
|
||||
*/
|
||||
bool is_initialized;
|
||||
/**
|
||||
* Is this a native token
|
||||
*/
|
||||
bool is_native;
|
||||
/**
|
||||
* The amount delegated
|
||||
*/
|
||||
uint64_t delegated_amount;
|
||||
} Token_Account;
|
||||
|
||||
/**
|
||||
* Multisignature data.
|
||||
*/
|
||||
typedef struct Token_Multisig {
|
||||
/**
|
||||
* Number of signers required
|
||||
*/
|
||||
uint8_t m;
|
||||
/**
|
||||
* Number of valid signers
|
||||
*/
|
||||
uint8_t n;
|
||||
/**
|
||||
* Is `true` if this structure has been initialized
|
||||
*/
|
||||
bool is_initialized;
|
||||
/**
|
||||
* Signer public keys
|
||||
*/
|
||||
Token_Pubkey signers[Token_MAX_SIGNERS];
|
||||
} Token_Multisig;
|
|
@ -1 +0,0 @@
|
|||
TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o
|
|
@ -1,24 +0,0 @@
|
|||
//! Program entrypoint
|
||||
|
||||
#![cfg(feature = "program")]
|
||||
#![cfg(not(feature = "no-entrypoint"))]
|
||||
|
||||
use crate::{error::TokenError, processor::Processor};
|
||||
use solana_sdk::{
|
||||
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult,
|
||||
program_error::PrintProgramError, pubkey::Pubkey,
|
||||
};
|
||||
|
||||
entrypoint!(process_instruction);
|
||||
fn process_instruction<'a>(
|
||||
program_id: &Pubkey,
|
||||
accounts: &'a [AccountInfo<'a>],
|
||||
instruction_data: &[u8],
|
||||
) -> ProgramResult {
|
||||
if let Err(error) = Processor::process(program_id, accounts, instruction_data) {
|
||||
// catch the error so we can print it
|
||||
error.print::<TokenError>();
|
||||
return Err(error);
|
||||
}
|
||||
Ok(())
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
//! Error types
|
||||
|
||||
use num_derive::FromPrimitive;
|
||||
use solana_sdk::{decode_error::DecodeError, program_error::ProgramError};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors that may be returned by the Token program.
|
||||
#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)]
|
||||
pub enum TokenError {
|
||||
/// Insufficient funds for the operation requested.
|
||||
#[error("Insufficient funds")]
|
||||
InsufficientFunds,
|
||||
/// Account not associated with this Mint.
|
||||
#[error("Account not associated with this Mint")]
|
||||
MintMismatch,
|
||||
/// Owner does not match.
|
||||
#[error("Owner does not match")]
|
||||
OwnerMismatch,
|
||||
/// This token's supply is fixed and new tokens cannot be minted.
|
||||
#[error("Fixed supply")]
|
||||
FixedSupply,
|
||||
/// The account cannot be initialized because it is already being used.
|
||||
#[error("AlreadyInUse")]
|
||||
AlreadyInUse,
|
||||
/// An owner is required if initial supply is zero.
|
||||
#[error("An owner is required if supply is zero")]
|
||||
OwnerRequiredIfNoInitialSupply,
|
||||
/// Invalid number of provided signers.
|
||||
#[error("Invalid number of provided signers")]
|
||||
InvalidNumberOfProvidedSigners,
|
||||
/// Invalid number of required signers.
|
||||
#[error("Invalid number of required signers")]
|
||||
InvalidNumberOfRequiredSigners,
|
||||
/// State is uninitialized.
|
||||
#[error("State is unititialized")]
|
||||
UninitializedState,
|
||||
/// Instruction does not support native tokens
|
||||
#[error("Instruction does not support native tokens")]
|
||||
NativeNotSupported,
|
||||
/// Instruction does not support non-native tokens
|
||||
#[error("Instruction does not support non-native tokens")]
|
||||
NonNativeNotSupported,
|
||||
/// Invalid instruction
|
||||
#[error("Invalid instruction")]
|
||||
InvalidInstruction,
|
||||
/// Operation overflowed
|
||||
#[error("Operation overflowed")]
|
||||
Overflow,
|
||||
}
|
||||
impl From<TokenError> for ProgramError {
|
||||
fn from(e: TokenError) -> Self {
|
||||
ProgramError::Custom(e as u32)
|
||||
}
|
||||
}
|
||||
impl<T> DecodeError<T> for TokenError {
|
||||
fn type_of() -> &'static str {
|
||||
"TokenError"
|
||||
}
|
||||
}
|
|
@ -1,708 +0,0 @@
|
|||
//! Instruction types
|
||||
|
||||
use crate::error::TokenError;
|
||||
use solana_sdk::{
|
||||
instruction::{AccountMeta, Instruction},
|
||||
program_error::ProgramError,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
use std::mem::size_of;
|
||||
|
||||
/// Minimum number of multisignature signers (min N)
|
||||
pub const MIN_SIGNERS: usize = 1;
|
||||
/// Maximum number of multisignature signers (max N)
|
||||
pub const MAX_SIGNERS: usize = 11;
|
||||
|
||||
/// Instructions supported by the token program.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum TokenInstruction {
|
||||
/// Initializes a new mint and optionally deposits all the newly minted tokens in an account.
|
||||
///
|
||||
/// The `InitializeMint` instruction requires no signers and MUST be included within
|
||||
/// the same Transaction as the system program's `CreateInstruction` that creates the account
|
||||
/// being initialized. Otherwise another party can acquire ownership of the uninitialized account.
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// 0. `[writable]` The mint to initialize.
|
||||
/// 1.
|
||||
/// * 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.
|
||||
///
|
||||
InitializeMint {
|
||||
/// Initial amount of tokens to mint.
|
||||
amount: u64,
|
||||
/// Number of base 10 digits to the right of the decimal place.
|
||||
decimals: u8,
|
||||
},
|
||||
/// 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.
|
||||
///
|
||||
/// 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.
|
||||
InitializeAccount,
|
||||
/// Initializes a multisignature account with N provided signers.
|
||||
///
|
||||
/// Multisignature accounts can used in place of any single owner/delegate accounts in any
|
||||
/// token instruction that require an owner/delegate to be present. The variant field represents the
|
||||
/// number of signers (M) required to validate this multisignature account.
|
||||
///
|
||||
/// The `InitializeMultisig` instruction requires no signers and MUST be included within
|
||||
/// the same Transaction as the system program's `CreateInstruction` that creates the account
|
||||
/// being initialized. Otherwise another party can acquire ownership of the uninitialized account.
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// 0. `[writable]` The multisignature account to initialize.
|
||||
/// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11.
|
||||
InitializeMultisig {
|
||||
/// The number of signers (M) required to validate this multisignature account.
|
||||
m: u8,
|
||||
},
|
||||
/// Transfers tokens from one account to another either directly or via a delegate. If this
|
||||
/// account is associated with the native mint then equal amounts of SOL and Tokens will be
|
||||
/// transferred to the destination account.
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// * Single owner/delegate
|
||||
/// 0. `[writable]` The source account.
|
||||
/// 1. `[writable]` The destination account.
|
||||
/// 2. '[signer]' The source account's owner/delegate.
|
||||
///
|
||||
/// * Multisignature owner/delegate
|
||||
/// 0. `[writable]` The source account.
|
||||
/// 1. `[writable]` The destination account.
|
||||
/// 2. '[]' The source account's multisignature owner/delegate.
|
||||
/// 3. ..3+M '[signer]' M signer accounts.
|
||||
Transfer {
|
||||
/// The amount of tokens to transfer.
|
||||
amount: u64,
|
||||
},
|
||||
/// Approves a delegate. A delegate is given the authority over
|
||||
/// tokens on behalf of the source account's owner.
|
||||
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// * Single owner
|
||||
/// 0. `[writable]` The source account.
|
||||
/// 1. `[]` The delegate.
|
||||
/// 2. `[signer]` The source account owner.
|
||||
///
|
||||
/// * Multisignature owner
|
||||
/// 0. `[writable]` The source account.
|
||||
/// 1. `[]` The delegate.
|
||||
/// 2. '[]' The source account's multisignature owner.
|
||||
/// 3. ..3+M '[signer]' M signer accounts
|
||||
Approve {
|
||||
/// The amount of tokens the delegate is approved for.
|
||||
amount: u64,
|
||||
},
|
||||
/// Revokes the delegate's authority.
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// * Single owner
|
||||
/// 0. `[writable]` The source account.
|
||||
/// 1. `[signer]` The source account owner.
|
||||
///
|
||||
/// * Multisignature owner
|
||||
/// 0. `[writable]` The source account.
|
||||
/// 1. '[]' The source account's multisignature owner.
|
||||
/// 2. ..2+M '[signer]' M signer accounts
|
||||
Revoke,
|
||||
/// Sets a new owner 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.
|
||||
///
|
||||
/// * 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.
|
||||
/// 3. ..3+M '[signer]' M signer accounts
|
||||
SetOwner,
|
||||
/// Mints new tokens to an account. The native mint does not support minting.
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// * Single owner
|
||||
/// 0. `[writable]` The mint.
|
||||
/// 1. `[writable]` The account to mint tokens to.
|
||||
/// 2. `[signer]` The mint's owner.
|
||||
///
|
||||
/// * Multisignature owner
|
||||
/// 0. `[writable]` The mint.
|
||||
/// 1. `[writable]` The account to mint tokens to.
|
||||
/// 2. `[]` The mint's multisignature owner.
|
||||
/// 3. ..3+M '[signer]' M signer accounts.
|
||||
MintTo {
|
||||
/// The amount of new tokens to mint.
|
||||
amount: u64,
|
||||
},
|
||||
/// Burns tokens by removing them from an account. `Burn` does not support accounts
|
||||
/// associated with the native mint, use `CloseAccount` instead.
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// * Single owner/delegate
|
||||
/// 0. `[writable]` The account to burn from.
|
||||
/// 1. `[signer]` The account's owner/delegate.
|
||||
///
|
||||
/// * Multisignature owner/delegate
|
||||
/// 0. `[writable]` The account to burn from.
|
||||
/// 1. `[]` The account's multisignature owner/delegate.
|
||||
/// 2. ..2+M '[signer]' M signer accounts.
|
||||
Burn {
|
||||
/// The amount of tokens to burn.
|
||||
amount: u64,
|
||||
},
|
||||
/// Close an account by transferring all its SOL to the destination account.
|
||||
/// Non-native accounts may only be closed if its token amount is zero.
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// * Single owner
|
||||
/// 0. `[writable]` The account to close.
|
||||
/// 1. '[writable]' The destination account.
|
||||
/// 2. `[signer]` The account's owner.
|
||||
///
|
||||
/// * Multisignature owner
|
||||
/// 0. `[writable]` The account to close.
|
||||
/// 1. '[writable]' The destination account.
|
||||
/// 2. `[]` The account's multisignature owner.
|
||||
/// 3. ..3+M '[signer]' M signer accounts.
|
||||
CloseAccount,
|
||||
}
|
||||
impl TokenInstruction {
|
||||
/// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html).
|
||||
pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
|
||||
if input.len() < size_of::<u8>() {
|
||||
return Err(TokenError::InvalidInstruction.into());
|
||||
}
|
||||
Ok(match input[0] {
|
||||
0 => {
|
||||
if input.len() < size_of::<u8>() + size_of::<u64>() + size_of::<u8>() {
|
||||
return Err(TokenError::InvalidInstruction.into());
|
||||
}
|
||||
#[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 }
|
||||
}
|
||||
1 => Self::InitializeAccount,
|
||||
2 => {
|
||||
if input.len() < size_of::<u8>() + size_of::<u8>() {
|
||||
return Err(TokenError::InvalidInstruction.into());
|
||||
}
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let m = unsafe { *(&input[1] as *const u8) };
|
||||
Self::InitializeMultisig { m }
|
||||
}
|
||||
3 => {
|
||||
if input.len() < size_of::<u8>() + size_of::<u64>() {
|
||||
return Err(TokenError::InvalidInstruction.into());
|
||||
}
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let amount = unsafe { *(&input[size_of::<u8>()] as *const u8 as *const u64) };
|
||||
Self::Transfer { amount }
|
||||
}
|
||||
4 => {
|
||||
if input.len() < size_of::<u8>() + size_of::<u64>() {
|
||||
return Err(TokenError::InvalidInstruction.into());
|
||||
}
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let amount = unsafe { *(&input[size_of::<u8>()] as *const u8 as *const u64) };
|
||||
Self::Approve { amount }
|
||||
}
|
||||
5 => Self::Revoke,
|
||||
6 => Self::SetOwner,
|
||||
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,
|
||||
_ => return Err(TokenError::InvalidInstruction.into()),
|
||||
})
|
||||
}
|
||||
|
||||
/// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer.
|
||||
pub fn pack(&self) -> Result<Vec<u8>, ProgramError> {
|
||||
let mut output = vec![0u8; size_of::<TokenInstruction>()];
|
||||
let mut output_len = 0;
|
||||
match self {
|
||||
Self::InitializeMint { amount, decimals } => {
|
||||
output[output_len] = 0;
|
||||
output_len += size_of::<u8>();
|
||||
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
|
||||
*value = *amount;
|
||||
output_len += size_of::<u64>();
|
||||
|
||||
let value = unsafe { &mut *(&mut output[output_len] as *mut u8) };
|
||||
*value = *decimals;
|
||||
output_len += size_of::<u8>();
|
||||
}
|
||||
Self::InitializeAccount => {
|
||||
output[output_len] = 1;
|
||||
output_len += size_of::<u8>();
|
||||
}
|
||||
Self::InitializeMultisig { m } => {
|
||||
output[output_len] = 2;
|
||||
output_len += size_of::<u8>();
|
||||
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u8) };
|
||||
*value = *m;
|
||||
output_len += size_of::<u8>();
|
||||
}
|
||||
Self::Transfer { amount } => {
|
||||
output[output_len] = 3;
|
||||
output_len += size_of::<u8>();
|
||||
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
|
||||
*value = *amount;
|
||||
output_len += size_of::<u64>();
|
||||
}
|
||||
Self::Approve { amount } => {
|
||||
output[output_len] = 4;
|
||||
output_len += size_of::<u8>();
|
||||
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) };
|
||||
*value = *amount;
|
||||
output_len += size_of::<u64>();
|
||||
}
|
||||
Self::Revoke => {
|
||||
output[output_len] = 5;
|
||||
output_len += size_of::<u8>();
|
||||
}
|
||||
Self::SetOwner => {
|
||||
output[output_len] = 6;
|
||||
output_len += size_of::<u8>();
|
||||
}
|
||||
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>();
|
||||
}
|
||||
}
|
||||
|
||||
output.truncate(output_len);
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a 'InitializeMint' instruction.
|
||||
pub fn initialize_mint(
|
||||
token_program_id: &Pubkey,
|
||||
mint_pubkey: &Pubkey,
|
||||
account_pubkey: Option<&Pubkey>,
|
||||
owner_pubkey: Option<&Pubkey>,
|
||||
amount: u64,
|
||||
decimals: u8,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::InitializeMint { amount, decimals }.pack()?;
|
||||
|
||||
let mut accounts = vec![AccountMeta::new(*mint_pubkey, false)];
|
||||
if amount != 0 {
|
||||
match account_pubkey {
|
||||
Some(pubkey) => accounts.push(AccountMeta::new(*pubkey, false)),
|
||||
None => {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
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),
|
||||
];
|
||||
|
||||
Ok(Instruction {
|
||||
program_id: *token_program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a `InitializeMultisig` instruction.
|
||||
pub fn initialize_multisig(
|
||||
token_program_id: &Pubkey,
|
||||
multisig_pubkey: &Pubkey,
|
||||
signer_pubkeys: &[&Pubkey],
|
||||
m: u8,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
if !is_valid_signer_index(m as usize)
|
||||
|| !is_valid_signer_index(signer_pubkeys.len())
|
||||
|| m as usize > signer_pubkeys.len()
|
||||
{
|
||||
return Err(ProgramError::MissingRequiredSignature);
|
||||
}
|
||||
let data = TokenInstruction::InitializeMultisig { m }.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(1 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*multisig_pubkey, false));
|
||||
for signer_pubkey in signer_pubkeys.iter() {
|
||||
accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
|
||||
}
|
||||
|
||||
Ok(Instruction {
|
||||
program_id: *token_program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a `Transfer` instruction.
|
||||
pub fn transfer(
|
||||
token_program_id: &Pubkey,
|
||||
source_pubkey: &Pubkey,
|
||||
destination_pubkey: &Pubkey,
|
||||
authority_pubkey: &Pubkey,
|
||||
signer_pubkeys: &[&Pubkey],
|
||||
amount: u64,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::Transfer { amount }.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*source_pubkey, false));
|
||||
accounts.push(AccountMeta::new(*destination_pubkey, false));
|
||||
accounts.push(AccountMeta::new_readonly(
|
||||
*authority_pubkey,
|
||||
signer_pubkeys.is_empty(),
|
||||
));
|
||||
for signer_pubkey in signer_pubkeys.iter() {
|
||||
accounts.push(AccountMeta::new(**signer_pubkey, true));
|
||||
}
|
||||
|
||||
Ok(Instruction {
|
||||
program_id: *token_program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates an `Approve` instruction.
|
||||
pub fn approve(
|
||||
token_program_id: &Pubkey,
|
||||
source_pubkey: &Pubkey,
|
||||
delegate_pubkey: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
signer_pubkeys: &[&Pubkey],
|
||||
amount: u64,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::Approve { amount }.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*source_pubkey, false));
|
||||
accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
|
||||
accounts.push(AccountMeta::new_readonly(
|
||||
*owner_pubkey,
|
||||
signer_pubkeys.is_empty(),
|
||||
));
|
||||
for signer_pubkey in signer_pubkeys.iter() {
|
||||
accounts.push(AccountMeta::new(**signer_pubkey, true));
|
||||
}
|
||||
|
||||
Ok(Instruction {
|
||||
program_id: *token_program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a `Revoke` instruction.
|
||||
pub fn revoke(
|
||||
token_program_id: &Pubkey,
|
||||
source_pubkey: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
signer_pubkeys: &[&Pubkey],
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::Revoke.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new_readonly(*source_pubkey, false));
|
||||
accounts.push(AccountMeta::new_readonly(
|
||||
*owner_pubkey,
|
||||
signer_pubkeys.is_empty(),
|
||||
));
|
||||
for signer_pubkey in signer_pubkeys.iter() {
|
||||
accounts.push(AccountMeta::new(**signer_pubkey, true));
|
||||
}
|
||||
|
||||
Ok(Instruction {
|
||||
program_id: *token_program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a `SetOwner` instruction.
|
||||
pub fn set_owner(
|
||||
token_program_id: &Pubkey,
|
||||
owned_pubkey: &Pubkey,
|
||||
new_owner_pubkey: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
signer_pubkeys: &[&Pubkey],
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::SetOwner.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(),
|
||||
));
|
||||
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,
|
||||
authority_pubkey: &Pubkey,
|
||||
signer_pubkeys: &[&Pubkey],
|
||||
amount: u64,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::Burn { amount }.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*account_pubkey, false));
|
||||
accounts.push(AccountMeta::new_readonly(
|
||||
*authority_pubkey,
|
||||
signer_pubkeys.is_empty(),
|
||||
));
|
||||
for signer_pubkey in signer_pubkeys.iter() {
|
||||
accounts.push(AccountMeta::new(**signer_pubkey, true));
|
||||
}
|
||||
|
||||
Ok(Instruction {
|
||||
program_id: *token_program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a `CloseAccount` instruction.
|
||||
pub fn close_account(
|
||||
token_program_id: &Pubkey,
|
||||
account_pubkey: &Pubkey,
|
||||
destination_pubkey: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
signer_pubkeys: &[&Pubkey],
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::CloseAccount.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*account_pubkey, false));
|
||||
accounts.push(AccountMeta::new(*destination_pubkey, false));
|
||||
accounts.push(AccountMeta::new_readonly(
|
||||
*owner_pubkey,
|
||||
signer_pubkeys.is_empty(),
|
||||
));
|
||||
for signer_pubkey in signer_pubkeys.iter() {
|
||||
accounts.push(AccountMeta::new(**signer_pubkey, true));
|
||||
}
|
||||
|
||||
Ok(Instruction {
|
||||
program_id: *token_program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
amount: 1,
|
||||
decimals: 2,
|
||||
};
|
||||
let packed = check.pack().unwrap();
|
||||
let expect = Vec::from([0u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
|
||||
assert_eq!(packed, expect);
|
||||
let unpacked = TokenInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
|
||||
let check = TokenInstruction::InitializeAccount;
|
||||
let packed = check.pack().unwrap();
|
||||
let expect = Vec::from([1u8]);
|
||||
assert_eq!(packed, expect);
|
||||
let unpacked = TokenInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
|
||||
let check = TokenInstruction::InitializeMultisig { m: 1 };
|
||||
let packed = check.pack().unwrap();
|
||||
let expect = Vec::from([2u8, 1]);
|
||||
assert_eq!(packed, expect);
|
||||
let unpacked = TokenInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
|
||||
let check = TokenInstruction::Transfer { amount: 1 };
|
||||
let packed = check.pack().unwrap();
|
||||
let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
|
||||
assert_eq!(packed, expect);
|
||||
let unpacked = TokenInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
|
||||
let check = TokenInstruction::Approve { amount: 1 };
|
||||
let packed = check.pack().unwrap();
|
||||
let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
|
||||
assert_eq!(packed, expect);
|
||||
let unpacked = TokenInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
|
||||
let check = TokenInstruction::Revoke;
|
||||
let packed = check.pack().unwrap();
|
||||
let expect = Vec::from([5u8]);
|
||||
assert_eq!(packed, expect);
|
||||
let unpacked = TokenInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
|
||||
let check = TokenInstruction::SetOwner;
|
||||
let packed = check.pack().unwrap();
|
||||
let expect = Vec::from([6u8]);
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
#![deny(missing_docs)]
|
||||
|
||||
//! An ERC20-like Token program for the Solana blockchain
|
||||
|
||||
pub mod entrypoint;
|
||||
pub mod error;
|
||||
pub mod instruction;
|
||||
pub mod native_mint;
|
||||
pub mod option;
|
||||
pub mod processor;
|
||||
pub mod state;
|
||||
|
||||
// Export current solana-sdk types for downstream users who may also be building with a different
|
||||
// solana-sdk version
|
||||
pub use solana_sdk;
|
||||
|
||||
/// Convert the UI representation of a token amount (using the decimals field defined in its mint)
|
||||
/// to the raw amount
|
||||
pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 {
|
||||
(ui_amount * 10_usize.pow(decimals as u32) as f64) as u64
|
||||
}
|
||||
|
||||
/// Convert a raw amount to its UI representation (using the decimals field defined in its mint)
|
||||
pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 {
|
||||
amount as f64 / 10_usize.pow(decimals as u32) as f64
|
||||
}
|
||||
|
||||
solana_sdk::declare_id!("TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o");
|
|
@ -1,24 +0,0 @@
|
|||
//! The Mint that represents the native token
|
||||
|
||||
/// There are 10^9 lamports in one SOL
|
||||
pub const DECIMALS: u8 = 9;
|
||||
|
||||
// The Mint for native SOL Token accounts
|
||||
solana_sdk::declare_id!("So11111111111111111111111111111111111111111");
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use solana_sdk::native_token::*;
|
||||
|
||||
#[test]
|
||||
fn test_decimals() {
|
||||
assert!(
|
||||
lamports_to_sol(42) - crate::amount_to_ui_amount(42, DECIMALS).abs() < f64::EPSILON
|
||||
);
|
||||
assert_eq!(
|
||||
sol_to_lamports(42.),
|
||||
crate::ui_amount_to_amount(42., DECIMALS)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,965 +0,0 @@
|
|||
//! A C representation of Rust's `std::option::Option` used accross the FFI
|
||||
//! boundary for Solana program interfaces
|
||||
//!
|
||||
//! This implementation mostly matches `std::option` except iterators since the iteration
|
||||
//! trait requires returning `std::option::Option`
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::{
|
||||
convert, hint, mem,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
/// A C representation of Rust's `std::option::Option`
|
||||
#[repr(C)]
|
||||
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
||||
pub enum COption<T> {
|
||||
/// No value
|
||||
None,
|
||||
/// Some value `T`
|
||||
Some(T),
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Type implementation
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T> COption<T> {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `true` if the option is a [`COption::Some`] value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x: COption<u32> = COption::Some(2);
|
||||
/// assert_eq!(x.is_some(), true);
|
||||
///
|
||||
/// let x: COption<u32> = COption::None;
|
||||
/// assert_eq!(x.is_some(), false);
|
||||
/// ```
|
||||
///
|
||||
/// [`COption::Some`]: #variant.COption::Some
|
||||
#[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"]
|
||||
#[inline]
|
||||
pub fn is_some(&self) -> bool {
|
||||
match *self {
|
||||
COption::Some(_) => true,
|
||||
COption::None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the option is a [`COption::None`] value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x: COption<u32> = COption::Some(2);
|
||||
/// assert_eq!(x.is_none(), false);
|
||||
///
|
||||
/// let x: COption<u32> = COption::None;
|
||||
/// assert_eq!(x.is_none(), true);
|
||||
/// ```
|
||||
///
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
#[must_use = "if you intended to assert that this doesn't have a value, consider \
|
||||
`.and_then(|| panic!(\"`COption` had a value when expected `COption::None`\"))` instead"]
|
||||
#[inline]
|
||||
pub fn is_none(&self) -> bool {
|
||||
!self.is_some()
|
||||
}
|
||||
|
||||
/// Returns `true` if the option is a [`COption::Some`] value containing the given value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// #![feature(option_result_contains)]
|
||||
///
|
||||
/// let x: COption<u32> = COption::Some(2);
|
||||
/// assert_eq!(x.contains(&2), true);
|
||||
///
|
||||
/// let x: COption<u32> = COption::Some(3);
|
||||
/// assert_eq!(x.contains(&2), false);
|
||||
///
|
||||
/// let x: COption<u32> = COption::None;
|
||||
/// assert_eq!(x.contains(&2), false);
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn contains<U>(&self, x: &U) -> bool
|
||||
where
|
||||
U: PartialEq<T>,
|
||||
{
|
||||
match self {
|
||||
COption::Some(y) => x == y,
|
||||
COption::None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `&COption<T>` to `COption<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, preserving the original.
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take an `COption` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: enum.COption.html#method.map
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```ignore
|
||||
/// let text: COption<String> = COption::Some("Hello, world!".to_string());
|
||||
/// // First, cast `COption<String>` to `COption<&String>` with `as_ref`,
|
||||
/// // then consume *that* with `map`, leaving `text` on the stack.
|
||||
/// let text_length: COption<usize> = text.as_ref().map(|s| s.len());
|
||||
/// println!("still can print text: {:?}", text);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_ref(&self) -> COption<&T> {
|
||||
match *self {
|
||||
COption::Some(ref x) => COption::Some(x),
|
||||
COption::None => COption::None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `&mut COption<T>` to `COption<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut x = COption::Some(2);
|
||||
/// match x.as_mut() {
|
||||
/// COption::Some(v) => *v = 42,
|
||||
/// COption::None => {},
|
||||
/// }
|
||||
/// assert_eq!(x, COption::Some(42));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut(&mut self) -> COption<&mut T> {
|
||||
match *self {
|
||||
COption::Some(ref mut x) => COption::Some(x),
|
||||
COption::None => COption::None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from [`Pin`]`<&COption<T>>` to `COption<`[`Pin`]`<&T>>`.
|
||||
///
|
||||
/// [`Pin`]: ../pin/struct.Pin.html
|
||||
#[inline]
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn as_pin_ref(self: Pin<&Self>) -> COption<Pin<&T>> {
|
||||
unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) }
|
||||
}
|
||||
|
||||
/// Converts from [`Pin`]`<&mut COption<T>>` to `COption<`[`Pin`]`<&mut T>>`.
|
||||
///
|
||||
/// [`Pin`]: ../pin/struct.Pin.html
|
||||
#[inline]
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn as_pin_mut(self: Pin<&mut Self>) -> COption<Pin<&mut T>> {
|
||||
unsafe {
|
||||
Pin::get_unchecked_mut(self)
|
||||
.as_mut()
|
||||
.map(|x| Pin::new_unchecked(x))
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Getting to contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Unwraps an option, yielding the content of a [`COption::Some`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is a [`COption::None`] with a custom panic message provided by
|
||||
/// `msg`.
|
||||
///
|
||||
/// [`COption::Some`]: #variant.COption::Some
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x = COption::Some("value");
|
||||
/// assert_eq!(x.expect("the world is ending"), "value");
|
||||
/// ```
|
||||
///
|
||||
/// ```ignore{.should_panic}
|
||||
/// let x: COption<&str> = COption::None;
|
||||
/// x.expect("the world is ending"); // panics with `the world is ending`
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn expect(self, msg: &str) -> T {
|
||||
match self {
|
||||
COption::Some(val) => val,
|
||||
COption::None => expect_failed(msg),
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves the value `v` out of the `COption<T>` if it is [`COption::Some(v)`].
|
||||
///
|
||||
/// In general, because this function may panic, its use is discouraged.
|
||||
/// Instead, prefer to use pattern matching and handle the [`COption::None`]
|
||||
/// case explicitly.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the self value equals [`COption::None`].
|
||||
///
|
||||
/// [`COption::Some(v)`]: #variant.COption::Some
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x = COption::Some("air");
|
||||
/// assert_eq!(x.unwrap(), "air");
|
||||
/// ```
|
||||
///
|
||||
/// ```ignore{.should_panic}
|
||||
/// let x: COption<&str> = COption::None;
|
||||
/// assert_eq!(x.unwrap(), "air"); // fails
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> T {
|
||||
match self {
|
||||
COption::Some(val) => val,
|
||||
COption::None => panic!("called `COption::unwrap()` on a `COption::None` value"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or a default.
|
||||
///
|
||||
/// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing
|
||||
/// the result of a function call, it is recommended to use [`unwrap_or_else`],
|
||||
/// which is lazily evaluated.
|
||||
///
|
||||
/// [`unwrap_or_else`]: #method.unwrap_or_else
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// assert_eq!(COption::Some("car").unwrap_or("bike"), "car");
|
||||
/// assert_eq!(COption::None.unwrap_or("bike"), "bike");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or(self, def: T) -> T {
|
||||
match self {
|
||||
COption::Some(x) => x,
|
||||
COption::None => def,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or computes it from a closure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let k = 10;
|
||||
/// assert_eq!(COption::Some(4).unwrap_or_else(|| 2 * k), 4);
|
||||
/// assert_eq!(COption::None.unwrap_or_else(|| 2 * k), 20);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
||||
match self {
|
||||
COption::Some(x) => x,
|
||||
COption::None => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Transforming contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps an `COption<T>` to `COption<U>` by applying a function to a contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, consuming the original:
|
||||
///
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```ignore
|
||||
/// let maybe_some_string = COption::Some(String::from("Hello, World!"));
|
||||
/// // `COption::map` takes self *by value*, consuming `maybe_some_string`
|
||||
/// let maybe_some_len = maybe_some_string.map(|s| s.len());
|
||||
///
|
||||
/// assert_eq!(maybe_some_len, COption::Some(13));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> COption<U> {
|
||||
match self {
|
||||
COption::Some(x) => COption::Some(f(x)),
|
||||
COption::None => COption::None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or returns the provided default (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x = COption::Some("foo");
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: COption<&str> = COption::None;
|
||||
/// assert_eq!(x.map_or(42, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
|
||||
match self {
|
||||
COption::Some(t) => f(t),
|
||||
COption::None => default,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies a function to the contained value (if any),
|
||||
/// or computes a default (if not).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let k = 21;
|
||||
///
|
||||
/// let x = COption::Some("foo");
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
|
||||
///
|
||||
/// let x: COption<&str> = COption::None;
|
||||
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
|
||||
match self {
|
||||
COption::Some(t) => f(t),
|
||||
COption::None => default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `COption<T>` into a [`Result<T, E>`], mapping [`COption::Some(v)`] to
|
||||
/// [`Ok(v)`] and [`COption::None`] to [`Err(err)`].
|
||||
///
|
||||
/// Arguments passed to `ok_or` are eagerly evaluated; if you are passing the
|
||||
/// result of a function call, it is recommended to use [`ok_or_else`], which is
|
||||
/// lazily evaluated.
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [`Err(err)`]: ../../std/result/enum.Result.html#variant.Err
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
/// [`COption::Some(v)`]: #variant.COption::Some
|
||||
/// [`ok_or_else`]: #method.ok_or_else
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x = COption::Some("foo");
|
||||
/// assert_eq!(x.ok_or(0), Ok("foo"));
|
||||
///
|
||||
/// let x: COption<&str> = COption::None;
|
||||
/// assert_eq!(x.ok_or(0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
|
||||
match self {
|
||||
COption::Some(v) => Ok(v),
|
||||
COption::None => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the `COption<T>` into a [`Result<T, E>`], mapping [`COption::Some(v)`] to
|
||||
/// [`Ok(v)`] and [`COption::None`] to [`Err(err())`].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [`Err(err())`]: ../../std/result/enum.Result.html#variant.Err
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
/// [`COption::Some(v)`]: #variant.COption::Some
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x = COption::Some("foo");
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
|
||||
///
|
||||
/// let x: COption<&str> = COption::None;
|
||||
/// assert_eq!(x.ok_or_else(|| 0), Err(0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
|
||||
match self {
|
||||
COption::Some(v) => Ok(v),
|
||||
COption::None => Err(err()),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Boolean operations on the values, eager and lazy
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns [`COption::None`] if the option is [`COption::None`], otherwise returns `optb`.
|
||||
///
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x = COption::Some(2);
|
||||
/// let y: COption<&str> = COption::None;
|
||||
/// assert_eq!(x.and(y), COption::None);
|
||||
///
|
||||
/// let x: COption<u32> = COption::None;
|
||||
/// let y = COption::Some("foo");
|
||||
/// assert_eq!(x.and(y), COption::None);
|
||||
///
|
||||
/// let x = COption::Some(2);
|
||||
/// let y = COption::Some("foo");
|
||||
/// assert_eq!(x.and(y), COption::Some("foo"));
|
||||
///
|
||||
/// let x: COption<u32> = COption::None;
|
||||
/// let y: COption<&str> = COption::None;
|
||||
/// assert_eq!(x.and(y), COption::None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and<U>(self, optb: COption<U>) -> COption<U> {
|
||||
match self {
|
||||
COption::Some(_) => optb,
|
||||
COption::None => COption::None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `f` with the
|
||||
/// wrapped value and returns the result.
|
||||
///
|
||||
/// COption::Some languages call this operation flatmap.
|
||||
///
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn sq(x: u32) -> COption<u32> { COption::Some(x * x) }
|
||||
/// fn nope(_: u32) -> COption<u32> { COption::None }
|
||||
///
|
||||
/// assert_eq!(COption::Some(2).and_then(sq).and_then(sq), COption::Some(16));
|
||||
/// assert_eq!(COption::Some(2).and_then(sq).and_then(nope), COption::None);
|
||||
/// assert_eq!(COption::Some(2).and_then(nope).and_then(sq), COption::None);
|
||||
/// assert_eq!(COption::None.and_then(sq).and_then(sq), COption::None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn and_then<U, F: FnOnce(T) -> COption<U>>(self, f: F) -> COption<U> {
|
||||
match self {
|
||||
COption::Some(x) => f(x),
|
||||
COption::None => COption::None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `predicate`
|
||||
/// with the wrapped value and returns:
|
||||
///
|
||||
/// - [`COption::Some(t)`] if `predicate` returns `true` (where `t` is the wrapped
|
||||
/// value), and
|
||||
/// - [`COption::None`] if `predicate` returns `false`.
|
||||
///
|
||||
/// This function works similar to [`Iterator::filter()`]. You can imagine
|
||||
/// the `COption<T>` being an iterator over one or zero elements. `filter()`
|
||||
/// lets you decide which elements to keep.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn is_even(n: &i32) -> bool {
|
||||
/// n % 2 == 0
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(COption::None.filter(is_even), COption::None);
|
||||
/// assert_eq!(COption::Some(3).filter(is_even), COption::None);
|
||||
/// assert_eq!(COption::Some(4).filter(is_even), COption::Some(4));
|
||||
/// ```
|
||||
///
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
/// [`COption::Some(t)`]: #variant.COption::Some
|
||||
/// [`Iterator::filter()`]: ../../std/iter/trait.Iterator.html#method.filter
|
||||
#[inline]
|
||||
pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self {
|
||||
if let COption::Some(x) = self {
|
||||
if predicate(&x) {
|
||||
return COption::Some(x);
|
||||
}
|
||||
}
|
||||
COption::None
|
||||
}
|
||||
|
||||
/// Returns the option if it contains a value, otherwise returns `optb`.
|
||||
///
|
||||
/// Arguments passed to `or` are eagerly evaluated; if you are passing the
|
||||
/// result of a function call, it is recommended to use [`or_else`], which is
|
||||
/// lazily evaluated.
|
||||
///
|
||||
/// [`or_else`]: #method.or_else
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x = COption::Some(2);
|
||||
/// let y = COption::None;
|
||||
/// assert_eq!(x.or(y), COption::Some(2));
|
||||
///
|
||||
/// let x = COption::None;
|
||||
/// let y = COption::Some(100);
|
||||
/// assert_eq!(x.or(y), COption::Some(100));
|
||||
///
|
||||
/// let x = COption::Some(2);
|
||||
/// let y = COption::Some(100);
|
||||
/// assert_eq!(x.or(y), COption::Some(2));
|
||||
///
|
||||
/// let x: COption<u32> = COption::None;
|
||||
/// let y = COption::None;
|
||||
/// assert_eq!(x.or(y), COption::None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or(self, optb: COption<T>) -> COption<T> {
|
||||
match self {
|
||||
COption::Some(_) => self,
|
||||
COption::None => optb,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the option if it contains a value, otherwise calls `f` and
|
||||
/// returns the result.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn nobody() -> COption<&'static str> { COption::None }
|
||||
/// fn vikings() -> COption<&'static str> { COption::Some("vikings") }
|
||||
///
|
||||
/// assert_eq!(COption::Some("barbarians").or_else(vikings), COption::Some("barbarians"));
|
||||
/// assert_eq!(COption::None.or_else(vikings), COption::Some("vikings"));
|
||||
/// assert_eq!(COption::None.or_else(nobody), COption::None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn or_else<F: FnOnce() -> COption<T>>(self, f: F) -> COption<T> {
|
||||
match self {
|
||||
COption::Some(_) => self,
|
||||
COption::None => f(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns [`COption::Some`] if exactly one of `self`, `optb` is [`COption::Some`], otherwise returns [`COption::None`].
|
||||
///
|
||||
/// [`COption::Some`]: #variant.COption::Some
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x = COption::Some(2);
|
||||
/// let y: COption<u32> = COption::None;
|
||||
/// assert_eq!(x.xor(y), COption::Some(2));
|
||||
///
|
||||
/// let x: COption<u32> = COption::None;
|
||||
/// let y = COption::Some(2);
|
||||
/// assert_eq!(x.xor(y), COption::Some(2));
|
||||
///
|
||||
/// let x = COption::Some(2);
|
||||
/// let y = COption::Some(2);
|
||||
/// assert_eq!(x.xor(y), COption::None);
|
||||
///
|
||||
/// let x: COption<u32> = COption::None;
|
||||
/// let y: COption<u32> = COption::None;
|
||||
/// assert_eq!(x.xor(y), COption::None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn xor(self, optb: COption<T>) -> COption<T> {
|
||||
match (self, optb) {
|
||||
(COption::Some(a), COption::None) => COption::Some(a),
|
||||
(COption::None, COption::Some(b)) => COption::Some(b),
|
||||
_ => COption::None,
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Entry-like operations to insert if COption::None and return a reference
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Inserts `v` into the option if it is [`COption::None`], then
|
||||
/// returns a mutable reference to the contained value.
|
||||
///
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut x = COption::None;
|
||||
///
|
||||
/// {
|
||||
/// let y: &mut u32 = x.get_or_insert(5);
|
||||
/// assert_eq!(y, &5);
|
||||
///
|
||||
/// *y = 7;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(x, COption::Some(7));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn get_or_insert(&mut self, v: T) -> &mut T {
|
||||
self.get_or_insert_with(|| v)
|
||||
}
|
||||
|
||||
/// Inserts a value computed from `f` into the option if it is [`COption::None`], then
|
||||
/// returns a mutable reference to the contained value.
|
||||
///
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut x = COption::None;
|
||||
///
|
||||
/// {
|
||||
/// let y: &mut u32 = x.get_or_insert_with(|| 5);
|
||||
/// assert_eq!(y, &5);
|
||||
///
|
||||
/// *y = 7;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(x, COption::Some(7));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
|
||||
if let COption::None = *self {
|
||||
*self = COption::Some(f())
|
||||
}
|
||||
|
||||
match *self {
|
||||
COption::Some(ref mut v) => v,
|
||||
COption::None => unsafe { hint::unreachable_unchecked() },
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Replaces the actual value in the option by the value given in parameter,
|
||||
/// returning the old value if present,
|
||||
/// leaving a [`COption::Some`] in its place without deinitializing either one.
|
||||
///
|
||||
/// [`COption::Some`]: #variant.COption::Some
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut x = COption::Some(2);
|
||||
/// let old = x.replace(5);
|
||||
/// assert_eq!(x, COption::Some(5));
|
||||
/// assert_eq!(old, COption::Some(2));
|
||||
///
|
||||
/// let mut x = COption::None;
|
||||
/// let old = x.replace(3);
|
||||
/// assert_eq!(x, COption::Some(3));
|
||||
/// assert_eq!(old, COption::None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn replace(&mut self, value: T) -> COption<T> {
|
||||
mem::replace(self, COption::Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> COption<&T> {
|
||||
/// Maps an `COption<&T>` to an `COption<T>` by copying the contents of the
|
||||
/// option.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x = 12;
|
||||
/// let opt_x = COption::Some(&x);
|
||||
/// assert_eq!(opt_x, COption::Some(&12));
|
||||
/// let copied = opt_x.copied();
|
||||
/// assert_eq!(copied, COption::Some(12));
|
||||
/// ```
|
||||
pub fn copied(self) -> COption<T> {
|
||||
self.map(|&t| t)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> COption<&mut T> {
|
||||
/// Maps an `COption<&mut T>` to an `COption<T>` by copying the contents of the
|
||||
/// option.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut x = 12;
|
||||
/// let opt_x = COption::Some(&mut x);
|
||||
/// assert_eq!(opt_x, COption::Some(&mut 12));
|
||||
/// let copied = opt_x.copied();
|
||||
/// assert_eq!(copied, COption::Some(12));
|
||||
/// ```
|
||||
pub fn copied(self) -> COption<T> {
|
||||
self.map(|&mut t| t)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> COption<&T> {
|
||||
/// Maps an `COption<&T>` to an `COption<T>` by cloning the contents of the
|
||||
/// option.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let x = 12;
|
||||
/// let opt_x = COption::Some(&x);
|
||||
/// assert_eq!(opt_x, COption::Some(&12));
|
||||
/// let cloned = opt_x.cloned();
|
||||
/// assert_eq!(cloned, COption::Some(12));
|
||||
/// ```
|
||||
pub fn cloned(self) -> COption<T> {
|
||||
self.map(|t| t.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> COption<&mut T> {
|
||||
/// Maps an `COption<&mut T>` to an `COption<T>` by cloning the contents of the
|
||||
/// option.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut x = 12;
|
||||
/// let opt_x = COption::Some(&mut x);
|
||||
/// assert_eq!(opt_x, COption::Some(&mut 12));
|
||||
/// let cloned = opt_x.cloned();
|
||||
/// assert_eq!(cloned, COption::Some(12));
|
||||
/// ```
|
||||
pub fn cloned(self) -> COption<T> {
|
||||
self.map(|t| t.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> COption<T> {
|
||||
/// Returns the contained value or a default
|
||||
///
|
||||
/// Consumes the `self` argument then, if [`COption::Some`], returns the contained
|
||||
/// value, otherwise if [`COption::None`], returns the [default value] for that
|
||||
/// type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Converts a string to an integer, turning poorly-formed strings
|
||||
/// into 0 (the default value for integers). [`parse`] converts
|
||||
/// a string to any other type that implements [`FromStr`], returning
|
||||
/// [`COption::None`] on error.
|
||||
///
|
||||
/// ```ignore
|
||||
/// let good_year_from_input = "1909";
|
||||
/// let bad_year_from_input = "190blarg";
|
||||
/// let good_year = good_year_from_input.parse().ok().unwrap_or_default();
|
||||
/// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default();
|
||||
///
|
||||
/// assert_eq!(1909, good_year);
|
||||
/// assert_eq!(0, bad_year);
|
||||
/// ```
|
||||
///
|
||||
/// [`COption::Some`]: #variant.COption::Some
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
/// [default value]: ../default/trait.Default.html#tymethod.default
|
||||
/// [`parse`]: ../../std/primitive.str.html#method.parse
|
||||
/// [`FromStr`]: ../../std/str/trait.FromStr.html
|
||||
#[inline]
|
||||
pub fn unwrap_or_default(self) -> T {
|
||||
match self {
|
||||
COption::Some(x) => x,
|
||||
COption::None => Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Deref> COption<T> {
|
||||
/// Converts from `COption<T>` (or `&COption<T>`) to `COption<&T::Target>`.
|
||||
///
|
||||
/// Leaves the original COption in-place, creating a new one with a reference
|
||||
/// to the original one, additionally coercing the contents via [`Deref`].
|
||||
///
|
||||
/// [`Deref`]: ../../std/ops/trait.Deref.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// #![feature(inner_deref)]
|
||||
///
|
||||
/// let x: COption<String> = COption::Some("hey".to_owned());
|
||||
/// assert_eq!(x.as_deref(), COption::Some("hey"));
|
||||
///
|
||||
/// let x: COption<String> = COption::None;
|
||||
/// assert_eq!(x.as_deref(), COption::None);
|
||||
/// ```
|
||||
pub fn as_deref(&self) -> COption<&T::Target> {
|
||||
self.as_ref().map(|t| t.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DerefMut> COption<T> {
|
||||
/// Converts from `COption<T>` (or `&mut COption<T>`) to `COption<&mut T::Target>`.
|
||||
///
|
||||
/// Leaves the original `COption` in-place, creating a new one containing a mutable reference to
|
||||
/// the inner type's `Deref::Target` type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// #![feature(inner_deref)]
|
||||
///
|
||||
/// let mut x: COption<String> = COption::Some("hey".to_owned());
|
||||
/// assert_eq!(x.as_deref_mut().map(|x| {
|
||||
/// x.make_ascii_uppercase();
|
||||
/// x
|
||||
/// }), COption::Some("HEY".to_owned().as_mut_str()));
|
||||
/// ```
|
||||
pub fn as_deref_mut(&mut self) -> COption<&mut T::Target> {
|
||||
self.as_mut().map(|t| t.deref_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> COption<Result<T, E>> {
|
||||
/// Transposes an `COption` of a [`Result`] into a [`Result`] of an `COption`.
|
||||
///
|
||||
/// [`COption::None`] will be mapped to [`Ok`]`(`[`COption::None`]`)`.
|
||||
/// [`COption::Some`]`(`[`Ok`]`(_))` and [`COption::Some`]`(`[`Err`]`(_))` will be mapped to
|
||||
/// [`Ok`]`(`[`COption::Some`]`(_))` and [`Err`]`(_)`.
|
||||
///
|
||||
/// [`COption::None`]: #variant.COption::None
|
||||
/// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [`COption::Some`]: #variant.COption::Some
|
||||
/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// #[derive(Debug, Eq, PartialEq)]
|
||||
/// struct COption::SomeErr;
|
||||
///
|
||||
/// let x: Result<COption<i32>, COption::SomeErr> = Ok(COption::Some(5));
|
||||
/// let y: COption<Result<i32, COption::SomeErr>> = COption::Some(Ok(5));
|
||||
/// assert_eq!(x, y.transpose());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn transpose(self) -> Result<COption<T>, E> {
|
||||
match self {
|
||||
COption::Some(Ok(x)) => Ok(COption::Some(x)),
|
||||
COption::Some(Err(e)) => Err(e),
|
||||
COption::None => Ok(COption::None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is a separate function to reduce the code size of .expect() itself.
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn expect_failed(msg: &str) -> ! {
|
||||
panic!("{}", msg)
|
||||
}
|
||||
|
||||
// // This is a separate function to reduce the code size of .expect_none() itself.
|
||||
// #[inline(never)]
|
||||
// #[cold]
|
||||
// fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! {
|
||||
// panic!("{}: {:?}", msg, value)
|
||||
// }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Trait implementations
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T: Clone> Clone for COption<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
COption::Some(x) => COption::Some(x.clone()),
|
||||
COption::None => COption::None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clone_from(&mut self, source: &Self) {
|
||||
match (self, source) {
|
||||
(COption::Some(to), COption::Some(from)) => to.clone_from(from),
|
||||
(to, from) => *to = from.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for COption<T> {
|
||||
/// Returns [`COption::None`][COption::COption::None].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let opt: COption<u32> = COption::default();
|
||||
/// assert!(opt.is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
fn default() -> COption<T> {
|
||||
COption::None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for COption<T> {
|
||||
fn from(val: T) -> COption<T> {
|
||||
COption::Some(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> From<&'a COption<T>> for COption<&'a T> {
|
||||
fn from(o: &'a COption<T>) -> COption<&'a T> {
|
||||
o.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> From<&'a mut COption<T>> for COption<&'a mut T> {
|
||||
fn from(o: &'a mut COption<T>) -> COption<&'a mut T> {
|
||||
o.as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> COption<COption<T>> {
|
||||
/// Converts from `COption<COption<T>>` to `COption<T>`
|
||||
///
|
||||
/// # Examples
|
||||
/// Basic usage:
|
||||
/// ```ignore
|
||||
/// #![feature(option_flattening)]
|
||||
/// let x: COption<COption<u32>> = COption::Some(COption::Some(6));
|
||||
/// assert_eq!(COption::Some(6), x.flatten());
|
||||
///
|
||||
/// let x: COption<COption<u32>> = COption::Some(COption::None);
|
||||
/// assert_eq!(COption::None, x.flatten());
|
||||
///
|
||||
/// let x: COption<COption<u32>> = COption::None;
|
||||
/// assert_eq!(COption::None, x.flatten());
|
||||
/// ```
|
||||
/// Flattening once only removes one level of nesting:
|
||||
/// ```ignore
|
||||
/// #![feature(option_flattening)]
|
||||
/// let x: COption<COption<COption<u32>>> = COption::Some(COption::Some(COption::Some(6)));
|
||||
/// assert_eq!(COption::Some(COption::Some(6)), x.flatten());
|
||||
/// assert_eq!(COption::Some(6), x.flatten().flatten());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn flatten(self) -> COption<T> {
|
||||
self.and_then(convert::identity)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,92 +0,0 @@
|
|||
//! State transition types
|
||||
|
||||
use crate::{error::TokenError, instruction::MAX_SIGNERS, option::COption};
|
||||
use solana_sdk::{program_error::ProgramError, pubkey::Pubkey};
|
||||
use std::mem::size_of;
|
||||
|
||||
/// Mint data.
|
||||
#[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>,
|
||||
/// 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,
|
||||
}
|
||||
impl IsInitialized for Mint {
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.is_initialized
|
||||
}
|
||||
}
|
||||
|
||||
/// Account data.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct Account {
|
||||
/// The mint associated with this account
|
||||
pub mint: Pubkey,
|
||||
/// The owner of this account.
|
||||
pub owner: Pubkey,
|
||||
/// The amount of tokens this account holds.
|
||||
pub amount: u64,
|
||||
/// 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,
|
||||
/// Is this a native token
|
||||
pub is_native: bool,
|
||||
/// The amount delegated
|
||||
pub delegated_amount: u64,
|
||||
}
|
||||
impl IsInitialized for Account {
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.is_initialized
|
||||
}
|
||||
}
|
||||
|
||||
/// Multisignature data.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct Multisig {
|
||||
/// Number of signers required
|
||||
pub m: u8,
|
||||
/// Number of valid signers
|
||||
pub n: u8,
|
||||
/// Is `true` if this structure has been initialized
|
||||
pub is_initialized: bool,
|
||||
/// Signer public keys
|
||||
pub signers: [Pubkey; MAX_SIGNERS],
|
||||
}
|
||||
impl IsInitialized for Multisig {
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.is_initialized
|
||||
}
|
||||
}
|
||||
|
||||
/// Check is a token state is initialized
|
||||
pub trait IsInitialized {
|
||||
/// Is initialized
|
||||
fn is_initialized(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Unpacks a token state from a bytes buffer while assuring that the state is initialized.
|
||||
pub fn unpack<T: IsInitialized>(input: &mut [u8]) -> Result<&mut T, ProgramError> {
|
||||
let mut_ref: &mut T = unpack_unchecked(input)?;
|
||||
if !mut_ref.is_initialized() {
|
||||
return Err(TokenError::UninitializedState.into());
|
||||
}
|
||||
Ok(mut_ref)
|
||||
}
|
||||
/// Unpacks a token state from a bytes buffer without checking that the state is initialized.
|
||||
pub fn unpack_unchecked<T: IsInitialized>(input: &mut [u8]) -> Result<&mut T, ProgramError> {
|
||||
if input.len() != size_of::<T>() {
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
Ok(unsafe { &mut *(&mut input[0] as *mut u8 as *mut T) })
|
||||
}
|
Loading…
Reference in New Issue