本文详细介绍了如何在Solana区块链上创建和执行版本0(V0)交易,包括设置项目、导入依赖、创建钱包、设置API端点以及发送和确认交易的步骤。
在 2022 年 10 月 10 日(Epoch 358),Solana 通过一个称为“ 版本化交易”的概念,添加了对新交易版本类型的支持。在此更改之后,Solana 运行时现在支持两种类型的交易:“遗留”(旧交易)和“0”(包含 地址查找表 的交易)。版本化交易将允许你今天使用地址查找表,并在未来可能具备其他功能。
在本指南中,你将创建并执行版本 0 (V0) 交易。
如果你需要帮助确保你现有的客户端应用程序可以支持版本化交易,请查看我们的 指南:如何更新你的 Solana 客户端以处理版本化交易。
在终端中创建一个新的项目目录:
mkdir solana-versioned-tx
cd solana-versioned-tx
为你的应用创建一个文件,app.ts:
echo > app.ts
使用“yes”标志初始化你的项目,以使用新包的默认值:
yarn init --yes
#或
npm init --yes
创建一个启用了 .json 导入的 tsconfig.json:
tsc -init --resolveJsonModule true
我们需要添加 Solana Web3 库以用于本练习。在终端中输入:
yarn add @solana/web3.js@1
#或
npm install @solana/web3.js@1
让我们开始吧。
打开 app.ts,在第1行 粘贴以下导入,以获取 Solana Web3 库中的一些基本方法和类:
import { Connection, Keypair, LAMPORTS_PER_SOL, SystemProgram, TransactionInstruction, TransactionMessage, VersionedTransaction } from '@solana/web3.js';
简化调试的日志
你现在可以访问 RPC 端点的日志,帮助你更有效地排除问题。如果你在 RPC 调用中遇到问题,只需查看 QuickNode 仪表板上的日志以快速识别和解决问题。了解有关日志历史限制的更多信息,请访问 我们的定价页面。
我们需要完成的第一项任务是创建一个带有钱包的账户并为其提供资金。我们将使用下面的实用工具自动生成一个新钱包并空投 1 SOL 到其上。(如果你更喜欢手动方式,你也可以使用 Keypair.generate()
和 requestAirdrop()
函数来实现)。
🔑使用 Devnet SOL 生成新钱包
创建新钱包
一旦你成功生成了密钥对,你将注意到两个新常量:secret
和 SIGNER_WALLET
,这是一个 Keypair。secret
是一个 32 字节数组,用于生成公钥和私钥。SIGNER_WALLET
是一个 Keypair 实例,用于签署交易(我们已空投一些 devnet SOL 以支付 gas 费用)。如果你还没有将其添加到代码中,请确保将其放在其他常量下方。
在按导入内容粘贴新密钥后,添加:
const secret = [0,...,0]; // 👈 用你的密钥替换
const SIGNER_WALLET = Keypair.fromSecretKey(new Uint8Array(secret));
const DESTINATION_WALLET = Keypair.generate();
我们定义了两个钱包:SIGNER_WALLET
将向我们的 DESTINATION_WALLET
发送 SOL。我们还添加了一个常量 LOOKUP_TABLE_ADDRESS
,稍后我们将更新它以引用地址查找表的链上账户 ID。
要在 Solana 上进行构建,你需要一个 API 端点来连接网络。你可以使用公共节点或部署和管理自己的基础架构;但是,如果你想要 8 倍的响应速度,你可以将繁重的工作交给我们。
QuickNode 现在接受 Solana 付款 🚀
你现在可以 使用 USDC 在 Solana 上支付 QuickNode 计划。作为第一个接受 Solana 付款的多链供应商,我们为开发人员简化了过程——无论你是在创建新帐户还是管理现有帐户。在这里了解有关使用 Solana 付款的更多信息。
了解为什么超过 50% 的 Solana 项目选择 QuickNode,并在 这里 注册一个免费账户。我们将使用 Solana Devnet 节点。
复制 HTTP 供应商链接:
在 app.ts 的导入语句下,声明你的 RPC 并建立与 Solana 的 连接:
const QUICKNODE_RPC = 'https://example.solana-devnet.quiknode.pro/0123456/';
const SOLANA_CONNECTION = new Connection(QUICKNODE_RPC);
你的环境看起来应该是这样的:
好了,让我们构建吧!
版本 0 交易要求我们使用一个新类 VersionedTransaction,它需要我们传递一个 VersionedMessage 作为参数。VersionedMessage 接受一个 Message 或 MessageV0。虽然非常相似,但 MessageV0 允许使用地址查找表!
让我们开始创建一个新的转账 TransactionInstruction,将 0.1 SOL 从我们的 SIGNER_WALLET 发送到我们的 DESTINATION_WALLET。由于我们的交易消息需要一个 Transaction Instructions 的数组,请将指令包含在数组中:
const instructions: TransactionInstruction[] = [\
SystemProgram.transfer({\
fromPubkey: SIGNER_WALLET.publicKey,\
toPubkey: DESTINATION_WALLET.publicKey,\
lamports: 0.01 * LAMPORTS_PER_SOL,\
}),\
];
现在让我们构建一个新的函数 createAndSendV0Tx,接受我们的 TransactionInstruction 数组:
async function createAndSendV0Tx(txInstructions: TransactionInstruction[]) {
}
接下来,我们定义一个 confirmTransaction
函数,我们将其在我们的 createAndSendV0Tx 函数中调用。将以下代码添加到 app.ts 文件中:
async function confirmTransaction(
connection: Connection,
signature: TransactionSignature,
desiredConfirmationStatus: TransactionConfirmationStatus = 'confirmed',
timeout: number = 30000,
pollInterval: number = 1000,
searchTransactionHistory: boolean = false
): Promise<SignatureStatus> {
const start = Date.now();
while (Date.now() - start < timeout) {
const { value: statuses } = await connection.getSignatureStatuses([signature], { searchTransactionHistory });
if (!statuses || statuses.length === 0) {
throw new Error('无法获得签名状态');
}
const status = statuses[0];
if (status === null) {
// 如果状态为 null,交易尚未被认可
await new Promise(resolve => setTimeout(resolve, pollInterval));
continue;
}
if (status.err) {
throw new Error(`交易失败: ${JSON.stringify(status.err)}`);
}
if (status.confirmationStatus && status.confirmationStatus === desiredConfirmationStatus) {
return status;
}
if (status.confirmationStatus === 'finalized') {
return status;
}
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
throw new Error(`交易确认超时,超过 ${timeout}ms`);
}
这将不断轮询 Solana 网络,直到交易状态被确认或达到超时。我们添加了一些超时和轮询间隔的默认值,但你可以根据需要进行调整。
现在让我们组装我们的函数。将这 5 个步骤添加到你的 createAndSendV0Tx 函数的主体中。
步骤 1: 使用 getLatestBlockhash 从网络中获取最新的区块哈希:
// 步骤 1 - 获取最新区块哈希
let latestBlockhash = await SOLANA_CONNECTION.getLatestBlockhash('confirmed');
console.log(" ✅ - 获取最新区块哈希。最后有效高度:", latestBlockhash.lastValidBlockHeight);
注意:我们传递了参数 'confirmed',以使哈希不太可能属于已丢弃的分支。
步骤 2: 使用我们的 txInstructions 参数和 latestBlockhash,我们可以通过构造一个新的 Message 并执行 .compileToV0Message() 方法来创建一个新的 MessageV0:
// 步骤 2 - 生成交易消息
const messageV0 = new TransactionMessage({
payerKey: SIGNER_WALLET.publicKey,
recentBlockhash: latestBlockhash.blockhash,
instructions: txInstructions
}).compileToV0Message();
console.log(" ✅ - 编译交易消息");
const transaction = new VersionedTransaction(messageV0);
接着将我们的消息传递给 VersionedTransaction 的新实例。恭喜!你已创建了一个版本化交易!
步骤 3: 使用所需的 Signers
数组签署交易。在这种情况下,仅使用我们的 SIGNER_WALLET。
// 步骤 3 - 用所需的 `Signers` 签署你的交易
transaction.sign([SIGNER_WALLET]);
console.log(" ✅ - 交易已签署");
注意:在将版本化交易发送到集群之前,必须先签署它。来源: edge.docs.solana.com 。
步骤 4: 使用 sendTransaction 将交易发送到集群,这将返回一个交易签名/ID:
// 步骤 4 - 将我们的 v0 交易发送到集群
const txid = await SOLANA_CONNECTION.sendTransaction(transaction, { maxRetries: 5 });
console.log(" ✅ - 交易已发送到网络");
注意:我们传递了参数 'maxRetries',以允许 RPC 在必要时重试将交易发送给领导者。
步骤 5: 最后,等待集群确认交易已成功:
// 步骤 5 - 确认交易
const confirmation = await confirmTransaction(SOLANA_CONNECTION, txid);
if (confirmation.err) { throw new Error(" ❌ - 交易未确认.") }
console.log('🎉 交易成功确认!', '\n', `https://explorer.solana.com/tx/${txid}?cluster=devnet`);
如果成功,我们记录成功交易的查询 URL。
好的!我们准备好尝试了!
要执行我们的函数,在文件底部调用 createAndSendV0Tx,并将 instructions 作为参数传递:
createAndSendV0Tx(instructions);
我们的最终代码可在 GitHub 上找到,在这里。
然后,在终端中调用:
ts-node app.ts
你是否看到类似的内容?
干得好!如果你想将你的代码与我们的代码进行对比,我们已在 GitHub, 这里 提供。
现在你可以构建并执行版本化交易,接下来是看看 V0 交易能做些什么。请查看我们的指南:如何在 Solana 上使用查找表(即将推出),以了解 Solana 新的查找表功能及其使用方法。
如果你遇到问题,或者有疑问,或者只是想讨论一下,欢迎通过 Discord 或 Twitter 联系我们!
- 原文链接: quicknode.com/guides/sol...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!