mintCnft.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { NextApiRequest, NextApiResponse } from "next"
  2. import { PublicKey, SystemProgram, Transaction } from "@solana/web3.js"
  3. import {
  4. SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
  5. SPL_NOOP_PROGRAM_ID,
  6. } from "@solana/spl-account-compression"
  7. import { PROGRAM_ID as BUBBLEGUM_PROGRAM_ID } from "@metaplex-foundation/mpl-bubblegum"
  8. import { program, connection, treeAddress } from "@/utils/setup"
  9. import { uris } from "@/utils/uri"
  10. function get(res: NextApiResponse) {
  11. res.status(200).json({
  12. label: "My Store",
  13. icon: "https://solana.com/src/img/branding/solanaLogoMark.svg",
  14. })
  15. }
  16. async function post(req: NextApiRequest, res: NextApiResponse) {
  17. const { account } = req.body
  18. const { reference } = req.query
  19. if (!account || !reference) {
  20. res.status(400).json({
  21. error: "Required data missing. Account or reference not provided.",
  22. })
  23. return
  24. }
  25. try {
  26. const transaction = await buildTransaction(
  27. new PublicKey(account),
  28. new PublicKey(reference)
  29. )
  30. res.status(200).json({
  31. transaction,
  32. message: "Please approve the transaction to mint your NFT!",
  33. })
  34. } catch (error) {
  35. console.error(error)
  36. res.status(500).json({ error: "error creating transaction" })
  37. return
  38. }
  39. }
  40. async function buildTransaction(account: PublicKey, reference: PublicKey) {
  41. // Required solang dataAccount, even though we're not using it.
  42. const [dataAccount] = PublicKey.findProgramAddressSync(
  43. [Buffer.from("seed")],
  44. program.programId
  45. )
  46. // tree authority
  47. const [treeAuthority] = PublicKey.findProgramAddressSync(
  48. [treeAddress.toBuffer()],
  49. BUBBLEGUM_PROGRAM_ID
  50. )
  51. // Randomly select a uri.
  52. const randomUri = uris[Math.floor(Math.random() * uris.length)]
  53. // Initialize the dataAccount.
  54. const instruction = await program.methods
  55. .mint(
  56. treeAuthority, // treeAuthority
  57. account, // leafOwner
  58. account, // leafDelegate
  59. treeAddress, // merkleTree
  60. account, // payer
  61. account, // treeDelegate, public tree (no delegate check, just require signer)
  62. randomUri // uri
  63. )
  64. .accounts({ dataAccount: dataAccount })
  65. .remainingAccounts([
  66. {
  67. pubkey: account,
  68. isWritable: true,
  69. isSigner: true,
  70. },
  71. {
  72. pubkey: treeAuthority,
  73. isWritable: true,
  74. isSigner: false,
  75. },
  76. {
  77. pubkey: treeAddress,
  78. isWritable: true,
  79. isSigner: false,
  80. },
  81. {
  82. pubkey: SPL_NOOP_PROGRAM_ID,
  83. isWritable: false,
  84. isSigner: false,
  85. },
  86. {
  87. pubkey: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
  88. isWritable: false,
  89. isSigner: false,
  90. },
  91. {
  92. pubkey: BUBBLEGUM_PROGRAM_ID,
  93. isWritable: false,
  94. isSigner: false,
  95. },
  96. {
  97. pubkey: SystemProgram.programId,
  98. isWritable: false,
  99. isSigner: false,
  100. },
  101. ])
  102. .instruction()
  103. // Add the reference account to the instruction
  104. // Used in client to find the transaction once sent
  105. instruction.keys.push({
  106. pubkey: reference,
  107. isSigner: false,
  108. isWritable: false,
  109. })
  110. const latestBlockhash = await connection.getLatestBlockhash()
  111. // create new Transaction and add instruction
  112. const transaction = new Transaction({
  113. feePayer: account,
  114. blockhash: latestBlockhash.blockhash,
  115. lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
  116. }).add(instruction)
  117. return transaction
  118. .serialize({ requireAllSignatures: false })
  119. .toString("base64")
  120. }
  121. export default async function handler(
  122. req: NextApiRequest,
  123. res: NextApiResponse
  124. ) {
  125. if (req.method === "GET") {
  126. return get(res)
  127. } else if (req.method === "POST") {
  128. return await post(req, res)
  129. } else {
  130. return res.status(405).json({ error: "Method not allowed" })
  131. }
  132. }