Token
What do I need to get started with SPL-Tokens?
Every time you interact with tokens on Solana, you are actually interacting with the Solana Program Library Token, or SPL-Token standard. The SPL-Token standard requires a specific library to be used, which you can find below based on your language.
"@solana/spl-token": "^0.2.0"
How to create a new Token
Creating tokens is done by creating what is called a "mint account". This mint account is later used to mint tokens to a token account and create the initial supply.
import {
clusterApiUrl,
Connection,
Keypair,
Transaction,
SystemProgram,
} from "@solana/web3.js";
import {
createInitializeMintInstruction,
TOKEN_PROGRAM_ID,
MINT_SIZE,
getMinimumBalanceForRentExemptMint,
createMint,
} from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
// 1) use build-in function
let mintPubkey = await createMint(
connection, // conneciton
feePayer, // fee payer
alice.publicKey, // mint authority
alice.publicKey, // freeze authority (you can use `null` to disable it. when you disable it, you can't turn it on again)
8 // decimals
);
console.log(`mint: ${mintPubkey.toBase58()}`);
// or
// 2) compose by yourself
const mint = Keypair.generate();
console.log(`mint: ${mint.publicKey.toBase58()}`);
let tx = new Transaction().add(
// create mint account
SystemProgram.createAccount({
fromPubkey: feePayer.publicKey,
newAccountPubkey: mint.publicKey,
space: MINT_SIZE,
lamports: await getMinimumBalanceForRentExemptMint(connection),
programId: TOKEN_PROGRAM_ID,
}),
// init mint account
createInitializeMintInstruction(
mint.publicKey, // mint pubkey
8, // decimals
alice.publicKey, // mint authority
alice.publicKey // freeze authority (you can use `null` to disable it. when you disable it, you can't turn it on again)
)
);
console.log(
`txhash: ${await connection.sendTransaction(tx, [feePayer, mint])}`
);
})();
// 1) use build-in function
let mintPubkey = await createMint(
connection, // conneciton
feePayer, // fee payer
alice.publicKey, // mint authority
alice.publicKey, // freeze authority (you can use `null` to disable it. when you disable it, you can't turn it on again)
8 // decimals
);
// or
// 2) compose by yourself
let tx = new Transaction().add(
// create mint account
SystemProgram.createAccount({
fromPubkey: feePayer.publicKey,
newAccountPubkey: mint.publicKey,
space: MINT_SIZE,
lamports: await getMinimumBalanceForRentExemptMint(connection),
programId: TOKEN_PROGRAM_ID,
}),
// init mint account
createInitializeMintInstruction(
mint.publicKey, // mint pubkey
8, // decimals
alice.publicKey, // mint authority
alice.publicKey // freeze authority (you can use `null` to disable it. when you disable it, you can't turn it on again)
)
);
How to get a token mint
In order to get the current supply, authority, or decimals a token has, you will need to get the account info for the token mint.
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
import { getMint } from "@solana/spl-token";
(async () => {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const mint = new PublicKey("8mAKLjGGmjKTnmcXeyr3pr7iX13xXVjJJiL6RujDbSPV");
let mintAccount = await getMint(connection, mint);
console.log(mintAccount);
/*
{
address: PublicKey {
_bn: <BN: 7351e5e067cc7cfefef42e78915d3c513edbb8adeeab4d9092e814fe68c39fec>
},
mintAuthority: PublicKey {
_bn: <BN: df30e6ca0981c1a677eed6f7cb46b2aa442ca9b7a10a10e494badea4b9b6944f>
},
supply: 0n,
decimals: 8,
isInitialized: true,
freezeAuthority: PublicKey {
_bn: <BN: df30e6ca0981c1a677eed6f7cb46b2aa442ca9b7a10a10e494badea4b9b6944f>
}
}
*/
})();
let mintAccount = await getMint(connection, mint);
How to create a token account
A token account is required in order to hold tokens. Every token mint has a different token account associated with it.
Associated Token Accounts are deterministicly created accounts for every keypair. ATAs are the recommended method of managing token accounts.
import {
clusterApiUrl,
Connection,
PublicKey,
Keypair,
Transaction,
SystemProgram,
} from "@solana/web3.js";
import {
createAssociatedTokenAccount,
getAssociatedTokenAddress,
createAssociatedTokenAccountInstruction,
} from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
const mintPubkey = new PublicKey(
"2SKpuBU9ksneBZD4nqbZkw75NE11HsSHsGRtW2BZh5aQ"
);
// 1) use build-in function
{
let ata = await createAssociatedTokenAccount(
connection, // connection
feePayer, // fee payer
mintPubkey, // mint
alice.publicKey // owner,
);
console.log(`ATA: ${ata.toBase58()}`);
}
// or
// 2) composed by yourself
{
// calculate ATA
let ata = await getAssociatedTokenAddress(
mintPubkey, // mint
alice.publicKey // owner
);
console.log(`ATA: ${ata.toBase58()}`);
// if your wallet is off-curve, you should use
// let ata = await getAssociatedTokenAddress(
// mintPubkey, // mint
// alice.publicKey // owner
// true, // allowOwnerOffCurve
// );
let tx = new Transaction().add(
createAssociatedTokenAccountInstruction(
feePayer.publicKey, // payer
ata, // ata
alice.publicKey, // owner
mintPubkey // mint
)
);
console.log(`txhash: ${await connection.sendTransaction(tx, [feePayer])}`);
}
})();
// 1) use build-in function
{
let ata = await createAssociatedTokenAccount(
connection, // connection
feePayer, // fee payer
mintPubkey, // mint
alice.publicKey // owner,
);
}
// or
// 2) composed by yourself
{
let tx = new Transaction().add(
createAssociatedTokenAccountInstruction(
feePayer.publicKey, // payer
ata, // ata
alice.publicKey, // owner
mintPubkey // mint
)
);
}
How to get a Token Account
Every token account has information on the token such as the owner, mint, amount(balance), and decimals.
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
import { getAccount } from "@solana/spl-token";
(async () => {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const tokenAccountPubkey = new PublicKey(
"2XYiFjmU1pCXmC2QfEAghk6S7UADseupkNQdnRBXszD5"
);
let tokenAccount = await getAccount(connection, tokenAccountPubkey);
console.log(tokenAccount);
/*
{
address: PublicKey {
_bn: <BN: 16aef79dfadb39ffedb3b6f77688b8c162b18bb9cba2ffefe152303629ae3030>
},
mint: PublicKey {
_bn: <BN: 7351e5e067cc7cfefef42e78915d3c513edbb8adeeab4d9092e814fe68c39fec>
},
owner: PublicKey {
_bn: <BN: df30e6ca0981c1a677eed6f7cb46b2aa442ca9b7a10a10e494badea4b9b6944f>
},
amount: 0n,
delegate: null,
delegatedAmount: 0n,
isInitialized: true,
isFrozen: false,
isNative: false,
rentExemptReserve: null,
closeAuthority: null
}
*/
})();
let tokenAccount = await getAccount(connection, tokenAccountPubkey);
How to get a token account's balance
The token account has the token balance, which can be retrieved with a single call.
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
(async () => {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const tokenAccount = new PublicKey(
"FWZedVtyKQtP4CXhT7XDnLidRADrJknmZGA2qNjpTPg8"
);
let tokenAmount = await connection.getTokenAccountBalance(tokenAccount);
console.log(`amount: ${tokenAmount.value.amount}`);
console.log(`decimals: ${tokenAmount.value.decimals}`);
})();
let tokenAmount = await connection.getTokenAccountBalance(tokenAccount);
use solana_client::rpc_client::RpcClient;
use solana_program::pubkey::Pubkey;
use solana_sdk::commitment_config::CommitmentConfig;
use std::str::FromStr;
fn main() {
let rpc_url = String::from("https://api.devnet.solana.com");
let connection = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
let token_account = Pubkey::from_str("FWZedVtyKQtP4CXhT7XDnLidRADrJknmZGA2qNjpTPg8").unwrap();
let balance = connection
.get_token_account_balance(&token_account)
.unwrap();
println!("amount: {}, decimals: {}", balance.amount, balance.decimals);
}
let balance = connection
.get_token_account_balance(&token_account)
.unwrap();
TIP
A token account can only hold one kind of mint. When you specify a token account, you also specific a mint too.
How to mint tokens
When you mint tokens, you increase the supply and transfer the new tokens to a specific token account.
import {
clusterApiUrl,
Connection,
PublicKey,
Keypair,
Transaction,
} from "@solana/web3.js";
import {
createMintToCheckedInstruction,
mintToChecked,
} from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
const mintPubkey = new PublicKey(
"8mAKLjGGmjKTnmcXeyr3pr7iX13xXVjJJiL6RujDbSPV"
);
const tokenAccountPubkey = new PublicKey(
"2XYiFjmU1pCXmC2QfEAghk6S7UADseupkNQdnRBXszD5"
);
// 1) use build-in function
{
let txhash = await mintToChecked(
connection, // connection
feePayer, // fee payer
mintPubkey, // mint
tokenAccountPubkey, // receiver (sholud be a token account)
alice, // mint authority
1e8, // amount. if your decimals is 8, you mint 10^8 for 1 token.
8 // decimals
);
console.log(`txhash: ${txhash}`);
// if alice is a multisig account
// let txhash = await mintToChecked(
// connection, // connection
// feePayer, // fee payer
// mintPubkey, // mint
// tokenAccountPubkey, // receiver (sholud be a token account)
// alice.publicKey, // !! mint authority pubkey !!
// 1e8, // amount. if your decimals is 8, you mint 10^8 for 1 token.
// 8, // decimals
// [signer1, signer2 ...],
// );
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createMintToCheckedInstruction(
mintPubkey, // mint
tokenAccountPubkey, // receiver (sholud be a token account)
alice.publicKey, // mint authority
1e8, // amount. if your decimals is 8, you mint 10^8 for 1 token.
8 // decimals
// [signer1, signer2 ...], // only multisig account will use
)
);
console.log(
`txhash: ${await connection.sendTransaction(tx, [
feePayer,
alice /* fee payer + mint authority */,
])}`
);
}
})();
// 1) use build-in function
{
let txhash = await mintToChecked(
connection, // connection
feePayer, // fee payer
mintPubkey, // mint
tokenAccountPubkey, // receiver (sholud be a token account)
alice, // mint authority
1e8, // amount. if your decimals is 8, you mint 10^8 for 1 token.
8 // decimals
);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createMintToCheckedInstruction(
mintPubkey, // mint
tokenAccountPubkey, // receiver (sholud be a token account)
alice.publicKey, // mint authority
1e8, // amount. if your decimals is 8, you mint 10^8 for 1 token.
8 // decimals
// [signer1, signer2 ...], // only multisig account will use
)
);
}
How to transfer tokens
You can transfer tokens from one token account to another token account.
import {
clusterApiUrl,
Connection,
PublicKey,
Keypair,
Transaction,
} from "@solana/web3.js";
import {
createTransferCheckedInstruction,
TOKEN_PROGRAM_ID,
transferChecked,
} from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
const mintPubkey = new PublicKey(
"8mAKLjGGmjKTnmcXeyr3pr7iX13xXVjJJiL6RujDbSPV"
);
const tokenAccountXPubkey = new PublicKey(
"2XYiFjmU1pCXmC2QfEAghk6S7UADseupkNQdnRBXszD5"
);
const tokenAccountYPubkey = new PublicKey(
"GMxZfDmpR1b3vdJYXHzdF5noVLQogZuUAsDHHQ3ytPfV"
);
// 1) use build-in function
{
let txhash = await transferChecked(
connection, // connection
feePayer, // payer
tokenAccountXPubkey, // from (should be a token account)
mintPubkey, // mint
tokenAccountYPubkey, // to (should be a token account)
alice, // from's owner
1e8, // amount, if your deciamls is 8, send 10^8 for 1 token
8 // decimals
);
console.log(`txhash: ${txhash}`);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createTransferCheckedInstruction(
tokenAccountXPubkey, // from (should be a token account)
mintPubkey, // mint
tokenAccountYPubkey, // to (should be a token account)
alice.publicKey, // from's owner
1e8, // amount, if your deciamls is 8, send 10^8 for 1 token
8 // decimals
)
);
console.log(
`txhash: ${await connection.sendTransaction(tx, [
feePayer,
alice /* fee payer + owner */,
])}`
);
}
})();
// 1) use build-in function
{
let txhash = await transferChecked(
connection, // connection
feePayer, // payer
tokenAccountXPubkey, // from (should be a token account)
mintPubkey, // mint
tokenAccountYPubkey, // to (should be a token account)
alice, // from's owner
1e8, // amount, if your deciamls is 8, send 10^8 for 1 token
8 // decimals
);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createTransferCheckedInstruction(
tokenAccountXPubkey, // from (should be a token account)
mintPubkey, // mint
tokenAccountYPubkey, // to (should be a token account)
alice.publicKey, // from's owner
1e8, // amount, if your deciamls is 8, send 10^8 for 1 token
8 // decimals
)
);
}
How to burn tokens
You can burn token if you are the token owner.
import {
clusterApiUrl,
Connection,
PublicKey,
Keypair,
Transaction,
} from "@solana/web3.js";
import {
burnChecked,
createBurnCheckedInstruction,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
const mintPubkey = new PublicKey(
"8mAKLjGGmjKTnmcXeyr3pr7iX13xXVjJJiL6RujDbSPV"
);
const tokenAccountPubkey = new PublicKey(
"2XYiFjmU1pCXmC2QfEAghk6S7UADseupkNQdnRBXszD5"
);
// 1) use build-in function
{
let txhash = await burnChecked(
connection, // connection
feePayer, // payer
tokenAccountPubkey, // token account
mintPubkey, // mint
alice, // owner
1e8, // amount, if your deciamls is 8, 10^8 for 1 token
8
);
console.log(`txhash: ${txhash}`);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createBurnCheckedInstruction(
tokenAccountPubkey, // token account
mintPubkey, // mint
alice.publicKey, // owner of token account
1e8, // amount, if your deciamls is 8, 10^8 for 1 token
8 // decimals
)
);
console.log(
`txhash: ${await connection.sendTransaction(tx, [
feePayer,
alice /* fee payer + token authority */,
])}`
);
}
})();
// 1) use build-in function
{
let txhash = await burnChecked(
connection, // connection
feePayer, // payer
tokenAccountPubkey, // token account
mintPubkey, // mint
alice, // owner
1e8, // amount, if your deciamls is 8, 10^8 for 1 token
8
);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createBurnCheckedInstruction(
tokenAccountPubkey, // token account
mintPubkey, // mint
alice.publicKey, // owner of token account
1e8, // amount, if your deciamls is 8, 10^8 for 1 token
8 // decimals
)
);
}
How to close token accounts
You can close a token account if you don't want to use it anymore. There are two situations:
- Wrapped SOL - Closing converts Wrapped SOL to SOL
- Other Tokens - You can close it only if token account's balance is 0.
import {
clusterApiUrl,
Connection,
PublicKey,
Keypair,
Transaction,
} from "@solana/web3.js";
import { closeAccount, createCloseAccountInstruction } from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
const tokenAccountPubkey = new PublicKey(
"2XYiFjmU1pCXmC2QfEAghk6S7UADseupkNQdnRBXszD5"
);
// 1) use build-in function
{
let txhash = await closeAccount(
connection, // connection
feePayer, // payer
tokenAccountPubkey, // token account which you want to close
alice.publicKey, // destination
alice // owner of token account
);
console.log(`txhash: ${txhash}`);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createCloseAccountInstruction(
tokenAccountPubkey, // token account which you want to close
alice.publicKey, // destination
alice.publicKey // owner of token account
)
);
console.log(
`txhash: ${await connection.sendTransaction(tx, [
feePayer,
alice /* fee payer + owner */,
])}`
);
}
})();
// 1) use build-in function
{
let txhash = await closeAccount(
connection, // connection
feePayer, // payer
tokenAccountPubkey, // token account which you want to close
alice.publicKey, // destination
alice // owner of token account
);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createCloseAccountInstruction(
tokenAccountPubkey, // token account which you want to close
alice.publicKey, // destination
alice.publicKey // owner of token account
)
);
}
How to set authority on token accounts or mints
You can set/update authority. There are 4 types:
- MintTokens (mint account)
- FreezeAccount (mint account)
- AccountOwner (token account)
- CloseAccount (token account)
import {
clusterApiUrl,
Connection,
PublicKey,
Keypair,
Transaction,
} from "@solana/web3.js";
import {
AuthorityType,
createSetAuthorityInstruction,
setAuthority,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
const randomGuy = Keypair.generate();
console.log(`random guy: ${randomGuy.publicKey.toBase58()}`);
const mintPubkey = new PublicKey(
"8mAKLjGGmjKTnmcXeyr3pr7iX13xXVjJJiL6RujDbSPV"
);
// authority type
// 1) for mint account
// AuthorityType.MintTokens
// AuthorityType.FreezeAccount
// 2) for token account
// AuthorityType.AccountOwner
// AuthorityType.CloseAccount
// 1) use build-in function
{
let txhash = await setAuthority(
connection, // connection
feePayer, // payer
mintPubkey, // mint acocunt || token account
alice, // current authority
AuthorityType.MintTokens, // authority type
randomGuy.publicKey // new authority (you can pass `null` to close it)
);
console.log(`txhash: ${txhash}`);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createSetAuthorityInstruction(
mintPubkey, // mint acocunt || token account
alice.publicKey, // current auth
AuthorityType.MintTokens, // authority type
feePayer.publicKey // new auth (you can pass `null` to close it)
)
);
console.log(
`txhash: ${await connection.sendTransaction(tx, [
feePayer,
alice /* fee payer + origin auth */,
])}`
);
}
})();
// 1) use build-in function
{
let txhash = await setAuthority(
connection, // connection
feePayer, // payer
mintPubkey, // mint acocunt || token account
alice, // current authority
AuthorityType.MintTokens, // authority type
randomGuy.publicKey // new authority (you can pass `null` to close it)
);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createSetAuthorityInstruction(
mintPubkey, // mint acocunt || token account
alice.publicKey, // current auth
AuthorityType.MintTokens, // authority type
randomGuy.publicKey // new auth (you can pass `null` to close it)
)
);
}
How to approve a token delegate
You can set a delegate with an allowed amount. After you setting, the delegate is like an another owner of your token account. A token account can only delegate to one account at the same time
import {
clusterApiUrl,
Connection,
PublicKey,
Keypair,
Transaction,
} from "@solana/web3.js";
import {
approveChecked,
createApproveCheckedInstruction,
} from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
const randomGuy = Keypair.generate();
const mintPubkey = new PublicKey(
"8mAKLjGGmjKTnmcXeyr3pr7iX13xXVjJJiL6RujDbSPV"
);
const tokenAccountPubkey = new PublicKey(
"GMxZfDmpR1b3vdJYXHzdF5noVLQogZuUAsDHHQ3ytPfV"
);
// 1) use build-in function
{
let txhash = await approveChecked(
connection, // connection
feePayer, // fee payer
mintPubkey, // mint
tokenAccountPubkey, // token account
randomGuy.publicKey, // delegate
alice, // owner of token account
1e8, // amount, if your deciamls is 8, 10^8 for 1 token
8 // decimals
);
console.log(`txhash: ${txhash}`);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createApproveCheckedInstruction(
tokenAccountPubkey, // token account
mintPubkey, // mint
randomGuy.publicKey, // delegate
alice.publicKey, // owner of token account
1e8, // amount, if your deciamls is 8, 10^8 for 1 token
8 // decimals
)
);
console.log(
`txhash: ${await connection.sendTransaction(tx, [
feePayer,
alice /* fee payer + owner */,
])}`
);
}
})();
// 1) use build-in function
{
let txhash = await approveChecked(
connection, // connection
feePayer, // fee payer
mintPubkey, // mint
tokenAccountPubkey, // token account
randomGuy.publicKey, // delegate
alice, // owner of token account
1e8, // amount, if your deciamls is 8, 10^8 for 1 token
8 // decimals
);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createApproveCheckedInstruction(
tokenAccountPubkey, // token account
mintPubkey, // mint
randomGuy.publicKey, // delegate
alice.publicKey, // owner of token account
1e8, // amount, if your deciamls is 8, 10^8 for 1 token
8 // decimals
)
);
}
How to revoke a token delegate
Revoke will set delegate to null and set delegated amount to 0.
import {
clusterApiUrl,
Connection,
PublicKey,
Keypair,
Transaction,
} from "@solana/web3.js";
import { createRevokeInstruction, revoke } from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
const tokenAccountPubkey = new PublicKey(
"DRS5CSgPQp4uvPPcUA34tckfYFNUPNBJi77fVbnSfQHr"
);
// 1) use build-in function
{
let txhash = await revoke(
connection, // connection
feePayer, // payer
tokenAccountPubkey, // token account
alice // owner of token account
);
console.log(`txhash: ${txhash}`);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createRevokeInstruction(
tokenAccountPubkey, // token account
alice.publicKey // owner of token account
)
);
console.log(
`txhash: ${await connection.sendTransaction(tx, [
feePayer,
alice /* fee payer + origin auth */,
])}`
);
}
})();
// 1) use build-in function
{
let txhash = await revoke(
connection, // connection
feePayer, // payer
tokenAccountPubkey, // token account
alice // owner of token account
);
}
// or
// 2) compose by yourself
{
let tx = new Transaction().add(
createRevokeInstruction(
tokenAccountPubkey, // token account
alice.publicKey // owner of token account
)
);
}
How to manage wrapped SOL
Wrapped SOL just like any other token mint. The difference is using syncNative
and creating token accounts specifically on the NATIVE_MINT
address.
Create Token Account
Like Create Token Account but replace mint with NATIVE_MINT
import { NATIVE_MINT } from "@solana/spl-token";
Add Balance
There are two ways to add balance for Wrapped SOL
1. By SOL Transfer
import {
clusterApiUrl,
Connection,
Keypair,
Transaction,
SystemProgram,
} from "@solana/web3.js";
import {
NATIVE_MINT,
getAssociatedTokenAddress,
createSyncNativeInstruction,
createAccount,
} from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
// remember to create ATA first
let ata = await getAssociatedTokenAddress(
NATIVE_MINT, // mint
alice.publicKey // owner
);
let amount = 1 * 1e9; /* Wrapped SOL's decimals is 9 */
let tx = new Transaction().add(
// trasnfer SOL
SystemProgram.transfer({
fromPubkey: alice.publicKey,
toPubkey: ata,
lamports: amount,
}),
// sync wrapped SOL balance
createSyncNativeInstruction(ata)
);
console.log(
`txhash: ${await connection.sendTransaction(tx, [feePayer, alice])}`
);
})();
let tx = new Transaction().add(
// trasnfer SOL
SystemProgram.transfer({
fromPubkey: alice.publicKey,
toPubkey: ata,
lamports: amount,
}),
// sync wrapped SOL balance
createSyncNativeInstruction(ata)
);
2. By Token Transfer
import {
clusterApiUrl,
Connection,
Keypair,
Transaction,
SystemProgram,
} from "@solana/web3.js";
import {
TOKEN_PROGRAM_ID,
NATIVE_MINT,
getMinimumBalanceForRentExemptAccount,
getAssociatedTokenAddress,
ACCOUNT_SIZE,
createInitializeAccountInstruction,
createTransferInstruction,
closeAccountInstructionData,
createCloseAccountInstruction,
} from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
// remember to create ATA first
let ata = await getAssociatedTokenAddress(
NATIVE_MINT, // mint
alice.publicKey // owner
);
let auxAccount = Keypair.generate();
let amount = 1 * 1e9; /* Wrapped SOL's decimals is 9 */
let tx = new Transaction().add(
// create token account
SystemProgram.createAccount({
fromPubkey: alice.publicKey,
newAccountPubkey: auxAccount.publicKey,
space: ACCOUNT_SIZE,
lamports:
(await getMinimumBalanceForRentExemptAccount(connection)) + amount, // rent + amount
programId: TOKEN_PROGRAM_ID,
}),
// init token account
createInitializeAccountInstruction(
auxAccount.publicKey,
NATIVE_MINT,
alice.publicKey
),
// transfer WSOL
createTransferInstruction(
auxAccount.publicKey,
ata,
alice.publicKey,
amount
),
// close aux account
createCloseAccountInstruction(
auxAccount.publicKey,
alice.publicKey,
alice.publicKey
)
);
console.log(
`txhash: ${await connection.sendTransaction(tx, [
feePayer,
auxAccount,
alice,
])}`
);
})();
let tx = new Transaction().add(
// create token account
SystemProgram.createAccount({
fromPubkey: alice.publicKey,
newAccountPubkey: auxAccount.publicKey,
space: ACCOUNT_SIZE,
lamports:
(await getMinimumBalanceForRentExemptAccount(connection)) + amount, // rent + amount
programId: TOKEN_PROGRAM_ID,
}),
// init token account
createInitializeAccountInstruction(
auxAccount.publicKey,
NATIVE_MINT,
alice.publicKey
),
// transfer WSOL
createTransferInstruction(auxAccount.publicKey, ata, alice.publicKey, amount),
// close aux account
createCloseAccountInstruction(
auxAccount.publicKey,
alice.publicKey,
alice.publicKey
)
);
How to get all token accounts by owner
You can fetch token accounts by owner. There are two ways to do it.
- Get All Token Account
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const owner = new PublicKey("G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY");
let response = await connection.getParsedTokenAccountsByOwner(owner, {
programId: TOKEN_PROGRAM_ID,
});
response.value.forEach((accountInfo) => {
console.log(`pubkey: ${accountInfo.pubkey.toBase58()}`);
console.log(`mint: ${accountInfo.account.data["parsed"]["info"]["mint"]}`);
console.log(
`owner: ${accountInfo.account.data["parsed"]["info"]["owner"]}`
);
console.log(
`decimals: ${accountInfo.account.data["parsed"]["info"]["tokenAmount"]["decimals"]}`
);
console.log(
`amount: ${accountInfo.account.data["parsed"]["info"]["tokenAmount"]["amount"]}`
);
console.log("====================");
});
})();
let response = await connection.getParsedTokenAccountsByOwner(owner, {
programId: TOKEN_PROGRAM_ID,
});
- Filter By Mint
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const owner = new PublicKey("G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY");
const mint = new PublicKey("54dQ8cfHsW1YfKYpmdVZhWpb9iSi6Pac82Nf7sg3bVb");
let response = await connection.getParsedTokenAccountsByOwner(owner, {
mint: mint,
});
response.value.forEach((accountInfo) => {
console.log(`pubkey: ${accountInfo.pubkey.toBase58()}`);
console.log(`mint: ${accountInfo.account.data["parsed"]["info"]["mint"]}`);
console.log(
`owner: ${accountInfo.account.data["parsed"]["info"]["owner"]}`
);
console.log(
`decimals: ${accountInfo.account.data["parsed"]["info"]["tokenAmount"]["decimals"]}`
);
console.log(
`amount: ${accountInfo.account.data["parsed"]["info"]["tokenAmount"]["amount"]}`
);
console.log("====================");
});
})();
let response = await connection.getParsedTokenAccountsByOwner(owner, {
mint: mint,
});