mintCnft.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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. randomUri // uri
  57. )
  58. .accounts({
  59. tree_authority: treeAuthority, // treeAuthority
  60. leaf_owner: account, // leafOwner
  61. leaf_delegate: account, // leafDelegate
  62. merkle_tree: account, // merkleTree
  63. payer: account, // payer
  64. tree_delegate: account, // treeDelegate, public tree (no delegate check, just require signer)
  65. noop_address: SPL_NOOP_PROGRAM_ID,
  66. compression_pid: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
  67. bubblegum_pid: BUBBLEGUM_PROGRAM_ID,
  68. })
  69. .instruction()
  70. // Add the reference account to the instruction
  71. // Used in client to find the transaction once sent
  72. instruction.keys.push({
  73. pubkey: reference,
  74. isSigner: false,
  75. isWritable: false,
  76. })
  77. const latestBlockhash = await connection.getLatestBlockhash()
  78. // create new Transaction and add instruction
  79. const transaction = new Transaction({
  80. feePayer: account,
  81. blockhash: latestBlockhash.blockhash,
  82. lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
  83. }).add(instruction)
  84. return transaction
  85. .serialize({ requireAllSignatures: false })
  86. .toString("base64")
  87. }
  88. export default async function handler(
  89. req: NextApiRequest,
  90. res: NextApiResponse
  91. ) {
  92. if (req.method === "GET") {
  93. return get(res)
  94. } else if (req.method === "POST") {
  95. return await post(req, res)
  96. } else {
  97. return res.status(405).json({ error: "Method not allowed" })
  98. }
  99. }