How to create an NFT
To 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.ts
import 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.ts
import { 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);
}
})();