本文介绍了Solana Web3.js SDK 2.0的重大更新,包括性能改进、应用程序包体积减小和增强的灵活性,提供了代码示例和迁移指南,并强调了新SDK对开发者的帮助。文章最后介绍了最佳实践和如何发送交易的具体步骤,适合有一定技术基础的开发者阅读。
在深入之前,我们要感谢 Evan 和 Nick 对这篇文章的审阅。他们的宝贵反馈和见解非常感谢。
Solana Web3.js SDK 是一个强大的 TypeScript 和 JavaScript 库,用于在 Node.js、Web 和 React Native 平台上构建 Solana 应用程序。在2024年11月7日,Anza推出了备受期待的2.0 SDK更新,引入了一系列现代 JavaScript 特性和改进。关键亮点包括大整数和加密的标准 JS 类型以及减少的包大小,使其成为开发人员的一次重要升级。
如果你一直在使用 @solana/web3.js
,则需要将你的软件移植到新版本 v2.0 包,或明确指定版本以将其锁定为 v1.x。
在本文中,我们将探索 Web3.js 2.0 SDK 的最新更新,指导你完成迁移过程,并提供示例以帮助你入门。
本文假设读者对基础的 Solana 概念有一定的理解,比如发送交易、Solana 账户模型、区块哈希和 优先费用,同时具备 TypeScript 或 JavaScript 的经验。虽然建议熟悉 Web3.js SDK 的先前版本,但并不是强制要求。让我们开始吧!
让我们快速了解一下新的 Web3.js 2.0 SDK 提供了什么:
更快的加密操作:密钥对生成、交易签名和消息验证的速度提高了 10倍,利用了现代 JavaScript 环境(如 Node.js 和当前浏览器)中的本地加密 API。
Web3.js 2.0 完全支持 tree-shaking,允许你仅包含你使用的库的部分,从而将包大小降到最小。此外,新 SDK 没有外部依赖项,确保构建的轻量和安全。
开发者现在可以通过以下方式创建自定义解决方案:
新的 TypeScript 客户端现在托管在 @solana-program GitHub 组织下。这些客户端是通过 Codama 自动生成的,使开发者能够快速为自定义程序生成客户端。
截至 2025 年 2 月:
如果你使用过 web3.js v1,这里是重要差异的快速总结:
在任何需要使用 Keypair
的地方,现在使用 KeyPairSigner
。Keypair.generate()
现在是 generateKeyPairSigner()
。此外,密钥对在任何地方都拼写为 keyPair,就像正常的 JS/TS camelCase。
私钥现在称为 privateKey
,可通过 keyPairSigner.privateKey
访问 . 一般来说,在 web3.js v2 中,你在任何使用 secretKey 的地方使用 KeyPairSigner
。
在 web3.js v1 中使用 PublicKey 的地方,在 web3.js v2 中只需使用 address。例如,KeyPairSigner
有一个 keypairSigner.address
属性,这是它们的公钥。你可以使用 address
函数将字符串公钥转换为地址。
数量使用原生的 JS BigInt
类型。因此,你需要在数字的末尾添加 n
,使 1
变为 1n
。
许多特性是可配置的,因此不会有预设的实现(例如 doThing()
),而是有一个工厂(称为 doThingFactory()
),你可以用它创建自己的 doThing()
函数。例如:
sendAndConfirmTransactionFactory()
,并返回一个自定义的 sendAndConfirmTransaction()
函数。然后,你可以在需要发送和确认交易时使用你的 sendAndConfirmTransaction()
。airdropFactory()
,然后得到一个自定义的 airdrop()
函数,以便在你想要空投时使用。Helius 最近发布了 Kite,这是一个用于 web3.js v2 的 TypeScript 框架,其中包含大多数常见 Solana 任务的一次性函数。
我们将使用 Web3.js 2.0 构建一个客户端程序,以便将 lamports 转移到另一个钱包。该程序将展示提高交易成功率和更快确认时间的技术。
我们将遵循以下最佳实践来发送交易:
这种方法确保了即使在 网络拥塞 的情况下,仍然可以获得最佳的性能和可靠性。
先决条件
首先创建一个基本的 Node.js 项目以结构化你的应用。
运行以下命令以创建一个管理你的依赖项和项目元数据的 package.json
文件:
Shell 命令
npm init -y
创建一个 src
目录,并在其中添加一个 index.ts
文件,其中将放置主要代码:
Shell 命令
mkdir src
touch src/index.ts
接下来,使用 npm
安装用于操作 Solana 的 Web3.js 2.0 SDK 所需的依赖项:
Shell 命令
npm install @solana/web3.js@2 @solana-program/system @solana-program/compute-budget esrun
以下是每个包的描述:
@solana/web3.js
: Solana Web3.js 2.0 SDK,对构建和管理 Solana 交易至关重要@solana-program/system
: 提供对 Solana 系统程序的访问,允许进行如 lamport 转移等操作@solana-program/compute-budget
: 用于设置优先费用和优化交易的计算单位esrun
是一种简单的方法,可以直接从命令行运行 TypeScript 应用,而无需配置或包装函数。在 index.ts
中,定义用于转移 lamports 的源地址和目标地址。我们将使用 address()
函数从提供的字符串生成目标公钥。
对于源地址,我们将根据其 secretKey
推导出 KeyPair
。
send-transaction.ts
import { address, createKeyPairSignerFromBytes, getBase58Encoder } from "@solana/web3.js";
const destinationAddress = address("public-key-to-send-lamports-to");
const secretKey = "add-your-private-key";
const sourceKeypair = await createKeyPairSignerFromBytes(getBase58Encoder().encode(secretKey));
接下来,我们可以设置相关的 RPC 连接。createSolanaRpc
函数使用默认的 HTTP 传输与 RPC 服务器建立通信,适用于大多数用例。
同样,我们使用 createSolanaRpcSubscriptions
来建立 WebSocket 连接。rpc_url
和 wss_url
在 Helius Dashboard 中——只需注册或登录并导航到“端点”部分。
sendAndConfirmTransactionFactory
函数构建了一个可重用的交易发送器。该发送器需要 RPC 连接来发送交易和一个 RPC 订阅来监控交易状态。
send-transaction.ts
import {
// ...
createSolanaRpcSubscriptions,
createSolanaRpc,
sendAndConfirmTransactionFactory,
} from "@solana/web3.js";
const rpc_url = "https://mainnet.helius-rpc.com/?api-key=<your-key>";
const wss_url = "wss://mainnet.helius-rpc.com/?api-key=<your-key>";
const rpc = createSolanaRpc(rpc_url);
const rpcSubscriptions = createSolanaRpcSubscriptions(wss_url);
const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({
rpc,
rpcSubscriptions,
});
包括最近的区块哈希可以防止交易重复并为交易提供有效期——每个交易都必须包括一个有效的区块哈希才能被接受执行。对于此交易,我们将使用确认的承诺级别来获取最新的区块哈希。
然后,我们将使用 getTransferSolInstruction()
来创建由系统程序提供的预定义转账指令。这需要指定金额、源地址和目标地址。源地址必须始终是 Signer,而目标应为公钥。
send-transaction.ts
import {
// ...
lamports,
} from "@solana/web3.js";
import { getTransferSolInstruction } from "@solana-program/system";
/**
* 步骤 1:创建转账交易
*/
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const instruction = getTransferSolInstruction({
amount: lamports(1n),
destination: destinationAddress,
source: sourceKeypair,
});
然后我们将创建交易消息。所有交易消息现在都能够感知版本,消除了处理不同类型(如 Transaction
与 VersionedTransaction
)的需要。
我们将设置源地址作为手续费支付者,包含区块哈希,并添加转移 lamports 的指令。
send-transaction.ts
import {
// ...
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
} from "@solana/web3.js";
// ...
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(message) => setTransactionMessageFeePayer(sourceKeypair.address, message),
(message) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, message),
(message) => appendTransactionMessageInstruction(instruction, message),
);
console.log("交易消息已创建");
pipe 函数,常用于函数式编程,创建一个函数序列,其中一个的输出成为下一个的输入。这里,它逐步构建交易消息,应用设置费用支付者、有效期和添加指令等变换。
createTransactionMessage({ version: 0 })
从基本的交易消息开始。
message
=> setTransactionMessageFeePayer(fromKeypair.address, message)
添加费用支付者地址。
message => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, message)
确保交易在一段时间内是有效的,使用最新的区块哈希。
message => appendTransactionMessageInstruction(instruction, message)
将动作(如转移 lamports)附加到消息。
每个箭头函数 message => (...)
修改并将更新后的消息传递给下一步,从而生成一个完全构造的新交易消息。
我们将使用指定的签名者签署交易,即源 Keypair
。
send-transaction.ts
import {
// ...
signTransactionMessageWithSigners,
} from "@solana/web3.js";
// ...
/**
* 步骤 2:签署交易
*/
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
console.log("交易已签署");
在这一步,我们可以继续发送和确认交易。然而,我们应该通过设置优先费用和调整计算单位来优化交易。这些优化有助于提高交易成功率并减少确认时间,尤其是在网络拥塞期间。
为了设置优先费用,我们将使用 Helius的优先费用 API。这要求将交易序列化为 Base64 格式。虽然该 API 也支持 Base58 编码,但当前 SDK 直接提供 Base64 格式的交易,简化了这一过程。
send-transaction.ts
import {
// ...
getBase64EncodedWireTransaction,
} from "@solana/web3.js";
/**
* 步骤 3:从签署的交易中获取优先费用
*/
const base64EncodedWireTransaction = getBase64EncodedWireTransaction(signedTransaction);
const response = await fetch(rpc_url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "helius-example",
method: "getPriorityFeeEstimate",
params: [\
{\
transaction: base64EncodedWireTransaction,\
options: {\
transactionEncoding: "base64",\
priorityLevel: "High",\
},\
},\
],
}),
});
const { result } = await response.json();
const priorityFee = result.priorityFeeEstimate;
console.log("将优先费用设置为 ", priorityFee);
将 priorityLevel
设置为 High
通常是足够的。然而,实现 高级优先费用策略 可以显著提高在网络拥塞期间的交易成功率。
接下来,我们将评估该交易消息实际消耗的计算单位。
然后,我们通过将此值乘以 1.1 来添加10%的缓冲。此缓冲意味着用于优先费用和其他计算单位指令的计算单位,这些指令将在以后的操作中加入。
某些指令,如转移 lamports,可能具有较低的计算单位估算。为了确保资源充足,我们添加了一项保护措施,如果估算低于此阈值,则将计算单位设置为最低 1000。
send-transaction.ts
import {
// ...
getComputeUnitEstimateForTransactionMessageFactory,
} from "@solana/web3.js";
/**
* 步骤 4:优化计算单位
*/
const getComputeUnitEstimateForTransactionMessage = getComputeUnitEstimateForTransactionMessageFactory({
rpc,
});
// 请求该消息实际消耗的计算单位的估计。
let computeUnitsEstimate = await getComputeUnitEstimateForTransactionMessage(transactionMessage);
computeUnitsEstimate = computeUnitsEstimate < 1000 ? 1000 : Math.ceil(computeUnitsEstimate * 1.1);
console.log("将计算单位设置为 ", computeUnitsEstimate);
我们现在获得了此次交易所需的优先费用和计算单位。由于交易已经签署,我们不能直接添加新指令。因此,我们将使用新的区块哈希重建整个交易消息。
区块哈希的有效期大约为 1-2 分钟,获取优先费用和计算单位需要一些时间。为了避免在发送交易时丢失区块哈希,重建交易时获取一个新的区块哈希会更安全。
在此重建的交易中,我们将包含两项附加指令:
最后,我们将签署这一更新的交易以准备提交:
send-transaction.ts
import {
// ...
appendTransactionMessageInstructions,
} from "@solana/web3.js";
import { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from "@solana-program/compute-budget";
/**
* 步骤 5:重建并签署最终交易
*/
const { value: finalLatestBlockhash } = await rpc.getLatestBlockhash().send();
const finalTransactionMessage = appendTransactionMessageInstructions(
[\
getSetComputeUnitPriceInstruction({ microLamports: priorityFee }),\
getSetComputeUnitLimitInstruction({ units: computeUnitsEstimate }),\
],
transactionMessage,
);
setTransactionMessageLifetimeUsingBlockhash(finalLatestBlockhash, finalTransactionMessage);
const finalSignedTransaction = await signTransactionMessageWithSigners(finalTransactionMessage);
console.log("重建交易并签署完成");
接下来,使用 sendAndConfirmTransaction
函数发送并确认签署的交易。
提交的承诺级别设置为已确认,这与之前获取的区块哈希一致,而 maxRetries
设置为 0
。skipPreflight
选项设置为 true
,跳过 预检 检查以加快执行速度;然而,这只能在你确信交易签名已验证且没有其他错误时使用。
在创建之前的 sendAndConfirmTransaction
时,提供了 RPC 和 RPC 订阅 URL。使用 RPC 订阅 URL 检查交易状态,消除了手动轮询的需要。
在错误处理部分,代码检查预检过程中发生的错误。由于我们将 skipPreflight
设置为 true
,因此该检查是多余的。然而,如果你没有将其设置为 true,这将很有用。
send-transaction.ts
import {
getSignatureFromTransaction,
isSolanaError,
SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE,
} from "@solana/web3.js";
import { getSystemErrorMessage, isSystemError } from "@solana-program/system";
/**
* 步骤 6:发送并确认最终交易
*/
console.log("发送并确认交易");
await sendAndConfirmTransaction(finalSignedTransaction, {
commitment: "confirmed",
maxRetries: 0n,
skipPreflight: true,
});
console.log("转账确认: ", getSignatureFromTransaction(finalSignedTransaction));
最后,我们可以运行代码:
npx esrun send-transaction.ts
Solana 的 Web3.js 2.0 SDK 的发布是一次变革性的更新,使开发者能够在 Solana 上创造出更快、更高效和可扩展的应用程序。通过采用现代 JavaScript 标准和引入本地加密 API、tree-shakin 和自动生成的 TypeScript 客户端等特性,SDK 显著提升了开发者体验和应用程序性能。
编程示例的完整代码可在 GitHub 上找到。
如果你读到这里,感谢你,匿名者!确保在下面输入你的电子邮件地址,你将永远不会错过有关 Solana 的新动态的更新。准备深入了解吗?探索 Helius 博客 上的最新文章,继续你的 Solana 之旅。
- 原文链接: helius.dev/blog/how-to-s...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!