如果你正用 JavaScript 对接 Solana,这份 Web3.js 实战手册 能帮你少走弯路。示例覆盖连接集群、转账、创建密钥对、编写交易、质押 SOL、管理 Nonce 账户等高频场景,全部由 @solana/web3.js 官方 API 驱动,可直接复制到本地 Devnet 演练。
1. 建立 Connection:三行代码跑通 RPC
Connection 是一切交互的起点,设置集群端点与确认级别即可。
import { Connection, clusterApiUrl } from "@solana/web3.js";
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const slot = await connection.getSlot();
console.log("当前 Slot:", slot);核心关键词:Connection、Solana Devnet、RPC 节点
2. 密钥对 Keypair:随机、种子、私钥三种方法一把抓
生成或恢复密钥对只需:
import { Keypair } from "@solana/web3.js";
// 随机
const account = Keypair.generate();
// 从种子(32字节)
const seed = new Uint8Array(32).fill(42);
const fromSeed = Keypair.fromSeed(seed);
// 从私钥
const fromSecret = Keypair.fromSecretKey(account.secretKey);安全提示:种子与私钥等同,请离线保存,切勿上传至代码仓库。
3. PublicKey:地址派生与程序地址一次讲透
地址可以来自 Base58 字符串,也可官方派生程序地址:
import { PublicKey } from "@solana/web3.js";
const base58Key = new PublicKey("5xot9PVkphiX2adznghwrAuxGs2zeWisNSxMW6hU6Hkj");
const [programAddr] = await PublicKey.findProgramAddress(
[Buffer.from("anchor")],
base58Key
);4. 构建 Transaction:转账 + 签名全流程演示
import {
Transaction,
SystemProgram,
sendAndConfirmTransaction,
} from "@solana/web3.js";
const payer = Keypair.generate();
await connection.requestAirdrop(payer.publicKey, 1e9); // 1 SOL
const receiver = Keypair.generate().publicKey;
const ix = SystemProgram.transfer({
fromPubkey: payer.publicKey,
toPubkey: receiver,
lamports: 1000,
});
const tx = new Transaction().add(ix);
await sendAndConfirmTransaction(connection, tx, [payer]);5. 系统程序 SystemProgram:创建、分配、指派账户
除了转账,SystemProgram 还能分派账号给任意程序、初始化空白账号:
const newAccount = Keypair.generate();
const createAccIx = SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: newAccount.publicKey,
lamports: await connection.getMinimumBalanceForRentExemption(100),
space: 100,
programId: SystemProgram.programId,
});6. Nonce 账户:离线构造交易的保险锁
Nonce 账户把当前区块 hash 缓存成固定值,避免交易过期。
const nonceKey = Keypair.generate();
await connection.requestAirdrop(payer.publicKey, 2e9);
const minLamports = await connection.getMinimumBalanceForRentExemption(
80 // Nonce 账户占用
);
const createNonceTx = new Transaction().add(
SystemProgram.createNonceAccount({
fromPubkey: payer.publicKey,
noncePubkey: nonceKey.publicKey,
authorizedPubkey: payer.publicKey,
lamports: minLamports,
})
);
await sendAndConfirmTransaction(connection, createNonceTx, [payer, nonceKey]);
const nonceData = await connection.getNonce(nonceKey.publicKey, "confirmed");
console.log("Nonce 值:", nonceData.nonce);7. 质押 SOL:StakeProgram 全攻略
从创建质押账户到委托、停用、提款,五步搞定:
import { StakeProgram, Authorized, Lockup } from "@solana/web3.js";
const stakeAccount = Keypair.generate();
const stakeAmount = 1 * 1e9 + // 质押的 SOL
(await connection.getMinimumBalanceForRentExemption(StakeProgram.space));
const createStakeIx = StakeProgram.createAccount({
fromPubkey: payer.publicKey,
authorized: new Authorized(payer.publicKey, payer.publicKey),
lockup: new Lockup(0, 0, payer.publicKey),
lamports: stakeAmount,
stakePubkey: stakeAccount.publicKey,
});
await sendAndConfirmTransaction(connection, new Transaction().add(createStakeIx), [
payer,
stakeAccount,
]);
// 选验证节点
const { current } = await connection.getVoteAccounts();
const votePubkey = new PublicKey(current[0].votePubkey);
const delegateIx = StakeProgram.delegate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: payer.publicKey,
votePubkey,
});
await sendAndConfirmTransaction(connection, new Transaction().add(delegateIx), [payer]);8. Secp256k1 程序:把以太坊签名校验搬进 Solana
链上验证比特币 / 以太坊签名:
import { Secp256k1Program } from "@solana/web3.js";
const ethAddress = Buffer.alloc(20); // 实际来自 keccak
const sig = new Uint8Array(64);
const tx = new Transaction().add(
Secp256k1Program.createInstructionWithEthAddress({
ethAddress: ethAddress.toString("hex"),
plaintext: Buffer.from("Hello Solana"),
signature: sig,
recoveryId: 0,
})
);9. Message & Struct:低层玩法,构建离线交易
Message 用于构造可在浏览器以外签名的交易:
const msg = new Message({
accountKeys: [payer.publicKey.toString(), receiver.toString(), SystemProgram.programId.toString()],
header: {
numRequiredSignatures: 1,
numReadonlySignedAccounts: 0,
numReadonlyUnsignedAccounts: 1,
},
instructions: [
{
accounts: [0, 1],
data: Buffer.from([2, ...]), // transfer 指令二进制
programIdIndex: 2,
},
],
recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
});
const txFromMsg = Transaction.populate(msg, [payer.publicKey.toString()]);10. Rust ↔ JS 边界:Struct & Enum 互相映射
Solidity 碰到结构体和枚举会头大,但在 Solana 只要用 Borsh:
// Rust
pub struct Price { price: u64 }
// JS
import { Struct } from "@solana/web3.js";
export class Price extends Struct<{ price: BN }> {}常见问题 FAQ
Q1:用 Mainnet 会不会被反撸手续费?
A:先在 Devnet 跑示例,确认无误再切 Mainnet,还可以申请 devnet SOL 无限复用体验 👉 点击领取最新空投水龙头
Q2:getRecentBlockhash 已被弃用怎么办?
A:改调用 getLatestBlockhash;两者结构相同,切换一行即可。
Q3:Nonce 账号必须租用吗?
A:必须。Nonce 数据占用约 80 字节,需满足租金豁免门槛;停用后可赎回。
Q4:如何把一个地址标记为“只读”?
A:Transaction Header 里的 numReadonlySignedAccounts 与 numReadonlyUnsignedAccounts 控制。
Q5:Keypair.generate 可重复吗?
A:随机种子熵源自操作系统,理论碰撞概率极低。如需可复现,使用 fromSeed。
Q6:质押年化收益是多少?
A:取决于验证节点绩效和网络通胀参数,Solana explorer 实时可查。也可 👉 在线计算器速查
结语
通读 10 步示例,你已掌握 Web3.js 操作 Solana 的核心链路:连接 → 密钥 → 转账 → 高级账户 → 质押。把代码复制到本地 npm init && npm i @solana/web3.js,马上开启高性能链上开发之旅。