Thanks to visit codestin.com
Credit goes to github.com

Skip to content

How to Include Multiple Signers in a Transaction for a Smart Contract Method Call? #123

@drgimenez

Description

@drgimenez

Discussed in https://github.com/orgs/sol4k/discussions/122

Originally posted by drgimenez February 4, 2025
Hi Sol4K Team,

I am currently integrating Sol4K into a project where I am implementing a bridge using Circle’s CCTP. As part of this, I need to call the depositForBurn(...) method of the TokenMessengerMinter program.

This method requires at least two accounts to be passed as signers in the transaction. However, I am encountering signature verification failures when attempting to include multiple signers.

What i have

  • I have constructed the transaction using TransactionMessage.newMessage(...) with feePayer signer.
  • I have called transaction.sign(signer); with each account that was included as a signer in the instructions or only with the fee payer and none of the forms worked.

Question
What is the correct way to include multiple signers in a Sol4K transaction when invoking a smart contract method that requires multiple signers?

Here is the relevant portion of my code:

    signer1 = Keypair.fromSecretKey(Base58.decode(SIGNER_PRIVATE_KEY));
    signer2 = Keypair.generate();

    ProgramDerivedAddress authorityPda = PublicKey.findProgramAddress(sender_authority_seed, tokenMessengerMinter_program);
    ProgramDerivedAddress messageTransmitterAccount = PublicKey.findProgramAddress(message_transmitter_seed, messageTransmitter_program);
    ProgramDerivedAddress tokenMessengerAccount = PublicKey.findProgramAddress(token_messenger_seed, tokenMessengerMinter_program);
    ProgramDerivedAddress remoteTokenMessengerKey = PublicKey.findProgramAddress(remote_token_messenger_seed, tokenMessengerMinter_program);
    ProgramDerivedAddress tokenMinterAccount = PublicKey.findProgramAddress(token_minter_seed, tokenMessengerMinter_program);
    ProgramDerivedAddress localToken = PublicKey.findProgramAddress(local_token_seed, tokenMessengerMinter_contract_address);
    ProgramDerivedAddress eventAuthorityPda = PublicKey.findProgramAddress(__event_authority_seed, tokenMessengerMinter_program);

    List<AccountMeta> accounts = List.of(
      AccountMeta.signerAndWritable(signer1.getPublicKey()),
      AccountMeta.signerAndWritable(signer1.getPublicKey()),
      AccountMeta.writable(authorityPda.getPublicKey()),
      AccountMeta.writable(associatedTokenAccount),
      AccountMeta.writable(messageTransmitterAccount.getPublicKey()),    
      AccountMeta.writable(tokenMessengerAccount.getPublicKey()),
      AccountMeta.writable(remoteTokenMessengerKey.getPublicKey()),
      AccountMeta.writable(tokenMinterAccount.getPublicKey()),
      AccountMeta.writable(localToken.getPublicKey()),
      AccountMeta.writable(usdc_contract_address),
      AccountMeta.signerAndWritable(signer2.getPublicKey()),            // <== This is the second signer that I must include
      AccountMeta.writable(messageTransmitter_contract_address),
      AccountMeta.writable(tokenMessengerMinter_contract_address),
      AccountMeta.writable(token_program),
      AccountMeta.writable(system_program),
      AccountMeta.writable(eventAuthorityPda.getPublicKey()),
      AccountMeta.writable(tokenMessengerMinter_contract_address)
    );

    String blockHash = nodeProvider.getLatestBlockhash();

    ByteBuffer instructionData = ByteBuffer.allocate(52);
    data.put(getFunctionDiscriminator("deposit_for_burn"));
    data.putLong(Long.reverseBytes(amount));
    data.putInt(Integer.reverseBytes(destinationDomain));
    data.put(mintRecipient.bytes());

    Instruction instruction = new org.sol4k.instruction.BaseInstruction(
        instructionData.array(), 
        accounts, 
        tokenMessengerMinter_program
    );

    TransactionMessage transactionMessage = TransactionMessage.newMessage(
          signer1.getPublicKey(),
          blockHash,
          instruction
    );

    VersionedTransaction transaction = new VersionedTransaction(transactionMessage);

    transaction.sign(signer1);
    //transaction.sign(signer2);

    String transactionHash = connection.sendTransaction(transaction.serialize());
    //String transactionHash = connection.sendTransaction(transaction);
    System.out.println("transaction Hash: " + transactionHash);

Errors I have received:

  • SerializationException(message=Signature verification failed) at org.sol4k.VersionedTransaction.serialize(VersionedTransaction.kt:38) at line String transactionHash = nodeProvider.sendTransaction(transaction.serialize());
  • java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1 at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100) at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106) at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302) at java.base/java.util.Objects.checkIndex(Objects.java:365) at java.base/java.util.ArrayList.set(ArrayList.java:471) at org.sol4k.VersionedTransaction.sign(VersionedTransaction.kt:29) If I enable the line transaction.sign(signer2);

I apologize if this is a basic question, but I am still new to Solana and Sol4K. Any guidance on the correct approach to include both required signers correctly would be greatly appreciated.

Thank you for your time and assistance!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions