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

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

概述

Solana 最近宣布 了 Solana Web3.js 2.0 的发布候选版本,这是他们与 Solana 区块链交互的 JavaScript 库的重要更新。本指南将教你使用这个新库发送交易的基础知识。

让我们开始吧!

你将要做的事情

编写一个脚本,以使用 Solana Web3.js 2.0 库执行基本的 Solana 交易:

  • 使用本地 RPC 方法和工厂函数进行 SOL 空投
  • 使用新 API 创建并发送转账交易

你将需要的内容

本指南中使用的依赖项

依赖项 版本
@solana/web3.js >=2.0
@solana-program/system ^0.5.0
solana cli 1.18.8

让我们开始吧!

什么是 Solana Web3.js 2.0?

Solana Web3.js 2.0 是与 Solana 区块链交互的 JavaScript 库的重要更新。它引入了一种新的 API 设计,专注于可组合性、模块化和改进的开发者体验。一些关键特性包括:

  1. 函数式 API:新的 API 使用函数式编程风格,使组合复杂操作变得更加容易。
  2. 改进的 TypeScript 支持:更好的类型推断和更严格的类型以增强代码安全性。
  3. 模块化设计:功能被分成更小、更专注的模块,允许树摇和更小的捆绑大小。
  4. 加强的错误处理:更具信息性的错误消息和改进的错误类型。

有关 API 更改的更多信息,请查看我们的( 博客:Solana Web3.js 2.0 中的新特性 )。

让我们通过创建一个脚本来执行基本转账交易来探索这些功能。

创建一个新项目

首先,让我们设置项目:

mkdir solana-transfer-demo && cd solana-transfer-demo

接下来,将你的项目初始化为 Node.js 项目:

npm init -y

安装依赖项:

npm install @solana/web3.js@2 @solana-program/system && npm install --save-dev @types/node

注意:如果你使用的 Node.js 版本低于 18,你可能需要使用 --legacy-peer-deps 标志安装 @solana-program/system 包。

向项目中添加一个 tsconfig.json 文件,并启用 resolveJsonModule

tsc --init --resolveJsonModule true

在你的项目目录中创建一个名为 transfer.ts 的新文件。

echo > transfer.ts

太好了。让我们写一些代码!

导入依赖

在你的 transfer.ts 文件中,首先导入所需的依赖:

import {
    airdropFactory,
    createKeyPairSignerFromBytes,
    createSolanaRpc,
    createSolanaRpcSubscriptions,
    generateKeyPairSigner,
    lamports,
    sendAndConfirmTransactionFactory,
    pipe,
    createTransactionMessage,
    setTransactionMessageFeePayer,
    setTransactionMessageLifetimeUsingBlockhash,
    appendTransactionMessageInstruction,
    signTransactionMessageWithSigners,
    getSignatureFromTransaction,
    address,
} from "@solana/web3.js";
import { getTransferSolInstruction } from "@solana-program/system";

const LAMPORTS_PER_SOL = BigInt(1_000_000_000);

在这里,我们正在从新的 Solana Web3.js 2.0 库中导入各种函数。请注意导入的函数式风格 - 每个函数负责特定的任务,促使模块化和可组合性。LAMPORTS_PER_SOL 常量不再通过 SDK 提供,因此我们必须自己定义它。与以前的 SDK 不同,新的 SDK 对所有金额使用 bigint(以更好地与 Rust 编程兼容,Rust 支持 u64,这是 Solana 程序中的常见类型)。

创建主函数

接下来,让我们创建我们的 main 函数,它将容纳脚本的逻辑:

async function main() {
    // 1 - 建立与 Solana 集群的连接

    // 2 - 生成签名者

    // 3 - 为账户空投 SOL

    // 4 - 创建转账交易

    // 5 - 签名并发送交易
}

main();

建立与 Solana 集群的连接

main 函数内,让我们建立与本地 Solana 集群的连接:

    // 1 - 建立与 Solana 集群的连接
    const httpProvider = 'http://127.0.0.1:8899';
    const wssProvider = 'ws://127.0.0.1:8900';
    const rpc = createSolanaRpc(httpProvider);
    const rpcSubscriptions = createSolanaRpcSubscriptions(wssProvider);
    console.log(`✅ - 已建立与 ${httpProvider} 的连接`);

