Solanaで「unknown signer: ${pubkey.toString()」エラー

現象

Solanaで、複数署名してからネイティブSOLを送信(SystemProgram.transfer)すると以下のエラー。

ターミナル:

/solana-anchor-react-minimal-example/scripts/solana/spl-token-v0.3.x/node_modules/@solana/web3.js/src/transaction/legacy.ts:686
      throw new Error(`unknown signer: ${pubkey.toString()}`);
            ^
Error: unknown signer: CiizbbYBtt27qS3MbvTbEK7mUhSTeErbh3sbW4YHEL7u
    at Transaction._addSignature (/solana-anchor-react-minimal-example/scripts/solana/spl-token-v0.3.x/node_modules/@solana/web3.js/src/transaction/legacy.ts:686:13)
    at forEach (/solana-anchor-react-minimal-example/scripts/solana/spl-token-v0.3.x/node_modules/@solana/web3.js/src/transaction/legacy.ts:662:12)
    at Array.forEach (<anonymous>)
    at Transaction._partialSign (/solana-anchor-react-minimal-example/scripts/solana/spl-token-v0.3.x/node_modules/@solana/web3.js/src/transaction/legacy.ts:660:13)
    at Transaction.partialSign (/solana-anchor-react-minimal-example/scripts/solana/spl-token-v0.3.x/node_modules/@solana/web3.js/src/transaction/legacy.ts:652:10)
    at main (/solana-anchor-react-minimal-example/scripts/solana/spl-token-v0.3.x/createPartialSignTransactionNativeSOL.ts:84:15)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)

tsファイル:

  // Transfer 0.01 SOL from Alice -> Bob
  transaction.add(
    SystemProgram.transfer({
      fromPubkey: aliceKeypair.publicKey,
      toPubkey: bobKeypair.publicKey,
      lamports: 0.01 * LAMPORTS_PER_SOL,
    })
  );

  transaction.partialSign(aliceKeypair);

  // Transfer 0.01 SOL from Bob -> Alice
  transaction.add(
    SystemProgram.transfer({
      fromPubkey: bobKeypair.publicKey,
      toPubkey: aliceKeypair.publicKey,
      lamports: 0.01 * LAMPORTS_PER_SOL,
    })
  );

  transaction.partialSign(bobKeypair);

原因

署名タイミングが誤っている。

transaction の合間に partialSign を実施しているが、 partialSign は transaction の instruction が全部作成された最後に署名する必要があるため、エラーになる。

対応

最後に署名する。

tsファイル:

  // Transfer 0.01 SOL from Alice -> Bob
  transaction.add(
    SystemProgram.transfer({
      fromPubkey: aliceKeypair.publicKey,
      toPubkey: bobKeypair.publicKey,
      lamports: 0.01 * LAMPORTS_PER_SOL,
    })
  );

  // Transfer 0.01 SOL from Bob -> Alice
  transaction.add(
    SystemProgram.transfer({
      fromPubkey: bobKeypair.publicKey,
      toPubkey: aliceKeypair.publicKey,
      lamports: 0.01 * LAMPORTS_PER_SOL,
    })
  );

  transaction.partialSign(aliceKeypair);
  transaction.partialSign(bobKeypair);

参考サイト

StackExchange - How to Sign a Transaction with Multiple Signers