代币
我需要什么才能开始使用SPL代币?
每当你在Solana上与代币进行交互时,实际上你正在与Solana程序库代币(SPL-Token)或SPL代币标准交互。SPL代币标准需要使用特定的库,你可以根据你使用的编程语言在下面找到相应的库。
"@solana/spl-token": "^0.2.0"
如何创建一个新的代币
创建代币是通过创建所谓的“铸币账户”来完成的。这个铸币账户随后用于向用户的代币账户铸造代币。
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)
)
);
如何获得一个代币铸币账户
为了获得代币的当前供应量、授权信息或小数位数,你需要获取代币铸币账户的账户信息。
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);
如何创建一个代币账户
用户需要一个代币账户来持有代币。
对于用户所拥有的每种类型的代币,他们将至少拥有一个代币账户。
关联代币账户(Associated Token Accounts, ATA) 是根据每个密钥对确定性地创建的账户。关联代币账户是管理代币账户的推荐方法。
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
)
);
}
如何获得一个代币账户
每个代币账户都包含有关代币的信息,例如所有者、铸币账户、数量(余额)和小数位数。
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);
如何获得一个代币账户的余额
每个代币账户都包含有关代币的信息,例如所有者、铸币账户、数量(余额)和小数位数。
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();
::: 贴士 一个代币账户只能持有一种铸币。当您指定一个代币账户时,您也需要指定一个铸币。 :::
如何铸造(mint)代币
当你铸造代币时,你会增加供应量并将新代币转移到特定的代币账户。
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
)
);
}
如何转移代币
你可以将代币从一个代币账户转移到另一个代币账户。
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
)
);
}
如何销代币
如果你是代币的所有者,你可以销毁代币。
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
)
);
}
如何关闭代币账户
如果你不再需要使用某个代币账户,你可以关闭它。有两种情况:
- 包装的 SOL(Wrapped SOL)- 关闭操作会将包装的 SOL 转换为 SOL。
- 其他代币(Other Tokens)- 只有当代币账户的余额为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
)
);
}
如何在代币账户或铸币账户上设置权限
你可以设置/更新权限。有四种类型:
- MintTokens(铸币账户):用于控制在铸币账户上铸造代币的权限。
- FreezeAccount(铸币账户):用于冻结或解冻铸币账户的权限。
- AccountOwner(代币账户):用于控制代币账户所有权的权限。
- CloseAccount(代币账户):用于关闭代币账户的权限。
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)
)
);
}
如何批准代币委托
你可以设置一个委托代理,并指定一个允许的代币数量。设置后,委托代理就像代币账户的另一个所有者。一个代币账户在同一时间只能委托给一个账户。
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
)
);
}
如何撤销代币委托
撤销操作将把代币委托设置为空,并将委托的代币数量设置为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
)
);
}
如何管理包装的SOL
包装的 SOL与其他代币铸币类似,区别在于使用 syncNative
并在 NATIVE_MINT
地址上专门创建代币账户。
创建代币账户
与 创建代币账户 但将mint替换为NATIVE_MINT
。
import { NATIVE_MINT } from "@solana/spl-token";
增加余额
有两种方法可以增加包装的 SOL 的余额:
1. 通过 SOL 转账方式
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. 通过代币转账方式
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
)
);
如何通过所有者获取所有代币账户
你可以通过所有者获取代币账户。有两种方法可以实现。
- 获取所有代币账户
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,
});
- 按照铸币进行过滤
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,
});