如何开始使用 Solana Web3.js 2.0 SDK 进行构建

  • Helius
  • 发布于 2024-12-01 16:16
  • 阅读 125

本文介绍了Solana Web3.js SDK 2.0的重大更新,包括性能改进、应用程序包体积减小和增强的灵活性,提供了代码示例和迁移指南,并强调了新SDK对开发者的帮助。文章最后介绍了最佳实践和如何发送交易的具体步骤,适合有一定技术基础的开发者阅读。

在深入之前,我们要感谢 EvanNick 对这篇文章的审阅。他们的宝贵反馈和见解非常感谢。

引言

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 中的新内容有什么?

让我们快速了解一下新的 Web3.js 2.0 SDK 提供了什么:

1. 性能改进

更快的加密操作:密钥对生成、交易签名和消息验证的速度提高了 10倍,利用了现代 JavaScript 环境(如 Node.js 和当前浏览器)中的本地加密 API。

2. 更小且高效的应用

Web3.js 2.0 完全支持 tree-shaking,允许你仅包含你使用的库的部分,从而将包大小降到最小。此外,新 SDK 没有外部依赖项,确保构建的轻量和安全。

3. 增强灵活性

开发者现在可以通过以下方式创建自定义解决方案:

  • 使用自定义方法定义 RPC 实例
  • 使用专门的网络传输或交易签名器
  • 为网络、交易确认和编解码器组合自定义原语

‍新的 TypeScript 客户端现在托管在 @solana-program GitHub 组织下。这些客户端是通过 Codama 自动生成的,使开发者能够快速为自定义程序生成客户端。

你应该立即迁移到 Web3.js v2 吗?

截至 2025 年 2 月:

  • 如果你正在用 JS/TS 制作新的 Solana 应用,并使用像系统程序、代币程序、关联代币程序等现有程序,你现在可以使用 web3.js v2。
  • 如果你使用 Anchor 创建自定义链上应用,你可能希望等待——Anchor 并不支持 web3.js v2。你可能希望等待未来的 Anchor 更新。或者,使用 Codama 为你的链上应用创建 TypeScript 客户端,尽管这工作量稍大。

从 web3.js 版本 1 迁移

‍如果你使用过 web3.js v1,这里是重要差异的快速总结:

密钥对

在任何需要使用 Keypair 的地方,现在使用 KeyPairSignerKeypair.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 函数将字符串公钥转换为地址。

SOL 和代币数量

数量使用原生的 JS BigInt 类型。因此,你需要在数字的末尾添加 n,使 1 变为 1n

工厂方法

许多特性是可配置的,因此不会有预设的实现(例如 doThing()),而是有一个工厂(称为 doThingFactory()),你可以用它创建自己的 doThing() 函数。例如:

  • 要发送和确认交易,你运行一次带有你首选选项的 sendAndConfirmTransactionFactory(),并返回一个自定义的 sendAndConfirmTransaction() 函数。然后,你可以在需要发送和确认交易时使用你的 sendAndConfirmTransaction()
  • 若要在 devnet 或 localnet 上获得空投,你运行一次 airdropFactory(),然后得到一个自定义的 airdrop() 函数,以便在你想要空投时使用。

如何使用 Web3.js 2.0 发送交易

Kite 框架

Helius 最近发布了 Kite,这是一个用于 web3.js v2 的 TypeScript 框架,其中包含大多数常见 Solana 任务的一次性函数。

我们将使用 Web3.js 2.0 构建一个客户端程序,以便将 lamports 转移到另一个钱包。该程序将展示提高交易成功率和更快确认时间的技术。

我们将遵循以下最佳实践来发送交易:

  1. 使用确认的承诺级别获取最新的区块哈希
  2. 设置 Helius 的 优先费用 API 推荐的优先费用
  3. 优化计算单位
  4. 将交易发送设置为 maxRetries0,并将 skipPreflight 设置为 true

这种方法确保了即使在 网络拥塞 的情况下,仍然可以获得最佳的性能和可靠性。

先决条件

  • 安装 Node.js
  • 一个兼容的 IDE(例如 VS Code 或 Cursor)

安装

首先创建一个基本的 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 连接

接下来,我们可以设置相关的 RPC 连接。createSolanaRpc 函数使用默认的 HTTP 传输与 RPC 服务器建立通信,适用于大多数用例。

同样,我们使用 createSolanaRpcSubscriptions 来建立 WebSocket 连接。rpc_urlwss_urlHelius 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,
});

创建交易消息

然后我们将创建交易消息。所有交易消息现在都能够感知版本,消除了处理不同类型(如 TransactionVersionedTransaction)的需要。

我们将设置源地址作为手续费支付者,包含区块哈希,并添加转移 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 分钟,获取优先费用和计算单位需要一些时间。为了避免在发送交易时丢失区块哈希,重建交易时获取一个新的区块哈希会更安全。

在此重建的交易中,我们将包含两项附加指令:

  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 设置为 0skipPreflight 选项设置为 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 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Helius
Helius
https://www.helius.dev/