本指南聚焦于 Solana Web3.js 2.0 的「函数式」用法,一次演练从空投资金到发送转账的完整流程。十分钟读完,你就能用不到百行代码把 Solana JavaScript 交互跑通。
1 项目准备
1.1 环境依赖
- Node.js ≥ 19
- TypeScript & ts-node
- Solana CLI(本地验证器)
1.2 安装依赖包
mkdir solana-transfer-demo && cd solana-transfer-demo
npm init -y
npm install @solana/web3.js@2 @solana-program/system
npm install --save-dev @types/node
npx tsc --init --resolveJsonModule true
echo > transfer.ts
2 初始化连接:掌握 RPC 和订阅
在发送任何交易前,先建立 RPC 和 WebSocket 连接,它们是驱动 Solana 交易的两条主线。
// transfer.ts
import {
createSolanaRpc,
createSolanaRpcSubscriptions
} from "@solana/web3.js";
const HTTP_ENDPOINT = "http://127.0.0.1:8899"; // 本地验证器
const WS_ENDPOINT = "ws://127.0.0.1:8900";
const rpc = createSolanaRpc(HTTP_ENDPOINT);
const rpcSubscriptions = createSolanaRpcSubscriptions(WS_ENDPOINT);
console.log("✅ RPC 已连接");
3 钱包准备:两种密钥生成方式
为了让 Solana Web3.js 2.0 尽显灵活性,这里演示“算法生成”与“字节导入”双轨并行:
import {
generateKeyPairSigner,
createKeyPairSignerFromBytes
} from "@solana/web3.js";
const user1 = await generateKeyPairSigner();
console.log("user1 地址:", user1.address);
// 如已有 my-keypair.json
import secret from "./my-keypair.json";
const user2 = await createKeyPairSignerFromBytes(new Uint8Array(secret));
4 领取测试代币:空投 1 SOL
Solana 开发离不开充足的 lamports。展示两种空投风格:
import { lamports, airdropFactory } from "@solana/web3.js";
const LAMPORTS_PER_SOL = BigInt(1_000_000_000);
// 方法 A:原生 RPC
const tx1 = await rpc
.requestAirdrop(user1.address, lamports(LAMPORTS_PER_SOL))
.send();
// 方法 B:工厂模式
const airdrop = airdropFactory({ rpc, rpcSubscriptions });
await airdrop({ recipientAddress: user2.address, lamports: lamports(LAMPORTS_PER_SOL) });
两种路径均以 commitment: 'processed'
接收后立即刷新余额,满足高频测试需求。
5 构造转账交易:函数式「管道」解析
Web3.js 2.0 的核心变化之一是用 函数式管道 取代「对象链式操作」。继续拆解:
import {
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
sendAndConfirmTransactionFactory,
signTransactionMessageWithSigners,
getSignatureFromTransaction
} from "@solana/web3.js";
import { getTransferSolInstruction } from "@solana-program/system";
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const transferMsg = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayer(user1.address, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstruction(
getTransferSolInstruction({
source: user1,
destination: user2.address,
amount: lamports(LAMPORTS_PER_SOL / 2n) // 0.5 SOL
}),
tx
)
);
const signed = await signTransactionMessageWithSigners(transferMsg);
const sendAndConfirm = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
await sendAndConfirm(signed, { commitment: "confirmed" });
console.log("✅ 转账成功,签名:", getSignatureFromTransaction(signed));
- 每一步都返回新增字段的新对象,保持 链上交易不可变性
- 函数签名与类型无缝结合,减少 80% 的隐式错误
6 本地验证与运行
打开新终端:
solana-test-validator -r
回放:
ts-node transfer.ts
输出示例:
✅ RPC 已连接
✅ user1 地址: 8sFgz...
✅ user2 地址: 5o3Xy...
✅ 空投完成
✅ 转账成功,签名:5k7QW...
7 扩展:多指令打包
在函数式 Solana风格里,pipe
天然支持追加指令。例如再转 0.3 SOL 给第三个账户:
const thirdAddress = "<SECRET_KEY>";
const multiTx = pipe(
// 上文已有步骤省略 ...
(tx) => appendTransactionMessageInstruction(
getTransferSolInstruction({
source: user1,
destination: thirdAddress,
amount: lamports(LAMPORTS_PER_SOL * 3n / 10n)
}),
tx
)
);
一行即可完成批量 SOL 转账的场景封装,适合 DeFi、空投脚本、NFT 批量铸造等高并发案例。
8 常见问题速览
Q1 Web3.js 2.0 与 1.x 可以同时共存吗?
A 不可以。项目须迁移到 2.x,唯一的向下兼容方案是为旧项目保留独立工作区。
Q2 lamports 为什么要改成 BigInt?
A 70% 新增 bug 来自精度溢出。使用 BigInt 可避免 2^53 限制,确保 Solana Rust 合约 对齐 u64。
Q3 管道式写法会不会太长?
A 可以把重复步骤封装为 util 函数,依旧保持可读;团队内部可共享模块,微信搜索「Solana 2.0 模板库」获取更多示例。
Q4 生产环境节点如何选?
A 推荐使用专业 RPC。👉 点此配置高可用节点,享受低延迟 + 100万次每日免费请求
Q5 本地验证器连接失败怎么办?
A 检查 8899/8900 端口被占用;或直接替换成 Devnet 端点,命令仅需改动两行。
Q6 TypeScript 报错找不到模块?
A 确认 tsconfig.json 包含 "moduleResolution": "node"
,并运行 npm ci
还原依赖锁。
9 小结
通过本指南,你已掌握:
- Solana Web3.js 2.0 的模块化导入
- 空投/查询/交易 的函数式拼装
- 用最少的改动,把旧脚本无痛迁移到 2.0
坚持链上交易安全第一,精确验证 every lamport。下一步可以尝试 PDA、SPL Token 转账,或将代码抽象为 CLI 工具正式发布。加油编码,祝你和 Solana 一起飞升!