Not sure if this is a but, or just something that I'm doing wrong, but I'm working on a React app integrated with Solana blockchain, and I'm facing a challenge with the token minting flow. The goal is for users to request minting of new tokens through a backend service, which then creates and signs a transaction. The user's wallet should submit this transaction to the blockchain and pay the associated fees.
Here's the flow I need:
User requests token minting via UI.
React app sends a request to the backend.
Backend creates a signed transaction with minting instructions.
Backend sends the signed transaction back to the frontend.
User's wallet submits the transaction, paying the fees.
Issue:
The backend seems to create the transaction successfully, but when the frontend tries to submit it, I encounter an unexpected error.
Backend Code (Node.js):
router.post("/sol", authenticationMiddleware, corsMiddleware, async (req, res) => {
try {
const { decodedToken } = res.locals;
if (!decodedToken) {
return res.status(500).send("Token error");
}
const getUser = await db.collection("users").doc(decodedToken.uid).get();
const user = getUser.data();
const userTokens = Math.floor(user?.tokens); // Use numeric value for Solana transactions
const userWallet = user?.solWallet;
// Assuming you have a function to create a transaction for minting tokens
// This function should prepare the transaction with the mint instruction but not sign it
// The transaction is then serialized to a base64 string to be sent to the client
const transactionBase64 = await prepareMintTransaction(userWallet, userTokens);
return res.status(200).send({ transaction: transactionBase64 });
} catch (error) {
console.log("Error:", error);
return res.status(500).send({ "error": "An error occurred while processing your request. Please try again." });
}
});
async function prepareMintTransaction(userWallet, userTokens) {
// Convert the secret key and mint public key string to their respective types
const mintAuthoritySecretKey = Uint8Array.from(MINT_AUTHORITY_SECRET_KEY);
const mintPublicKeyStr = MINT_PUBLIC_KEY_STR;
const userPublicKeyStr = userWallet; // Assuming userWallet is a string
const amount = userTokens; // Assuming userTokens is the amount to mint
const connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");
const mintPublicKey = new web3.PublicKey(mintPublicKeyStr);
const userPublicKey = new web3.PublicKey(userPublicKeyStr);
const mintAuthorityKeypair = web3.Keypair.fromSecretKey(mintAuthoritySecretKey);
// Fetch or create the associated token account for the recipient user
const toTokenAccount = await splToken.getOrCreateAssociatedTokenAccount(
connection,
mintAuthorityKeypair,
mintPublicKey,
userPublicKey
);
// Make sure the amount is specified correctly, accounting for decimals.
// If your token has 9 decimals and you want to mint 1 token, you need to pass 1000000000 as the amount.
const decimals = 9; // This should match the decimals of your token.
const mintAmount = BigInt(amount) * BigInt(10 ** decimals);
// Create the 'mint to' instruction
const mintToInstruction = splToken.createMintToInstruction(
mintPublicKey, // The public key of the mint
toTokenAccount.address, // The associated token account of the recipient
mintAuthorityKeypair.publicKey, // The mint authority public key
mintAmount, // The amount to mint, as a BigInt or number
);
// Create a new transaction and add the mint instruction
let theTransaction = new web3.Transaction().add(mintToInstruction);
// Fetch the recent blockhash to include in the transaction
// theTransaction.recentBlockhash = (await connection.getRecentBlockhash()).blockhash;
const { blockhash } = (await connection.getLatestBlockhash());
theTransaction.recentBlockhash = blockhash;
// Temporarily set the fee payer for the sake of transaction structure
theTransaction.feePayer = mintAuthorityKeypair.publicKey;
// const serializedTransaction = transaction.serializeMessage();
const serializedTransaction = theTransaction.serialize({
requireAllSignatures: false, // Indicates not all signatures are present yet
verifySignatures: false, // No need to verify signatures at this point
});
// Encode the serialized transaction to base64
const base64Transaction = serializedTransaction.toString("base64");
return base64Transaction;
}
I deployed a program here: https://solscan.io/token/2RbY2xRtSwgvKdyqvvFpZPrDwknnZY63HqfSQGxr5x6y?cluster=devnet
In the above code, the MINT_PUBLIC_KEY_STR is defined like this:
Not sure if this is a but, or just something that I'm doing wrong, but I'm working on a React app integrated with Solana blockchain, and I'm facing a challenge with the token minting flow. The goal is for users to request minting of new tokens through a backend service, which then creates and signs a transaction. The user's wallet should submit this transaction to the blockchain and pay the associated fees.
Here's the flow I need:
Issue:
The backend seems to create the transaction successfully, but when the frontend tries to submit it, I encounter an unexpected error.
Backend Code (Node.js):
I deployed a program here:
https://solscan.io/token/2RbY2xRtSwgvKdyqvvFpZPrDwknnZY63HqfSQGxr5x6y?cluster=devnet
In the above code, the
MINT_PUBLIC_KEY_STR
is defined like this:const MINT_PUBLIC_KEY_STR = "2RbY2xRtSwgvKdyqvvFpZPrDwknnZY63HqfSQGxr5x6y";
The
MINT_AUTHORITY_SECRET_KEY
is the value taken frommint-authority.json
from the project that deployed the program.Frontend Code (React):
Screenshot of the error below