Solana CookbookHow to create an NFTTo create an NFT you have to: Upload the image to IPFS like Arweave Upload the JSON metadata to Arweave or similar storage service. Call metaplex to create an account for the NFT Upload to Arweave upload-to-arweave.tsimport fs from "node:fs"; import Arweave from "arweave"; (async () => { const arweave = Arweave.init({ host: "localhost", port: 1984, protocol: "http", timeout: 20000, logging: false, }); const host = arweave.getConfig().api.host; const port = arweave.getConfig().api.port; const protocol = arweave.getConfig().api.protocol; // Upload image to Arweave const data = fs.readFileSync("./code/nfts/upload-arweave/lowres-dog.png"); const transaction = await arweave.createTransaction({ data: data, }); transaction.addTag("Content-Type", "image/png"); // Instead of generating a new wallet, you can use an existing one from your file system // useful in production environments // const wallet = JSON.parse(fs.readFileSync("./code/nfts/upload-arweave/wallet.json", "utf-8")) const wallet = await arweave.wallets.generate(); const address = await arweave.wallets.getAddress(wallet); console.log("address:, ", address); await arweave.api.get(`/mint/${encodeURI(addr)}/10000000000000000`); await arweave.transactions.sign(transaction, wallet); const response = await arweave.transactions.post(transaction); console.log(response); const id = transaction.id; const imageUrl = id ? `${protocol}://${host}:${port}/${id}` : null; console.log("imageUrl", imageUrl); // Upload metadata to Arweave const metadata = { name: "Custom NFT #1", symbol: "CNFT", description: "A description about my custom NFT #1", seller_fee_basis_points: 500, external_url: "https://www.customnft.com/", attributes: [ { trait_type: "NFT type", value: "Custom", }, ], collection: { name: "Test Collection", family: "Custom NFTs", }, properties: { files: [ { uri: imageUrl, type: "image/png", }, ], category: "image", maxSupply: 0, creators: [ { address: "CBBUMHRmbVUck99mTCip5sHP16kzGj3QTYB8K3XxwmQx", share: 100, }, ], }, image: imageUrl, }; const metadataString = JSON.stringify(metadata); const metadataTransaction = await arweave.createTransaction({ data: metadataString, }); metadataTransaction.addTag("Content-Type", "application/json"); await arweave.transactions.sign(metadataTransaction, wallet); console.log("metadata txid", metadataTransaction.id); const txnResult = await arweave.transactions.post(metadataTransaction); console.log(txnResult); })(); Mint the NFT mint-nft.tsimport { createUmi } from "@metaplex-foundation/umi-bundle-defaults"; import { generateSigner, percentAmount, keypairIdentity, } from "@metaplex-foundation/umi"; import { clusterApiUrl } from "@solana/web3.js"; import { createNft, fetchDigitalAsset, mplTokenMetadata, } from "@metaplex-foundation/mpl-token-metadata"; import "dotenv/config"; (async () => { try { console.log("Loading keypair from environment..."); const privateKey = JSON.parse(process.env.SOLANA_PRIVATE_KEY || "[]"); if (privateKey.length === 0) { throw new Error("SOLANA_PRIVATE_KEY is not set in .env file"); } console.log("Creating Umi instance..."); const umi = createUmi(clusterApiUrl("devnet")); const keypair = umi.eddsa.createKeypairFromSecretKey( new Uint8Array(privateKey), ); // Use keypairIdentity to set the keypair as the signer const signer = keypairIdentity(keypair); umi.use(signer); umi.use(mplTokenMetadata()); console.log("Keypair loaded. Public key:", keypair.publicKey); console.log("Generating new mint address..."); const mint = generateSigner(umi); console.log("Creating NFT..."); const { signature } = await createNft(umi, { mint, name: "My NFT", // Replace this with your Arweave metadata URI uri: "https://ffaaqinzhkt4ukhbohixfliubnvpjgyedi3f2iccrq4efh3s.arweave.net/KUAIIbk6p8oo4XHRcq0U__C2r0mwQaNl0gQow4Qp9yk", maxSupply: 1, sellerFeeBasisPoints: percentAmount(0), creators: [ { address: keypair.publicKey, share: 100, verified: true, }, ], }).sendAndConfirm(umi); console.log("NFT created successfully!"); console.log("Mint address:", mint.publicKey); console.log("Transaction signature:", signature); console.log("Fetching digital asset..."); const asset = await fetchDigitalAsset(umi, mint.publicKey); console.log("Digital Asset:", asset); } catch (error) { console.error("Error:", error); console.error("Stack trace:", error.stack); } })();