Whittle down the token program across the board (#93)
* Whittle down the token program across the board * nit * nudge
This commit is contained in:
parent
69e9023a8f
commit
7a3fb516bc
|
@ -359,24 +359,18 @@ impl State {
|
|||
pub fn token_account_deserialize(
|
||||
info: &AccountInfo,
|
||||
) -> Result<spl_token::state::Account, Error> {
|
||||
if let Ok(spl_token::state::State::Account(account)) =
|
||||
spl_token::state::State::deserialize(&info.data.borrow())
|
||||
{
|
||||
Ok(account)
|
||||
} else {
|
||||
Err(Error::ExpectedAccount)
|
||||
}
|
||||
Ok(
|
||||
*spl_token::state::State::unpack(&mut info.data.borrow_mut())
|
||||
.map_err(|_| Error::ExpectedAccount)?,
|
||||
)
|
||||
}
|
||||
|
||||
/// Deserializes a spl_token `State`.
|
||||
pub fn token_deserialize(info: &AccountInfo) -> Result<spl_token::state::Token, Error> {
|
||||
if let Ok(spl_token::state::State::Mint(token)) =
|
||||
spl_token::state::State::deserialize(&info.data.borrow())
|
||||
{
|
||||
Ok(token)
|
||||
} else {
|
||||
Err(Error::ExpectedToken)
|
||||
}
|
||||
/// Deserializes a spl_token `Mint`.
|
||||
pub fn mint_deserialize(info: &AccountInfo) -> Result<spl_token::state::Mint, Error> {
|
||||
Ok(
|
||||
*spl_token::state::State::unpack(&mut info.data.borrow_mut())
|
||||
.map_err(|_| Error::ExpectedToken)?,
|
||||
)
|
||||
}
|
||||
|
||||
/// Calculates the authority id by generating a program address.
|
||||
|
@ -470,7 +464,7 @@ impl State {
|
|||
}
|
||||
let token_a = Self::token_account_deserialize(token_a_info)?;
|
||||
let token_b = Self::token_account_deserialize(token_b_info)?;
|
||||
let pool_mint = Self::token_deserialize(pool_info)?;
|
||||
let pool_mint = Self::mint_deserialize(pool_info)?;
|
||||
if *authority_info.key != token_a.owner {
|
||||
return Err(Error::InvalidOwner.into());
|
||||
}
|
||||
|
@ -799,7 +793,7 @@ mod tests {
|
|||
};
|
||||
use spl_token::{
|
||||
instruction::{initialize_account, initialize_mint},
|
||||
state::State as SplState,
|
||||
state::{Account as SplAccount, Mint as SplMint, State as SplState},
|
||||
};
|
||||
|
||||
const TOKEN_PROGRAM_ID: Pubkey = Pubkey::new_from_array([1u8; 32]);
|
||||
|
@ -837,9 +831,9 @@ mod tests {
|
|||
amount: u64,
|
||||
) -> ((Pubkey, Account), (Pubkey, Account)) {
|
||||
let token_key = pubkey_rand();
|
||||
let mut token_account = Account::new(0, size_of::<SplState>(), &program_id);
|
||||
let mut token_account = Account::new(0, size_of::<SplMint>(), &program_id);
|
||||
let account_key = pubkey_rand();
|
||||
let mut account_account = Account::new(0, size_of::<SplState>(), &program_id);
|
||||
let mut account_account = Account::new(0, size_of::<SplAccount>(), &program_id);
|
||||
|
||||
// create pool and pool account
|
||||
do_process_instruction(
|
||||
|
|
|
@ -8,7 +8,7 @@ style = "both"
|
|||
|
||||
[export]
|
||||
prefix = "Token_"
|
||||
include = ["TokenInstruction", "State"]
|
||||
include = ["TokenInstruction", "Mint", "Account", "Multisig"]
|
||||
|
||||
[parse]
|
||||
parse_deps = true
|
||||
|
|
|
@ -256,11 +256,9 @@ typedef struct Token_COption_Pubkey {
|
|||
} Token_COption_Pubkey;
|
||||
|
||||
/**
|
||||
* Represents a token type identified by its public key. Accounts
|
||||
* are associated with a specific token type and only accounts with
|
||||
* matching types my inter-opt.
|
||||
* Mint data.
|
||||
*/
|
||||
typedef struct Token_Token {
|
||||
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
|
||||
|
@ -271,10 +269,14 @@ typedef struct Token_Token {
|
|||
* Number of base 10 digits to the right of the decimal place.
|
||||
*/
|
||||
uint8_t decimals;
|
||||
} Token_Token;
|
||||
/**
|
||||
* Is `true` if this structure has been initialized
|
||||
*/
|
||||
bool is_initialized;
|
||||
} Token_Mint;
|
||||
|
||||
/**
|
||||
* Account that holds tokens or may delegate tokens.
|
||||
* Account data.
|
||||
*/
|
||||
typedef struct Token_Account {
|
||||
/**
|
||||
|
@ -294,6 +296,10 @@ typedef struct Token_Account {
|
|||
* the amount authorized by the delegate
|
||||
*/
|
||||
Token_COption_Pubkey delegate;
|
||||
/**
|
||||
* Is `true` if this structure has been initialized
|
||||
*/
|
||||
bool is_initialized;
|
||||
/**
|
||||
* The amount delegated
|
||||
*/
|
||||
|
@ -301,35 +307,23 @@ typedef struct Token_Account {
|
|||
} Token_Account;
|
||||
|
||||
/**
|
||||
* Program states.
|
||||
* Multisignature data.
|
||||
*/
|
||||
typedef enum Token_State_Tag {
|
||||
typedef struct Token_Multisig {
|
||||
/**
|
||||
* Unallocated state, may be initialized into another state.
|
||||
* Number of signers required
|
||||
*/
|
||||
Unallocated,
|
||||
uint8_t m;
|
||||
/**
|
||||
* A mint.
|
||||
* Number of valid signers
|
||||
*/
|
||||
Mint,
|
||||
uint8_t n;
|
||||
/**
|
||||
* An account that holds tokens
|
||||
* Is `true` if this structure has been initialized
|
||||
*/
|
||||
Account,
|
||||
} Token_State_Tag;
|
||||
|
||||
typedef struct Token_Mint_Body {
|
||||
Token_Token _0;
|
||||
} Token_Mint_Body;
|
||||
|
||||
typedef struct Token_Account_Body {
|
||||
Token_Account _0;
|
||||
} Token_Account_Body;
|
||||
|
||||
typedef struct Token_State {
|
||||
Token_State_Tag tag;
|
||||
union {
|
||||
Token_Mint_Body mint;
|
||||
Token_Account_Body account;
|
||||
};
|
||||
} Token_State;
|
||||
bool is_initialized;
|
||||
/**
|
||||
* Signer public keys
|
||||
*/
|
||||
Token_Pubkey signers[Token_MAX_SIGNERS];
|
||||
} Token_Multisig;
|
||||
|
|
|
@ -57,23 +57,26 @@ export class TokenAmount extends BN {
|
|||
* Information about the mint
|
||||
*/
|
||||
type MintInfo = {|
|
||||
/**
|
||||
* Owner of the mint, given authority to mint new tokens
|
||||
*/
|
||||
owner: null | PublicKey,
|
||||
/**
|
||||
* Number of base 10 digits to the right of the decimal place
|
||||
*/
|
||||
decimals: number,
|
||||
/**
|
||||
* Owner of the mint, given authority to mint new tokens
|
||||
* Is this mint initialized
|
||||
*/
|
||||
owner: null | PublicKey,
|
||||
initialized: Boolean,
|
||||
|};
|
||||
|
||||
const MintLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('state'),
|
||||
BufferLayout.u32('option'),
|
||||
Layout.publicKey('owner'),
|
||||
BufferLayout.u8('decimals'),
|
||||
BufferLayout.u16('padding1'),
|
||||
BufferLayout.nu64('padding2'),
|
||||
BufferLayout.u8('is_initialized'),
|
||||
BufferLayout.u16('padding'),
|
||||
]);
|
||||
|
||||
/**
|
||||
|
@ -110,13 +113,14 @@ type AccountInfo = {|
|
|||
* @private
|
||||
*/
|
||||
const AccountLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('state'),
|
||||
Layout.publicKey('mint'),
|
||||
Layout.publicKey('owner'),
|
||||
Layout.uint64('amount'),
|
||||
BufferLayout.u32('option'),
|
||||
Layout.publicKey('delegate'),
|
||||
BufferLayout.u32('padding'),
|
||||
BufferLayout.u8('is_initialized'),
|
||||
BufferLayout.u8('padding'),
|
||||
BufferLayout.u16('padding'),
|
||||
Layout.uint64('delegatedAmount'),
|
||||
]);
|
||||
|
||||
|
@ -158,6 +162,7 @@ type MultisigInfo = {|
|
|||
const MultisigLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('m'),
|
||||
BufferLayout.u8('n'),
|
||||
BufferLayout.u8('is_initialized'),
|
||||
Layout.publicKey('signer1'),
|
||||
Layout.publicKey('signer2'),
|
||||
Layout.publicKey('signer3'),
|
||||
|
@ -471,13 +476,12 @@ export class Token {
|
|||
`Invalid mint owner: ${JSON.stringify(info.owner)}`,
|
||||
);
|
||||
}
|
||||
if (info.data.length != MintLayout.span) {
|
||||
throw new Error(`Invalid mint size`);
|
||||
}
|
||||
|
||||
const data = Buffer.from(info.data);
|
||||
|
||||
const mintInfo = MintLayout.decode(data);
|
||||
if (mintInfo.state !== 1) {
|
||||
throw new Error(`Invalid account data`);
|
||||
}
|
||||
if (mintInfo.option === 0) {
|
||||
mintInfo.owner = null;
|
||||
} else {
|
||||
|
@ -499,13 +503,12 @@ export class Token {
|
|||
if (!info.owner.equals(this.programId)) {
|
||||
throw new Error(`Invalid account owner`);
|
||||
}
|
||||
if (info.data.length != AccountLayout.span) {
|
||||
throw new Error(`Invalid account size`);
|
||||
}
|
||||
|
||||
const data = Buffer.from(info.data);
|
||||
const accountInfo = AccountLayout.decode(data);
|
||||
|
||||
if (accountInfo.state !== 2) {
|
||||
throw new Error(`Invalid account data`);
|
||||
}
|
||||
accountInfo.mint = new PublicKey(accountInfo.mint);
|
||||
accountInfo.owner = new PublicKey(accountInfo.owner);
|
||||
accountInfo.amount = TokenAmount.fromBuffer(accountInfo.amount);
|
||||
|
@ -542,6 +545,9 @@ export class Token {
|
|||
if (!info.owner.equals(this.programId)) {
|
||||
throw new Error(`Invalid multisig owner`);
|
||||
}
|
||||
if (info.data.length != MultisigLayout.span) {
|
||||
throw new Error(`Invalid multisig size`);
|
||||
}
|
||||
|
||||
const data = Buffer.from(info.data);
|
||||
const multisigInfo = MultisigLayout.decode(data);
|
||||
|
|
|
@ -36,6 +36,9 @@ pub enum TokenError {
|
|||
/// Invalid number of required signers.
|
||||
#[error("Invalid number of required signers")]
|
||||
InvalidNumberOfRequiredSigners,
|
||||
/// State is uninitialized.
|
||||
#[error("State is unititialized")]
|
||||
UninitializedState,
|
||||
}
|
||||
impl From<TokenError> for ProgramError {
|
||||
fn from(e: TokenError) -> Self {
|
||||
|
@ -67,6 +70,7 @@ impl PrintProgramError for TokenError {
|
|||
TokenError::InvalidNumberOfRequiredSigners => {
|
||||
info!("Error: Invalid number of required signers")
|
||||
}
|
||||
TokenError::UninitializedState => info!("Error: State is uninitialized"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,8 +169,8 @@ pub enum TokenInstruction {
|
|||
},
|
||||
}
|
||||
impl TokenInstruction {
|
||||
/// Deserializes a byte buffer into an [TokenInstruction](enum.TokenInstruction.html).
|
||||
pub fn deserialize(input: &[u8]) -> Result<Self, ProgramError> {
|
||||
/// 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(ProgramError::InvalidAccountData);
|
||||
}
|
||||
|
@ -232,8 +232,8 @@ impl TokenInstruction {
|
|||
})
|
||||
}
|
||||
|
||||
/// Serializes an [TokenInstruction](enum.TokenInstruction.html) into a byte buffer.
|
||||
pub fn serialize(self: &Self) -> Result<Vec<u8>, ProgramError> {
|
||||
/// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer.
|
||||
pub fn pack(self: &Self) -> Result<Vec<u8>, ProgramError> {
|
||||
let mut output = vec![0u8; size_of::<TokenInstruction>()];
|
||||
match self {
|
||||
Self::InitializeMint { amount, decimals } => {
|
||||
|
@ -292,7 +292,7 @@ pub fn initialize_mint(
|
|||
amount: u64,
|
||||
decimals: u8,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::InitializeMint { amount, decimals }.serialize()?;
|
||||
let data = TokenInstruction::InitializeMint { amount, decimals }.pack()?;
|
||||
|
||||
let mut accounts = vec![AccountMeta::new(*mint_pubkey, false)];
|
||||
if amount != 0 {
|
||||
|
@ -326,7 +326,7 @@ pub fn initialize_account(
|
|||
mint_pubkey: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::InitializeAccount.serialize()?;
|
||||
let data = TokenInstruction::InitializeAccount.pack()?;
|
||||
|
||||
let accounts = vec![
|
||||
AccountMeta::new(*account_pubkey, false),
|
||||
|
@ -354,7 +354,7 @@ pub fn initialize_multisig(
|
|||
{
|
||||
return Err(ProgramError::MissingRequiredSignature);
|
||||
}
|
||||
let data = TokenInstruction::InitializeMultisig { m }.serialize()?;
|
||||
let data = TokenInstruction::InitializeMultisig { m }.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(1 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*multisig_pubkey, false));
|
||||
|
@ -378,7 +378,7 @@ pub fn transfer(
|
|||
signer_pubkeys: &[&Pubkey],
|
||||
amount: u64,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::Transfer { amount }.serialize()?;
|
||||
let data = TokenInstruction::Transfer { amount }.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*source_pubkey, false));
|
||||
|
@ -407,7 +407,7 @@ pub fn approve(
|
|||
signer_pubkeys: &[&Pubkey],
|
||||
amount: u64,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::Approve { amount }.serialize()?;
|
||||
let data = TokenInstruction::Approve { amount }.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new_readonly(*source_pubkey, false));
|
||||
|
@ -434,7 +434,7 @@ pub fn revoke(
|
|||
owner_pubkey: &Pubkey,
|
||||
signer_pubkeys: &[&Pubkey],
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::Revoke.serialize()?;
|
||||
let data = TokenInstruction::Revoke.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new_readonly(*source_pubkey, false));
|
||||
|
@ -461,7 +461,7 @@ pub fn set_owner(
|
|||
owner_pubkey: &Pubkey,
|
||||
signer_pubkeys: &[&Pubkey],
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::SetOwner.serialize()?;
|
||||
let data = TokenInstruction::SetOwner.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*owned_pubkey, false));
|
||||
|
@ -490,7 +490,7 @@ pub fn mint_to(
|
|||
signer_pubkeys: &[&Pubkey],
|
||||
amount: u64,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::MintTo { amount }.serialize()?;
|
||||
let data = TokenInstruction::MintTo { amount }.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*mint_pubkey, false));
|
||||
|
@ -518,7 +518,7 @@ pub fn burn(
|
|||
signer_pubkeys: &[&Pubkey],
|
||||
amount: u64,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::Burn { amount }.serialize()?;
|
||||
let data = TokenInstruction::Burn { amount }.pack()?;
|
||||
|
||||
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*account_pubkey, false));
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue