在上一节中,您学习了如何通过获取账户来 从 Solana 网络读取数据。向 Solana 网络写入数据需要发送 交易。一笔交易包含一条或多条 指令,每条指令都会调用一个程序。
程序为每条指令定义业务逻辑。当您发送交易时,Solana 运行时会按顺序执行交易中的指令。交易具有原子性:要么交易中的所有指令全部成功,要么整笔交易全部失败。
本节示例将展示如何:
- 在账户之间转移 SOL
- 创建新的代币铸造账户
转移 SOL
以下示例演示如何将 SOL 从一个账户转移到另一个账户。只有被指定为账户所有者的程序才能修改账户数据或从其余额中扣除 lamport。钱包账户由 System Program 所有,因此在钱包账户之间转移 SOL 需要一条调用 System Program 的 transfer 指令。源账户还必须对交易进行签名。
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";import { getTransferSolInstruction } from "@solana-program/system";const client = await createClient().use(generatedPayer()).use(solanaRpc({rpcUrl: "http://localhost:8899",rpcSubscriptionsUrl: "ws://localhost:8900"})).use(rpcAirdrop()).use(airdropPayer(lamports(1_000_000_000n)));const receiver = await generateKeyPairSigner();const transferInstruction = getTransferSolInstruction({source: client.payer,destination: receiver.address,amount: lamports(10_000_000n)});const result = await client.sendTransaction([transferInstruction]);console.log("Transaction Signature:", result.context.signature);const { value: senderBalance } = await client.rpc.getBalance(client.payer.address).send();const { value: receiverBalance } = await client.rpc.getBalance(receiver.address).send();console.log("Sender Balance:", senderBalance);console.log("Receiver Balance:", receiverBalance);
为本地测试 validator 创建 Kit 客户端。此代码片段添加了付款方签名者,连接到本地 RPC 端点,启用空投功能,并为付款方充值测试 SOL 以用于转账。
const client = await createClient().use(generatedPayer()).use(solanaRpc({rpcUrl: "http://localhost:8899",rpcSubscriptionsUrl: "ws://localhost:8900"})).use(rpcAirdrop()).use(airdropPayer(lamports(1_000_000_000n)));
为接收方生成一个签名者。发送方为 client.payer,该账户由 generatedPayer()
创建,并由 airdropPayer() 充值。
const receiver = await generateKeyPairSigner();
getTransferSolInstruction() 辅助函数用于创建 System
Program 指令。该指令将 SOL 从 source 签名者转移到
destination 地址,转移指定数量的
amount lamports。
const transferInstruction = getTransferSolInstruction({source: client.payer,destination: receiver.address,amount: lamports(10_000_000n)});
以指令数组为参数调用
client.sendTransaction()。Kit 客户端将这些指令组合为一笔交易,使用指令所附的签名者进行签名,发送交易并等待确认。
const result = await client.sendTransaction([transferInstruction]);console.log("Transaction Signature:", result.context.signature);
交易确认后,使用 client.rpc 获取两个账户的余额。
const { value: senderBalance } = await client.rpc.getBalance(client.payer.address).send();const { value: receiverBalance } = await client.rpc.getBalance(receiver.address).send();
创建代币
以下示例使用 Token Extensions Program 创建一个新的代币 mint account。mint account 是定义代币全局设置的账户,例如小数位数、供应量、铸造权限和冻结权限。
创建 mint account 需要两条指令:
- 调用 System Program 创建一个新账户,该账户归 Token Extensions Program 所有。
- 调用 Token Extensions Program 将该账户初始化为铸造账户。
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";import { getCreateAccountInstruction } from "@solana-program/system";import {fetchMint,getInitializeMintInstruction,getMintSize,TOKEN_2022_PROGRAM_ADDRESS} from "@solana-program/token-2022";const client = await createClient().use(generatedPayer()).use(solanaRpc({rpcUrl: "http://localhost:8899",rpcSubscriptionsUrl: "ws://localhost:8900"})).use(rpcAirdrop()).use(airdropPayer(lamports(1_000_000_000n)));const mint = await generateKeyPairSigner();const space = BigInt(getMintSize());const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();const createAccountInstruction = getCreateAccountInstruction({payer: client.payer,newAccount: mint,space,lamports: rent,programAddress: TOKEN_2022_PROGRAM_ADDRESS});const initializeMintInstruction = getInitializeMintInstruction({mint: mint.address,decimals: 2,mintAuthority: client.payer.address,freezeAuthority: client.payer.address,tokenProgram: TOKEN_2022_PROGRAM_ADDRESS});const result = await client.sendTransaction([createAccountInstruction,initializeMintInstruction]);console.log("Mint Address:", mint.address);console.log("Transaction Signature:", result.context.signature);const mintAccount = await fetchMint(client.rpc, mint.address);console.log("Mint Account:", mintAccount);
创建并为 Kit 客户端充值,然后生成一个签名者,用作新 mint account 的地址。客户端的付款方负责资助账户创建并支付交易费用。
const client = await createClient().use(generatedPayer()).use(solanaRpc({rpcUrl: "http://localhost:8899",rpcSubscriptionsUrl: "ws://localhost:8900"})).use(rpcAirdrop()).use(airdropPayer(lamports(1_000_000_000n)));const mint = await generateKeyPairSigner();
计算 mint account 的字节大小,然后发起 RPC 请求以计算在账户中存储该数据所需的 lamport 数量。这个所需余额称为 rent。
const space = BigInt(getMintSize());const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();
第一条指令调用 System Program。该指令使用 payer 为
newAccount 提供资金,分配 mint account 的
space,转移免租
lamports,并将所有权分配给
programAddress。
const createAccountInstruction = getCreateAccountInstruction({payer: client.payer,newAccount: mint,space,lamports: rent,programAddress: TOKEN_2022_PROGRAM_ADDRESS});
第二条指令调用 Token Extensions Program。该指令使用
mint 地址,并初始化 decimals
值、mintAuthority、freezeAuthority,以及指定拥有该 mint
account 的 tokenProgram。
const initializeMintInstruction = getInitializeMintInstruction({mint: mint.address,decimals: 2,mintAuthority: client.payer.address,freezeAuthority: client.payer.address,tokenProgram: TOKEN_2022_PROGRAM_ADDRESS});
在一笔交易中发送两条指令。创建账户的指令必须在初始化铸币指令之前执行,因为 mint account 必须先存在,Token Extensions Program 才能将铸币数据写入该账户。
const result = await client.sendTransaction([createAccountInstruction,initializeMintInstruction]);
交易确认后,获取 mint account。
const mintAccount = await fetchMint(client.rpc, mint.address);console.log("Mint Account:", mintAccount);
Is this page helpful?