Token type renaming (#70)
This commit is contained in:
parent
b292d4cb3f
commit
fc7a808461
|
@ -11,7 +11,7 @@ import { newAccountWithLamports } from '../client/util/new-account-with-lamports
|
|||
import { url } from '../url';
|
||||
import { sleep } from '../client/util/sleep';
|
||||
|
||||
// The following globals are created by `createNewTokenSwap` and used by subsequent tests
|
||||
// The following globals are created by `createTokenSwap` and used by subsequent tests
|
||||
// Token swap
|
||||
let tokenSwap: TokenSwap;
|
||||
// authority of the token and accounts
|
||||
|
@ -116,7 +116,7 @@ export async function createTokenSwap(): Promise<void> {
|
|||
);
|
||||
|
||||
// create pool
|
||||
[tokenPool, tokenAccountPool] = await Token.createNewToken(
|
||||
[tokenPool, tokenAccountPool] = await Token.createToken(
|
||||
connection,
|
||||
payer,
|
||||
authority,
|
||||
|
@ -128,7 +128,7 @@ export async function createTokenSwap(): Promise<void> {
|
|||
);
|
||||
|
||||
// create token A
|
||||
[tokenA, tokenAccountA] = await Token.createNewToken(
|
||||
[tokenA, tokenAccountA] = await Token.createToken(
|
||||
connection,
|
||||
payer,
|
||||
owner.publicKey,
|
||||
|
@ -140,7 +140,7 @@ export async function createTokenSwap(): Promise<void> {
|
|||
);
|
||||
|
||||
// create token B
|
||||
[tokenB, tokenAccountB] = await Token.createNewToken(
|
||||
[tokenB, tokenAccountB] = await Token.createToken(
|
||||
connection,
|
||||
payer,
|
||||
owner.publicKey,
|
||||
|
@ -177,25 +177,25 @@ export async function createTokenSwap(): Promise<void> {
|
|||
}
|
||||
|
||||
export async function deposit(): Promise<void> {
|
||||
let userAccountA = await tokenA.newAccount(owner.publicKey);
|
||||
let userAccountA = await tokenA.createAccount(owner.publicKey);
|
||||
await tokenA.mintTo(owner, userAccountA, USER_AMOUNT);
|
||||
let delegateAccountA = await tokenA.newAccount(authority, userAccountA);
|
||||
let delegateAccountA = await tokenA.createAccount(authority, userAccountA);
|
||||
await tokenA.approve(
|
||||
owner,
|
||||
userAccountA,
|
||||
delegateAccountA,
|
||||
USER_AMOUNT,
|
||||
);
|
||||
let userAccountB = await tokenB.newAccount(owner.publicKey);
|
||||
let userAccountB = await tokenB.createAccount(owner.publicKey);
|
||||
await tokenB.mintTo(owner, userAccountB, USER_AMOUNT);
|
||||
let delegateAccountB = await tokenB.newAccount(authority, userAccountB);
|
||||
let delegateAccountB = await tokenB.createAccount(authority, userAccountB);
|
||||
await tokenB.approve(
|
||||
owner,
|
||||
userAccountB,
|
||||
delegateAccountB,
|
||||
USER_AMOUNT,
|
||||
);
|
||||
let newAccountPool = await tokenPool.newAccount(owner.publicKey);
|
||||
let newAccountPool = await tokenPool.createAccount(owner.publicKey);
|
||||
const [tokenProgramId,] = await GetPrograms(connection);
|
||||
|
||||
await tokenSwap.deposit(
|
||||
|
@ -237,9 +237,9 @@ export async function deposit(): Promise<void> {
|
|||
}
|
||||
|
||||
export async function withdraw(): Promise<void> {
|
||||
let userAccountA = await tokenA.newAccount(owner.publicKey);
|
||||
let userAccountB = await tokenB.newAccount(owner.publicKey);
|
||||
let delegateAccountPool = await tokenPool.newAccount(authority, tokenAccountPool);
|
||||
let userAccountA = await tokenA.createAccount(owner.publicKey);
|
||||
let userAccountB = await tokenB.createAccount(owner.publicKey);
|
||||
let delegateAccountPool = await tokenPool.createAccount(authority, tokenAccountPool);
|
||||
await tokenPool.approve(
|
||||
owner,
|
||||
tokenAccountPool,
|
||||
|
@ -283,16 +283,16 @@ export async function withdraw(): Promise<void> {
|
|||
}
|
||||
|
||||
export async function swap(): Promise<void> {
|
||||
let userAccountA = await tokenA.newAccount(owner.publicKey);
|
||||
let userAccountA = await tokenA.createAccount(owner.publicKey);
|
||||
await tokenA.mintTo(owner, userAccountA, USER_AMOUNT);
|
||||
let delegateAccountA = await tokenA.newAccount(authority, userAccountA);
|
||||
let delegateAccountA = await tokenA.createAccount(authority, userAccountA);
|
||||
await tokenA.approve(
|
||||
owner,
|
||||
userAccountA,
|
||||
delegateAccountA,
|
||||
USER_AMOUNT,
|
||||
);
|
||||
let userAccountB = await tokenB.newAccount(owner.publicKey);
|
||||
let userAccountB = await tokenB.createAccount(owner.publicKey);
|
||||
const [tokenProgramId,] = await GetPrograms(connection);
|
||||
|
||||
await tokenSwap.swap(
|
||||
|
|
|
@ -382,7 +382,7 @@ impl State {
|
|||
|
||||
/// Deserializes a spl_token `State`.
|
||||
pub fn token_deserialize(info: &AccountInfo) -> Result<spl_token::state::Token, Error> {
|
||||
if let Ok(spl_token::state::State::Token(token)) =
|
||||
if let Ok(spl_token::state::State::Mint(token)) =
|
||||
spl_token::state::State::deserialize(&info.data.borrow())
|
||||
{
|
||||
Ok(token)
|
||||
|
@ -838,7 +838,7 @@ mod tests {
|
|||
account::Account, account_info::create_is_signer_account_infos, instruction::Instruction,
|
||||
};
|
||||
use spl_token::{
|
||||
instruction::{new_account, new_token, TokenInfo},
|
||||
instruction::{initialize_account, initialize_mint, TokenInfo},
|
||||
state::State as SplState,
|
||||
};
|
||||
|
||||
|
@ -883,7 +883,8 @@ mod tests {
|
|||
|
||||
// create pool and pool account
|
||||
do_process_instruction(
|
||||
new_account(&program_id, &account_key, &authority_key, &token_key, None).unwrap(),
|
||||
initialize_account(&program_id, &account_key, &authority_key, &token_key, None)
|
||||
.unwrap(),
|
||||
vec![
|
||||
&mut account_account,
|
||||
&mut Account::default(),
|
||||
|
@ -893,7 +894,7 @@ mod tests {
|
|||
.unwrap();
|
||||
let mut authority_account = Account::default();
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
Some(&account_key),
|
||||
|
|
|
@ -26,19 +26,20 @@ typedef struct Token_TokenInfo {
|
|||
*/
|
||||
typedef enum Token_TokenInstruction_Tag {
|
||||
/**
|
||||
* Creates a new token and deposit all the newly minted tokens in an account.
|
||||
* Initializes a new mint and deposits all the newly minted tokens in an account.
|
||||
*
|
||||
* # Accounts expected by this instruction:
|
||||
*
|
||||
* 0. `[writable, signer]` New token to create.
|
||||
* 0. `[writable, signer]` New mint to create.
|
||||
* 1.
|
||||
* * If supply is non-zero: `[writable]` Account to hold all the newly minted tokens.
|
||||
* * If supply is zero: `[]` Owner of the token.
|
||||
* 2. Optional: `[]` Owner of the token if supply is non-zero, if present then the token allows further minting of tokens.
|
||||
* * If supply is zero: `[]` Owner of the mint.
|
||||
* 2. Optional: `[]` Owner of the mint if supply is non-zero, if present then the
|
||||
* token allows further minting of tokens.
|
||||
*/
|
||||
NewToken,
|
||||
InitializeMint,
|
||||
/**
|
||||
* Creates a new account. The new account can either hold tokens or be a delegate
|
||||
* Initializes a new account. The new account can either hold tokens or be a delegate
|
||||
* for another account.
|
||||
*
|
||||
* # Accounts expected by this instruction:
|
||||
|
@ -48,7 +49,7 @@ typedef enum Token_TokenInstruction_Tag {
|
|||
* 2. `[]` Token this account will be associated with.
|
||||
* 3. Optional: `[]` Source account that this account will be a delegate for.
|
||||
*/
|
||||
NewAccount,
|
||||
InitializeAccount,
|
||||
/**
|
||||
* Transfers tokens from one account to another either directly or via a delegate.
|
||||
*
|
||||
|
@ -104,9 +105,9 @@ typedef enum Token_TokenInstruction_Tag {
|
|||
Burn,
|
||||
} Token_TokenInstruction_Tag;
|
||||
|
||||
typedef struct Token_NewToken_Body {
|
||||
typedef struct Token_InitializeMint_Body {
|
||||
Token_TokenInfo _0;
|
||||
} Token_NewToken_Body;
|
||||
} Token_InitializeMint_Body;
|
||||
|
||||
typedef struct Token_Transfer_Body {
|
||||
uint64_t _0;
|
||||
|
@ -127,7 +128,7 @@ typedef struct Token_Burn_Body {
|
|||
typedef struct Token_TokenInstruction {
|
||||
Token_TokenInstruction_Tag tag;
|
||||
union {
|
||||
Token_NewToken_Body new_token;
|
||||
Token_InitializeMint_Body initialize_mint;
|
||||
Token_Transfer_Body transfer;
|
||||
Token_Approve_Body approve;
|
||||
Token_MintTo_Body mint_to;
|
||||
|
@ -163,7 +164,7 @@ typedef struct Token_COption_Pubkey {
|
|||
} Token_COption_Pubkey;
|
||||
|
||||
/**
|
||||
* Represents a token type identified and identified by its public key. Accounts
|
||||
* 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.
|
||||
*/
|
||||
|
@ -173,8 +174,8 @@ typedef struct Token_Token {
|
|||
*/
|
||||
Token_TokenInfo info;
|
||||
/**
|
||||
* Optional token owner, used to mint new tokens. The owner may only
|
||||
* be provided during token creation. If no owner is present then the token
|
||||
* 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;
|
||||
|
@ -220,7 +221,7 @@ typedef struct Token_COption_AccountDelegate {
|
|||
} Token_COption_AccountDelegate;
|
||||
|
||||
/**
|
||||
* Account that holds or may delegate tokens.
|
||||
* Account that holds tokens or may delegate tokens.
|
||||
*/
|
||||
typedef struct Token_Account {
|
||||
/**
|
||||
|
@ -244,7 +245,7 @@ typedef struct Token_Account {
|
|||
} Token_Account;
|
||||
|
||||
/**
|
||||
* Token program states.
|
||||
* Program states.
|
||||
*/
|
||||
typedef enum Token_State_Tag {
|
||||
/**
|
||||
|
@ -252,9 +253,9 @@ typedef enum Token_State_Tag {
|
|||
*/
|
||||
Unallocated,
|
||||
/**
|
||||
* A token type.
|
||||
* A token mint.
|
||||
*/
|
||||
Token,
|
||||
Mint,
|
||||
/**
|
||||
* An account that holds an amount of tokens or was delegated the authority to transfer
|
||||
* tokens on behalf of another account.
|
||||
|
@ -266,9 +267,9 @@ typedef enum Token_State_Tag {
|
|||
Invalid,
|
||||
} Token_State_Tag;
|
||||
|
||||
typedef struct Token_Token_Body {
|
||||
typedef struct Token_Mint_Body {
|
||||
Token_Token _0;
|
||||
} Token_Token_Body;
|
||||
} Token_Mint_Body;
|
||||
|
||||
typedef struct Token_Account_Body {
|
||||
Token_Account _0;
|
||||
|
@ -277,7 +278,7 @@ typedef struct Token_Account_Body {
|
|||
typedef struct Token_State {
|
||||
Token_State_Tag tag;
|
||||
union {
|
||||
Token_Token_Body token;
|
||||
Token_Mint_Body mint;
|
||||
Token_Account_Body account;
|
||||
};
|
||||
} Token_State;
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
import {
|
||||
loadTokenProgram,
|
||||
createNewToken,
|
||||
createNewAccount,
|
||||
createToken,
|
||||
createAccount,
|
||||
transfer,
|
||||
approveRevoke,
|
||||
invalidApprove,
|
||||
|
@ -20,10 +20,10 @@ import {
|
|||
async function main() {
|
||||
console.log('Run test: loadTokenProgram');
|
||||
await loadTokenProgram('../target/bpfel-unknown-unknown/release/spl_token.so');
|
||||
console.log('Run test: createNewToken');
|
||||
await createNewToken();
|
||||
console.log('Run test: createNewAccount');
|
||||
await createNewAccount();
|
||||
console.log('Run test: createToken');
|
||||
await createToken();
|
||||
console.log('Run test: createAccount');
|
||||
await createAccount();
|
||||
console.log('Run test: transfer');
|
||||
await transfer();
|
||||
console.log('Run test: approveRevoke');
|
||||
|
|
|
@ -76,12 +76,12 @@ export async function loadTokenProgram(path: string): Promise<PublicKey> {
|
|||
return programId;
|
||||
}
|
||||
|
||||
export async function createNewToken(): Promise<void> {
|
||||
export async function createToken(): Promise<void> {
|
||||
const connection = await getConnection();
|
||||
const payer = await newAccountWithLamports(connection, 100000000000 /* wag */);
|
||||
tokenOwner = new Account();
|
||||
testAccountOwner = new Account();
|
||||
[testToken, testAccount] = await Token.createNewToken(
|
||||
[testToken, testAccount] = await Token.createToken(
|
||||
connection,
|
||||
payer,
|
||||
tokenOwner.publicKey,
|
||||
|
@ -92,7 +92,7 @@ export async function createNewToken(): Promise<void> {
|
|||
false,
|
||||
);
|
||||
|
||||
const tokenInfo = await testToken.getTokenInfo();
|
||||
const tokenInfo = await testToken.getMintInfo();
|
||||
assert(tokenInfo.supply.toNumber() == 10000);
|
||||
assert(tokenInfo.decimals == 2);
|
||||
assert(tokenInfo.owner == null);
|
||||
|
@ -105,13 +105,13 @@ export async function createNewToken(): Promise<void> {
|
|||
assert(accountInfo.originalAmount.toNumber() == 0);
|
||||
}
|
||||
|
||||
export async function createNewAccount(): Promise<void> {
|
||||
export async function createAccount(): Promise<void> {
|
||||
const connection = await getConnection();
|
||||
const balanceNeeded = await Token.getMinBalanceRentForExemptAccount(
|
||||
connection,
|
||||
);
|
||||
const destOwner = await newAccountWithLamports(connection, balanceNeeded);
|
||||
const dest = await testToken.newAccount(destOwner.publicKey);
|
||||
const dest = await testToken.createAccount(destOwner.publicKey);
|
||||
const accountInfo = await testToken.getAccountInfo(dest);
|
||||
assert(accountInfo.token.equals(testToken.publicKey));
|
||||
assert(accountInfo.owner.equals(destOwner.publicKey));
|
||||
|
@ -125,13 +125,13 @@ export async function transfer(): Promise<void> {
|
|||
connection,
|
||||
);
|
||||
const destOwner = await newAccountWithLamports(connection, balanceNeeded);
|
||||
const dest = await testToken.newAccount(destOwner.publicKey);
|
||||
const dest = await testToken.createAccount(destOwner.publicKey);
|
||||
|
||||
await testToken.transfer(testAccountOwner, testAccount, dest, 123);
|
||||
await sleep(500);
|
||||
|
||||
let destTokenAccountInfo = await testToken.getAccountInfo(dest);
|
||||
assert(destTokenAccountInfo.amount.toNumber() == 123);
|
||||
let destAccountInfo = await testToken.getAccountInfo(dest);
|
||||
assert(destAccountInfo.amount.toNumber() == 123);
|
||||
}
|
||||
|
||||
export async function approveRevoke(): Promise<void> {
|
||||
|
@ -145,7 +145,7 @@ export async function approveRevoke(): Promise<void> {
|
|||
connection,
|
||||
);
|
||||
const delegateOwner = await newAccountWithLamports(connection, balanceNeeded);
|
||||
const delegate = await testToken.newAccount(
|
||||
const delegate = await testToken.createAccount(
|
||||
delegateOwner.publicKey,
|
||||
testAccount,
|
||||
);
|
||||
|
@ -182,9 +182,9 @@ export async function invalidApprove(): Promise<void> {
|
|||
const balanceNeeded =
|
||||
(await Token.getMinBalanceRentForExemptAccount(connection)) * 3;
|
||||
const owner = await newAccountWithLamports(connection, balanceNeeded);
|
||||
const account1 = await testToken.newAccount(owner.publicKey);
|
||||
const account1Delegate = await testToken.newAccount(owner.publicKey, account1);
|
||||
const account2 = await testToken.newAccount(owner.publicKey);
|
||||
const account1 = await testToken.createAccount(owner.publicKey);
|
||||
const account1Delegate = await testToken.createAccount(owner.publicKey, account1);
|
||||
const account2 = await testToken.createAccount(owner.publicKey);
|
||||
|
||||
// account2 is not a delegate account of account1
|
||||
assert(didThrow(testToken.approve, [owner, account1, account2, 123]));
|
||||
|
@ -197,9 +197,9 @@ export async function failOnApproveOverspend(): Promise<void> {
|
|||
const balanceNeeded =
|
||||
(await Token.getMinBalanceRentForExemptAccount(connection)) * 3;
|
||||
const owner = await newAccountWithLamports(connection, balanceNeeded);
|
||||
const account1 = await testToken.newAccount(owner.publicKey);
|
||||
const account1Delegate = await testToken.newAccount(owner.publicKey, account1);
|
||||
const account2 = await testToken.newAccount(owner.publicKey);
|
||||
const account1 = await testToken.createAccount(owner.publicKey);
|
||||
const account1Delegate = await testToken.createAccount(owner.publicKey, account1);
|
||||
const account2 = await testToken.createAccount(owner.publicKey);
|
||||
|
||||
await testToken.transfer(
|
||||
testAccountOwner,
|
||||
|
@ -236,7 +236,7 @@ export async function setOwner(): Promise<void> {
|
|||
);
|
||||
const owner = await newAccountWithLamports(connection, balanceNeeded);
|
||||
const newOwner = await newAccountWithLamports(connection, balanceNeeded);
|
||||
const owned = await testToken.newAccount(owner.publicKey);
|
||||
const owned = await testToken.createAccount(owner.publicKey);
|
||||
|
||||
await testToken.setOwner(owner, owned, newOwner.publicKey);
|
||||
assert(didThrow(testToken.setOwner, [owner, owned, newOwner.publicKey]));
|
||||
|
@ -248,7 +248,7 @@ export async function mintTo(): Promise<void> {
|
|||
const payer = await newAccountWithLamports(connection, 100000000000 /* wag */);
|
||||
const tokenOwner = new Account();
|
||||
const testAccountOwner = new Account();
|
||||
const [mintableToken, initialAccount] = await Token.createNewToken(
|
||||
const [mintableToken, initialAccount] = await Token.createToken(
|
||||
connection,
|
||||
payer,
|
||||
tokenOwner.publicKey,
|
||||
|
@ -260,7 +260,7 @@ export async function mintTo(): Promise<void> {
|
|||
);
|
||||
|
||||
{
|
||||
const tokenInfo = await mintableToken.getTokenInfo();
|
||||
const tokenInfo = await mintableToken.getMintInfo();
|
||||
assert(tokenInfo.supply.toNumber() == 10000);
|
||||
assert(tokenInfo.decimals == 2);
|
||||
if (tokenInfo.owner === null) {
|
||||
|
@ -277,11 +277,11 @@ export async function mintTo(): Promise<void> {
|
|||
assert(accountInfo.originalAmount.toNumber() == 0);
|
||||
}
|
||||
|
||||
const dest = await mintableToken.newAccount(testAccountOwner.publicKey);
|
||||
const dest = await mintableToken.createAccount(testAccountOwner.publicKey);
|
||||
await mintableToken.mintTo(tokenOwner, dest, 42);
|
||||
|
||||
{
|
||||
const tokenInfo = await mintableToken.getTokenInfo();
|
||||
const tokenInfo = await mintableToken.getMintInfo();
|
||||
assert(tokenInfo.supply.toNumber() == 10042);
|
||||
assert(tokenInfo.decimals == 2);
|
||||
if (tokenInfo.owner === null) {
|
||||
|
@ -300,7 +300,7 @@ export async function mintTo(): Promise<void> {
|
|||
}
|
||||
|
||||
export async function burn(): Promise<void> {
|
||||
let tokenInfo = await testToken.getTokenInfo();
|
||||
let tokenInfo = await testToken.getMintInfo();
|
||||
const supply = tokenInfo.supply.toNumber();
|
||||
let accountInfo = await testToken.getAccountInfo(testAccount);
|
||||
const amount = accountInfo.amount.toNumber();
|
||||
|
@ -308,7 +308,7 @@ export async function burn(): Promise<void> {
|
|||
await testToken.burn(testAccountOwner, testAccount, 1);
|
||||
await sleep(500);
|
||||
|
||||
tokenInfo = await testToken.getTokenInfo();
|
||||
tokenInfo = await testToken.getMintInfo();
|
||||
assert(tokenInfo.supply.toNumber() == supply - 1);
|
||||
accountInfo = await testToken.getAccountInfo(testAccount);
|
||||
assert(accountInfo.amount.toNumber() == amount - 1);
|
||||
|
|
|
@ -56,7 +56,7 @@ export class TokenAmount extends BN {
|
|||
/**
|
||||
* Information about a token
|
||||
*/
|
||||
type TokenInfo = {|
|
||||
type MintInfo = {|
|
||||
/**
|
||||
* Total supply of tokens
|
||||
*/
|
||||
|
@ -72,7 +72,7 @@ type TokenInfo = {|
|
|||
owner: null | PublicKey,
|
||||
|};
|
||||
|
||||
const TokenInfoLayout = BufferLayout.struct([
|
||||
const MintLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('state'),
|
||||
Layout.uint64('supply'),
|
||||
BufferLayout.nu64('decimals'),
|
||||
|
@ -119,7 +119,7 @@ type AccountInfo = {|
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
const AccountInfoLayout = BufferLayout.struct([
|
||||
const AccountLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('state'),
|
||||
Layout.publicKey('token'),
|
||||
Layout.publicKey('owner'),
|
||||
|
@ -177,7 +177,7 @@ export class Token {
|
|||
connection: Connection,
|
||||
): Promise<number> {
|
||||
return await connection.getMinimumBalanceForRentExemption(
|
||||
TokenInfoLayout.span,
|
||||
MintLayout.span,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -190,12 +190,12 @@ export class Token {
|
|||
connection: Connection,
|
||||
): Promise<number> {
|
||||
return await connection.getMinimumBalanceForRentExemption(
|
||||
AccountInfoLayout.span,
|
||||
AccountLayout.span,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Token
|
||||
* Creates and initializes a token.
|
||||
*
|
||||
* @param connection The connection to use
|
||||
* @param owner User account that will own the returned account
|
||||
|
@ -204,7 +204,7 @@ export class Token {
|
|||
* @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
|
||||
*/
|
||||
static async createNewToken(
|
||||
static async createToken(
|
||||
connection: Connection,
|
||||
payer: Account,
|
||||
tokenOwner: PublicKey,
|
||||
|
@ -217,7 +217,7 @@ export class Token {
|
|||
let transaction;
|
||||
const tokenAccount = new Account();
|
||||
const token = new Token(connection, tokenAccount.publicKey, programId, payer);
|
||||
const initialAccountPublicKey = await token.newAccount(accountOwner, null);
|
||||
const initialAccountPublicKey = await token.createAccount(accountOwner, null);
|
||||
|
||||
// Allocate memory for the account
|
||||
const balanceNeeded = await Token.getMinBalanceRentForExemptToken(
|
||||
|
@ -227,7 +227,7 @@ export class Token {
|
|||
fromPubkey: payer.publicKey,
|
||||
newAccountPubkey: tokenAccount.publicKey,
|
||||
lamports: balanceNeeded,
|
||||
space: TokenInfoLayout.span,
|
||||
space: MintLayout.span,
|
||||
programId,
|
||||
});
|
||||
await sendAndConfirmTransaction(
|
||||
|
@ -257,7 +257,7 @@ export class Token {
|
|||
{
|
||||
const encodeLength = commandDataLayout.encode(
|
||||
{
|
||||
instruction: 0, // NewToken instruction
|
||||
instruction: 0, // InitializeToken instruction
|
||||
supply: supply.toBuffer(),
|
||||
decimals,
|
||||
},
|
||||
|
@ -272,7 +272,7 @@ export class Token {
|
|||
data,
|
||||
});
|
||||
await sendAndConfirmTransaction(
|
||||
'New Account',
|
||||
'InitializeToken',
|
||||
connection,
|
||||
transaction,
|
||||
payer,
|
||||
|
@ -288,7 +288,7 @@ export class Token {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a new and empty account.
|
||||
* Create and initializes a new account.
|
||||
*
|
||||
* This account may then be used as a `transfer()` or `approve()` destination
|
||||
*
|
||||
|
@ -297,7 +297,7 @@ export class Token {
|
|||
* may transfer tokens from this `source` account
|
||||
* @return Public key of the new empty account
|
||||
*/
|
||||
async newAccount(
|
||||
async createAccount(
|
||||
owner: PublicKey,
|
||||
source: null | PublicKey = null,
|
||||
): Promise<PublicKey> {
|
||||
|
@ -308,12 +308,11 @@ export class Token {
|
|||
const balanceNeeded = await Token.getMinBalanceRentForExemptAccount(
|
||||
this.connection,
|
||||
);
|
||||
|
||||
transaction = SystemProgram.createAccount({
|
||||
fromPubkey: this.payer.publicKey,
|
||||
newAccountPubkey: tokenAccount.publicKey,
|
||||
lamports: balanceNeeded,
|
||||
space: AccountInfoLayout.span,
|
||||
space: AccountLayout.span,
|
||||
programId: this.programId,
|
||||
});
|
||||
await sendAndConfirmTransaction(
|
||||
|
@ -337,7 +336,7 @@ export class Token {
|
|||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 1, // NewAccount instruction
|
||||
instruction: 1, // InitializeAccount instruction
|
||||
},
|
||||
data,
|
||||
);
|
||||
|
@ -347,7 +346,7 @@ export class Token {
|
|||
data,
|
||||
});
|
||||
await sendAndConfirmTransaction(
|
||||
'new account',
|
||||
'InitializeAccount',
|
||||
this.connection,
|
||||
transaction,
|
||||
this.payer,
|
||||
|
@ -360,30 +359,30 @@ export class Token {
|
|||
/**
|
||||
* Retrieve token information
|
||||
*/
|
||||
async getTokenInfo(): Promise<TokenInfo> {
|
||||
const accountInfo = await this.connection.getAccountInfo(this.publicKey);
|
||||
if (accountInfo === null) {
|
||||
async getMintInfo(): Promise<MintInfo> {
|
||||
const info = await this.connection.getAccountInfo(this.publicKey);
|
||||
if (info === null) {
|
||||
throw new Error('Failed to find token info account');
|
||||
}
|
||||
if (!accountInfo.owner.equals(this.programId)) {
|
||||
if (!info.owner.equals(this.programId)) {
|
||||
throw new Error(
|
||||
`Invalid token owner: ${JSON.stringify(accountInfo.owner)}`,
|
||||
`Invalid token owner: ${JSON.stringify(info.owner)}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = Buffer.from(accountInfo.data);
|
||||
const data = Buffer.from(info.data);
|
||||
|
||||
const tokenInfo = TokenInfoLayout.decode(data);
|
||||
if (tokenInfo.state !== 1) {
|
||||
const mintInfo = MintLayout.decode(data);
|
||||
if (mintInfo.state !== 1) {
|
||||
throw new Error(`Invalid account data`);
|
||||
}
|
||||
tokenInfo.supply = TokenAmount.fromBuffer(tokenInfo.supply);
|
||||
if (tokenInfo.option === 0) {
|
||||
tokenInfo.owner = null;
|
||||
mintInfo.supply = TokenAmount.fromBuffer(mintInfo.supply);
|
||||
if (mintInfo.option === 0) {
|
||||
mintInfo.owner = null;
|
||||
} else {
|
||||
tokenInfo.owner = new PublicKey(tokenInfo.owner);
|
||||
mintInfo.owner = new PublicKey(mintInfo.owner);
|
||||
}
|
||||
return tokenInfo;
|
||||
return mintInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -392,41 +391,41 @@ export class Token {
|
|||
* @param account Public key of the account
|
||||
*/
|
||||
async getAccountInfo(account: PublicKey): Promise<AccountInfo> {
|
||||
const accountInfo = await this.connection.getAccountInfo(account);
|
||||
if (accountInfo === null) {
|
||||
const info = await this.connection.getAccountInfo(account);
|
||||
if (info === null) {
|
||||
throw new Error('Failed to find account');
|
||||
}
|
||||
if (!accountInfo.owner.equals(this.programId)) {
|
||||
if (!info.owner.equals(this.programId)) {
|
||||
throw new Error(`Invalid account owner`);
|
||||
}
|
||||
|
||||
const data = Buffer.from(accountInfo.data);
|
||||
const tokenAccountInfo = AccountInfoLayout.decode(data);
|
||||
const data = Buffer.from(info.data);
|
||||
const accountInfo = AccountLayout.decode(data);
|
||||
|
||||
if (tokenAccountInfo.state !== 2) {
|
||||
if (accountInfo.state !== 2) {
|
||||
throw new Error(`Invalid account data`);
|
||||
}
|
||||
tokenAccountInfo.token = new PublicKey(tokenAccountInfo.token);
|
||||
tokenAccountInfo.owner = new PublicKey(tokenAccountInfo.owner);
|
||||
tokenAccountInfo.amount = TokenAmount.fromBuffer(tokenAccountInfo.amount);
|
||||
if (tokenAccountInfo.option === 0) {
|
||||
tokenAccountInfo.source = null;
|
||||
tokenAccountInfo.originalAmount = new TokenAmount();
|
||||
accountInfo.token = new PublicKey(accountInfo.token);
|
||||
accountInfo.owner = new PublicKey(accountInfo.owner);
|
||||
accountInfo.amount = TokenAmount.fromBuffer(accountInfo.amount);
|
||||
if (accountInfo.option === 0) {
|
||||
accountInfo.source = null;
|
||||
accountInfo.originalAmount = new TokenAmount();
|
||||
} else {
|
||||
tokenAccountInfo.source = new PublicKey(tokenAccountInfo.source);
|
||||
tokenAccountInfo.originalAmount = TokenAmount.fromBuffer(
|
||||
tokenAccountInfo.originalAmount,
|
||||
accountInfo.source = new PublicKey(accountInfo.source);
|
||||
accountInfo.originalAmount = TokenAmount.fromBuffer(
|
||||
accountInfo.originalAmount,
|
||||
);
|
||||
}
|
||||
|
||||
if (!tokenAccountInfo.token.equals(this.publicKey)) {
|
||||
if (!accountInfo.token.equals(this.publicKey)) {
|
||||
throw new Error(
|
||||
`Invalid account token: ${JSON.stringify(
|
||||
tokenAccountInfo.token,
|
||||
accountInfo.token,
|
||||
)} !== ${JSON.stringify(this.publicKey)}`,
|
||||
);
|
||||
}
|
||||
return tokenAccountInfo;
|
||||
return accountInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,7 +9,7 @@ use solana_sdk::{
|
|||
};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors that may be returned by the Token program
|
||||
/// 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.
|
||||
|
@ -37,19 +37,16 @@ pub enum TokenError {
|
|||
#[error("An owner is required if supply is zero")]
|
||||
OwnerRequiredIfNoInitialSupply,
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
impl PrintProgramError for TokenError {
|
||||
fn print<E>(&self)
|
||||
where
|
||||
|
|
|
@ -22,17 +22,18 @@ pub struct TokenInfo {
|
|||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum TokenInstruction {
|
||||
/// Creates a new token and deposit all the newly minted tokens in an account.
|
||||
/// Initializes a new mint and deposits all the newly minted tokens in an account.
|
||||
///
|
||||
/// # Accounts expected by this instruction:
|
||||
///
|
||||
/// 0. `[writable, signer]` New token to create.
|
||||
/// 0. `[writable, signer]` New mint to create.
|
||||
/// 1.
|
||||
/// * If supply is non-zero: `[writable]` Account to hold all the newly minted tokens.
|
||||
/// * If supply is zero: `[]` Owner of the token.
|
||||
/// 2. Optional: `[]` Owner of the token if supply is non-zero, if present then the token allows further minting of tokens.
|
||||
NewToken(TokenInfo),
|
||||
/// Creates a new account. The new account can either hold tokens or be a delegate
|
||||
/// * If supply is zero: `[]` Owner of the mint.
|
||||
/// 2. Optional: `[]` Owner of the mint if supply is non-zero, if present then the
|
||||
/// token allows further minting of tokens.
|
||||
InitializeMint(TokenInfo),
|
||||
/// Initializes a new account. The new account can either hold tokens or be a delegate
|
||||
/// for another account.
|
||||
///
|
||||
/// # Accounts expected by this instruction:
|
||||
|
@ -41,7 +42,7 @@ pub enum TokenInstruction {
|
|||
/// 1. `[]` Owner of the new account.
|
||||
/// 2. `[]` Token this account will be associated with.
|
||||
/// 3. Optional: `[]` Source account that this account will be a delegate for.
|
||||
NewAccount,
|
||||
InitializeAccount,
|
||||
/// Transfers tokens from one account to another either directly or via a delegate.
|
||||
///
|
||||
/// # Accounts expected by this instruction:
|
||||
|
@ -87,7 +88,7 @@ pub enum TokenInstruction {
|
|||
Burn(u64),
|
||||
}
|
||||
impl TokenInstruction {
|
||||
/// Deserializes a byte buffer into an [TokenInstruction](enum.TokenInstruction.html)
|
||||
/// Deserializes a byte buffer into an [TokenInstruction](enum.TokenInstruction.html).
|
||||
pub fn deserialize(input: &[u8]) -> Result<Self, ProgramError> {
|
||||
if input.len() < size_of::<u8>() {
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
|
@ -99,9 +100,9 @@ impl TokenInstruction {
|
|||
}
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let info: &TokenInfo = unsafe { &*(&input[1] as *const u8 as *const TokenInfo) };
|
||||
Self::NewToken(*info)
|
||||
Self::InitializeMint(*info)
|
||||
}
|
||||
1 => Self::NewAccount,
|
||||
1 => Self::InitializeAccount,
|
||||
2 => {
|
||||
if input.len() < size_of::<u8>() + size_of::<u64>() {
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
|
@ -139,17 +140,17 @@ impl TokenInstruction {
|
|||
})
|
||||
}
|
||||
|
||||
/// Serializes an [TokenInstruction](enum.TokenInstruction.html) into a byte buffer
|
||||
/// Serializes an [TokenInstruction](enum.TokenInstruction.html) into a byte buffer.
|
||||
pub fn serialize(self: &Self) -> Result<Vec<u8>, ProgramError> {
|
||||
let mut output = vec![0u8; size_of::<TokenInstruction>()];
|
||||
match self {
|
||||
Self::NewToken(info) => {
|
||||
Self::InitializeMint(info) => {
|
||||
output[0] = 0;
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let value = unsafe { &mut *(&mut output[1] as *mut u8 as *mut TokenInfo) };
|
||||
*value = *info;
|
||||
}
|
||||
Self::NewAccount => output[0] = 1,
|
||||
Self::InitializeAccount => output[0] = 1,
|
||||
Self::Transfer(amount) => {
|
||||
output[0] = 2;
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
|
@ -180,15 +181,15 @@ impl TokenInstruction {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a 'NewToken' instruction
|
||||
pub fn new_token(
|
||||
/// Creates a 'InitializeMint' instruction.
|
||||
pub fn initialize_mint(
|
||||
token_program_id: &Pubkey,
|
||||
token_pubkey: &Pubkey,
|
||||
account_pubkey: Option<&Pubkey>,
|
||||
owner_pubkey: Option<&Pubkey>,
|
||||
token_info: TokenInfo,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::NewToken(token_info).serialize()?;
|
||||
let data = TokenInstruction::InitializeMint(token_info).serialize()?;
|
||||
|
||||
let mut accounts = vec![AccountMeta::new(*token_pubkey, true)];
|
||||
if token_info.supply != 0 {
|
||||
|
@ -215,15 +216,15 @@ pub fn new_token(
|
|||
})
|
||||
}
|
||||
|
||||
/// Creates a `NewAccount` instruction
|
||||
pub fn new_account(
|
||||
/// Creates a `InitializeAccount` instruction.
|
||||
pub fn initialize_account(
|
||||
token_program_id: &Pubkey,
|
||||
account_pubkey: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
token_pubkey: &Pubkey,
|
||||
source_pubkey: Option<&Pubkey>,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = TokenInstruction::NewAccount.serialize()?;
|
||||
let data = TokenInstruction::InitializeAccount.serialize()?;
|
||||
|
||||
let mut accounts = vec![
|
||||
AccountMeta::new(*account_pubkey, true),
|
||||
|
@ -241,7 +242,7 @@ pub fn new_account(
|
|||
})
|
||||
}
|
||||
|
||||
/// Creates a `Transfer` instruction
|
||||
/// Creates a `Transfer` instruction.
|
||||
pub fn transfer(
|
||||
token_program_id: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
|
@ -268,7 +269,7 @@ pub fn transfer(
|
|||
})
|
||||
}
|
||||
|
||||
/// Creates an `Approve` instruction
|
||||
/// Creates an `Approve` instruction.
|
||||
pub fn approve(
|
||||
token_program_id: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
|
@ -291,11 +292,7 @@ pub fn approve(
|
|||
})
|
||||
}
|
||||
|
||||
/// 0. `[signer]` Current owner of the account.
|
||||
/// 1. `[writable]` account to change the owner of.
|
||||
/// 2. `[]` New owner of the account.
|
||||
|
||||
/// Creates an `SetOwner` instruction
|
||||
/// Creates an `SetOwner` instruction.
|
||||
pub fn set_owner(
|
||||
token_program_id: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
|
@ -317,7 +314,7 @@ pub fn set_owner(
|
|||
})
|
||||
}
|
||||
|
||||
/// Creates an `MintTo` instruction
|
||||
/// Creates an `MintTo` instruction.
|
||||
pub fn mint_to(
|
||||
token_program_id: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
|
@ -340,7 +337,7 @@ pub fn mint_to(
|
|||
})
|
||||
}
|
||||
|
||||
/// Creates an `Burn` instruction
|
||||
/// Creates an `Burn` instruction.
|
||||
pub fn burn(
|
||||
token_program_id: &Pubkey,
|
||||
owner_pubkey: &Pubkey,
|
||||
|
|
|
@ -11,7 +11,7 @@ use solana_sdk::{
|
|||
};
|
||||
use std::mem::size_of;
|
||||
|
||||
/// Represents a token type identified and identified by its public key. Accounts
|
||||
/// 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.
|
||||
#[repr(C)]
|
||||
|
@ -19,8 +19,8 @@ use std::mem::size_of;
|
|||
pub struct Token {
|
||||
/// The total supply of tokens.
|
||||
pub info: TokenInfo,
|
||||
/// Optional token owner, used to mint new tokens. The owner may only
|
||||
/// be provided during token creation. If no owner is present then the token
|
||||
/// 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>,
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ pub struct AccountDelegate {
|
|||
pub original_amount: u64,
|
||||
}
|
||||
|
||||
/// Account that holds or may delegate tokens.
|
||||
/// Account that holds tokens or may delegate tokens.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct Account {
|
||||
|
@ -51,14 +51,14 @@ pub struct Account {
|
|||
pub delegate: COption<AccountDelegate>,
|
||||
}
|
||||
|
||||
/// Token program states.
|
||||
/// Program states.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum State {
|
||||
/// Unallocated state, may be initialized into another state.
|
||||
Unallocated,
|
||||
/// A token type.
|
||||
Token(Token),
|
||||
/// A token mint.
|
||||
Mint(Token),
|
||||
/// An account that holds an amount of tokens or was delegated the authority to transfer
|
||||
/// tokens on behalf of another account.
|
||||
Account(Account),
|
||||
|
@ -70,10 +70,9 @@ impl Default for State {
|
|||
Self::Unallocated
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
/// Processes a [NewToken](enum.TokenInstruction.html) instruction.
|
||||
pub fn process_new_token(accounts: &[AccountInfo], info: TokenInfo) -> ProgramResult {
|
||||
/// Processes a [InitializeMint](enum.TokenInstruction.html) instruction.
|
||||
pub fn process_initialize_mint(accounts: &[AccountInfo], info: TokenInfo) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
let token_account_info = next_account_info(account_info_iter)?;
|
||||
|
||||
|
@ -113,23 +112,23 @@ impl State {
|
|||
return Err(TokenError::OwnerRequiredIfNoInitialSupply.into());
|
||||
};
|
||||
|
||||
State::Token(Token { info, owner }).serialize(&mut token_account_info.data.borrow_mut())
|
||||
State::Mint(Token { info, owner }).serialize(&mut token_account_info.data.borrow_mut())
|
||||
}
|
||||
|
||||
/// Processes a [NewAccount](enum.TokenInstruction.html) instruction.
|
||||
pub fn process_new_account(accounts: &[AccountInfo]) -> ProgramResult {
|
||||
/// Processes a [InitializeAccount](enum.TokenInstruction.html) instruction.
|
||||
pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
let new_account_info = next_account_info(account_info_iter)?;
|
||||
let initialize_account_info = next_account_info(account_info_iter)?;
|
||||
let owner_account_info = next_account_info(account_info_iter)?;
|
||||
let token_account_info = next_account_info(account_info_iter)?;
|
||||
|
||||
if !new_account_info.is_signer {
|
||||
if !initialize_account_info.is_signer {
|
||||
return Err(ProgramError::MissingRequiredSignature);
|
||||
}
|
||||
|
||||
let mut new_account_data = new_account_info.data.borrow_mut();
|
||||
let mut initialize_account_data = initialize_account_info.data.borrow_mut();
|
||||
|
||||
if State::Unallocated != State::deserialize(&new_account_data)? {
|
||||
if State::Unallocated != State::deserialize(&initialize_account_data)? {
|
||||
return Err(TokenError::AlreadyInUse.into());
|
||||
}
|
||||
|
||||
|
@ -146,7 +145,7 @@ impl State {
|
|||
});
|
||||
}
|
||||
|
||||
State::Account(token_account).serialize(&mut new_account_data)
|
||||
State::Account(token_account).serialize(&mut initialize_account_data)
|
||||
}
|
||||
|
||||
/// Processes a [Transfer](enum.TokenInstruction.html) instruction.
|
||||
|
@ -279,7 +278,7 @@ impl State {
|
|||
account.owner = *new_owner_account_info.key;
|
||||
State::Account(account).serialize(&mut account_data)?;
|
||||
}
|
||||
State::Token(mut token) => {
|
||||
State::Mint(mut token) => {
|
||||
if COption::Some(*owner_account_info.key) != token.owner {
|
||||
return Err(TokenError::NoOwner.into());
|
||||
}
|
||||
|
@ -288,7 +287,7 @@ impl State {
|
|||
}
|
||||
|
||||
token.owner = COption::Some(*new_owner_account_info.key);
|
||||
State::Token(token).serialize(&mut account_data)?;
|
||||
State::Mint(token).serialize(&mut account_data)?;
|
||||
}
|
||||
_ => {
|
||||
return Err(ProgramError::InvalidArgument);
|
||||
|
@ -298,7 +297,7 @@ impl State {
|
|||
}
|
||||
|
||||
/// Processes a [MintTo](enum.TokenInstruction.html) instruction.
|
||||
pub fn process_mintto(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
|
||||
pub fn process_mint_to(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
let owner_account_info = next_account_info(account_info_iter)?;
|
||||
let token_account_info = next_account_info(account_info_iter)?;
|
||||
|
@ -309,7 +308,7 @@ impl State {
|
|||
}
|
||||
|
||||
let mut token_account_data = token_account_info.data.borrow_mut();
|
||||
if let State::Token(mut token) = State::deserialize(&token_account_data)? {
|
||||
if let State::Mint(mut token) = State::deserialize(&token_account_data)? {
|
||||
match token.owner {
|
||||
COption::Some(owner) => {
|
||||
if *owner_account_info.key != owner {
|
||||
|
@ -332,7 +331,7 @@ impl State {
|
|||
}
|
||||
|
||||
token.info.supply += amount;
|
||||
State::Token(token).serialize(&mut token_account_data)?;
|
||||
State::Mint(token).serialize(&mut token_account_data)?;
|
||||
|
||||
dest_token_account.amount = amount;
|
||||
State::Account(dest_token_account).serialize(&mut dest_account_data)?;
|
||||
|
@ -362,10 +361,10 @@ impl State {
|
|||
}
|
||||
};
|
||||
|
||||
let (mut token_account, mut token_data) = {
|
||||
let (mut token, mut token_data) = {
|
||||
let token_data = token_account_info.data.borrow_mut();
|
||||
match State::deserialize(&token_data)? {
|
||||
State::Token(token_account) => (token_account, token_data),
|
||||
State::Mint(token) => (token, token_data),
|
||||
_ => {
|
||||
return Err(ProgramError::InvalidArgument);
|
||||
}
|
||||
|
@ -409,8 +408,8 @@ impl State {
|
|||
source_account.amount -= amount;
|
||||
State::Account(source_account).serialize(&mut source_data)?;
|
||||
|
||||
token_account.info.supply -= amount;
|
||||
State::Token(token_account).serialize(&mut token_data)?;
|
||||
token.info.supply -= amount;
|
||||
State::Mint(token).serialize(&mut token_data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -419,13 +418,13 @@ impl State {
|
|||
let instruction = TokenInstruction::deserialize(input)?;
|
||||
|
||||
match instruction {
|
||||
TokenInstruction::NewToken(info) => {
|
||||
info!("Instruction: NewToken");
|
||||
Self::process_new_token(accounts, info)
|
||||
TokenInstruction::InitializeMint(info) => {
|
||||
info!("Instruction: InitializeMint");
|
||||
Self::process_initialize_mint(accounts, info)
|
||||
}
|
||||
TokenInstruction::NewAccount => {
|
||||
info!("Instruction: NewAccount");
|
||||
Self::process_new_account(accounts)
|
||||
TokenInstruction::InitializeAccount => {
|
||||
info!("Instruction: InitializeAccount");
|
||||
Self::process_initialize_account(accounts)
|
||||
}
|
||||
TokenInstruction::Transfer(amount) => {
|
||||
info!("Instruction: Transfer");
|
||||
|
@ -441,7 +440,7 @@ impl State {
|
|||
}
|
||||
TokenInstruction::MintTo(amount) => {
|
||||
info!("Instruction: MintTo");
|
||||
Self::process_mintto(accounts, amount)
|
||||
Self::process_mint_to(accounts, amount)
|
||||
}
|
||||
TokenInstruction::Burn(amount) => {
|
||||
info!("Instruction: Burn");
|
||||
|
@ -450,7 +449,7 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
/// Deserializes a byte buffer into a Token Program [State](struct.State.html)
|
||||
/// Deserializes a byte buffer into a Token Program [State](struct.State.html).
|
||||
pub fn deserialize(input: &[u8]) -> Result<Self, ProgramError> {
|
||||
if input.len() < size_of::<u8>() {
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
|
@ -463,7 +462,7 @@ impl State {
|
|||
}
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let token: &Token = unsafe { &*(&input[1] as *const u8 as *const Token) };
|
||||
Self::Token(*token)
|
||||
Self::Mint(*token)
|
||||
}
|
||||
2 => {
|
||||
if input.len() < size_of::<u8>() + size_of::<Account>() {
|
||||
|
@ -478,14 +477,14 @@ impl State {
|
|||
})
|
||||
}
|
||||
|
||||
/// Serializes Token Program [State](struct.State.html) into a byte buffer
|
||||
/// Serializes Token Program [State](struct.State.html) into a byte buffer.
|
||||
pub fn serialize(self: &Self, output: &mut [u8]) -> ProgramResult {
|
||||
if output.len() < size_of::<u8>() {
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
match self {
|
||||
Self::Unallocated => output[0] = 0,
|
||||
Self::Token(token) => {
|
||||
Self::Mint(token) => {
|
||||
if output.len() < size_of::<u8>() + size_of::<Token>() {
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
|
@ -509,14 +508,16 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
// Pulls in the stubs required for `info!()`
|
||||
// Pulls in the stubs required for `info!()`.
|
||||
#[cfg(not(target_arch = "bpf"))]
|
||||
solana_sdk_bpf_test::stubs!();
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::instruction::{approve, burn, mint_to, new_account, new_token, set_owner, transfer};
|
||||
use crate::instruction::{
|
||||
approve, burn, initialize_account, initialize_mint, mint_to, set_owner, transfer,
|
||||
};
|
||||
use solana_sdk::{
|
||||
account::Account, account_info::create_is_signer_account_infos, instruction::Instruction,
|
||||
};
|
||||
|
@ -541,7 +542,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_token() {
|
||||
fn test_initialize_mint() {
|
||||
let program_id = pubkey_rand();
|
||||
let token_account_key = pubkey_rand();
|
||||
let mut token_account_account = Account::new(0, size_of::<State>(), &program_id);
|
||||
|
@ -560,7 +561,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(ProgramError::InvalidArgument),
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
Some(&token_account_key),
|
||||
|
@ -577,7 +578,7 @@ mod tests {
|
|||
|
||||
// create account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account_key,
|
||||
&owner_key,
|
||||
|
@ -595,7 +596,7 @@ mod tests {
|
|||
|
||||
// create new token
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
Some(&token_account_key),
|
||||
|
@ -612,7 +613,7 @@ mod tests {
|
|||
|
||||
// create another account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account2_key,
|
||||
&owner_key,
|
||||
|
@ -632,7 +633,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(TokenError::TokenMismatch.into()),
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token2_key,
|
||||
Some(&token_account2_key),
|
||||
|
@ -649,7 +650,7 @@ mod tests {
|
|||
|
||||
// create delegate account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&delegate_account_key,
|
||||
&owner_key,
|
||||
|
@ -670,7 +671,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(TokenError::AlreadyInUse.into()),
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
Some(&delegate_account_key),
|
||||
|
@ -689,7 +690,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(TokenError::AlreadyInUse.into()),
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
Some(&token_account_key),
|
||||
|
@ -706,7 +707,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_token_account() {
|
||||
fn test_initialize_mint_account() {
|
||||
let program_id = pubkey_rand();
|
||||
let token_account_key = pubkey_rand();
|
||||
let mut token_account_account = Account::new(0, size_of::<State>(), &program_id);
|
||||
|
@ -716,7 +717,7 @@ mod tests {
|
|||
let mut token_account = Account::new(0, size_of::<State>(), &program_id);
|
||||
|
||||
// missing signer
|
||||
let mut instruction = new_account(
|
||||
let mut instruction = initialize_account(
|
||||
&program_id,
|
||||
&token_account_key,
|
||||
&owner_key,
|
||||
|
@ -739,7 +740,7 @@ mod tests {
|
|||
|
||||
// create account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account_key,
|
||||
&owner_key,
|
||||
|
@ -759,7 +760,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
Err(TokenError::AlreadyInUse.into()),
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account_key,
|
||||
&owner_key,
|
||||
|
@ -803,7 +804,7 @@ mod tests {
|
|||
|
||||
// create account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account_key,
|
||||
&owner_key,
|
||||
|
@ -821,7 +822,7 @@ mod tests {
|
|||
|
||||
// create another account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account2_key,
|
||||
&owner_key,
|
||||
|
@ -839,7 +840,7 @@ mod tests {
|
|||
|
||||
// create another account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account3_key,
|
||||
&owner_key,
|
||||
|
@ -857,7 +858,7 @@ mod tests {
|
|||
|
||||
// create mismatch account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&mismatch_account_key,
|
||||
&owner_key,
|
||||
|
@ -875,7 +876,7 @@ mod tests {
|
|||
|
||||
// create delegate account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&delegate_account_key,
|
||||
&owner_key,
|
||||
|
@ -894,7 +895,7 @@ mod tests {
|
|||
|
||||
// create mismatch delegate account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&mismatch_delegate_account_key,
|
||||
&owner_key,
|
||||
|
@ -913,7 +914,7 @@ mod tests {
|
|||
|
||||
// create new token
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
Some(&token_account_key),
|
||||
|
@ -1267,7 +1268,7 @@ mod tests {
|
|||
|
||||
// create account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account_key,
|
||||
&owner_key,
|
||||
|
@ -1283,8 +1284,8 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
// create mintable token without owner
|
||||
let mut instruction = new_token(
|
||||
// create mint-able token without owner
|
||||
let mut instruction = initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
None,
|
||||
|
@ -1301,17 +1302,17 @@ mod tests {
|
|||
do_process_instruction(instruction, vec![&mut token_account])
|
||||
);
|
||||
|
||||
// create mintable token with zero supply
|
||||
// create mint-able token with zero supply
|
||||
let info = TokenInfo {
|
||||
supply: 0,
|
||||
decimals: 2,
|
||||
};
|
||||
do_process_instruction(
|
||||
new_token(&program_id, &token_key, None, Some(&owner_key), info).unwrap(),
|
||||
initialize_mint(&program_id, &token_key, None, Some(&owner_key), info).unwrap(),
|
||||
vec![&mut token_account, &mut token_account_account],
|
||||
)
|
||||
.unwrap();
|
||||
if let State::Token(token) = State::deserialize(&token_account.data).unwrap() {
|
||||
if let State::Mint(token) = State::deserialize(&token_account.data).unwrap() {
|
||||
assert_eq!(
|
||||
token,
|
||||
Token {
|
||||
|
@ -1334,7 +1335,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
if let State::Token(token) = State::deserialize(&token_account.data).unwrap() {
|
||||
if let State::Mint(token) = State::deserialize(&token_account.data).unwrap() {
|
||||
assert_eq!(token.info.supply, 42);
|
||||
} else {
|
||||
panic!("not an account");
|
||||
|
@ -1371,7 +1372,7 @@ mod tests {
|
|||
|
||||
// create account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account_key,
|
||||
&owner_key,
|
||||
|
@ -1389,7 +1390,7 @@ mod tests {
|
|||
|
||||
// create another account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account2_key,
|
||||
&owner_key,
|
||||
|
@ -1407,7 +1408,7 @@ mod tests {
|
|||
|
||||
// create delegate account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&delegate_account_key,
|
||||
&owner_key,
|
||||
|
@ -1426,7 +1427,7 @@ mod tests {
|
|||
|
||||
// create mismatch delegate account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&mismatch_delegate_account_key,
|
||||
&owner_key,
|
||||
|
@ -1445,7 +1446,7 @@ mod tests {
|
|||
|
||||
// create new token
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
Some(&token_account_key),
|
||||
|
@ -1634,7 +1635,7 @@ mod tests {
|
|||
|
||||
// create account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account_key,
|
||||
&owner_key,
|
||||
|
@ -1652,7 +1653,7 @@ mod tests {
|
|||
|
||||
// create token account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account2_key,
|
||||
&owner_key,
|
||||
|
@ -1710,7 +1711,7 @@ mod tests {
|
|||
|
||||
// create new token with owner
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
Some(&token_account_key),
|
||||
|
@ -1758,7 +1759,7 @@ mod tests {
|
|||
|
||||
// create new token without owner
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token2_key,
|
||||
Some(&token_account2_key),
|
||||
|
@ -1773,7 +1774,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
// set owner for unownable token
|
||||
// set owner for non-mint-able token
|
||||
assert_eq!(
|
||||
Err(TokenError::NoOwner.into()),
|
||||
do_process_instruction(
|
||||
|
@ -1809,7 +1810,7 @@ mod tests {
|
|||
|
||||
// create token account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account_key,
|
||||
&owner_key,
|
||||
|
@ -1827,7 +1828,7 @@ mod tests {
|
|||
|
||||
// create another token account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account2_key,
|
||||
&owner_key,
|
||||
|
@ -1845,7 +1846,7 @@ mod tests {
|
|||
|
||||
// create another token account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account3_key,
|
||||
&owner_key,
|
||||
|
@ -1863,7 +1864,7 @@ mod tests {
|
|||
|
||||
// create mismatch token account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&mismatch_account_key,
|
||||
&owner_key,
|
||||
|
@ -1881,7 +1882,7 @@ mod tests {
|
|||
|
||||
// create delegate account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&delegate_account_key,
|
||||
&owner_key,
|
||||
|
@ -1900,7 +1901,7 @@ mod tests {
|
|||
|
||||
// create new token with owner
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
Some(&token_account_key),
|
||||
|
@ -1930,7 +1931,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
if let State::Token(token) = State::deserialize(&token_account.data).unwrap() {
|
||||
if let State::Mint(token) = State::deserialize(&token_account.data).unwrap() {
|
||||
assert_eq!(token.info.supply, 1000 + 42);
|
||||
} else {
|
||||
panic!("not an account");
|
||||
|
@ -2060,7 +2061,7 @@ mod tests {
|
|||
|
||||
// create token account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account_key,
|
||||
&owner_key,
|
||||
|
@ -2078,7 +2079,7 @@ mod tests {
|
|||
|
||||
// create another token account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account2_key,
|
||||
&owner_key,
|
||||
|
@ -2096,7 +2097,7 @@ mod tests {
|
|||
|
||||
// create another token account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&token_account3_key,
|
||||
&owner_key,
|
||||
|
@ -2114,7 +2115,7 @@ mod tests {
|
|||
|
||||
// create mismatch token account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&mismatch_account_key,
|
||||
&owner_key,
|
||||
|
@ -2132,7 +2133,7 @@ mod tests {
|
|||
|
||||
// create delegate account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&delegate_account_key,
|
||||
&owner_key,
|
||||
|
@ -2150,7 +2151,7 @@ mod tests {
|
|||
.unwrap();
|
||||
// create mismatch delegate account
|
||||
do_process_instruction(
|
||||
new_account(
|
||||
initialize_account(
|
||||
&program_id,
|
||||
&mismatch_delegate_account_key,
|
||||
&owner_key,
|
||||
|
@ -2169,7 +2170,7 @@ mod tests {
|
|||
|
||||
// create new token
|
||||
do_process_instruction(
|
||||
new_token(
|
||||
initialize_mint(
|
||||
&program_id,
|
||||
&token_key,
|
||||
Some(&token_account_key),
|
||||
|
@ -2268,7 +2269,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
if let State::Token(token) = State::deserialize(&token_account.data).unwrap() {
|
||||
if let State::Mint(token) = State::deserialize(&token_account.data).unwrap() {
|
||||
assert_eq!(token.info.supply, 1000 - 42);
|
||||
} else {
|
||||
panic!("not a token account");
|
||||
|
@ -2359,7 +2360,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
if let State::Token(token) = State::deserialize(&token_account.data).unwrap() {
|
||||
if let State::Mint(token) = State::deserialize(&token_account.data).unwrap() {
|
||||
assert_eq!(token.info.supply, 1000 - 42 - 84);
|
||||
} else {
|
||||
panic!("not a token account");
|
||||
|
|
Loading…
Reference in New Issue