Whittle down the token program across the board (#93)

* Whittle down the token program across the board

* nit

* nudge
This commit is contained in:
Jack May 2020-07-08 12:41:08 -07:00 committed by GitHub
parent 69e9023a8f
commit 7a3fb516bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 388 additions and 473 deletions

View File

@ -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(

View File

@ -8,7 +8,7 @@ style = "both"
[export]
prefix = "Token_"
include = ["TokenInstruction", "State"]
include = ["TokenInstruction", "Mint", "Account", "Multisig"]
[parse]
parse_deps = true

View File

@ -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;

View File

@ -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);

View File

@ -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"),
}
}
}

View File

@ -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