2

I am trying to call the rpc function getFeeForMessage but i cant figure out what to pass into the function:


  // What do I need to do here? 

  // Doesnt work: Argument of type 'LegacyCompiledTransactionMessage' is not assignable to parameter of type 'TransactionMessageBytesBase64'.
  // Type 'LegacyCompiledTransactionMessage' is not assignable to type 'string'.
  var compiledTransaction = compileTransactionMessage(
    budgetedTransactionMessage
  );
  // Doesnt work: Argument of type 'Buffer' is not assignable to parameter of type 'TransactionMessageBytesBase64'.
  // Type 'Buffer' is not assignable to type 'string'.ts(2345) 
  var serialized = serialize(compiledTransaction);

  // Using budgetedTransactionMessage Argument of type 'TransactionMessageWithBlockhashLifetime & ITransactionMessageWithFeePayerSigner<string, TransactionSigner<string>> & Omit<...>' is not assignable to parameter of type 'TransactionMessageBytesBase64'.
  // Type 'TransactionMessageWithBlockhashLifetime & ITransactionMessageWithFeePayerSigner<string, TransactionSigner<string>> & Omit<...>' is not assignable to type 'string'.ts(2345)
  const transactionCost = await rpc
    .getFeeForMessage(budgetedTransactionMessage)
    .send();

Full source:

import {
  airdropFactory,
  appendTransactionMessageInstructions,
  compileTransactionMessage,
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  createTransactionMessage,
  devnet,
  generateKeyPairSigner,
  getComputeUnitEstimateForTransactionMessageFactory,
  getSignatureFromTransaction,
  lamports,
  pipe,
  prependTransactionMessageInstructions,
  sendAndConfirmTransactionFactory,
  setTransactionMessageFeePayerSigner,
  setTransactionMessageLifetimeUsingBlockhash,
  signTransactionMessageWithSigners,
} from "@solana/web3.js";
import {
  getSetComputeUnitLimitInstruction,
  getSetComputeUnitPriceInstruction,
} from "@solana-program/compute-budget";
import { getAddMemoInstruction } from "@solana-program/memo";
import { serialize } from "v8";

async function writeMemo(message: string) {
  // Create an RPC.
  const CLUSTER = "devnet";
  const rpc = createSolanaRpc(devnet(`https://api.${CLUSTER}.solana.com`));
  const rpcSubscriptions = createSolanaRpcSubscriptions(
    devnet(`wss://api.${CLUSTER}.solana.com`)
  );

  // Create an airdrop function.
  const airdrop = airdropFactory({ rpc, rpcSubscriptions });

  // Create a utility that estimates a transaction message's compute consumption.
  const getComputeUnitEstimate =
    getComputeUnitEstimateForTransactionMessageFactory({ rpc });

  // Create a transaction sending function.
  const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({
    rpc,
    rpcSubscriptions,
  });

  // Create and fund an account.
  const keypairSigner = await generateKeyPairSigner();
  console.log("Created an account with address", keypairSigner.address);
  console.log("Requesting airdrop");
  await airdrop({
    commitment: "confirmed",
    lamports: lamports(1000_000n),
    recipientAddress: keypairSigner.address,
  });
  console.log("Airdrop confirmed");

  // Create a memo transaction.
  console.log("Creating a memo transaction");
  const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
  const transactionMessage = pipe(
    createTransactionMessage({ version: "legacy" }),
    (m) => setTransactionMessageFeePayerSigner(keypairSigner, m),
    (m) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, m),
    (m) =>
      appendTransactionMessageInstructions(
        [
          getSetComputeUnitPriceInstruction({ microLamports: 5000n }),
          getAddMemoInstruction({ memo: message }),
        ],
        m
      )
  );

  // Figure out how many compute units to budget for this transaction
  // so that you can right-size the compute budget to maximize the
  // chance that it will be selected for inclusion into a block.
  console.log("Estimating the compute consumption of the transaction");
  const estimatedComputeUnits = await getComputeUnitEstimate(
    transactionMessage
  );
  console.log(
    `Transaction is estimated to consume ${estimatedComputeUnits} compute units`
  );

  const budgetedTransactionMessage = prependTransactionMessageInstructions(
    [getSetComputeUnitLimitInstruction({ units: estimatedComputeUnits })],
    transactionMessage
  );
  
  // What do I need to do here? 

  // Doesnt work: Argument of type 'LegacyCompiledTransactionMessage' is not assignable to parameter of type 'TransactionMessageBytesBase64'.
  // Type 'LegacyCompiledTransactionMessage' is not assignable to type 'string'.
  var compiledTransaction = compileTransactionMessage(
    budgetedTransactionMessage
  );
  // Doesnt work: Argument of type 'Buffer' is not assignable to parameter of type 'TransactionMessageBytesBase64'.
  // Type 'Buffer' is not assignable to type 'string'.ts(2345) 
  var serialized = serialize(compiledTransaction);

  // Using budgetedTransactionMessage Argument of type 'TransactionMessageWithBlockhashLifetime & ITransactionMessageWithFeePayerSigner<string, TransactionSigner<string>> & Omit<...>' is not assignable to parameter of type 'TransactionMessageBytesBase64'.
  // Type 'TransactionMessageWithBlockhashLifetime & ITransactionMessageWithFeePayerSigner<string, TransactionSigner<string>> & Omit<...>' is not assignable to type 'string'.ts(2345)
  const transactionCost = await rpc
    .getFeeForMessage(budgetedTransactionMessage)
    .send();

  // Sign and send the transaction.
  console.log("Signing and sending the transaction");
  const signedTx = await signTransactionMessageWithSigners(
    budgetedTransactionMessage
  );
  const signature = getSignatureFromTransaction(signedTx);
  console.log(
    "Sending transaction https://explorer.solana.com/tx/" +
      signature +
      "/?cluster=" +
      CLUSTER
  );
  await sendAndConfirmTransaction(signedTx, { commitment: "confirmed" });
  console.log("Transaction confirmed");
}

writeMemo("Hello, Solana!");

1 Answer 1

3

The getFeeForMessage() method requires the transaction message as a base64 string representation of the message bytes themselves. You can use the following transforms to produce that.

const base64EncodedMessage = pipe(
    // Start with the message you want the fee for.
    budgetedTransactionMessage,

    // Compile it.
    compileTransactionMessage,

    // Convert the compiled message into a byte array.
    getCompiledTransactionMessageEncoder().encode,

    // Encode that byte array as a base64 string.
    getBase64Decoder().decode,
) as TransactionMessageBytesBase64;

// Send the RPC request to get the fee.
const { value: lamports } = await rpc
    .getFeeForMessage(base64EncodedMessage)
    .send();

console.log("Message fee, in Lamports", lamports);

If you already have a compiled Transaction, you can obtain the bytes from it directly.

const base64EncodedMessage = getBase64Decoder().decode(
    signedTx.messageBytes,
) as TransactionMessageBytesBase64;

I would agree that having to cast from string to TransactionMessageBytesBase64 is a bit unintuitive. We would welcome helper methods that did this, as pull requests to @solana/transaction-messages

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.