Token
What do I need to get started with SPL-Tokens?
Solana에서 당신이 Token들과 통신할 때, 당신은 실제로는 SPL-Token standard 라고도 하는 Solana Program Library Token과 통신하는 것입니다. SPL-Token standard를 사용하기 위해서는 특정 라이브러리가 필요합니다. 아래에서 언어에 따라 찾을 수 있습니다.
"@solana/spl-token": "^0.2.0"
How to create a new Token
Token을 생성하는 것은 "mint account"라고 불리는 것을 생성하는 것으로 이뤄집니다. 이 mint Account는 나중에 사용자의 token Account에 token들을 mint 할 때 사용됩니다.
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
현재 Token이 가진 Token의 양, 권한 또는 decimal들을 알기 위해서는 token mint에 대한 Account 정보를 얻을 필요가 있을 것입니다.
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
import { getMint } from "@solana/spl-token";
(async () => {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const mintAccountPublicKey = new PublicKey("8mAKLjGGmjKTnmcXeyr3pr7iX13xXVjJJiL6RujDbSPV");
let mintAccount = await getMint(connection, mintAccountPublicKey);
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, mintAccountPublicKey);
How to create a token account
Token Account를 만들기 위해서는 Token들을 가지고 있을 사용자가 필요합니다.
사용자는 그들이 소유한 모든 종류의 Token 마다 최소한 하나의 Token Account를 가질 것입니다.
Associated Token Account는 모든 키쌍마다 생성된 Account들입니다. ATA들은 Token Account들을 관리하기 위해 추천되는 방법입니다.
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
모든 Token Account는 소유자, mint, 양(balance), 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
모든 Token Account는 Token balance를 가지고, 이것은 하나의 호출을 통해 조회할 수 있습니다.
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
Token Account는 오직 한 종류의 mint를 쥐고 있을 수 있습니다. 당신이 Token Account를 명세할 때, mint 또한 해야 합니다.
How to mint tokens
당신이 Token들을 mint 할 때, 당신은 공급을 증가시키고 새로운 Token들을 특정 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 (should 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 (should 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 (should 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 (should 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 (should 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
당신은 Token들을 하나의 Token Account에서 다른 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
만약 당신이 Token 소유자라면 token을 태울 수 있습니다.
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
만약 당신이 Token Account를 더 이상 사용하고 싶지 않다면, 당신은 Token Account를 닫을 수 있습니다. 두 가지 상황이 있습니다.
- Wrapped SOL - 닫는 것은 Wrapped SOL을 SOL로 전환시킵니다.
- Other Tokens - Token Account의 balance가 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
당신은 권한을 설정하거나 업데이트할 수 있습니다. 여기엔 4 가지 종류가 있습니다:
- 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 account || 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 account || 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
당신은 허락된 양에 대해 위임자를 지정할 수 있습니다. 지정하고 나면 위임자는 당신의 Token Account의 또 다른 소유자와 같습니다. Token Account는 한 번에 오직 하나의 Account에 위임할 수 있다
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
철회는 위임자에게 null을 설정할 것이고 위임된 양을 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은 다른 Token mint와 같습니다. 차이는 syncNative
를 사용하는 것과 NATIVE_MINT
주소에 구체적으로 Token Account들을 생성하는 것입니다.
Create Token Account
Create Token Account와 같지만 NATIVE_MINT
로 바꿔봅시다.
import { NATIVE_MINT } from "@solana/spl-token";
Add Balance
Wrapped SOL에 balance를 추가하는 두 가지 방법이 있습니다.
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
당신은 소유자 값으로 모든 Token Account들을 조회할 수 있습니다. 여기엔 두 가지 방법이 있습니다.
- 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,
});