在这里,我们使用 createSolanaRpccreateSolanaRpcSubscriptions 函数来创建我们的 RPC 连接。如果你熟悉旧 SDK,你可能会注意到新的 SDK 使用不同的方法来建立连接。我们将在本指南中使用本地主机,但如果你准备好连接到远程 Solana 集群,你可以使用你的 QuickNode HTTP Provider 和 WSS Provider 端点,从你的 QuickNode Dashboard

QuickNode 端点

如果你还没有 QuickNode 账户,你可以 在这里 免费创建一个。

生成签名者

现在,让我们为我们的交易生成两个签名者:

    // 2 - 生成签名者
    const user1 = await generateKeyPairSigner();
    console.log(`✅ - 新的 user1 地址已创建:${user1.address}`);
    const user2 = await createKeyPairSignerFromBytes(new Uint8Array([/* 在这里填写你的私钥字节 */]));
    console.log(`✅ - 从文件生成 user2 地址:${user2.address}`);

出于学习目的,我们将采用两种方式生成密钥对。首先,使用 generateKeyPairSigner 为 user1 创建新的密钥对,然后使用 createKeyPairSignerFromBytes 从现有后秘钥创建 user2 的密钥对。如果你还没有私钥,可以使用 Solana CLI 生成一个:

solana-keygen new --no-bip39-passphrase --outfile ./my-keypair.json

如果你更喜欢从文件加载秘密,可以使用 import 语句(因为我们在 tsconfig.json 文件中使用了 --resolveJsonModule 标志):

// 添加到你的导入中
import secret from './my-keypair.json';

    // 用以下内容替换 `user2` 行:
    const user2 = await createKeyPairSignerFromBytes(new Uint8Array(secret));

为账户空投 SOL

在我们可以转账 SOL 之前,我们需要为我们的账户提供资金。同样,为了演示目的,我们将使用两种不同的方法(一种使用本地的 requestAirdrop 方法,另一种使用 airdropFactory 函数)。将以下代码添加到 main 函数:


