オフライントランザクション

トランザクションの署名

オフライントランザクションを作成するには、トランザクションに署名する必要があります。その後、誰でもネットワーク上でブロードキャストできます。

Press </> button to view full source
// there are two ways you can recover the tx
// 3.a Recover Tranasction (use populate then addSignauture)
{
  let recoverTx = Transaction.populate(Message.from(realDataNeedToSign));
  recoverTx.addSignature(feePayer.publicKey, Buffer.from(feePayerSignature));
  recoverTx.addSignature(alice.publicKey, Buffer.from(aliceSignature));

  // 4. Send transaction
  console.log(
    `txhash: ${await connection.sendRawTransaction(recoverTx.serialize())}`
  );
}

// or

// 3.b. Recover Tranasction (use populate with signature)
{
  let recoverTx = Transaction.populate(Message.from(realDataNeedToSign), [
    bs58.encode(feePayerSignature),
    bs58.encode(aliceSignature),
  ]);

  // 4. Send transaction
  console.log(
    `txhash: ${await connection.sendRawTransaction(recoverTx.serialize())}`
  );
}

部分署名トランザクション

トランザクションに複数の署名が必要な場合は、部分的に署名できます。その後、他の署名者が署名し、ネットワーク上でブロードキャストできます。

これが役立つ場合のいくつかの例:

  • 支払いと引き換えにSPLトークンを送信する
  • ランザクションに署名して、後でその信頼性を確認できるようにする
  • 署名が必要なトランザクションでカスタム プログラムを呼び出す

この例では、BobはAliceに支払いの見返りにSPLトークンを送信します:

Press </> button to view full source
// 1. Add an instruction to send the token from Bob to Alice
transaction.add(
  createTransferCheckedInstruction(
    bobTokenAddress, // source
    tokenAddress, // mint
    aliceTokenAccount.address, // destination
    bobKeypair.publicKey, // owner of source account
    1 * 10 ** tokenMint.decimals, // amount to transfer
    tokenMint.decimals // decimals of token
  )
);

// 2. Bob partially signs the transaction
transaction.partialSign(bobKeypair);

// 3. Serialize the transaction without requiring all signatures
const serializedTransaction = transaction.serialize({
  requireAllSignatures: false,
});

// 4. Alice can deserialize the transaction
const recoveredTransaction = Transaction.from(
  Buffer.from(transactionBase64, "base64")
);

耐久性のあるナンス

RecentBlockhashはトランザクションにとって重要な値です。期限切れの最近のブロックハッシュ(150 ブロック後)を使用すると、トランザクションは拒否されます耐久性のあるナンスを使用して、期限切れのない最近のブロックハッシュを取得できます。この仕組みを鳥がするには、トランザクションは下記を満たす必要があります。

  1. 最近のブロックハッシュとしてnonce accountに保存されているnonceを使用する
  2. 最初の命令にnonce advance操作を入れる

ナンスアカウントを取得

Press </> button to view full source
let tx = new Transaction().add(
  // create nonce account
  SystemProgram.createAccount({
    fromPubkey: feePayer.publicKey,
    newAccountPubkey: nonceAccount.publicKey,
    lamports: await connection.getMinimumBalanceForRentExemption(
      NONCE_ACCOUNT_LENGTH
    ),
    space: NONCE_ACCOUNT_LENGTH,
    programId: SystemProgram.programId,
  }),
  // init nonce account
  SystemProgram.nonceInitialize({
    noncePubkey: nonceAccount.publicKey, // nonce account pubkey
    authorizedPubkey: nonceAccountAuth.publicKey, // nonce account authority (for advance and close)
  })
);

console.log(
  `txhash: ${await connection.sendTransaction(tx, [feePayer, nonceAccount])}`
);

ナンスアカウントを取得

Press </> button to view full source
let accountInfo = await connection.getAccountInfo(nonceAccountPubkey);
let nonceAccount = NonceAccount.fromAccountData(accountInfo.data);

ナンスアカウントを使用

Press </> button to view full source
let tx = new Transaction().add(
  // nonce advance must be the first insturction
  SystemProgram.nonceAdvance({
    noncePubkey: nonceAccountPubkey,
    authorizedPubkey: nonceAccountAuth.publicKey,
  }),
  // after that, you do what you really want to do, here we append a transfer instruction as an example.
  SystemProgram.transfer({
    fromPubkey: feePayer.publicKey,
    toPubkey: nonceAccountAuth.publicKey,
    lamports: 1,
  })
);
// assign `nonce` as recentBlockhash
tx.recentBlockhash = nonceAccount.nonce;
tx.feePayer = feePayer.publicKey;
tx.sign(
  feePayer,
  nonceAccountAuth
); /* fee payer + nonce account authority + ... */

console.log(`txhash: ${await connection.sendRawTransaction(tx.serialize())}`);
Last Updated: 4/22/2023, 6:27:11 PM
Contributors: PokoPoko2ry