Remove supply from Token (#82)
This commit is contained in:
parent
a831eddb8d
commit
56dd582c6f
|
@ -73,7 +73,6 @@ typedef enum TokenSwap_SwapInstruction_Tag {
|
|||
* 0. `[]` Token-swap
|
||||
* 1. `[]` $authority
|
||||
* 2. `[writable]` SOURCE Pool account, amount is transferable by $authority.
|
||||
* 4. `[writable]` Pool MINT account, $authority is the owner.
|
||||
* 5. `[writable]` token_a Account to withdraw FROM.
|
||||
* 6. `[writable]` token_b Account to withdraw FROM.
|
||||
* 7. `[writable]` token_a user Account.
|
||||
|
|
|
@ -244,7 +244,6 @@ export async function withdraw(): Promise<void> {
|
|||
await tokenSwap.withdraw(
|
||||
authority,
|
||||
tokenAccountPool,
|
||||
tokenPool.publicKey,
|
||||
tokenAccountA,
|
||||
tokenAccountB,
|
||||
userAccountA,
|
||||
|
|
|
@ -453,7 +453,6 @@ export class TokenSwap {
|
|||
async withdraw(
|
||||
authority: PublicKey,
|
||||
sourcePoolAccount: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
fromA: PublicKey,
|
||||
fromB: PublicKey,
|
||||
userAccountA: PublicKey,
|
||||
|
@ -468,7 +467,6 @@ export class TokenSwap {
|
|||
this.withdrawInstruction(
|
||||
authority,
|
||||
sourcePoolAccount,
|
||||
poolToken,
|
||||
fromA,
|
||||
fromB,
|
||||
userAccountA,
|
||||
|
@ -483,7 +481,6 @@ export class TokenSwap {
|
|||
withdrawInstruction(
|
||||
authority: PublicKey,
|
||||
sourcePoolAccount: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
fromA: PublicKey,
|
||||
fromB: PublicKey,
|
||||
userAccountA: PublicKey,
|
||||
|
@ -509,7 +506,6 @@ export class TokenSwap {
|
|||
{pubkey: this.tokenSwap, isSigner: false, isWritable: false},
|
||||
{pubkey: authority, isSigner: false, isWritable: false},
|
||||
{pubkey: sourcePoolAccount, isSigner: false, isWritable: true},
|
||||
{pubkey: poolToken, isSigner: false, isWritable: true},
|
||||
{pubkey: fromA, isSigner: false, isWritable: true},
|
||||
{pubkey: fromB, isSigner: false, isWritable: true},
|
||||
{pubkey: userAccountA, isSigner: false, isWritable: true},
|
||||
|
|
|
@ -80,7 +80,6 @@ pub enum SwapInstruction {
|
|||
/// 0. `[]` Token-swap
|
||||
/// 1. `[]` $authority
|
||||
/// 2. `[writable]` SOURCE Pool account, amount is transferable by $authority.
|
||||
/// 4. `[writable]` Pool MINT account, $authority is the owner.
|
||||
/// 5. `[writable]` token_a Account to withdraw FROM.
|
||||
/// 6. `[writable]` token_b Account to withdraw FROM.
|
||||
/// 7. `[writable]` token_a user Account.
|
||||
|
@ -289,7 +288,6 @@ pub enum State {
|
|||
struct Invariant {
|
||||
token_a: u64,
|
||||
token_b: u64,
|
||||
pool: Option<u64>,
|
||||
fee: Fee,
|
||||
}
|
||||
impl Invariant {
|
||||
|
@ -310,17 +308,6 @@ impl Invariant {
|
|||
fn exchange_rate(&self, token_a: u64) -> Option<u64> {
|
||||
token_a.checked_mul(self.token_b)?.checked_div(self.token_a)
|
||||
}
|
||||
fn redeem(&self, user_pool: u64) -> Option<(u64, u64)> {
|
||||
let token_a = self
|
||||
.token_a
|
||||
.checked_mul(user_pool)?
|
||||
.checked_div(self.pool?)?;
|
||||
let token_b = self
|
||||
.token_b
|
||||
.checked_mul(user_pool)?
|
||||
.checked_div(self.pool?)?;
|
||||
Some((token_a, token_b))
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
@ -403,20 +390,13 @@ impl State {
|
|||
token_program_id: &Pubkey,
|
||||
swap: &Pubkey,
|
||||
burn_account: &Pubkey,
|
||||
mint: &Pubkey,
|
||||
authority: &Pubkey,
|
||||
amount: u64,
|
||||
) -> Result<(), ProgramError> {
|
||||
let swap_string = swap.to_string();
|
||||
let signers = &[&[&swap_string[..32]][..]];
|
||||
let ix = spl_token::instruction::burn(
|
||||
token_program_id,
|
||||
burn_account,
|
||||
mint,
|
||||
authority,
|
||||
&[],
|
||||
amount,
|
||||
)?;
|
||||
let ix =
|
||||
spl_token::instruction::burn(token_program_id, burn_account, authority, &[], amount)?;
|
||||
invoke_signed(&ix, accounts, signers)
|
||||
}
|
||||
|
||||
|
@ -500,9 +480,6 @@ impl State {
|
|||
if spl_token::option::COption::Some(*authority_info.key) != pool_mint.owner {
|
||||
return Err(Error::InvalidOwner.into());
|
||||
}
|
||||
if 0 != pool_mint.info.supply {
|
||||
return Err(Error::InvalidSupply.into());
|
||||
}
|
||||
if token_b.amount == 0 {
|
||||
return Err(Error::InvalidSupply.into());
|
||||
}
|
||||
|
@ -573,7 +550,6 @@ impl State {
|
|||
token_a: into_token.amount,
|
||||
token_b: from_token.amount,
|
||||
fee: token_swap.fee,
|
||||
pool: None,
|
||||
};
|
||||
let output = invariant
|
||||
.swap(amount)
|
||||
|
@ -635,7 +611,6 @@ impl State {
|
|||
token_a: token_a.amount,
|
||||
token_b: token_b.amount,
|
||||
fee: token_swap.fee,
|
||||
pool: None,
|
||||
};
|
||||
let b_amount = invariant
|
||||
.exchange_rate(a_amount)
|
||||
|
@ -686,7 +661,6 @@ impl State {
|
|||
let swap_info = next_account_info(account_info_iter)?;
|
||||
let authority_info = next_account_info(account_info_iter)?;
|
||||
let source_info = next_account_info(account_info_iter)?;
|
||||
let pool_info = next_account_info(account_info_iter)?;
|
||||
let token_a_info = next_account_info(account_info_iter)?;
|
||||
let token_b_info = next_account_info(account_info_iter)?;
|
||||
let dest_token_a_info = next_account_info(account_info_iter)?;
|
||||
|
@ -703,23 +677,21 @@ impl State {
|
|||
if *token_b_info.key != token_swap.token_b {
|
||||
return Err(Error::InvalidInput.into());
|
||||
}
|
||||
if *pool_info.key != token_swap.pool_mint {
|
||||
return Err(Error::InvalidInput.into());
|
||||
}
|
||||
|
||||
let token_a = Self::token_account_deserialize(token_a_info)?;
|
||||
let token_b = Self::token_account_deserialize(token_b_info)?;
|
||||
let pool_token = Self::token_deserialize(pool_info)?;
|
||||
|
||||
let invariant = Invariant {
|
||||
token_a: token_a.amount,
|
||||
token_b: token_b.amount,
|
||||
fee: token_swap.fee,
|
||||
pool: Some(pool_token.info.supply),
|
||||
};
|
||||
|
||||
let (a_amount, b_amount) = invariant
|
||||
.redeem(amount)
|
||||
let a_amount = amount;
|
||||
let b_amount = invariant
|
||||
.exchange_rate(a_amount)
|
||||
.ok_or_else(|| Error::CalculationFailure)?;
|
||||
|
||||
Self::token_transfer(
|
||||
accounts,
|
||||
token_program_info.key,
|
||||
|
@ -743,7 +715,6 @@ impl State {
|
|||
token_program_info.key,
|
||||
swap_info.key,
|
||||
source_info.key,
|
||||
pool_info.key,
|
||||
authority_info.key,
|
||||
amount,
|
||||
)?;
|
||||
|
@ -827,7 +798,7 @@ mod tests {
|
|||
account::Account, account_info::create_is_signer_account_infos, instruction::Instruction,
|
||||
};
|
||||
use spl_token::{
|
||||
instruction::{initialize_account, initialize_mint, TokenInfo},
|
||||
instruction::{initialize_account, initialize_mint},
|
||||
state::State as SplState,
|
||||
};
|
||||
|
||||
|
@ -863,7 +834,7 @@ mod tests {
|
|||
fn mint_token(
|
||||
program_id: &Pubkey,
|
||||
authority_key: &Pubkey,
|
||||
supply: u64,
|
||||
amount: u64,
|
||||
) -> ((Pubkey, Account), (Pubkey, Account)) {
|
||||
let token_key = pubkey_rand();
|
||||
let mut token_account = Account::new(0, size_of::<SplState>(), &program_id);
|
||||
|
@ -887,13 +858,11 @@ mod tests {
|
|||
&token_key,
|
||||
Some(&account_key),
|
||||
Some(&authority_key),
|
||||
TokenInfo {
|
||||
supply,
|
||||
decimals: 2,
|
||||
},
|
||||
amount,
|
||||
2,
|
||||
)
|
||||
.unwrap(),
|
||||
if supply == 0 {
|
||||
if amount == 0 {
|
||||
vec![&mut token_account, &mut authority_account]
|
||||
} else {
|
||||
vec![
|
||||
|
|
|
@ -17,20 +17,6 @@
|
|||
*/
|
||||
#define Token_MIN_SIGNERS 1
|
||||
|
||||
/**
|
||||
* Specifies the financial specifics of a token.
|
||||
*/
|
||||
typedef struct Token_TokenInfo {
|
||||
/**
|
||||
* Total supply of tokens.
|
||||
*/
|
||||
uint64_t supply;
|
||||
/**
|
||||
* Number of base 10 digits to the right of the decimal place in the total supply.
|
||||
*/
|
||||
uint64_t decimals;
|
||||
} Token_TokenInfo;
|
||||
|
||||
/**
|
||||
* Instructions supported by the token program.
|
||||
*/
|
||||
|
@ -186,9 +172,13 @@ typedef enum Token_TokenInstruction_Tag {
|
|||
|
||||
typedef struct Token_InitializeMint_Body {
|
||||
/**
|
||||
* The financial specifics of the token.
|
||||
* Initial amount of tokens to mint.
|
||||
*/
|
||||
Token_TokenInfo info;
|
||||
uint64_t amount;
|
||||
/**
|
||||
* Number of base 10 digits to the right of the decimal place.
|
||||
*/
|
||||
uint8_t decimals;
|
||||
} Token_InitializeMint_Body;
|
||||
|
||||
typedef struct Token_InitializeMultisig_Body {
|
||||
|
@ -271,16 +261,16 @@ typedef struct Token_COption_Pubkey {
|
|||
* matching types my inter-opt.
|
||||
*/
|
||||
typedef struct Token_Token {
|
||||
/**
|
||||
* Token details.
|
||||
*/
|
||||
Token_TokenInfo info;
|
||||
/**
|
||||
* 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;
|
||||
} Token_Token;
|
||||
|
||||
/**
|
||||
|
|
|
@ -120,7 +120,6 @@ export async function createMint(): Promise<void> {
|
|||
);
|
||||
|
||||
const mintInfo = await testToken.getMintInfo();
|
||||
assert(mintInfo.supply.toNumber() == 10000);
|
||||
assert(mintInfo.decimals == 2);
|
||||
assert(mintInfo.owner == null);
|
||||
|
||||
|
@ -264,7 +263,6 @@ export async function mintTo(): Promise<void> {
|
|||
|
||||
{
|
||||
const mintInfo = await testMintableToken.getMintInfo();
|
||||
assert(mintInfo.supply.toNumber() == 10000);
|
||||
assert(mintInfo.decimals == 2);
|
||||
if (mintInfo.owner === null) {
|
||||
throw new Error('owner should not be null');
|
||||
|
@ -285,7 +283,6 @@ export async function mintTo(): Promise<void> {
|
|||
|
||||
{
|
||||
const mintInfo = await testMintableToken.getMintInfo();
|
||||
assert(mintInfo.supply.toNumber() == 10042);
|
||||
assert(mintInfo.decimals == 2);
|
||||
if (mintInfo.owner === null) {
|
||||
throw new Error('owner should not be null');
|
||||
|
@ -303,16 +300,12 @@ export async function mintTo(): Promise<void> {
|
|||
}
|
||||
|
||||
export async function burn(): Promise<void> {
|
||||
let mintInfo = await testToken.getMintInfo();
|
||||
const supply = mintInfo.supply.toNumber();
|
||||
let accountInfo = await testToken.getAccountInfo(testAccount);
|
||||
const amount = accountInfo.amount.toNumber();
|
||||
|
||||
await testToken.burn(testAccount, testAccountOwner, [], 1);
|
||||
await sleep(500);
|
||||
|
||||
mintInfo = await testToken.getMintInfo();
|
||||
assert(mintInfo.supply.toNumber() == supply - 1);
|
||||
accountInfo = await testToken.getAccountInfo(testAccount);
|
||||
assert(accountInfo.amount.toNumber() == amount - 1);
|
||||
}
|
||||
|
|
|
@ -57,11 +57,6 @@ export class TokenAmount extends BN {
|
|||
* Information about the mint
|
||||
*/
|
||||
type MintInfo = {|
|
||||
/**
|
||||
* Total supply of tokens
|
||||
*/
|
||||
supply: TokenAmount,
|
||||
|
||||
/**
|
||||
* Number of base 10 digits to the right of the decimal place
|
||||
*/
|
||||
|
@ -74,11 +69,11 @@ type MintInfo = {|
|
|||
|
||||
const MintLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('state'),
|
||||
Layout.uint64('supply'),
|
||||
BufferLayout.nu64('decimals'),
|
||||
BufferLayout.u32('option'),
|
||||
Layout.publicKey('owner'),
|
||||
BufferLayout.nu64('padding'),
|
||||
BufferLayout.u8('decimals'),
|
||||
BufferLayout.u16('padding1'),
|
||||
BufferLayout.nu64('padding2'),
|
||||
]);
|
||||
|
||||
/**
|
||||
|
@ -258,10 +253,11 @@ export class Token {
|
|||
*
|
||||
* @param connection The connection to use
|
||||
* @param owner User account that will own the returned account
|
||||
* @param supply Total supply of the new mint
|
||||
* @param supply Initial supply to mint
|
||||
* @param decimals Location of the decimal place
|
||||
* @param programId Optional token programId, uses the system programId by default
|
||||
* @return Token object for the newly minted token, Public key of the account holding the total supply of new tokens
|
||||
* @return Token object for the newly minted token, Public key of the account
|
||||
* holding the total amount of new tokens
|
||||
*/
|
||||
static async createMint(
|
||||
connection: Connection,
|
||||
|
@ -303,7 +299,7 @@ export class Token {
|
|||
const commandDataLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('instruction'),
|
||||
Layout.uint64('supply'),
|
||||
BufferLayout.nu64('decimals'),
|
||||
BufferLayout.u8('decimals'),
|
||||
]);
|
||||
let data = Buffer.alloc(1024);
|
||||
{
|
||||
|
@ -482,7 +478,6 @@ export class Token {
|
|||
if (mintInfo.state !== 1) {
|
||||
throw new Error(`Invalid account data`);
|
||||
}
|
||||
mintInfo.supply = TokenAmount.fromBuffer(mintInfo.supply);
|
||||
if (mintInfo.option === 0) {
|
||||
mintInfo.owner = null;
|
||||
} else {
|
||||
|
@ -1029,7 +1024,6 @@ export class Token {
|
|||
|
||||
let keys = [
|
||||
{pubkey: account, isSigner: false, isWritable: true},
|
||||
{pubkey: this.publicKey, isSigner: false, isWritable: true},
|
||||
];
|
||||
if (authority instanceof Account) {
|
||||
keys.push({pubkey: authority.publicKey, isSigner: true, isWritable: false});
|
||||
|
|
|
@ -13,16 +13,6 @@ pub const MIN_SIGNERS: usize = 1;
|
|||
/// Maximum number of multisignature signers (max N)
|
||||
pub const MAX_SIGNERS: usize = 11;
|
||||
|
||||
/// Specifies the financial specifics of a token.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct TokenInfo {
|
||||
/// Total supply of tokens.
|
||||
pub supply: u64,
|
||||
/// Number of base 10 digits to the right of the decimal place in the total supply.
|
||||
pub decimals: u64,
|
||||
}
|
||||
|
||||
/// Instructions supported by the token program.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -43,8 +33,10 @@ pub enum TokenInstruction {
|
|||
/// present then further minting is supported.
|
||||
///
|
||||
InitializeMint {
|
||||
/// The financial specifics of the token.
|
||||
info: TokenInfo,
|
||||
/// 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.
|
||||
///
|
||||
|
@ -188,8 +180,10 @@ impl TokenInstruction {
|
|||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let info = unsafe { *(&input[1] as *const u8 as *const TokenInfo) };
|
||||
Self::InitializeMint { info }
|
||||
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 => {
|
||||
|
@ -242,11 +236,14 @@ impl TokenInstruction {
|
|||
pub fn serialize(self: &Self) -> Result<Vec<u8>, ProgramError> {
|
||||
let mut output = vec![0u8; size_of::<TokenInstruction>()];
|
||||
match self {
|
||||
Self::InitializeMint { info } => {
|
||||
Self::InitializeMint { amount, decimals } => {
|
||||
output[0] = 0;
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut TokenInfo) };
|
||||
*value = *info;
|
||||
let value = unsafe { &mut *(&mut output[size_of::<u8>()] as *mut u8 as *mut u64) };
|
||||
*value = *amount;
|
||||
let value =
|
||||
unsafe { &mut *(&mut output[size_of::<u8>() + size_of::<u64>()] as *mut u8) };
|
||||
*value = *decimals;
|
||||
}
|
||||
Self::InitializeAccount => output[0] = 1,
|
||||
Self::InitializeMultisig { m } => {
|
||||
|
@ -292,12 +289,13 @@ pub fn initialize_mint(
|
|||
mint_pubkey: &Pubkey,
|
||||
account_pubkey: Option<&Pubkey>,
|
||||
owner_pubkey: Option<&Pubkey>,
|
||||
info: TokenInfo,
|
||||
amount: u64,
|
||||
decimals: u8,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::InitializeMint { info }.serialize()?;
|
||||
let data = TokenInstruction::InitializeMint { amount, decimals }.serialize()?;
|
||||
|
||||
let mut accounts = vec![AccountMeta::new(*mint_pubkey, false)];
|
||||
if info.supply != 0 {
|
||||
if amount != 0 {
|
||||
match account_pubkey {
|
||||
Some(pubkey) => accounts.push(AccountMeta::new(*pubkey, false)),
|
||||
None => {
|
||||
|
@ -308,7 +306,7 @@ pub fn initialize_mint(
|
|||
match owner_pubkey {
|
||||
Some(pubkey) => accounts.push(AccountMeta::new_readonly(*pubkey, false)),
|
||||
None => {
|
||||
if info.supply == 0 {
|
||||
if amount == 0 {
|
||||
return Err(TokenError::OwnerRequiredIfNoInitialSupply.into());
|
||||
}
|
||||
}
|
||||
|
@ -516,7 +514,6 @@ pub fn mint_to(
|
|||
pub fn burn(
|
||||
token_program_id: &Pubkey,
|
||||
account_pubkey: &Pubkey,
|
||||
mint_pubkey: &Pubkey,
|
||||
authority_pubkey: &Pubkey,
|
||||
signer_pubkeys: &[&Pubkey],
|
||||
amount: u64,
|
||||
|
@ -525,7 +522,6 @@ pub fn burn(
|
|||
|
||||
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
|
||||
accounts.push(AccountMeta::new(*account_pubkey, false));
|
||||
accounts.push(AccountMeta::new(*mint_pubkey, false));
|
||||
accounts.push(AccountMeta::new_readonly(
|
||||
*authority_pubkey,
|
||||
signer_pubkeys.is_empty(),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate::{
|
||||
error::TokenError,
|
||||
instruction::{is_valid_signer_index, TokenInfo, TokenInstruction, MAX_SIGNERS},
|
||||
instruction::{is_valid_signer_index, TokenInstruction, MAX_SIGNERS},
|
||||
option::COption,
|
||||
};
|
||||
use solana_sdk::{
|
||||
|
@ -17,12 +17,12 @@ use std::mem::size_of;
|
|||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct Token {
|
||||
/// Token details.
|
||||
pub info: TokenInfo,
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// Account that holds tokens or may delegate tokens.
|
||||
|
@ -93,7 +93,11 @@ impl Default for State {
|
|||
}
|
||||
impl State {
|
||||
/// Processes an [InitializeMint](enum.TokenInstruction.html) instruction.
|
||||
pub fn process_initialize_mint(accounts: &[AccountInfo], info: TokenInfo) -> ProgramResult {
|
||||
pub fn process_initialize_mint(
|
||||
accounts: &[AccountInfo],
|
||||
amount: u64,
|
||||
decimals: u8,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
let mint_info = next_account_info(account_info_iter)?;
|
||||
|
||||
|
@ -101,7 +105,7 @@ impl State {
|
|||
return Err(TokenError::AlreadyInUse.into());
|
||||
}
|
||||
|
||||
let owner = if info.supply != 0 {
|
||||
let owner = if amount != 0 {
|
||||
let dest_account_info = next_account_info(account_info_iter)?;
|
||||
let mut dest_account_data = dest_account_info.data.borrow_mut();
|
||||
if let State::Account(mut dest_account) = State::deserialize(&dest_account_data)? {
|
||||
|
@ -109,7 +113,7 @@ impl State {
|
|||
return Err(TokenError::MintMismatch.into());
|
||||
}
|
||||
|
||||
dest_account.amount = info.supply;
|
||||
dest_account.amount = amount;
|
||||
State::Account(dest_account).serialize(&mut dest_account_data)?;
|
||||
} else {
|
||||
return Err(ProgramError::InvalidArgument);
|
||||
|
@ -126,7 +130,7 @@ impl State {
|
|||
return Err(TokenError::OwnerRequiredIfNoInitialSupply.into());
|
||||
};
|
||||
|
||||
State::Mint(Token { info, owner }).serialize(&mut mint_info.data.borrow_mut())
|
||||
State::Mint(Token { decimals, owner }).serialize(&mut mint_info.data.borrow_mut())
|
||||
}
|
||||
|
||||
/// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction.
|
||||
|
@ -335,8 +339,7 @@ impl State {
|
|||
let dest_account_info = next_account_info(account_info_iter)?;
|
||||
let owner_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let mut mint_data = mint_info.data.borrow_mut();
|
||||
if let State::Mint(mut token) = State::deserialize(&mint_data)? {
|
||||
if let State::Mint(token) = State::deserialize(&mint_info.data.borrow())? {
|
||||
match token.owner {
|
||||
COption::Some(owner) => {
|
||||
Self::validate_owner(
|
||||
|
@ -357,9 +360,6 @@ impl State {
|
|||
return Err(TokenError::MintMismatch.into());
|
||||
}
|
||||
|
||||
token.info.supply += amount;
|
||||
State::Mint(token).serialize(&mut mint_data)?;
|
||||
|
||||
dest_account.amount += amount;
|
||||
State::Account(dest_account).serialize(&mut dest_account_data)
|
||||
} else {
|
||||
|
@ -378,7 +378,6 @@ impl State {
|
|||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
let source_account_info = next_account_info(account_info_iter)?;
|
||||
let mint_info = next_account_info(account_info_iter)?;
|
||||
let authority_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let (mut source_account, mut source_data) = {
|
||||
|
@ -391,19 +390,6 @@ impl State {
|
|||
}
|
||||
};
|
||||
|
||||
let (mut token, mut mint_data) = {
|
||||
let mint_data = mint_info.data.borrow_mut();
|
||||
match State::deserialize(&mint_data)? {
|
||||
State::Mint(token) => (token, mint_data),
|
||||
_ => {
|
||||
return Err(ProgramError::InvalidArgument);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if mint_info.key != &source_account.mint {
|
||||
return Err(TokenError::MintMismatch.into());
|
||||
}
|
||||
if source_account.amount < amount {
|
||||
return Err(TokenError::InsufficientFunds.into());
|
||||
}
|
||||
|
@ -434,10 +420,8 @@ impl State {
|
|||
}
|
||||
|
||||
source_account.amount -= amount;
|
||||
token.info.supply -= amount;
|
||||
|
||||
State::Account(source_account).serialize(&mut source_data)?;
|
||||
State::Mint(token).serialize(&mut mint_data)
|
||||
State::Account(source_account).serialize(&mut source_data)
|
||||
}
|
||||
|
||||
/// Processes an [Instruction](enum.Instruction.html).
|
||||
|
@ -445,9 +429,9 @@ impl State {
|
|||
let instruction = TokenInstruction::deserialize(input)?;
|
||||
|
||||
match instruction {
|
||||
TokenInstruction::InitializeMint { info } => {
|
||||
TokenInstruction::InitializeMint { amount, decimals } => {
|
||||
info!("Instruction: InitializeMint");
|
||||
Self::process_initialize_mint(accounts, info)
|
||||
Self::process_initialize_mint(accounts, amount, decimals)
|
||||
}
|
||||
TokenInstruction::InitializeAccount => {
|
||||
info!("Instruction: InitializeAccount");
|
||||
|
@ -634,17 +618,8 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(ProgramError::InvalidArgument),
|
||||
do_process_instruction(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&mint_key,
|
||||
Some(&account_key),
|
||||
None,
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
}
|
||||
)
|
||||
.unwrap(),
|
||||
initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2,)
|
||||
.unwrap(),
|
||||
vec![&mut mint_account, &mut account_account]
|
||||
)
|
||||
);
|
||||
|
@ -658,17 +633,7 @@ mod tests {
|
|||
|
||||
// create new token
|
||||
do_process_instruction(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&mint_key,
|
||||
Some(&account_key),
|
||||
None,
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(),
|
||||
vec![&mut mint_account, &mut account_account],
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -684,17 +649,8 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(TokenError::MintMismatch.into()),
|
||||
do_process_instruction(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&mint2_key,
|
||||
Some(&account2_key),
|
||||
None,
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
initialize_mint(&program_id, &mint2_key, Some(&account2_key), None, 1000, 2,)
|
||||
.unwrap(),
|
||||
vec![&mut mint2_account, &mut account2_account]
|
||||
)
|
||||
);
|
||||
|
@ -703,17 +659,8 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(TokenError::AlreadyInUse.into()),
|
||||
do_process_instruction(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&mint_key,
|
||||
Some(&account_key),
|
||||
None,
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2,)
|
||||
.unwrap(),
|
||||
vec![&mut mint_account, &mut account_account]
|
||||
)
|
||||
);
|
||||
|
@ -802,17 +749,7 @@ mod tests {
|
|||
|
||||
// create new token
|
||||
do_process_instruction(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&mint_key,
|
||||
Some(&account_key),
|
||||
None,
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(),
|
||||
vec![&mut mint_account, &mut account_account],
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -1102,17 +1039,8 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
// create mint-able token without owner
|
||||
let mut instruction = initialize_mint(
|
||||
&program_id,
|
||||
&mint_key,
|
||||
None,
|
||||
Some(&owner_key),
|
||||
TokenInfo {
|
||||
supply: 0,
|
||||
decimals: 2,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let mut instruction =
|
||||
initialize_mint(&program_id, &mint_key, None, Some(&owner_key), 0, 2).unwrap();
|
||||
instruction.accounts.pop();
|
||||
assert_eq!(
|
||||
Err(TokenError::OwnerRequiredIfNoInitialSupply.into()),
|
||||
|
@ -1120,12 +1048,18 @@ mod tests {
|
|||
);
|
||||
|
||||
// create mint-able token with zero supply
|
||||
let info = TokenInfo {
|
||||
supply: 0,
|
||||
decimals: 2,
|
||||
};
|
||||
let amount = 0;
|
||||
let decimals = 2;
|
||||
do_process_instruction(
|
||||
initialize_mint(&program_id, &mint_key, None, Some(&owner_key), info).unwrap(),
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&mint_key,
|
||||
None,
|
||||
Some(&owner_key),
|
||||
amount,
|
||||
decimals,
|
||||
)
|
||||
.unwrap(),
|
||||
vec![&mut mint_account, &mut account_account],
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -1133,7 +1067,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
token,
|
||||
Token {
|
||||
info,
|
||||
decimals,
|
||||
owner: COption::Some(owner_key)
|
||||
}
|
||||
);
|
||||
|
@ -1148,10 +1082,9 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
if let State::Mint(token) = State::deserialize(&mint_account.data).unwrap() {
|
||||
assert_eq!(token.info.supply, 42);
|
||||
} else {
|
||||
panic!("not an account");
|
||||
match State::deserialize(&mint_account.data).unwrap() {
|
||||
State::Mint(_) => (),
|
||||
_ => panic!("not a mint"),
|
||||
}
|
||||
if let State::Account(dest_account) = State::deserialize(&account_account.data).unwrap() {
|
||||
assert_eq!(dest_account.amount, 42);
|
||||
|
@ -1192,17 +1125,7 @@ mod tests {
|
|||
|
||||
// create new token
|
||||
do_process_instruction(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&mint_key,
|
||||
Some(&account_key),
|
||||
None,
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(),
|
||||
vec![&mut mint_account, &mut account_account],
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -1374,10 +1297,8 @@ mod tests {
|
|||
&mint_key,
|
||||
Some(&account_key),
|
||||
Some(&owner_key),
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
},
|
||||
1000,
|
||||
2,
|
||||
)
|
||||
.unwrap(),
|
||||
vec![&mut mint_account, &mut account_account, &mut owner_account],
|
||||
|
@ -1414,17 +1335,7 @@ mod tests {
|
|||
|
||||
// create new token without owner
|
||||
do_process_instruction(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&mint2_key,
|
||||
Some(&account2_key),
|
||||
None,
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
initialize_mint(&program_id, &mint2_key, Some(&account2_key), None, 1000, 2).unwrap(),
|
||||
vec![&mut mint2_account, &mut account2_account],
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -1500,10 +1411,8 @@ mod tests {
|
|||
&mint_key,
|
||||
Some(&account_key),
|
||||
Some(&owner_key),
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
},
|
||||
1000,
|
||||
2,
|
||||
)
|
||||
.unwrap(),
|
||||
vec![&mut mint_account, &mut account_account, &mut owner_account],
|
||||
|
@ -1517,10 +1426,9 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
if let State::Mint(token) = State::deserialize(&mint_account.data).unwrap() {
|
||||
assert_eq!(token.info.supply, 1000 + 42);
|
||||
} else {
|
||||
panic!("not an account");
|
||||
match State::deserialize(&mint_account.data).unwrap() {
|
||||
State::Mint(_) => (),
|
||||
_ => panic!("not a mint"),
|
||||
}
|
||||
if let State::Account(dest_account) = State::deserialize(&account2_account.data).unwrap() {
|
||||
assert_eq!(dest_account.amount, 42);
|
||||
|
@ -1640,43 +1548,19 @@ mod tests {
|
|||
|
||||
// create new token
|
||||
do_process_instruction(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&mint_key,
|
||||
Some(&account_key),
|
||||
None,
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(),
|
||||
vec![&mut mint_account, &mut account_account],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// missing signer
|
||||
let mut instruction =
|
||||
burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 42).unwrap();
|
||||
instruction.accounts[2].is_signer = false;
|
||||
let mut instruction = burn(&program_id, &account_key, &delegate_key, &[], 42).unwrap();
|
||||
instruction.accounts[1].is_signer = false;
|
||||
assert_eq!(
|
||||
Err(TokenError::OwnerMismatch.into()),
|
||||
do_process_instruction(
|
||||
instruction,
|
||||
vec![
|
||||
&mut account_account,
|
||||
&mut mint_account,
|
||||
&mut delegate_account
|
||||
],
|
||||
)
|
||||
);
|
||||
|
||||
// mismatch token
|
||||
assert_eq!(
|
||||
Err(TokenError::MintMismatch.into()),
|
||||
do_process_instruction(
|
||||
burn(&program_id, &mismatch_key, &mint_key, &owner_key, &[], 42).unwrap(),
|
||||
vec![&mut mismatch_account, &mut mint_account, &mut owner_account,],
|
||||
vec![&mut account_account, &mut delegate_account],
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -1684,22 +1568,21 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(TokenError::OwnerMismatch.into()),
|
||||
do_process_instruction(
|
||||
burn(&program_id, &account_key, &mint_key, &owner2_key, &[], 42).unwrap(),
|
||||
vec![&mut account_account, &mut mint_account, &mut owner2_account],
|
||||
burn(&program_id, &account_key, &owner2_key, &[], 42).unwrap(),
|
||||
vec![&mut account_account, &mut owner2_account],
|
||||
)
|
||||
);
|
||||
|
||||
// burn
|
||||
do_process_instruction(
|
||||
burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(),
|
||||
vec![&mut account_account, &mut mint_account, &mut owner_account],
|
||||
burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(),
|
||||
vec![&mut account_account, &mut owner_account],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let State::Mint(token) = State::deserialize(&mint_account.data).unwrap() {
|
||||
assert_eq!(token.info.supply, 1000 - 42);
|
||||
} else {
|
||||
panic!("not a token account");
|
||||
match State::deserialize(&mint_account.data).unwrap() {
|
||||
State::Mint(_) => (),
|
||||
_ => panic!("not a mint"),
|
||||
}
|
||||
if let State::Account(account) = State::deserialize(&account_account.data).unwrap() {
|
||||
assert_eq!(account.amount, 1000 - 42);
|
||||
|
@ -1711,16 +1594,8 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(TokenError::InsufficientFunds.into()),
|
||||
do_process_instruction(
|
||||
burn(
|
||||
&program_id,
|
||||
&account_key,
|
||||
&mint_key,
|
||||
&owner_key,
|
||||
&[],
|
||||
100_000_000
|
||||
)
|
||||
.unwrap(),
|
||||
vec![&mut account_account, &mut mint_account, &mut owner_account],
|
||||
burn(&program_id, &account_key, &owner_key, &[], 100_000_000).unwrap(),
|
||||
vec![&mut account_account, &mut owner_account],
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -1747,34 +1622,21 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(TokenError::InsufficientFunds.into()),
|
||||
do_process_instruction(
|
||||
burn(
|
||||
&program_id,
|
||||
&account_key,
|
||||
&mint_key,
|
||||
&owner_key,
|
||||
&[],
|
||||
100_000_000
|
||||
)
|
||||
.unwrap(),
|
||||
vec![&mut account_account, &mut mint_account, &mut owner_account],
|
||||
burn(&program_id, &account_key, &owner_key, &[], 100_000_000).unwrap(),
|
||||
vec![&mut account_account, &mut owner_account],
|
||||
)
|
||||
);
|
||||
|
||||
// burn via delegate
|
||||
do_process_instruction(
|
||||
burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 84).unwrap(),
|
||||
vec![
|
||||
&mut account_account,
|
||||
&mut mint_account,
|
||||
&mut delegate_account,
|
||||
],
|
||||
burn(&program_id, &account_key, &delegate_key, &[], 84).unwrap(),
|
||||
vec![&mut account_account, &mut delegate_account],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let State::Mint(token) = State::deserialize(&mint_account.data).unwrap() {
|
||||
assert_eq!(token.info.supply, 1000 - 42 - 84);
|
||||
} else {
|
||||
panic!("not a token account");
|
||||
match State::deserialize(&mint_account.data).unwrap() {
|
||||
State::Mint(_) => (),
|
||||
_ => panic!("not a mint"),
|
||||
}
|
||||
if let State::Account(account) = State::deserialize(&account_account.data).unwrap() {
|
||||
assert_eq!(account.amount, 1000 - 42 - 84);
|
||||
|
@ -1786,20 +1648,8 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(TokenError::OwnerMismatch.into()),
|
||||
do_process_instruction(
|
||||
burn(
|
||||
&program_id,
|
||||
&account_key,
|
||||
&mint_key,
|
||||
&delegate_key,
|
||||
&[],
|
||||
100
|
||||
)
|
||||
.unwrap(),
|
||||
vec![
|
||||
&mut account_account,
|
||||
&mut mint_account,
|
||||
&mut delegate_account,
|
||||
],
|
||||
burn(&program_id, &account_key, &delegate_key, &[], 100).unwrap(),
|
||||
vec![&mut account_account, &mut delegate_account,],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1892,10 +1742,8 @@ mod tests {
|
|||
&mint_key,
|
||||
Some(&account_key),
|
||||
Some(&multisig_key),
|
||||
TokenInfo {
|
||||
supply: 1000,
|
||||
decimals: 2,
|
||||
},
|
||||
1000,
|
||||
2,
|
||||
)
|
||||
.unwrap(),
|
||||
vec![&mut mint_account, &mut account, &mut multisig_account],
|
||||
|
@ -2002,7 +1850,6 @@ mod tests {
|
|||
burn(
|
||||
&program_id,
|
||||
&account_key,
|
||||
&mint_key,
|
||||
&multisig_key,
|
||||
&[&signer_keys[0]],
|
||||
42,
|
||||
|
@ -2010,7 +1857,6 @@ mod tests {
|
|||
.unwrap(),
|
||||
vec![
|
||||
&mut account,
|
||||
&mut mint_account,
|
||||
&mut multisig_account,
|
||||
&mut account_info_iter.next().unwrap(),
|
||||
],
|
||||
|
@ -2023,7 +1869,6 @@ mod tests {
|
|||
burn(
|
||||
&program_id,
|
||||
&account_key,
|
||||
&mint_key,
|
||||
&multisig_delegate_key,
|
||||
&signer_key_refs,
|
||||
42,
|
||||
|
@ -2031,7 +1876,6 @@ mod tests {
|
|||
.unwrap(),
|
||||
vec![
|
||||
&mut account,
|
||||
&mut mint_account,
|
||||
&mut multisig_delegate_account,
|
||||
&mut account_info_iter.next().unwrap(),
|
||||
&mut account_info_iter.next().unwrap(),
|
||||
|
|
Loading…
Reference in New Issue