```js
    // 3 - 向账户空投 SOL
    // 使用 RPC 方法
    const tx1 = await rpc.requestAirdrop(
        user1.address,
        lamports(LAMPORTS_PER_SOL),
        { commitment: 'processed' }
    ).send();
    console.log(`✅ - user1 使用 RPC 方法空投 1 SOL`);
    console.log(`✅ - tx1: ${tx1}`);

    // 使用工厂函数
    const airdrop = airdropFactory({ rpc, rpcSubscriptions });
    const tx2 = await airdrop({
        commitment: 'processed',
        lamports: lamports(LAMPORTS_PER_SOL),
        recipientAddress: user2.address
    });
    console.log(`✅ - user2 使用工厂函数空投 1 SOL`);
    console.log(`✅ - tx2: ${tx2}`);

这两种方法同样可行,因此你可以选择最适合你用例的方法。无论采用哪种方法,你都需要传递目标地址、要空投的 SOL 数量(请注意,新 SDK 要求我们使用 lamports 函数,这实际上扩展了 bigint 类型)和承诺级别。在这种情况下,我们使用 lamports 函数将 SOL 转换为 lamports,后者是 Solana 使用的计量单位。

创建并发送转账交易

现在,让我们创建并发送我们的转账交易。此过程展示了新 Solana Web3.js 2.0 SDK 的几个基本特性:

    // 4 - 创建转账交易
    const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

    const transactionMessage = pipe(
        createTransactionMessage({ version: 0 }),
        tx => setTransactionMessageFeePayer(user1.address, tx),
        tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
        tx => appendTransactionMessageInstruction(
            getTransferSolInstruction({
                amount: lamports(LAMPORTS_PER_SOL / BigInt(2)),
                destination: user2.address,
                source: user1,
            }),
            tx
        )
    );

让我们逐步分析:

  1. RPC 调用和 .send() 方法: 新 SDK 引入了一种一致的模式来使用 .send() 方法进行 RPC 调用。这在 getLatestBlockhash() 调用中非常明显:
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

这种模式将 RPC 请求的构建与其执行分开,使得在发起请求时更加灵活和可组合。

  1. 使用管道进行交易构建: pipe 函数是新 SDK 中一个关键特性,借鉴了函数式编程的概念。如果你不熟悉管道,它们允许你将多个操作链接在一起,将每次操作的结果作为输入传递给下一个操作。
const transactionMessage = pipe(
       createTransactionMessage({ version: 0 }),
       tx => setTransactionMessageFeePayer(user1.address, tx),
       // ... 更多操作
);

管道中的每个函数将前一个函数的结果作为其输入,逐步修改交易消息。这种方法使得交易构建过程更加清晰且易于维护,尤其是对于复杂的交易。

  1. 来自单独库的程序指令: getTransferSolInstruction 函数从 @solana-program/system 库导入:
import { getTransferSolInstruction } from "@solana-program/system";

将程序特定指令分隔到自己的库中是 Web3.js 2.0 中的一种新模式。这有助于更好的代码组织和对不同 Solana 程序的管理。你可以期待看到更多程序特定库遵循这一模式,从而使与各种 Solana 程序的交互更加简单。

  1. 细化的交易构建: 注意交易是如何逐步组装的:

    • createTransactionMessage({ version: 0 }): 初始化新的交易消息。
    • setTransactionMessageFeePayer: 设置交易的手续费支付者。
    • setTransactionMessageLifetimeUsingBlockhash: 使用最近的区块哈希设置交易的生命周期。
    • appendTransactionMessageInstruction: 将转账指令添加到交易中。

这种细化的方法使开发人员可以更好地控制交易的每个方面,并使得构建带有多条指令的复杂交易变得更加容易。

  1. 类型安全和不可变性: 通过为交易构建的每个步骤使用单独的函数,结合 TypeScript,提高了类型安全性,确保尽早捕获错误。每个函数返回一个新的交易对象,而不是修改现有对象,促进不可变性并减少意外副作用的可能性。

利用这些特性,新 Solana Web3.js 2.0 SDK 旨在提供一种更强大、灵活和开发者友好的与 Solana 区块链交互的方式。当你继续使用 SDK 时,你会发现这些模式使编写清晰、可维护和抗错误的 Solana 应用程序代码变得更加容易。

签名并发送交易

    // 5 - 签名并发送交易
    const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
    const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });

    try {
        await sendAndConfirmTransaction(
            signedTransaction,
            { commitment: 'confirmed', skipPreflight: true }
        );
        const signature = getSignatureFromTransaction(signedTransaction);
        console.log('✅ - 转账交易:', signature);
    } catch (e) {
        console.error('转账失败:', e);
    }

本节展示了 Web3.js 2.0 的几个关键特性:

  1. 我们使用 signTransactionMessageWithSigners 使用可能存储在指令账户的账户元数据中的任何签名者来签名我们的交易。如果你回顾我们的 getTransferSolInstruction 函数,你会看到在 source 参数中,我们传入 user1 密钥对(源账户的签名者)。然后,signTransactionMessageWithSigners 将使用该签名者对交易进行签名。
  2. 我们使用 sendAndConfirmTransactionFactory 函数创建一个 sendAndConfirmTransaction 函数。
  3. 最后,我们使用 sendAndConfirmTransaction 函数发送已签名的交易,并返回交易签名,该签名是通过 getSignatureFromTransaction 函数获得的。

设置本地环境

对于本指南,我们将使用一个本地 Solana 验证器。打开一个新的终端窗口并启动验证器:

solana-test-validator -r

运行脚本

要运行我们的脚本,请使用以下命令:

ts-node transfer.ts

你应该会看到指示成功连接、空投和转账交易的输出:

transfer.ts 的输出

做得好!

添加更多指令

如果你愿意,可以随意将附加指令附加到转账交易。例如,你可以在你的 pipe 中添加以下指令,以向另一个账户转账 SOL:

        tx => appendTransactionMessageInstruction(
            getTransferSolInstruction({
                amount: lamports(LAMPORTS_PER_SOL / BigInt(3)),
                destination: address('SOME_OTHER_ADDRESS'),
                source: user1,
            }),
            tx
        )

练习是提升技能的最佳方式,因此请随意尝试不同的指令和交易。 如果你想查看本指南的源代码,可以在这里找到它。 祝编码愉快!

总结

本指南通过创建一个脚本以执行基本转账交易,探索了新的 Solana Web3.js 2.0 库。通过其函数式编程风格和工厂函数的使用,新的 API 促进了模块化、可组合性和提高的开发者体验。

一些关键要点:

  1. 新的 API 允许对交易创建和签名进行更细粒度的控制。
  2. 工厂函数提供了一种创建可重用和可定制函数的方法。
  3. pipe 函数允许操作的清晰和可读的组合。

随着你继续探索 Web3.js 2.0,你将发现更多强大的功能和改进。祝编码愉快!

资源

我是 AI 翻译官,为大家转译优秀英文文章,如有翻译不通的地方,在这里修改,还请包涵~

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。