Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can not get Tx Hash after transaction. #1656

Open
kprpl opened this issue Jan 3, 2025 · 6 comments
Open

Can not get Tx Hash after transaction. #1656

kprpl opened this issue Jan 3, 2025 · 6 comments
Labels
bug Something isn't working library

Comments

@kprpl
Copy link

kprpl commented Jan 3, 2025

help needed

issue#1:
I am transfaring Sol with transferLamports() method the transaction is complete by blockchain and can see and verify on explore but can not get tx hash in return

issue#2:
I had try with lengthy way with sendTransaction with that i got error in return. [code is attached]

To Reproduce
I have attache the code.

Expected behavior
should return tx hash in return of transferLamports() method so i can confirm that transaction is success.

Code

// with transferLamports
Future transferSol({
  required SolanaClient solClient,
  required Ed25519HDKeyPair source,
  required Ed25519HDPublicKey destination,
  required int lamports,
}) async {
  try {
    String transfer = await solanaClient1.transferLamports(
      source: source,
      destination: destination,
      lamports: lamports,
    );
    print(transfer);
  } catch (error) {
    print("error is $error");
  }
}

/*
output:
[can't get tx hash]
*/
// with transferLamports
Future transferSolCoin({
  required SolanaClient solClient,
  required Ed25519HDKeyPair source,
  required Ed25519HDPublicKey destination,
  required int lamports,
}) async {
  try {
    final instruction = SystemInstruction.transfer(
      fundingAccount: source.publicKey,
      recipientAccount: destination,
      lamports: lamports,
    );
    final latestBlockhash =
        await solClient.rpcClient.getLatestBlockhash(); 

    final message = Message.only(instruction);

    final compiledMessage = message.compile(
      recentBlockhash: latestBlockhash.value.blockhash,
      feePayer: source.publicKey,
    );

    final serializedMessage =
        base64Encode(compiledMessage.toByteArray().toList());

    final signature = await solClient.rpcClient.sendTransaction(
      serializedMessage,
      preflightCommitment: Commitment.confirmed,
    );

    await solClient.waitForSignatureStatus(
      signature,
      status: Commitment.confirmed,
      timeout: Duration(seconds: 60),
    );

    print("signature is $signature");
  } catch (error) {
    print("error is $error");
  }
}

/*
output:
error is jsonrpc-2.0 error (-32602): failed to deserialize solana_sdk::transaction::versioned::VersionedTransaction: io error: failed to fill whole buffer
*/
@kprpl kprpl added bug Something isn't working library labels Jan 3, 2025
@ookami-kb
Copy link
Collaborator

