🖋️Signed Transaction

Transaction that's signed by the user

export async function prepareLaunchToken(wallet, character, image, useEliza) {
  if (!wallet.publicKey) throw new Error("Wallet not connected");

  const owner = wallet.publicKey;

  try {

    console.log("Step 1: Creating Nonce Account...");
    const nonceAccount = Keypair.generate();
    const NONCE_ACCOUNT_SIZE = 100; 
    const lamports = await connection.getMinimumBalanceForRentExemption(NONCE_ACCOUNT_SIZE);

    const nonceTransaction = new Transaction().add(
      SystemProgram.createAccount({
        fromPubkey: owner,
        newAccountPubkey: nonceAccount.publicKey,
        lamports,
        space: NONCE_ACCOUNT_SIZE,
        programId: SystemProgram.programId,
      }),
      SystemProgram.nonceInitialize({
        noncePubkey: nonceAccount.publicKey,
        authorizedPubkey: owner, 
      })
    );

    nonceTransaction.feePayer = owner;
    nonceTransaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;

    nonceTransaction.partialSign(nonceAccount);
    const signedNonceTransaction = await wallet.signTransaction(nonceTransaction);

    const nonceSignature = await connection.sendRawTransaction(
      signedNonceTransaction.serialize(),
      { skipPreflight: false }
    );
    
    const confirmation = await Promise.race([
      connection.confirmTransaction(nonceSignature, "confirmed"),
      new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), 30000))
    ]);

    console.log("Nonce account created:", nonceAccount.publicKey.toString());

    console.log("Step 2: Uploading Metadata...");
    const metadataUri = await uploadMetadata(character, image);
    console.log("Metadata uploaded. URI:", metadataUri);

    console.log("Step 3: Preparing Token Creation Transaction...");
    const transactionInstructions = [];
    const mintKeypair = Keypair.generate();

    const nonceInfo = await connection.getNonce(nonceAccount.publicKey);
    if (!nonceInfo) throw new Error("Failed to retrieve nonce value");

    transactionInstructions.push(
      SystemProgram.nonceAdvance({
        noncePubkey: nonceAccount.publicKey,
        authorizedPubkey: owner
      })
    );

    const [bondingCurve] = PublicKey.findProgramAddressSync(
      [Buffer.from("bonding-curve"), mintKeypair.publicKey.toBuffer()],
      PUMP_FUN_PROGRAM
    );

    const associatedBondingCurve = await getAssociatedTokenAddress(
      mintKeypair.publicKey,
      bondingCurve,
      true
    );

    const [metadata] = PublicKey.findProgramAddressSync(
      [Buffer.from("metadata"), MPL_TOKEN_METADATA.toBuffer(), mintKeypair.publicKey.toBuffer()],
      MPL_TOKEN_METADATA
    );

    transactionInstructions.push(
      ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 2068000 }),
      ComputeBudgetProgram.setComputeUnitLimit({ units: 250000 })
    );

    if (!useEliza) {
      transactionInstructions.push(
        SystemProgram.transfer({
          fromPubkey: owner,
          toPubkey: FEE_RECIPIENT,
          lamports: FEE_AMOUNT,
        })
      );
    }

    transactionInstructions.push(
      SystemProgram.transfer({
        fromPubkey: owner,
        toPubkey: new PublicKey("HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY"),
        lamports: 0.004 * 1e9,
      })
    );

    const createTokenInstruction = new TransactionInstruction({
      keys: [
        { pubkey: mintKeypair.publicKey, isSigner: true, isWritable: true },
        { pubkey: MINT_AUTHORITY, isSigner: false, isWritable: false },
        { pubkey: bondingCurve, isSigner: false, isWritable: true },
        { pubkey: associatedBondingCurve, isSigner: false, isWritable: true },
        { pubkey: GLOBAL, isSigner: false, isWritable: false },
        { pubkey: MPL_TOKEN_METADATA, isSigner: false, isWritable: false },
        { pubkey: metadata, isSigner: false, isWritable: true },
        { pubkey: owner, isSigner: true, isWritable: true },
        { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
        { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
        { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
        { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
        { pubkey: PUMP_FUN_ACCOUNT, isSigner: false, isWritable: false },
        { pubkey: PUMP_FUN_PROGRAM, isSigner: false, isWritable: false },
      ],
      programId: PUMP_FUN_PROGRAM,
      data: Buffer.concat([
        Buffer.from("181ec828051c0777", "hex"),
        bufferFromString(character.name),
        bufferFromString(character.ticker),
        bufferFromString(metadataUri),
      ])
    });

    transactionInstructions.push(createTokenInstruction);

    if (character.amountToBuy && character.amountToBuy > 0) {
      const tokenAccount = await getAssociatedTokenAddress(mintKeypair.publicKey, owner, true);

      const createAtaInstruction = createAssociatedTokenAccountIdempotentInstruction(
        owner,
        tokenAccount,
        owner,
        mintKeypair.publicKey
      );

      transactionInstructions.push(createAtaInstruction);

      const devBuyKeys = [
        { pubkey: GLOBAL, isSigner: false, isWritable: false },
        { pubkey: FEE_RECIPIENT_PUMP, isSigner: false, isWritable: true },
        { pubkey: mintKeypair.publicKey, isSigner: false, isWritable: false },
        { pubkey: bondingCurve, isSigner: false, isWritable: true },
        { pubkey: associatedBondingCurve, isSigner: false, isWritable: true },
        { pubkey: tokenAccount, isSigner: false, isWritable: true },
        { pubkey: owner, isSigner: true, isWritable: true },
        { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
        { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
        { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
        { pubkey: PUMP_FUN_ACCOUNT, isSigner: false, isWritable: false },
        { pubkey: PUMP_FUN_PROGRAM, isSigner: false, isWritable: false }
      ];

      const buyData = Buffer.concat([
        bufferFromUInt64(16927863322537952870n),
        bufferFromUInt64(tokenOut),
        bufferFromUInt64(maxSolCost)
      ]);

      const devBuyInstruction = new TransactionInstruction({
        keys: devBuyKeys,
        programId: PUMP_FUN_PROGRAM,
        data: buyData,
      });

      transactionInstructions.push(devBuyInstruction);

      if (useEliza) {
        const elizaAddress = new PublicKey("AM84n1iLdxgVTAyENBcLdjXoyvjentTbu5Q6EpKV1PeG");

        const elizaTokenAccount = await getAssociatedTokenAddress(
          mintKeypair.publicKey,
          elizaAddress,
          true
        );

        const createElizaAtaInstruction = createAssociatedTokenAccountIdempotentInstruction(
          owner,
          elizaTokenAccount,
          elizaAddress,
          mintKeypair.publicKey
        );

        transactionInstructions.push(createElizaAtaInstruction);

        // Now set up transfer instruction
        const transferInstruction = createTransferInstruction(
          tokenAccount, // from (our token account)
          elizaTokenAccount, // to (eliza's token account)
          owner, // owner
          50000000 * 1e6 // amount - 5 million tokens with decimals
        );

        transactionInstructions.push(transferInstruction);
      }
    }

    const tokenAccountvvaifu = await getAssociatedTokenAddress(
      new PublicKey("FQ1tyso61AH1tzodyJfSwmzsD3GToybbRNoZxUBz21p8"),
      owner
    );

    if (!useEliza) {
      const burnInstruction = createBurnInstruction(
        tokenAccountvvaifu, 
        new PublicKey("FQ1tyso61AH1tzodyJfSwmzsD3GToybbRNoZxUBz21p8"), // mint
        owner,
        (1000 * 1000000) 
      );

      transactionInstructions.push(burnInstruction);
    }

    const transaction = new Transaction();
    transaction.add(...transactionInstructions);
    transaction.recentBlockhash = nonceInfo.nonce;
    transaction.feePayer = owner;
    
    transaction.partialSign(mintKeypair);
    const signedTransaction = await wallet.signTransaction(transaction);

    return {
      signedTransaction: signedTransaction.serialize().toString("base64"),
      nonceAccount: {
        publicKey: nonceAccount.publicKey.toString(),
        secretKey: [], // not saving,
        authorizedPubkey: owner.toString(),
      },
      mintKeypair: {
        publicKey: mintKeypair.publicKey.toString(),
        secretKey: [] // not saving,
      },
      metadata: {
        metadataUri,
        amountToBuy: character.amountToBuy,
        useEliza,
      },
      owner: owner.toString(),
      bondingCurve: bondingCurve.toString(),
      associatedBondingCurve: associatedBondingCurve.toString(),
      tokenAddress: mintKeypair.publicKey.toString(),
      characterData: character,
      transactionDetails: {
        instructions: transactionInstructions.length,
        estimatedSize: signedTransaction.serialize().length,
        nonceValue: nonceInfo.nonce,
      }
    };

  } catch (error) {
    console.error("Error preparing token launch:", error);
    throw new Error(`Failed to prepare launch token: ${error.message || 'Unknown error'}`);
  }
}

Last updated