介绍Solana[Web3.jsSDK]是一个功能强大的JavaScript库,可用于在Node.js、Web和ReactNative平台上构建Solana应用程序。2024年11月7日,AnzaLabs推出了备受期待的Web3.js2.0SDK,引入了
<!--StartFragment-->
Solana [Web3.js SDK]是一个功能强大的 JavaScript 库,可用于在 Node.js、Web 和 React Native 平台上构建 Solana 应用程序。2024 年 11 月 7 日,Anza Labs 推出了备受期待的 Web3.js 2.0 SDK,引入了一系列现代 JavaScript 功能和改进。主要亮点包括可摇树和减小的包大小,这对开发人员来说是一项重大升级。
如果您编写了自动安装@solana/web3.js的开发人员内容或 shell 脚本,则需要在两个选项之间做出选择:将您的软件移植到新的 v2.0 API 或通过[明确指定版本]将其锁定到v1.x。
在本文中,我们将探讨 Web3.js 2.0 SDK 中的最新更新,指导您完成迁移过程,并提供示例来帮助您入门。
在深入研究之前,我们假设您对 Solana 的基本概念(例如发送交易、[账户模型]、区块哈希和[优先级费用])有扎实的理解,并且具有 JavaScript 经验。虽然建议熟悉 Web3.js SDK 的先前版本,但这不是强制性的。让我们开始吧 <!--EndFragment--> <!--StartFragment-->
我们将快速探索新的 Web3.js 2.0 SDK 提供的功能:
更快的加密操作:利用 Node.js 和 Safari 17 等现代 JavaScript 环境中的原生 Ed25519 加密 API, 密钥对生成、交易签名和消息验证速度提高10 倍
Web3.js 2.0 完全可进行 tree-shak 优化,允许您仅包含您使用的库部分,从而最大限度地减少包大小。此外,新 SDK 没有任何外部依赖项,可确保轻量级且安全的构建。
开发人员现在可以通过以下方式创建自定义解决方案:
链上程序的新 TypeScript 客户端现在托管在[@solana-program GitHub 组织]中。这些客户端使用 Codama IDL 自动生成,使开发人员能够快速生成自定义程序的客户端。
我们将使用 Web3.js 2.0 构建一个程序,将 lamport 转移到另一个钱包。该程序将展示提高交易成功率和缩短确认时间的技术。
我们将遵循以下发送交易的最佳做法:
即使在网络拥塞期间,这种方法也能确保最佳性能和可靠性。
首先创建一个基本的 Node.js 项目来构建您的应用程序。运行以下命令创建一个package.json文件来管理您的依赖项和项目元数据: <!--EndFragment-->
npm init -y
<!--StartFragment-->
创建一个src目录,并在其中添加一个index.js文件,其中包含主代码:
<!--EndFragment-->
mkdir src
touch src/index.js
<!--StartFragment-->
接下来,使用npm安装使用 Solana 的 Web3.js 2.0 SDK 所需的依赖项:
@solana/web3.js@2 && npm install @solana-program/system && npm install @solana-program/compute-budget
<!--StartFragment-->
<!--EndFragment--> <!--StartFragment-->
在index.js中,我们定义传输 lampor 的源地址和目标地址。我们将使用address()函数从提供的字符串生成目标公钥。对于源,我们将使用它的secretKey派生**KeyPair**。 <!--EndFragment-->
import { address, createKeyPairSignerFromBytes, getBase58Encoder } from '@solana/web3.js';
async function main() {
const destinationAddress = address('public-key-to-send-lamports-to');
const secretKey = "add-your-private-key";
const sourceKeypair = await createKeyPairSignerFromBytes(
getBase58Encoder().encode(secretKey)
);
}
main();
<!--StartFragment-->
接下来,我们可以设置相关的 RPC 连接。createSolanaRpc函数使用默认 HTTP 传输与 RPC 服务器建立通信,这对于大多数用例来说已经足够了。同样,我们使用createSolanaRpcSubscriptions建立 WebSocket 连接。您可以在[Helius Dashboard中找到]rpc_url和wss_url —只需注册或登录并导航到 Endpoints 部分即可。
sendAndConfirmTransactionFactory函数构建可重复使用的交易发送方。此发送方需要 RPC 连接来发送交易,还需要 RPC 订阅来监控交易状态。
<!--EndFragment-->
import {
// ...
createSolanaRpcSubscriptions,
createSolanaRpc,
sendAndConfirmTransactionFactory
} from '@solana/web3.js';
async function main() {
// ...
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
});
}
<!--StartFragment-->
区块哈希可防止重复,并为交易提供生命周期——每笔交易都必须包含有效的区块哈希才能被接受执行。对于此交易,我们将使用已确认的承诺级别获取最新的区块哈希。
接下来,我们将使用getTransferSolInstruction函数创建系统程序提供的预定义转账指令。这需要指定金额、来源和目的地。来源必须始终是 Signer ,而目的地应该是公共地址。
<!--EndFragment-->
import {
// ...
lamports,
} from '@solana/web3.js';
import { getTransferSolInstruction } from '@solana-program/system';
async function main() {
// ...
/**
* STEP 1: CREATE THE TRANSFER TRANSACTION
*/
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const instruction = getTransferSolInstruction({
amount: lamports(1),
destination: toPubkey,
source: fromKeypair,
});
}
<!--StartFragment-->
然后我们将创建交易消息。现在所有交易消息都具有版本感知能力,无需处理不同类型(例如Transaction与VersionedTransaction)。
我们将把来源设置为费用支付者,包括区块哈希,并添加转移 lamport 的指令。
<!--EndFragment-->
import {
// ...
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
} from '@solana/web3.js';
async function main() {
// ...
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
tx => (
setTransactionMessageFeePayer(fromKeypair.address, tx)
),
tx => (
setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx)
),
tx =>
appendTransactionMessageInstruction(
instruction,
tx,
),
);
console.log("Transaction message created");
}
<!--StartFragment-->
pipe函数常用于函数式编程,它创建一系列函数,其中一个函数的输出将成为下一个函数的输入。在这里,它逐步构建交易消息,应用设置费用支付者和有效期等转换并添加指令。
初始化交易消息:\
createTransactionMessage({ version: 0 })
从基本交易消息开始。\
\
设置费用支付人:\
tx => setTransactionMessageFeePayer(fromKeypair.address, tx)
添加费用支付人的地址。\
\
使用区块哈希设置生命周期:\
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx)
使用最新的区块哈希确保交易在一定时间范围内有效。\
\
添加转移指令:\
tx => appendTransactionMessageInstruction(instruction, tx)
将操作(例如,转移灯塔)附加到消息中。
每个箭头函数tx => (...)修改并将更新的消息传递到下一步,生成一个完全构建的新交易消息。
<!--EndFragment--> <!--StartFragment-->
我们将使用指定的签名者,即源密钥对,对交易进行签名。
<!--EndFragment-->
import {
// ...
signTransactionMessageWithSigners
} from '@solana/web3.js';
async function sendTransaction() {
// ...
/**
* STEP 2: SIGN THE TRANSACTION
*/
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
console.log("Transaction signed");
}
<!--StartFragment-->
在此步骤中,我们可以继续发送和确认交易。但是,我们应该通过设置优先级费用和调整计算单位来优化交易。这些优化有助于提高交易成功率并减少确认时间,尤其是在网络拥堵期间。
要设置优先费用,我们将使用[Helius 的优先费用 API 。这需要]Base64格式的序列化交易。虽然 API 也支持Base58编码,但当前 SDK 直接提供**Base64**格式的交易,从而简化了流程。
<!--EndFragment-->
import {
// ...
getBase64EncodedWireTransaction
} from '@solana/web3.js';
async function sendTransaction() {
// ...
/**
* STEP 3: GET PRIORITY FEE FROM SIGNED TRANSACTION
*/
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",
recommended: true,
}
}]
}),
});
const { result } = await response.json();
const priorityFee = result.priorityFeeEstimate;
console.log("Setting priority fee to ", priorityFee);
}
<!--StartFragment-->
通常情况下,设置建议的优先费用就足够了。但是,实施[高级优先费用策略]可以显著提高网络拥堵期间的交易成功率。
接下来,我们将估算交易消息实际消耗的计算单元。然后,我们将该值乘以 1.1,添加 10% 的缓冲区。此缓冲区占优先费用和额外计算单元指令使用的计算单元,我们将在稍后纳入这些计算单元。
某些指令(例如传输 Lamport)的计算单元估计值可能较低。为了确保有足够的资源,我们添加了一项保护措施,如果估计值低于此阈值,则将计算单元设置为最低 1000 个。
<!--EndFragment-->
import {
// ...
getComputeUnitEstimateForTransactionMessageFactory
} from '@solana/web3.js';
async function sendTransaction() {
// ...
/**
* STEP 4: OPTIMIZE COMPUTE UNITS
*/
const getComputeUnitEstimateForTransactionMessage = getComputeUnitEstimateForTransactionMessageFactory({
rpc
});
// Request an estimate of the actual compute units this message will consume.
let computeUnitsEstimate = await getComputeUnitEstimateForTransactionMessage(transactionMessage);
computeUnitsEstimate = (computeUnitsEstimate < 1000) ? 1000 : Math.ceil(computeUnitsEstimate * 1.1);
console.log("Setting compute units to ", computeUnitsEstimate);
}
<!--StartFragment-->
我们现在有了这笔交易所需的优先费用和计算单元。由于交易已经签名,我们无法直接添加新指令。相反,我们将使用新的区块哈希重建整个交易消息。
区块哈希的有效期只有 1-2 分钟左右,获取优先费用和计算单位需要一些时间。为了避免在发送交易时区块哈希过期的风险,在重建交易时获取新的区块哈希更为安全。
在此重建的交易中,我们将包括两个附加指令:
最后,我们将签署此更新的交易以准备提交:
<!--EndFragment-->
import {
// ...
appendTransactionMessageInstructions,
} from '@solana/web3.js';
import { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from '@solana-program/compute-budget';
async function sendTransaction() {
// ...
/**
* STEP 5: REBUILD AND SIGN FINAL TRANSACTION
*/
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("Rebuilt the transaction and signed it");
}
<!--StartFragment-->
接下来,使用sendAndConfirmTransaction函数发送并确认已签名的交易。承诺级别设置为confirmed,与之前获取的区块哈希一致,而maxRetries设置为0。skipPreflight选项设置为true,绕过[预检检查]以加快执行速度;但是,仅当您确信您的交易签名已得到验证并且没有其他错误时才应使用此选项。
sendAndConfirmTransaction之前是通过提供 RPC 和RPC订阅 URL 创建的。使用 RPC 订阅 URL 检查交易状态,无需手动轮询。
在错误处理部分,代码会检查预检期间发生的错误。由于我们将skipPreflight设置为 true,因此此检查是多余的。但是,如果您不将其设置为 true,它将很有帮助。
<!--EndFragment-->
import {
getSignatureFromTransaction,
isSolanaError,
SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE
} from '@solana/web3.js';
import { getSystemErrorMessage, isSystemError } from '@solana-program/system';
async function sendTransaction() {
// ...
/**
* STEP 6: SEND AND CONFIRM THE FINAL TRANSACTION
*/
try {
console.log("Sending and confirming transaction");
await sendAndConfirmTransaction(finalSignedTransaction, { commitment: 'confirmed', maxRetries: 0, skipPreflight: true});
console.log('Transfer confirmed: ', getSignatureFromTransaction(finalSignedTransaction));
} catch (e) {
if (isSolanaError(e, SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE)) {
const preflightErrorContext = e.context;
const preflightErrorMessage = e.message;
const errorDetailMessage = isSystemError(e.cause, finalTransactionMessage) ?
getSystemErrorMessage(e.cause.context.code) : e.cause ? e.cause.message : '';
console.error(preflightErrorContext, '%s: %s', preflightErrorMessage, errorDetailMessage);
} else {
throw e;
}
}
}
<!--StartFragment-->
最后我们可以运行代码:
<!--EndFragment-->
<!--StartFragment-->
Solana 的 Web3.js 2.0 SDK 的发布是一项变革性更新,它使开发人员能够在 Solana 上创建更快、更高效、可扩展的应用程序。通过采用现代 JavaScript 标准并引入本机加密 API、tree-shakability 和自动生成的 TypeScript 客户端等功能,SDK 显著增强了开发人员体验和应用程序性能。
<!--EndFragment--> 作者:https://t.me/+P3Z7P_xQxbNlZWZl 来源:https://www.fabipingtai.com
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!