Skip to content

版本化交易

作者 崔棉大师 X:@MasterCui Youtube: 崔棉大师

知识点

本章节通过 js 脚本构建版本化交易,在这个过程中,你将学到通过创建指令IX,Solana 上交易内的步骤称为指令, 将指令打包成为交易,最终签署交易的整个过程

课程

0.计算账户费用

在 Solana 上保持账户活跃会产生一项存储费用,称为 租金/rent。通过存入至少两年租金的金额,你可以使账户完全免除租金收取。对于费用的计算,你需要考虑你打算在账户中存储的数据量。

完整代码

js
const lamports = await connection.getMinimumBalanceForRentExemption(space);

通过命令行快速计算

sh
$solana rent 1500
Rent-exempt minimum: 0.01133088 SOL

1.创建 IX

脚本中通过SystemProgram.createAccount函数,创建了一个指令 IX,这个指令的作用是调用系统程序创建一个账户,并且存入指定数量的 lamport 租金

完整代码

js
// 创建账号IX
// 使用 web3.js 辅助函数创建这个简单的指令
const createAccountIx = SystemProgram.createAccount({
  // `fromPubkey` - 该帐户需要签署交易
  fromPubkey: payer.publicKey,
  // `newAccountPubkey` - 在链上创建的账户地址
  newAccountPubkey: Pubkey,
  // 要存储在此帐户中的lamports
  lamports: lamports + amount,
  // 分配的总空间
  space: space,
  // 该帐户的owner程序id
  programId: programId,
});

2.创建版本化交易

定义

完整代码

js
// 创建版本化交易
// 创建消息 (v0)
const message = new TransactionMessage({
  payerKey: payerKey, // 支付账户的公钥
  recentBlockhash, // 获取最后的区块hash
  instructions: txs, // 交易的指令数组
}).compileToV0Message();

3.签署交易

完整代码

js
// 签署交易
// 使用我们所需的签名者(例如'Payer'和'keypair')签署交易,signers可以是多个签名人的keypair
tx.sign(signers);

4.发送交易

完整代码

js
// 发送交易
const sig = await connection.sendTransaction(tx);
// 输出交易签名:
console.log(`交易签名:${sig}`);

5.发送简单交易

将以上几步操作链接到一个完整的过程中,创建一个简单的交易,目的是在链上创建一个账户,并支付租金

完整代码

js
// 创建账户Ix,签署交易,发送交易
// 随机计算一个地址的keypair
let to = Keypair.generate();
// 创建账户的指令IX
let createAccountIx = await CreateAccountIx(
  payer,
  to.publicKey,
  connection,
  SystemProgram.programId
);
// 创建版本化交易
const tx = await CreateVersionedTx(payer.publicKey, connection, [
  createAccountIx,
]);
// 使用支付账户和to账户签名交易
const signedTx = await SignTx([payer, to], tx);
// 发送版本化交易
await SendVersionedTx(signedTx);

6.发送 SOL

通过系统程序的 transfer 函数,我们可以向指定账户发送 sol,这一小节内容将演示通过SystemProgram.transfer函数创建发送 SOL 的指令

完整代码

js
// 创建一个指令用于发送交易
const transferToTestWalletIx = SystemProgram.transfer({
  // 要发送的数量,以lamports为单位,加上空间租用成本
  lamports: lamports + amount,
  // `fromPubkey` - 该帐户需要签署交易
  fromPubkey: payer.publicKey,
  // `toPubkey` - 不需要签署交易
  toPubkey: toPubkey,
  // 该帐户的owner程序id为系统程序id
  programId: SystemProgram.programId,
});

6.发送复杂交易

前面的简单交易,在一笔交易中只有一个指令,接下来我们创建一个复杂交易,在一笔交易中同时包含 3 个指令

完整代码

js
// 创建账户Ix,两个发送交易
// 随机计算一个地址的keypair
let to = Keypair.generate();
// 创建账户的指令IX
let createAccountIx = await CreateAccountIx(
  payer,
  to.publicKey,
  connection,
  SystemProgram.programIdß
);
// 创建发送SOL的指令,发送到to地址2000lamport
let transfer_1 = await Transfer(connection, payer, to.publicKey, 2_000);
// 创建发送SOL的指令,发送到STATIC_PUBLICKEY地址1000000lamport
let transfer_2 = await Transfer(connection, payer, STATIC_PUBLICKEY, 1_000_000);
// 将三个指令IX打包创建版本化交易
const tx = await CreateVersionedTx(payer.publicKey, connection, [
  createAccountIx,
  transfer_1,
  transfer_2,
]);
// 使用支付账户和to账户签名交易
const signedTx = await SignTx([payer, to], tx);
// 发送版本化交易
await SendVersionedTx(signedTx);

7.计算交易成本

通过 message 计算

js
// 计算交易费
const fees = await connection.getFeeForMessage(tx.message);
console.log(`Estimated SOL transfer cost: ${fees.value} lamports`);