Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 7a3fb51

Browse files
authored
Whittle down the token program across the board (#93)
* Whittle down the token program across the board * nit * nudge
1 parent 69e9023 commit 7a3fb51

File tree

7 files changed

+386
-471
lines changed

7 files changed

+386
-471
lines changed

token-swap/src/lib.rs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -359,24 +359,18 @@ impl State {
359359
pub fn token_account_deserialize(
360360
info: &AccountInfo,
361361
) -> Result<spl_token::state::Account, Error> {
362-
if let Ok(spl_token::state::State::Account(account)) =
363-
spl_token::state::State::deserialize(&info.data.borrow())
364-
{
365-
Ok(account)
366-
} else {
367-
Err(Error::ExpectedAccount)
368-
}
362+
Ok(
363+
*spl_token::state::State::unpack(&mut info.data.borrow_mut())
364+
.map_err(|_| Error::ExpectedAccount)?,
365+
)
369366
}
370367

371-
/// Deserializes a spl_token `State`.
372-
pub fn token_deserialize(info: &AccountInfo) -> Result<spl_token::state::Token, Error> {
373-
if let Ok(spl_token::state::State::Mint(token)) =
374-
spl_token::state::State::deserialize(&info.data.borrow())
375-
{
376-
Ok(token)
377-
} else {
378-
Err(Error::ExpectedToken)
379-
}
368+
/// Deserializes a spl_token `Mint`.
369+
pub fn mint_deserialize(info: &AccountInfo) -> Result<spl_token::state::Mint, Error> {
370+
Ok(
371+
*spl_token::state::State::unpack(&mut info.data.borrow_mut())
372+
.map_err(|_| Error::ExpectedToken)?,
373+
)
380374
}
381375

382376
/// Calculates the authority id by generating a program address.
@@ -470,7 +464,7 @@ impl State {
470464
}
471465
let token_a = Self::token_account_deserialize(token_a_info)?;
472466
let token_b = Self::token_account_deserialize(token_b_info)?;
473-
let pool_mint = Self::token_deserialize(pool_info)?;
467+
let pool_mint = Self::mint_deserialize(pool_info)?;
474468
if *authority_info.key != token_a.owner {
475469
return Err(Error::InvalidOwner.into());
476470
}
@@ -799,7 +793,7 @@ mod tests {
799793
};
800794
use spl_token::{
801795
instruction::{initialize_account, initialize_mint},
802-
state::State as SplState,
796+
state::{Account as SplAccount, Mint as SplMint, State as SplState},
803797
};
804798

805799
const TOKEN_PROGRAM_ID: Pubkey = Pubkey::new_from_array([1u8; 32]);
@@ -837,9 +831,9 @@ mod tests {
837831
amount: u64,
838832
) -> ((Pubkey, Account), (Pubkey, Account)) {
839833
let token_key = pubkey_rand();
840-
let mut token_account = Account::new(0, size_of::<SplState>(), &program_id);
834+
let mut token_account = Account::new(0, size_of::<SplMint>(), &program_id);
841835
let account_key = pubkey_rand();
842-
let mut account_account = Account::new(0, size_of::<SplState>(), &program_id);
836+
let mut account_account = Account::new(0, size_of::<SplAccount>(), &program_id);
843837

844838
// create pool and pool account
845839
do_process_instruction(

token/cbindgen.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ style = "both"
88

99
[export]
1010
prefix = "Token_"
11-
include = ["TokenInstruction", "State"]
11+
include = ["TokenInstruction", "Mint", "Account", "Multisig"]
1212

1313
[parse]
1414
parse_deps = true

token/inc/token.h

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,9 @@ typedef struct Token_COption_Pubkey {
256256
} Token_COption_Pubkey;
257257

258258
/**
259-
* Represents a token type identified by its public key. Accounts
260-
* are associated with a specific token type and only accounts with
261-
* matching types my inter-opt.
259+
* Mint data.
262260
*/
263-
typedef struct Token_Token {
261+
typedef struct Token_Mint {
264262
/**
265263
* Optional owner, used to mint new tokens. The owner may only
266264
* be provided during mint creation. If no owner is present then the mint
@@ -271,10 +269,14 @@ typedef struct Token_Token {
271269
* Number of base 10 digits to the right of the decimal place.
272270
*/
273271
uint8_t decimals;
274-
} Token_Token;
272+
/**
273+
* Is `true` if this structure has been initialized
274+
*/
275+
bool is_initialized;
276+
} Token_Mint;
275277

276278
/**
277-
* Account that holds tokens or may delegate tokens.
279+
* Account data.
278280
*/
279281
typedef struct Token_Account {
280282
/**
@@ -294,42 +296,34 @@ typedef struct Token_Account {
294296
* the amount authorized by the delegate
295297
*/
296298
Token_COption_Pubkey delegate;
299+
/**
300+
* Is `true` if this structure has been initialized
301+
*/
302+
bool is_initialized;
297303
/**
298304
* The amount delegated
299305
*/
300306
uint64_t delegated_amount;
301307
} Token_Account;
302308

303309
/**
304-
* Program states.
310+
* Multisignature data.
305311
*/
306-
typedef enum Token_State_Tag {
312+
typedef struct Token_Multisig {
307313
/**
308-
* Unallocated state, may be initialized into another state.
314+
* Number of signers required
309315
*/
310-
Unallocated,
316+
uint8_t m;
311317
/**
312-
* A mint.
318+
* Number of valid signers
313319
*/
314-
Mint,
320+
uint8_t n;
315321
/**
316-
* An account that holds tokens
322+
* Is `true` if this structure has been initialized
317323
*/
318-
Account,
319-
} Token_State_Tag;
320-
321-
typedef struct Token_Mint_Body {
322-
Token_Token _0;
323-
} Token_Mint_Body;
324-
325-
typedef struct Token_Account_Body {
326-
Token_Account _0;
327-
} Token_Account_Body;
328-
329-
typedef struct Token_State {
330-
Token_State_Tag tag;
331-
union {
332-
Token_Mint_Body mint;
333-
Token_Account_Body account;
334-
};
335-
} Token_State;
324+
bool is_initialized;
325+
/**
326+
* Signer public keys
327+
*/
328+
Token_Pubkey signers[Token_MAX_SIGNERS];
329+
} Token_Multisig;

token/js/client/token.js

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,26 @@ export class TokenAmount extends BN {
5757
* Information about the mint
5858
*/
5959
type MintInfo = {|
60+
/**
61+
* Owner of the mint, given authority to mint new tokens
62+
*/
63+
owner: null | PublicKey,
6064
/**
6165
* Number of base 10 digits to the right of the decimal place
6266
*/
6367
decimals: number,
6468
/**
65-
* Owner of the mint, given authority to mint new tokens
69+
* Is this mint initialized
6670
*/
67-
owner: null | PublicKey,
71+
initialized: Boolean,
6872
|};
6973

7074
const MintLayout = BufferLayout.struct([
71-
BufferLayout.u8('state'),
7275
BufferLayout.u32('option'),
7376
Layout.publicKey('owner'),
7477
BufferLayout.u8('decimals'),
75-
BufferLayout.u16('padding1'),
76-
BufferLayout.nu64('padding2'),
78+
BufferLayout.u8('is_initialized'),
79+
BufferLayout.u16('padding'),
7780
]);
7881

7982
/**
@@ -110,13 +113,14 @@ type AccountInfo = {|
110113
* @private
111114
*/
112115
const AccountLayout = BufferLayout.struct([
113-
BufferLayout.u8('state'),
114116
Layout.publicKey('mint'),
115117
Layout.publicKey('owner'),
116118
Layout.uint64('amount'),
117119
BufferLayout.u32('option'),
118120
Layout.publicKey('delegate'),
119-
BufferLayout.u32('padding'),
121+
BufferLayout.u8('is_initialized'),
122+
BufferLayout.u8('padding'),
123+
BufferLayout.u16('padding'),
120124
Layout.uint64('delegatedAmount'),
121125
]);
122126

@@ -158,6 +162,7 @@ type MultisigInfo = {|
158162
const MultisigLayout = BufferLayout.struct([
159163
BufferLayout.u8('m'),
160164
BufferLayout.u8('n'),
165+
BufferLayout.u8('is_initialized'),
161166
Layout.publicKey('signer1'),
162167
Layout.publicKey('signer2'),
163168
Layout.publicKey('signer3'),
@@ -471,13 +476,12 @@ export class Token {
471476
`Invalid mint owner: ${JSON.stringify(info.owner)}`,
472477
);
473478
}
479+
if (info.data.length != MintLayout.span) {
480+
throw new Error(`Invalid mint size`);
481+
}
474482

475483
const data = Buffer.from(info.data);
476-
477484
const mintInfo = MintLayout.decode(data);
478-
if (mintInfo.state !== 1) {
479-
throw new Error(`Invalid account data`);
480-
}
481485
if (mintInfo.option === 0) {
482486
mintInfo.owner = null;
483487
} else {
@@ -499,13 +503,12 @@ export class Token {
499503
if (!info.owner.equals(this.programId)) {
500504
throw new Error(`Invalid account owner`);
501505
}
506+
if (info.data.length != AccountLayout.span) {
507+
throw new Error(`Invalid account size`);
508+
}
502509

503510
const data = Buffer.from(info.data);
504511
const accountInfo = AccountLayout.decode(data);
505-
506-
if (accountInfo.state !== 2) {
507-
throw new Error(`Invalid account data`);
508-
}
509512
accountInfo.mint = new PublicKey(accountInfo.mint);
510513
accountInfo.owner = new PublicKey(accountInfo.owner);
511514
accountInfo.amount = TokenAmount.fromBuffer(accountInfo.amount);
@@ -542,6 +545,9 @@ export class Token {
542545
if (!info.owner.equals(this.programId)) {
543546
throw new Error(`Invalid multisig owner`);
544547
}
548+
if (info.data.length != MultisigLayout.span) {
549+
throw new Error(`Invalid multisig size`);
550+
}
545551

546552
const data = Buffer.from(info.data);
547553
const multisigInfo = MultisigLayout.decode(data);

token/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ pub enum TokenError {
3636
/// Invalid number of required signers.
3737
#[error("Invalid number of required signers")]
3838
InvalidNumberOfRequiredSigners,
39+
/// State is uninitialized.
40+
#[error("State is unititialized")]
41+
UninitializedState,
3942
}
4043
impl From<TokenError> for ProgramError {
4144
fn from(e: TokenError) -> Self {
@@ -67,6 +70,7 @@ impl PrintProgramError for TokenError {
6770
TokenError::InvalidNumberOfRequiredSigners => {
6871
info!("Error: Invalid number of required signers")
6972
}
73+
TokenError::UninitializedState => info!("Error: State is uninitialized"),
7074
}
7175
}
7276
}

token/src/instruction.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ pub enum TokenInstruction {
169169
},
170170
}
171171
impl TokenInstruction {
172-
/// Deserializes a byte buffer into an [TokenInstruction](enum.TokenInstruction.html).
173-
pub fn deserialize(input: &[u8]) -> Result<Self, ProgramError> {
172+
/// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html).
173+
pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
174174
if input.len() < size_of::<u8>() {
175175
return Err(ProgramError::InvalidAccountData);
176176
}
@@ -232,8 +232,8 @@ impl TokenInstruction {
232232
})
233233
}
234234

235-
/// Serializes an [TokenInstruction](enum.TokenInstruction.html) into a byte buffer.
236-
pub fn serialize(self: &Self) -> Result<Vec<u8>, ProgramError> {
235+
/// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer.
236+
pub fn pack(self: &Self) -> Result<Vec<u8>, ProgramError> {
237237
let mut output = vec![0u8; size_of::<TokenInstruction>()];
238238
match self {
239239
Self::InitializeMint { amount, decimals } => {
@@ -292,7 +292,7 @@ pub fn initialize_mint(
292292
amount: u64,
293293
decimals: u8,
294294
) -> Result<Instruction, ProgramError> {
295-
let data = TokenInstruction::InitializeMint { amount, decimals }.serialize()?;
295+
let data = TokenInstruction::InitializeMint { amount, decimals }.pack()?;
296296

297297
let mut accounts = vec![AccountMeta::new(*mint_pubkey, false)];
298298
if amount != 0 {
@@ -326,7 +326,7 @@ pub fn initialize_account(
326326
mint_pubkey: &Pubkey,
327327
owner_pubkey: &Pubkey,
328328
) -> Result<Instruction, ProgramError> {
329-
let data = TokenInstruction::InitializeAccount.serialize()?;
329+
let data = TokenInstruction::InitializeAccount.pack()?;
330330

331331
let accounts = vec![
332332
AccountMeta::new(*account_pubkey, false),
@@ -354,7 +354,7 @@ pub fn initialize_multisig(
354354
{
355355
return Err(ProgramError::MissingRequiredSignature);
356356
}
357-
let data = TokenInstruction::InitializeMultisig { m }.serialize()?;
357+
let data = TokenInstruction::InitializeMultisig { m }.pack()?;
358358

359359
let mut accounts = Vec::with_capacity(1 + signer_pubkeys.len());
360360
accounts.push(AccountMeta::new(*multisig_pubkey, false));
@@ -378,7 +378,7 @@ pub fn transfer(
378378
signer_pubkeys: &[&Pubkey],
379379
amount: u64,
380380
) -> Result<Instruction, ProgramError> {
381-
let data = TokenInstruction::Transfer { amount }.serialize()?;
381+
let data = TokenInstruction::Transfer { amount }.pack()?;
382382

383383
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
384384
accounts.push(AccountMeta::new(*source_pubkey, false));
@@ -407,7 +407,7 @@ pub fn approve(
407407
signer_pubkeys: &[&Pubkey],
408408
amount: u64,
409409
) -> Result<Instruction, ProgramError> {
410-
let data = TokenInstruction::Approve { amount }.serialize()?;
410+
let data = TokenInstruction::Approve { amount }.pack()?;
411411

412412
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
413413
accounts.push(AccountMeta::new_readonly(*source_pubkey, false));
@@ -434,7 +434,7 @@ pub fn revoke(
434434
owner_pubkey: &Pubkey,
435435
signer_pubkeys: &[&Pubkey],
436436
) -> Result<Instruction, ProgramError> {
437-
let data = TokenInstruction::Revoke.serialize()?;
437+
let data = TokenInstruction::Revoke.pack()?;
438438

439439
let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
440440
accounts.push(AccountMeta::new_readonly(*source_pubkey, false));
@@ -461,7 +461,7 @@ pub fn set_owner(
461461
owner_pubkey: &Pubkey,
462462
signer_pubkeys: &[&Pubkey],
463463
) -> Result<Instruction, ProgramError> {
464-
let data = TokenInstruction::SetOwner.serialize()?;
464+
let data = TokenInstruction::SetOwner.pack()?;
465465

466466
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
467467
accounts.push(AccountMeta::new(*owned_pubkey, false));
@@ -490,7 +490,7 @@ pub fn mint_to(
490490
signer_pubkeys: &[&Pubkey],
491491
amount: u64,
492492
) -> Result<Instruction, ProgramError> {
493-
let data = TokenInstruction::MintTo { amount }.serialize()?;
493+
let data = TokenInstruction::MintTo { amount }.pack()?;
494494

495495
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
496496
accounts.push(AccountMeta::new(*mint_pubkey, false));
@@ -518,7 +518,7 @@ pub fn burn(
518518
signer_pubkeys: &[&Pubkey],
519519
amount: u64,
520520
) -> Result<Instruction, ProgramError> {
521-
let data = TokenInstruction::Burn { amount }.serialize()?;
521+
let data = TokenInstruction::Burn { amount }.pack()?;
522522

523523
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
524524
accounts.push(AccountMeta::new(*account_pubkey, false));

0 commit comments

Comments
 (0)