阅读时间 19 分钟
本指南提供 Solana Web3.js(旧版 v 1.x)和 Solana Kit(v 2.x)两个版本。请选择相应的选项卡,查看您所选库的代码片段和操作说明:
- Solana 工具包
- Solana Web3.js(旧版)
概述
发送 Solana 程序库(SPL)代币是 Solana 开发中的关键机制。无论您是向社区空投白名单代币、批量向其他钱包发送 NFT,还是管理托管账户之间的代币流转,都不可避免地需要能够转移 SPL 代币。转移 SPL 代币与发送 SOL 略有不同,因此在您的 Solana 开发过程中,了解其工作原理至关重要。
您将负责的工作内容
在本指南中,您将使用 TypeScript 编写一个脚本,用于在 Solana 开发网(devnet)上将一个 SPL 代币从一个账户转移到另一个账户。
如果您想了解如何在基于 Anchor 框架的程序中转账 SPL 代币和 SOL,请参阅我们的指南:《如何使用 Anchor 转账 SOL 和 SPL 代币》 。
更喜欢视频教程吗?跟着萨希尔一起学习如何在 Solana 开发网(Devnet)上转账 SPL 代币。
您需要准备的物品
SPL 代币账户概述
在开始之前,了解 Solana 代币计划账户中的几个组成部分——铸造 ID 和关联代币账户——的工作原理会很有帮助。
Mint ID
每个 SPL 代币都有一个唯一的铸造 ID,可用于将其与其他类型的代币区分开来。 例如,$USDC SPL 代币的铸造 ID 为EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v,而 $SAMO 的铸造 ID 为7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU。
值得注意的是,每个 NFT 都有一个唯一的铸造地址(这也是其不可替代性的部分原因)。例如, “Famous Fox #4679”的铸造 ID 为GS2AtoEoL9DgaYg9xC7cUumftB7vb2CPMrczZCKgJv1Y,而“Famous Fox #6562”的铸造 ID 为7FTdQdMqkk5Xc2oFsYR88BuJt2yyCPReTpqr3viH6b6C。 正如您稍后将看到的,这是这两个代币之间的一项重要区别。
如果您想进一步了解如何铸造 SPL 代币,请参阅我们的指南: 《如何使用新的 Metaplex 代币标准创建可互换的 SPL 代币》 以及 《如何在 Solana 上铸造 NFT》。
关联代币账户
Solana 代币计划“根据用户的主系统账户地址和代币铸造地址生成一个代币账户密钥,从而允许用户为其持有的每种代币创建一个主代币账户”(来源:spl.solana.com)。该账户被称为关联代币账户(Associated Token Account,简称“ATA”)。实际上,ATA 是一个与用户及特定代币铸造相关联的唯一账户。 例如,假设我是账户“DEMO...1234”的所有者。我可以拥有多个 ATA——每个 ATA 对应我持有的一个代币铸造地址(例如,每个 $USDC、$SAMO 等都有一个唯一的 ATA,如下图所示)。

代币转账必须始终在两个关联同一铸造地址的 ATA 之间进行。这意味着我们无法将 $USDC 从我的 ATA 转账到你的 $SAMO ATA(参见下例)。

正如您稍后将在我们的代码中看到的,并非每个账户都已为每个铸币厂分配了 ATA。如果用户此前从未与某枚代币进行过交互,发送方必须“创建”该代币,并存入必要的租金,以保持该账户的活跃状态。
这个概念起初可能有些晦涩,但非常重要,所以请花点时间确保自己真正理解它!我发现通过在 Solana Explorer 的代币详情页面浏览我的钱包非常有帮助:https://explorer.solana.com/address/YOUR_WALLET_ADDRESS/tokens?display=detail。在那里你可以看到你拥有的每一枚 ATA、其账户 ID 以及相关的铸造 ID:

如果您想进一步了解 Solana SPL 代币计划库,请访问spl.solana.com。
准备好开始编程了吗?我也是!
设置您的项目
- Solana 工具包
- Solana Web3.js(旧版)
在终端中使用以下命令创建一个新的项目目录:
mkdir spl-transfer-kit
cd spl-transfer-kit
为您的应用程序创建一个文件,命名为app.ts:
echo > app.ts
使用“yes”标志初始化项目,以便为新包采用默认值:
yarn init --yes
#或者
npm init --yes
创建一个采用现代模块解析方式的tsconfig.json文件:
tsc --init
请将tsconfig.json更新为以下内容:
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"target": "ESNext"
}
}
安装 Solana Kit 的依赖项
在本练习中,我们需要添加 Solana Kit 和 Token 程序库。请在终端中输入:
yarn add @solana/kit @solana-program/token
#或者
npm install @solana/kit @solana-program/token
在终端中使用以下命令创建一个新的项目目录:
mkdir spl-transfer
cd spl-transfer
为您的应用程序创建一个文件,命名为app.ts:
echo > app.ts
使用“yes”标志初始化项目,以便为新包采用默认值:
yarn init --yes
#或者
npm init --yes
创建一个启用了 .json 导入功能的tsconfig.json文件:
tsc -init --resolveJsonModule true
安装 Solana Web3 依赖项
为了完成本练习,我们需要添加 Solana Web3 和 SPL Token 库。请在终端中输入:
yarn add @solana/web3.js@1 @solana/spl-token
#或者
npm install @solana/web3.js@1 @solana/spl-token
创建钱包并领取SOL空投
- Solana 工具包
- Solana Web3.js(旧版)
我们需要完成的第一项任务是创建一个钱包账户并为其充值。我们将使用下方的便捷工具自动生成一个新钱包,并向其中空投 1 SOL。
注意:过频地发送空投请求可能会触发 429(请求过多)错误。
成功生成密钥对后,你会发现有两个新的常量: 秘密 以及 FROM_KEYPAIR,一个密钥对。该 秘密 是一个 32 字节的数组,用于生成公钥和私钥。该 FROM_KEYPAIR 这是一个用于签署交易的 Keypair 实例(我们已空投了一些开发网 SOL 用于支付 gas 费用)。如果您尚未添加,请务必将其添加到代码中,放在其他常量之后。
在导入语句下方,粘贴您的新密钥数组:
const secret = [0,...,0]; // 👈 请替换为您的密钥
我们需要完成的第一项任务是创建一个钱包账户并为其充值。我们将使用下方的便捷工具自动生成一个新钱包,并向其中空投 1 SOL。(您也可以通过 Keypair.generate() 以及 requestAirdrop() (如果您更喜欢手动操作,也可以使用这些函数)。
注意:过频地发送空投请求可能会触发 429(请求过多)错误。
成功生成密钥对后,你会发现有两个新的常量: 秘密 以及 FROM_KEYPAIR,一个密钥对。该 秘密 是一个 32 字节的数组,用于生成公钥和私钥。该 FROM_KEYPAIR 这是一个用于签署交易的 Keypair 实例(我们已空投了一些开发网 SOL 用于支付 gas 费用)。如果您尚未添加,请务必将其添加到代码中,放在其他常量之后。
在导入语句下方,粘贴您的新密钥,并添加:
import { Keypair } from "@solana/web3.js";
const secret = [0,...,0]; // 👈 Replace with your secret
const FROM_KEYPAIR = Keypair.fromSecretKey(new Uint8Array(secret));
console.log(`My public key is: ${FROM_KEYPAIR.publicKey.toString()}.`);
铸造或空投一些 SPL 代币
要完成本指南,您需要在 Devnet 上拥有一些 SPL 代币。获取 Devnet SPL 代币的方法有多种——以下列举了几种。
- 铸造您自己的可互换代币(指南:《如何使用新的 Metaplex 代币标准创建可互换的 SPL 代币》)。
- 使用 Candy Machine 铸造一个或多个 NFT(指南:《如何使用 Sugar(Candy Machine)在 Solana 上部署 NFT 系列》)。
- 从SPL 代币水龙头申请 $DUMMY 代币空投。*
- 如果您已经在其他钱包中持有 Devnet SPL 代币,可以使用 Phantom 或其他钱包界面将其转出。*
在继续之前,您应该能够访问 Solana 浏览器,并确认您的钱包在开发网(https://explorer.solana.com/address/YOUR_WALLET_ADDRESS/tokens?cluster=devnet)上拥有 SOL 余额以及至少一种 SPL 代币。界面应大致如下所示:

让我们开始吧。
设置您的应用
导入必要的依赖项
- Solana 工具包
- Solana Web3.js(旧版)
打开app.ts 文件,并在第1 行粘贴以下导入语句:
import {
createSolanaRpc,
createSolanaRpcSubscriptions,
address,
pipe,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
signTransactionMessageWithSigners,
sendAndConfirmTransactionFactory,
airdropFactory,
lamports,
getSignatureFromTransaction,
createKeyPairFromBytes,
createSignerFromKeyPair
} from '@solana/kit';
import {
TOKEN_PROGRAM_ADDRESS,
fetchToken,
getTransferInstruction,
findAssociatedTokenPda,
getCreateAssociatedTokenIdempotentInstruction
} from '@solana-program/token';
除了在上一步中创建的钱包外,我们还从 Solana Kit 和 Token 程序库中导入了必要的方法和类。
打开app.ts 文件,并在第1 行粘贴以下导入语句:
import { getOrCreateAssociatedTokenAccount, createTransferInstruction } from "@solana/spl-token";
import { Connection, Keypair, ParsedAccountData, PublicKey, sendAndConfirmTransaction, Transaction } from "@solana/web3.js";
除了在上一步中创建的钱包外,我们还将从 Solana Web3 库中导入几个关键的方法和类。
设置您的 Quicknode 端点
- Solana 工具包
- Solana Web3.js(旧版)
要在 Solana 上进行开发,您需要一个 API 端点来连接网络。您可以使用公共节点,也可以部署和管理自己的基础设施;不过,如果您希望响应速度提升 8 倍,不妨将繁重的工作交给我们处理。了解为何超过 50% 的 Solana 项目选择 Quicknode,并点击此处注册账户。我们将使用一个 Solana Devnet 节点。
复制 HTTP 提供程序的链接:

在app.ts文件中,在 import 语句下方声明您的 RPC 并建立与 Solana 的连接:
const QUICKNODE_RPC = 'https://example.solana-devnet.quiknode.pro/0123456/';
const QUICKNODE_RPC_SUBSCRIPTIONS = 'wss://example.solana-devnet.quiknode.pro/0123456/';
const rpc = createSolanaRpc(QUICKNODE_RPC);
const rpcSubscriptions = createSolanaRpcSubscriptions(QUICKNODE_RPC_SUBSCRIPTIONS);
const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
请务必替换 QUICKNODE_RPC 以及 QUICKNODE_RPC_SUBSCRIPTIONS 请填写您实际的 Quicknode 端点 URL(来自 Quicknode 控制台的 https 和 wss 链接)。
要在 Solana 上进行开发,您需要一个 API 端点来连接网络。您可以使用公共节点,也可以部署和管理自己的基础设施;不过,如果您希望响应速度提升 8 倍,不妨将繁重的工作交给我们处理。了解为何超过 50% 的 Solana 项目选择 Quicknode,并点击此处注册账户。我们将使用一个 Solana Devnet 节点。
复制 HTTP 提供程序的链接:

在app.ts文件中,在 import 语句下方声明您的 RPC 并建立与 Solana的连接:
const QUICKNODE_RPC = 'https://example.solana-devnet.quiknode.pro/0123456/';
const SOLANA_CONNECTION = new Connection(QUICKNODE_RPC);
声明变量
- Solana 工具包
- Solana Web3.js(旧版)
要运行该脚本,你需要声明几个变量:目标账户(即你希望将代币转账给的账户所有者)、要转账的代币的铸造地址,以及要转账的代币数量。请在 RPC 配置下方添加以下声明:
const DESTINATION_WALLET = 地址('DemoKMZWkk483hX4mUrcJoo3zVvsKhm8XXs28TuwZw9H');
const MINT_ADDRESS = 地址('DoJuta7joTSuuoozqQtjtnASRYiVsT435gh4srh5LLGK'); //您必须修改此值!
const TRANSFER_AMOUNT = 1n; // 使用 BigInt 实现代币金额的高精度计算
替换 MINT_ADDRESS 并填写您计划发送的代币的铸造地址。如果您不知道代币的铸造地址,可以前往 https://explorer.solana.com/address/YOUR_WALLET_ADDRESS/tokens?cluster=devnet 然后点击 复制 图标以获取您的Mint地址。将其粘贴到 MINT_ADDRESS 变量。

注意:您还可以更新您的 DESTINATION_WALLET 地址和 TRANSFER_AMOUNT ,但本示例中这两个值均可使用。
要运行该脚本,您需要声明几个变量:目标账户(即您希望将代币转账给的账户持有者)、要转账的代币的铸造地址,以及要转账的代币数量。请在下方添加以下声明: SOLANA_CONNECTION:
const DESTINATION_WALLET = 'DemoKMZWkk483hX4mUrcJoo3zVvsKhm8XXs28TuwZw9H';
const MINT_ADDRESS = 'DoJuta7joTSuuoozqQtjtnASRYiVsT435gh4srh5LLGK'; //您必须修改此值!
const TRANSFER_AMOUNT = 1;
替换 MINT_ADDRESS 并填写您计划发送的代币的铸造地址。如果您不知道代币的铸造地址,可以前往 https://explorer.solana.com/address/YOUR_WALLET_ADDRESS/tokens?cluster=devnet 然后点击 复制 图标以获取您的Mint地址。将其粘贴到 MINT_ADDRESS 变量。

注意:您还可以更新您的 DESTINATION_WALLET 地址和 TRANSFER_AMOUNT ,但本示例中这两个值均可使用。
获取小数位数
- Solana 工具包
- Solana Web3.js(旧版)
如果你之前创建过可互换的 SPL 代币,你就知道小数位数很重要。 由于区块链将代币供应量表示为整数值,我们必须根据代币元数据中分配的小数位数来转换代币数量(例如,如果铸造时设置了三位小数,则必须发送 1,000 个单位才能有效转移一个代币 [1,000 / 10**3])。
要获取小数部分,我们将调用rpc实例上的getAccountInfo方法,并解析 mint 账户数据。请在声明下方添加此函数:
async function getNumberDecimals(mintAddress) {
// getAccountInfo defaults to binary, using `jsonParsed` lets us read parsed.info.decimals without manual byte offsets.
const accountInfo = await rpc.getAccountInfo(mintAddress, { encoding: 'jsonParsed' }).send();
const data = accountInfo.value?.data;
if (!data || !('parsed' in data) || !data.parsed?.info) {
throw new Error('Failed to find mint account');
}
return (data.parsed.info as { decimals: number }).decimals;
}
严格来说,如果你知道代币铸造时的小数位数(可在 Solana Explorer 的代币页面上找到),其实并不需要这个。不过,我们还是想把它包含进来,因为这样你就可以针对不同的铸造情况修改代码,而无需更改其他变量。
让我们进入有趣的部分吧!
如果你之前创建过可互换的 SPL 代币,你就知道小数位数很重要。 由于区块链将代币供应量表示为整数值,我们必须根据代币元数据中分配的小数位数来转换代币数量(例如,如果铸造时设置了三位小数,则必须发送 1,000 个单位才能有效转移一个代币 [1,000 / 10**3])。
要获取小数部分,我们将调用SOLANA_CONNECTION上的getParsedAccountInfo 方法,并传入令牌MINT_ADDRESS。由于该方法可能返回多种类型,我们需要将类型声明为ParsedAccountData,以便有效解析数据。请在声明块下方添加此函数:
async function getNumberDecimals(mintAddress: string):Promise<number> {
const info = await SOLANA_CONNECTION.getParsedAccountInfo(new PublicKey(MINT_ADDRESS));
const result = (info.value?.data as ParsedAccountData).parsed.info.decimals as number;
return result;
}
严格来说,如果你知道代币铸造时的小数位数(可在 Solana Explorer 的代币页面上找到),其实并不需要这个。不过,我们还是想把它包含进来,因为这样你就可以针对不同的铸造情况修改代码,而无需更改其他变量。
让我们进入有趣的部分吧!
创建传递函数
- Solana 工具包
- Solana Web3.js(旧版)
创建一个新的异步函数sendTokens:
async 函数 sendTokens() {
}
首先,我们需要根据密钥数组创建签名密钥对,并为其充值 SOL。在sendTokens 方法中,添加步骤 1:
console.log(`Sending ${TRANSFER_AMOUNT} ${MINT_ADDRESS} to ${DESTINATION_WALLET}.`)
//Step 1
console.log(`1 - Creating keypair and funding with SOL`);
const keyPair = await createKeyPairFromBytes(new Uint8Array(secret));
const FROM_KEYPAIR = await createSignerFromKeyPair(keyPair);
// Fund the keypair with SOL for transaction fees
// (you can skip this step if you already have devnet SOL in your FROM_KEYPAIR)
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: FROM_KEYPAIR.address,
lamports: lamports(1_000_000_000n), // 1 SOL
commitment: 'confirmed',
});
console.log(` From wallet: ${FROM_KEYPAIR.address}`);
注意:在生产环境中,您应使用
generateKeyPairFromBytes(new Uint8Array(secret))请使用您实际的密钥,而不是生成一个新的密钥。
接下来,我们将为源账户和目标账户推导出关联代币账户(“ATA”)。请记住,每个账户都必须有一个ATA,用于将钱包与铸币厂关联起来;一个ATA只能持有来自单一铸币厂的代币;且发送方和接收方的关联代币账户所对应的铸币厂必须相同。添加步骤 2:
//Step 2
console.log(`2 - Deriving Associated Token Accounts`);
const [sourceTokenAccount] = await findAssociatedTokenPda({
owner: FROM_KEYPAIR.address,
mint: MINT_ADDRESS,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
});
const [destinationTokenAccount] = await findAssociatedTokenPda({
owner: DESTINATION_WALLET,
mint: MINT_ADDRESS,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
});
console.log(` Source Token Account: ${sourceTokenAccount}`);
console.log(` Destination Token Account: ${destinationTokenAccount}`);
接下来,我们需要检查目标代币账户是否存在,并在必要时创建该账户。添加步骤 3:
console.log(`3 - Checking Destination Token Account`);
let needsDestinationAccount = false;
try {
await rpc.getAccountInfo(destinationTokenAccount).send();
} catch (error) {
needsDestinationAccount = true;
}
if (needsDestinationAccount) {
console.log(` Destination token account does not exist, will create it`);
} else {
console.log(` Destination token account exists`);
}
为了正确计算金额,让我们获取小数位数。添加第 4 步:
//Step 4
console.log(`4 - Fetching Number of Decimals for Mint: ${MINT_ADDRESS}`);
const numberDecimals = await getNumberDecimals(MINT_ADDRESS);
console.log(` Number of Decimals: ${numberDecimals}`);
const transferAmountWithDecimals = TRANSFER_AMOUNT * BigInt(Math.pow(10, numberDecimals));
最后,我们需要使用 Solana Kit 的函数式方法来组装并发送交易。添加第 5 步:
//Step 5
console.log(`5 - Creating and Sending Transaction`);
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(FROM_KEYPAIR, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => {
// Add create ATA instruction if needed
if (needsDestinationAccount) {
return appendTransactionMessageInstruction(
getCreateAssociatedTokenIdempotentInstruction({
payer: FROM_KEYPAIR,
ata: destinationTokenAccount,
owner: DESTINATION_WALLET,
mint: MINT_ADDRESS,
}),
tx
);
}
return tx;
},
(tx) => appendTransactionMessageInstruction(
getTransferInstruction({
source: sourceTokenAccount,
destination: destinationTokenAccount,
authority: FROM_KEYPAIR,
amount: transferAmountWithDecimals,
}),
tx
)
);
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
await sendAndConfirmTransaction(signedTransaction, { commitment: 'confirmed' });
const signature = await getSignatureFromTransaction(signedTransaction);
console.log(
'\x1b[32m', //Green Text
` Transaction Success!🎉`,
`\n https://explorer.solana.com/tx/${signature}?cluster=devnet`
);
创建一个新的异步函数sendTokens:
async 函数 sendTokens() {
}
首先,我们需要获取源账户和目标账户的关联代币账户(“ATA”)。请注意,每个账户都必须有一个 ATA,用于将钱包与铸币厂关联;一个 ATA 只能持有单个铸币厂的代币;且发送方和接收方的关联代币账户所关联的铸币厂必须相同。
我们将使用getOrCreateAssociatedTokenAccount方法为该交易的每一方获取 ATA(若不存在则创建)。由于我们可能需要为这些交易创建关联账户,因此付款方可能需要向新的 ATA 存入少量 SOL 以支付租金。 在`sendTokens` 函数内部,向代码中添加步骤 1 以获取我们的源账户(严格来说,由于我们已知拥有 SPL 代币——因此已存在 ATA,所以也可以使用`getAssociatedTokenAddress`):
console.log(`Sending ${TRANSFER_AMOUNT} ${(MINT_ADDRESS)} from ${(FROM_KEYPAIR.publicKey.toString())} to ${(DESTINATION_WALLET)}.`)
//Step 1
console.log(`1 - Getting Source Token Account`);
let sourceAccount = await getOrCreateAssociatedTokenAccount(
SOLANA_CONNECTION,
FROM_KEYPAIR,
new PublicKey(MINT_ADDRESS),
FROM_KEYPAIR.publicKey
);
console.log(` Source Account: ${sourceAccount.address.toString()}`);
对于目标账户,我们将采取同样的操作。请按照下面的第 2 步操作,获取或创建目标账户(即代币将被发送到的收款方的 ATA):
//Step 2
console.log(`2 - Getting Destination Token Account`);
let destinationAccount = await getOrCreateAssociatedTokenAccount(
SOLANA_CONNECTION,
FROM_KEYPAIR,
new PublicKey(MINT_ADDRESS),
new PublicKey(DESTINATION_WALLET)
);
console.log(` Destination Account: ${destinationAccount.address.toString()}`);
要完成这笔交易,还差最后一个信息。还记得我们之前创建的getNumberDecimals函数吗?现在调用它,并将返回值存储在一个常量numberDecimals 中:
//Step 3
console.log(`3 - Fetching Number of Decimals for Mint: ${MINT_ADDRESS}`);
const numberDecimals = await getNumberDecimals(MINT_ADDRESS);
console.log(` Number of Decimals: ${numberDecimals}`);
最后,我们需要组装并发送交易。请在“步骤 3”下方添加以下指令组:
//第 4 步
控制台.log(`4 - 创建并发送事务`);
const tx = new Transaction();
tx.add(createTransferInstruction(
sourceAccount.地址,
destinationAccount.地址,
FROM_KEYPAIR.publicKey,
TRANSFER_AMOUNT * Math.pow(10, numberDecimals)
))
- Solana 工具包
- Solana Web3.js(旧版)
我们在这里要做的是指示我们的应用,将TRANSFER_AMOUNT个代币(请注意,必须乘以 10 的numberDecimals 次方)从sourceTokenAccount转账至destinationTokenAccount。
Solana Kit 的方法采用函数式编程风格,其中 管道 函数用于逐步构建事务。这提供了更好的类型安全性,并使事务构建过程更加明确。此外,如果目标 ATA 不存在,我们会在同一事务中使用幂等指令来创建它——即使该账户已经存在,该操作也不会失败。
别在意那个 console.log——那只是个小技巧,用来让成功提示以绿色文字显示。
我们在这里要做的是,指示我们的应用程序将TRANSFER_AMOUNT个代币(请注意,必须乘以 10 的numberDecimals 次方)从我们获取的sourceAccount转账至我们获取的destinationAccount。
为了遵循最佳实践,我们在发送交易之前应先获取最新的区块哈希。请将以下代码片段添加到你的`sendTokens` 函数中第 4 步的末尾:
const latestBlockHash = await SOLANA_CONNECTION.getLatestBlockhash('confirmed');
tx.recentBlockhash = await latestBlockHash.blockhash;
const signature = await sendAndConfirmTransaction(SOLANA_CONNECTION,tx,[FROM_KEYPAIR]);
console.log(
'\x1b[32m', //Green Text
` Transaction Success!🎉`,
`\n https://explorer.solana.com/tx/${signature}?cluster=devnet`
);
别在意那个 console.log——那只是个小技巧,用来让成功提示以绿色文字显示。
🏃♂️ 运行你的代码
- Solana 工具包
- Solana Web3.js(旧版)
最后,在代码结尾处调用sendTokens:
sendTokens().catch(控制台.error);
在终端中,输入以下命令运行你的代码:
ts-node app.ts
恭喜!如果您按照上述步骤操作,应该会看到类似以下的内容:

最后,在代码结尾处调用sendTokens:
sendTokens();
在终端中,输入以下命令运行你的代码:
ts-node app.ts
恭喜!如果您按照上述步骤操作,应该会看到类似以下的内容:

后续步骤与总结
太棒了!现在你已经知道如何将 SPL 代币从一个用户转给另一个用户了!想更进一步吗?以下是一些可以让你更深入探索的建议:
-
你能编写一个脚本,将你所有的 NFT 转移到另一个钱包吗?(提示:你可能需要先研究一下如何获取用户钱包中的所有代币)。
-
你能编写一个脚本,将 SPL 代币通过空投分发给一批钱包吗?这些钱包可能与你的铸造相关联,也可能无关。(提示:可参考我们关于批量分发 SOL 的指南以获取灵感)。
如果您愿意尝试一下,或者有任何问题想问我们,请告诉我们!欢迎在Discord和Twitter 上找到我们!
我们 ❤️ 您的反馈!
如果您有任何反馈或对新主题的建议,请告诉我们。我们非常期待您的来信。