What do you mean by [can't get tx hash]? We actually have your first use case in tests and it works fine. String returned by transferLamports is the transaction ID.

Your second example is incorrect though. You cannot just encode compiled message and pass it as transaction – you need to sign it. So instead of

final serializedMessage =
        base64Encode(compiledMessage.toByteArray().toList());

you can try something like this

final signedTx = SignedTx(
  compiledMessage: compiledMessage,
  signatures: [await source.sign(compiledMessage.toByteArray())],
);

final serializedMessage = signedTx.encode();

That's done under the hood by transferLamports method.

@kprpl
Copy link
Author

kprpl commented Jan 7, 2025

What do you mean by [can't get tx hash]? We actually have your first use case in tests and it works fine. String returned by transferLamports is the transaction ID.

Your second example is incorrect though. You cannot just encode compiled message and pass it as transaction – you need to sign it. So instead of

final serializedMessage =
        base64Encode(compiledMessage.toByteArray().toList());

you can try something like this

final signedTx = SignedTx(
  compiledMessage: compiledMessage,
  signatures: [await source.sign(compiledMessage.toByteArray())],
);

final serializedMessage = signedTx.encode();

That's done under the hood by transferLamports method.

thankyou for your response.

1).
What do you mean by [can't get tx hash]?
by tx hash, i mean the signature that we get from transaction or transaction ID that you mentioned.

2). i still have issue (need help)
what i figure out that transferSolCoin() method is stuck on here -> await solClient.waitForSignatureStatus(... while waiting for status.

because if i check transactionID in scanner/explorer that i got from here final signature = await solClient.rpcClient.sendTransaction( serializedMessage, preflightCommitment: Commitment.confirmed, ); is valid.

but method is waiting for SignatureStatus & here i got error from dart.

thankyou

@ookami-kb
Copy link
Collaborator

@kprpl please send fully reproducible example, it would be easier to find the root cause.

@kprpl
Copy link
Author

kprpl commented Jan 10, 2025

Sure here is code.

import 'package:solana/solana.dart';

void main() {
  mainFunction();
}

void mainFunction() async {
  // SolanaClient solanaClient = SolanaClient(
  //   rpcUrl: Uri.parse("https://api.mainnet-beta.solana.com/"),
  //   websocketUrl: Uri.parse("wss://api.mainnet-beta.solana.com/"),
  // );

  SolanaClient solanaClient = SolanaClient(
    rpcUrl: Uri.parse("https://api.devnet.solana.com"),
    websocketUrl: Uri.parse("wss://api.devnet.solana.com"),
  );

  String mnemonic = "...";  //  mnemonic phrase or seed phrase
  final Ed25519HDKeyPair senderWallet = await Ed25519HDKeyPair.fromMnemonic(mnemonic, account: 0);
  final Ed25519HDPublicKey receiverWallet = Ed25519HDPublicKey.fromBase58("...");  // receiver's public key or wallet address

  await transferSolCoin(
    solClient: solanaClient,
    source: senderWallet,
    destination: receiverWallet,
    amount: 0.01,
  );
}


Future transferSolCoin({
  required SolanaClient solClient,
  required Ed25519HDKeyPair source,
  required Ed25519HDPublicKey destination,
  required double amount,
}) async {
  try {
    final int lamports = (amount * 1e9).toInt();
    final instruction = SystemInstruction.transfer(
      fundingAccount: source.publicKey,
      recipientAccount: destination,
      lamports: lamports,
    );

    final latestBlockhash = await solClient.rpcClient.getLatestBlockhash();
    final message = Message.only(instruction);
    final compiledMessage = message.compile(
      recentBlockhash: latestBlockhash.value.blockhash,
      feePayer: source.publicKey,
    );

    final signedTx = SignedTx(
      compiledMessage: compiledMessage,
      signatures: [await source.sign(compiledMessage.toByteArray())],
    );

    final serializedMessage = signedTx.encode();
    final signature = await solClient.rpcClient.sendTransaction(
      serializedMessage,
      preflightCommitment: Commitment.finalized,
    );

    print("signature before waitForSignatureStatus: $signature");

    await solClient.waitForSignatureStatus(
      signature,
      status: Commitment.finalized,
      timeout: Duration(seconds: 60),
    );

    print("signature after waitForSignatureStatus $signature");
    print("transfer success");
  } catch (error) {
    print("error is $error");
  }
}

@ookami-kb
Copy link
Collaborator

@kprpl I cannot reproduce any error. This is the code I tried with local validator (basically, your code with a couple of minor fixes regarding wallet generation), and it works:

import 'package:solana/encoder.dart';
import 'package:solana/solana.dart';

Future<void> main() async {
  SolanaClient solanaClient = SolanaClient(
    rpcUrl: Uri.parse("http://127.0.0.1:8899"),
    websocketUrl: Uri.parse("ws://127.0.0.1:8900"),
  );

  final Ed25519HDKeyPair senderWallet = await Ed25519HDKeyPair.random();
  await solanaClient.requestAirdrop(
    address: senderWallet.publicKey,
    lamports: lamportsPerSol,
  );
  final Ed25519HDPublicKey receiverWallet =
      (await Ed25519HDKeyPair.random()).publicKey;

  await transferSolCoin(
    solClient: solanaClient,
    source: senderWallet,
    destination: receiverWallet,
    amount: 0.01,
  );
}

Future<void> transferSolCoin({
  required SolanaClient solClient,
  required Ed25519HDKeyPair source,
  required Ed25519HDPublicKey destination,
  required double amount,
}) async {
  try {
    final int lamports = (amount * 1e9).toInt();
    final instruction = SystemInstruction.transfer(
      fundingAccount: source.publicKey,
      recipientAccount: destination,
      lamports: lamports,
    );

    final latestBlockhash = await solClient.rpcClient.getLatestBlockhash();
    final message = Message.only(instruction);
    final compiledMessage = message.compile(
      recentBlockhash: latestBlockhash.value.blockhash,
      feePayer: source.publicKey,
    );

    final signedTx = SignedTx(
      compiledMessage: compiledMessage,
      signatures: [await source.sign(compiledMessage.toByteArray())],
    );

    final serializedMessage = signedTx.encode();
    final signature = await solClient.rpcClient.sendTransaction(
      serializedMessage,
      preflightCommitment: Commitment.finalized,
    );

    print("signature before waitForSignatureStatus: $signature");

    await solClient.waitForSignatureStatus(
      signature,
      status: Commitment.finalized,
      timeout: Duration(seconds: 60),
    );

    print("signature after waitForSignatureStatus $signature");
    print("transfer success");
  } catch (error) {
    print("error is $error");
  }
}

This is the output I get:

signature before waitForSignatureStatus: 4G8V9axvfmt7KZQraCPdCh1fbftaRxrJWRSpxfrANkDQk5wM7Ap5SbgvXfnQW9TJRVkmEMctjxkAAQM9Eyi6yzkL
signature after waitForSignatureStatus 4G8V9axvfmt7KZQraCPdCh1fbftaRxrJWRSpxfrANkDQk5wM7Ap5SbgvXfnQW9TJRVkmEMctjxkAAQM9Eyi6yzkL
transfer success

@AlexV525
Copy link

I got similar behavior when using the Mainnet beta endpoint which is timeout when waiting for signature status. However, switching to Devnet would return a valid transaction ID.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working library
Projects
None yet
Development

No branches or pull requests

3 participants