Non Fungible Token (NFTs)

Paano lumikha ng isang NFT

Upang lumikha ng isang NFT kailangan mong:

  1. I-upload ang larawan sa IPFS tulad ng Arweave
  2. I-upload ang json metadata sa IPFS tulad ng Arweave
  3. Tumawag sa metaplex para gumawa ng account para sa NFT

I-upload sa Arweave

Press </> button to view full source
import fs from "fs";
import Arweave from "arweave";

(async () => {
  const arweave = Arweave.init({
    host: "arweave.net",
    port: 443,
    protocol: "https",
    timeout: 20000,
    logging: false,
  });

  // Upload image to Arweave
  const data = fs.readFileSync("./code/nfts/arweave-upload/lowres-dog.png");

  const transaction = await arweave.createTransaction({
    data: data,
  });

  transaction.addTag("Content-Type", "image/png");

  const wallet = JSON.parse(fs.readFileSync("wallet.json", "utf-8"))
  
  await arweave.transactions.sign(transaction, wallet);

  const response = await arweave.transactions.post(transaction);
  console.log(response);

  const id = transaction.id;
  const imageUrl = id ? `https://arweave.net/${id}` : undefined;
  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 metadataRequest = JSON.stringify(metadata);

  const metadataTransaction = await arweave.createTransaction({
    data: metadataRequest,
  });

  metadataTransaction.addTag("Content-Type", "application/json");

  await arweave.transactions.sign(metadataTransaction, wallet);

  console.log("metadata txid", metadataTransaction.id);

  console.log(await arweave.transactions.post(metadataTransaction));
})();
from arweave.arweave_lib import Wallet, Transaction, API_URL
import json

# Load your arweave wallet
your_ar_wallet = Wallet('wallet.json')

with open('./code/nfts/arweave-upload/lowres-dog.png', 'rb') as f:
    img_in_bytes = f.read()

# Upload image to Arweave
transaction = Transaction(your_ar_wallet, data=img_in_bytes)
transaction.add_tag('Content-Type', 'image/png')
transaction.sign()
transaction.send()

image_url = API_URL+"/"+transaction.id

# Define metadata
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": image_url,
                "type": "image/png",
            },
        ],
        "category": "image",
        "maxSupply": 0,
        "creators": [
            {
                "address": "CBBUMHRmbVUck99mTCip5sHP16kzGj3QTYB8K3XxwmQx",
                "share": 100,
            },
        ],
    },
    "image": image_url,
}

# Upload metadata to Arweave
meta_transaction = Transaction(your_ar_wallet, data=json.dumps(metadata))
meta_transaction.add_tag('Content-Type', 'text/html')
meta_transaction.sign()
meta_transaction.send()

metadata_url = API_URL+"/"+meta_transaction.id

print(metadata_url)

Mint ang NFT

Kung na-upload mo na ang larawan at metadata, maaari kang mag-mint ang NFT na may sumusunod na code.

Press </> button to view full source
import { Metaplex, keypairIdentity } from "@metaplex-foundation/js";
import {
  Connection,
  clusterApiUrl,
  Keypair,
  LAMPORTS_PER_SOL,
} from "@solana/web3.js";
import dotenv from "dotenv";

dotenv.config();

(async () => {
  const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
  const keypair = Keypair.fromSecretKey(
    Buffer.from(JSON.parse(process.env.SOLANA_KEYPAIR!.toString()))
  );

  const metaplex = new Metaplex(connection);
  metaplex.use(keypairIdentity(keypair));

  const feePayerAirdropSignature = await connection.requestAirdrop(
    keypair.publicKey,
    LAMPORTS_PER_SOL
  );
  await connection.confirmTransaction(feePayerAirdropSignature);

  const mintNFTResponse = await metaplex.nfts().create({
    uri: "https://ffaaqinzhkt4ukhbohixfliubnvpjgyedi3f2iccrq4efh3s.arweave.net/KUAIIbk6p8oo4XHRcq0U__C2r0mwQaNl0gQow4Qp9yk",
    maxSupply: 1,
  });

  console.log(mintNFTResponse);
})();

Tandaan

Hindi ka makakagawa ng NFT na may ibang tagalikha kaysa sa iyong wallet. Kung magkakaroon ka ng mga isyu sa creator, tiyaking inilista ka ng iyong metadata bilang lumikha.

Paano makakuha ng NFT Metadata

Ang mga Metaplex NFT ay may metadata na nakaimbak sa Arweave. Sa pagkakasunud-sunod para makuha ang Arweave metadata, dapat mong makuha ang Metaplex PDA at i-decode ang data ng account.

Press </> button to view full source
import { Metaplex, keypairIdentity } from "@metaplex-foundation/js";
import { Connection, clusterApiUrl, Keypair, PublicKey } from "@solana/web3.js";

(async () => {
  const connection = new Connection(clusterApiUrl("mainnet-beta"));
  const keypair = Keypair.generate();

  const metaplex = new Metaplex(connection);
  metaplex.use(keypairIdentity(keypair));

  const mintAddress = new PublicKey(
    "Ay1U9DWphDgc7hq58Yj1yHabt91zTzvV2YJbAWkPNbaK"
  );

  const nft = await metaplex.nfts().findByMint({ mintAddress });

  console.log(nft.json);
  /*
  {
    name: 'SMB #139',
    symbol: 'SMB',
    description: 'SMB is a collection of 5000 randomly generated 24x24 pixels NFTs on the Solana Blockchain. Each SolanaMonkey is unique and comes with different type and attributes varying in rarity.',
    seller_fee_basis_points: 600,
    image: 'https://arweave.net/tZrNpbFUizSoFnyTqP4n2e1Tf7WvP3siUwFWKMMid_Q',
    external_url: 'https://solanamonkey.business/',
    collection: { name: 'SMB Gen2', family: 'SMB' },
    attributes: [
      { trait_type: 'Attributes Count', value: 2 },
      { trait_type: 'Type', value: 'Solana' },
      { trait_type: 'Clothes', value: 'Orange Shirt' },
      { trait_type: 'Ears', value: 'None' },
      { trait_type: 'Mouth', value: 'None' },
      { trait_type: 'Eyes', value: 'Cool Glasses' },
      { trait_type: 'Hat', value: 'None' }
    ],
    properties: {
      files: [ [Object], [Object] ],
      category: 'image',
      creators: [ [Object] ]
    }
  }
  */
})();

Paano makuha ang may-ari ng isang NFT

Kung mayroon kang mint key ng isang NFT, mahahanap mo ang kasalukuyang may-ari nito sa pamamagitan ng sneak-peeking sa pinakamalaking token account para sa mint key na iyon.

Tandaan na ang mga NFT ay may supply na 1, at sila ay hindi mahahati, ibig sabihin, isang token account lang ang hahawak ng token na iyon kahit saan punto sa oras, habang ang lahat ng iba pang mga token account para sa mint key na iyon may balanseng 0.

Kapag natukoy na ang pinakamalaking token account, maaari nating makuha ang may-ari nito.

Press </> button to view full source
import { Connection, PublicKey } from "@solana/web3.js";

(async () => {
  const connection = new Connection("https://api.mainnet-beta.solana.com");
  const tokenMint = "9ARngHhVaCtH5JFieRdSS5Y8cdZk2TMF4tfGSWFB9iSK";

  const largestAccounts = await connection.getTokenLargestAccounts(
    new PublicKey(tokenMint)
  );
  const largestAccountInfo = await connection.getParsedAccountInfo(
    largestAccounts.value[0].address
  );
  console.log(largestAccountInfo.value.data.parsed.info.owner);
  /*
    PublicKey {
        _bn: <BN: 6ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9>
    }
     */
})();

Paano makakuha ng NFT Mint Address

Kung alam mo ang pampublikong key ng Candy Machine, maaari mong makuha ang listahan ng lahat ng NFT mint address na nabuo mula sa Candy Machine na iyon gamit ang sumusunod na code. Tandaan na maaari nating gamitin ang sumusunod na memcmp na filter dahil, sa v1, ang unang gumawa ay palaging ang address ng Candy Machine.

Candy Machine V1

Press </> button to view full source
import { Connection, clusterApiUrl, PublicKey } from "@solana/web3.js";
import bs58 from "bs58";

const connection = new Connection(clusterApiUrl("mainnet-beta"));
const MAX_NAME_LENGTH = 32;
const MAX_URI_LENGTH = 200;
const MAX_SYMBOL_LENGTH = 10;
const MAX_CREATOR_LEN = 32 + 1 + 1;
const MAX_CREATOR_LIMIT = 5;
const MAX_DATA_SIZE =
  4 +
  MAX_NAME_LENGTH +
  4 +
  MAX_SYMBOL_LENGTH +
  4 +
  MAX_URI_LENGTH +
  2 +
  1 +
  4 +
  MAX_CREATOR_LIMIT * MAX_CREATOR_LEN;
const MAX_METADATA_LEN = 1 + 32 + 32 + MAX_DATA_SIZE + 1 + 1 + 9 + 172;
const CREATOR_ARRAY_START =
  1 +
  32 +
  32 +
  4 +
  MAX_NAME_LENGTH +
  4 +
  MAX_URI_LENGTH +
  4 +
  MAX_SYMBOL_LENGTH +
  2 +
  1 +
  4;

const TOKEN_METADATA_PROGRAM = new PublicKey(
  "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
);
const candyMachineId = new PublicKey("ENTER_YOUR_CANDY_MACHINE_ID_HERE");

const getMintAddresses = async (firstCreatorAddress: PublicKey) => {
  const metadataAccounts = await connection.getProgramAccounts(
    TOKEN_METADATA_PROGRAM,
    {
      // The mint address is located at byte 33 and lasts for 32 bytes.
      dataSlice: { offset: 33, length: 32 },

      filters: [
        // Only get Metadata accounts.
        { dataSize: MAX_METADATA_LEN },

        // Filter using the first creator.
        {
          memcmp: {
            offset: CREATOR_ARRAY_START,
            bytes: firstCreatorAddress.toBase58(),
          },
        },
      ],
    }
  );

  return metadataAccounts.map((metadataAccountInfo) =>
    bs58.encode(metadataAccountInfo.account.data)
  );
};

getMintAddresses(candyMachineId);

Candy Machine V2

Kung gumagamit ka ng Candy Machine v2, kakailanganin mo munang i-access ang "Candy Machine Creator" address nito na isang simpleng PDA gamit ang candy_machine at ang Candy Machine v2 address bilang mga buto. Kapag mayroon ka na ng address ng tagalikha, magagamit mo ito sa parehong paraan na ginamit namin para sa v1.

Press </> button to view full source
import { Connection, clusterApiUrl, PublicKey } from "@solana/web3.js";
import bs58 from "bs58";

const connection = new Connection(clusterApiUrl("mainnet-beta"));
const MAX_NAME_LENGTH = 32;
const MAX_URI_LENGTH = 200;
const MAX_SYMBOL_LENGTH = 10;
const MAX_CREATOR_LEN = 32 + 1 + 1;
const MAX_CREATOR_LIMIT = 5;
const MAX_DATA_SIZE =
  4 +
  MAX_NAME_LENGTH +
  4 +
  MAX_SYMBOL_LENGTH +
  4 +
  MAX_URI_LENGTH +
  2 +
  1 +
  4 +
  MAX_CREATOR_LIMIT * MAX_CREATOR_LEN;
const MAX_METADATA_LEN = 1 + 32 + 32 + MAX_DATA_SIZE + 1 + 1 + 9 + 172;
const CREATOR_ARRAY_START =
  1 +
  32 +
  32 +
  4 +
  MAX_NAME_LENGTH +
  4 +
  MAX_URI_LENGTH +
  4 +
  MAX_SYMBOL_LENGTH +
  2 +
  1 +
  4;

const TOKEN_METADATA_PROGRAM = new PublicKey(
  "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
);
const CANDY_MACHINE_V2_PROGRAM = new PublicKey(
  "cndy3Z4yapfJBmL3ShUp5exZKqR3z33thTzeNMm2gRZ"
);
const candyMachineId = new PublicKey("ENTER_YOUR_CANDY_MACHINE_ID_HERE");

const getMintAddresses = async (firstCreatorAddress: PublicKey) => {
  const metadataAccounts = await connection.getProgramAccounts(
    TOKEN_METADATA_PROGRAM,
    {
      // The mint address is located at byte 33 and lasts for 32 bytes.
      dataSlice: { offset: 33, length: 32 },

      filters: [
        // Only get Metadata accounts.
        { dataSize: MAX_METADATA_LEN },

        // Filter using the first creator.
        {
          memcmp: {
            offset: CREATOR_ARRAY_START,
            bytes: firstCreatorAddress.toBase58(),
          },
        },
      ],
    }
  );

  return metadataAccounts.map((metadataAccountInfo) =>
    bs58.encode(metadataAccountInfo.account.data)
  );
};

const getCandyMachineCreator = async (
  candyMachine: PublicKey
): Promise<[PublicKey, number]> =>
  PublicKey.findProgramAddress(
    [Buffer.from("candy_machine"), candyMachine.toBuffer()],
    CANDY_MACHINE_V2_PROGRAM
  );

(async () => {
  const candyMachineCreator = await getCandyMachineCreator(candyMachineId);
  getMintAddresses(candyMachineCreator[0]);
})();

Paano makukuha ang lahat ng NFT mula sa isang wallet?

Kapag nakuha ang lahat ng NFT mula sa isang wallet, kakailanganin mong makuha ang lahat ng token account at pagkatapos ay i-parse kung alin ang mga NFT. Magagawa ang lahat ng ito gamit ang findDataByOwneropen in new window mula sa Metaplex JS library.

Press </> button to view full source
import { Metaplex, keypairIdentity } from "@metaplex-foundation/js";
import { Connection, clusterApiUrl, Keypair, PublicKey } from "@solana/web3.js";

(async () => {
  const connection = new Connection(clusterApiUrl("mainnet-beta"), "confirmed");
  const keypair = Keypair.generate();

  const metaplex = new Metaplex(connection);
  metaplex.use(keypairIdentity(keypair));

  const owner = new PublicKey("2R4bHmSBHkHAskerTHE6GE1Fxbn31kaD5gHqpsPySVd7");
  const allNFTs = await metaplex.nfts().findAllByOwner({ owner });

  console.log(allNFTs);
})();

Candy Machine v2

Sinusuportahan na ngayon ng Metaplex JS SDK ang paggawa at pag-update ng Candy Machine v2 sa pamamagitan ng code. Nagbibigay-daan ito sa mga developer na makipag-ugnayan sa programang Candy Machine v2 at lumikha, mag-update, at magtanggal ng mga Candy Machine pati na rin ang mga mint na NFT mula sa kanila.

Paano gumawa ng Candy Machine

Press </> button to view full source
import {
  keypairIdentity,
  Metaplex,
  sol,
  toBigNumber,
} from "@metaplex-foundation/js";
import { Keypair, Connection, LAMPORTS_PER_SOL } from "@solana/web3.js";

const createCandyMachine = async () => {
  const connection = new Connection(
    "https://api.devnet.solana.com/",
    "confirmed"
  );
  const payer = Keypair.generate();

  // request airdrop
  const airdropSignature = await connection.requestAirdrop(
    payer.publicKey,
    2 * LAMPORTS_PER_SOL
  );

  console.log(`Airdrop signature - ${airdropSignature}`);

  // creating metaplex instance with payer as the authority
  const metaplex = Metaplex.make(connection).use(keypairIdentity(payer));

  // creating a candy machine
  const { candyMachine } = await metaplex.candyMachinesV2().create({
    sellerFeeBasisPoints: 5, // 0.05% royalties
    price: sol(0.0001), // 0.0001 SOL
    itemsAvailable: toBigNumber(5), // 5 items available
  });

  console.log(`Candy Machine ID - ${candyMachine.address.toString()}`);
};

createCandyMachine();

How to delete a Candy Machine

Press </> button to view full source
import {
  Metaplex,
  keypairIdentity,
  sol,
  toBigNumber,
} from "@metaplex-foundation/js";
import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";

const deleteCandyMachine = async () => {
  const connection = new Connection(
    "https://api.devnet.solana.com/",
    "confirmed"
  );
  const payer = Keypair.generate();

  // request airdrop
  const airdropSignature = await connection.requestAirdrop(
    payer.publicKey,
    2 * LAMPORTS_PER_SOL
  );

  console.log(`Airdrop signature - ${airdropSignature}`);

  // creating metaplex instance with payer as the authority
  const metaplex = Metaplex.make(connection).use(keypairIdentity(payer));

  // creating a candy machine
  const { candyMachine } = await metaplex.candyMachinesV2().create({
    sellerFeeBasisPoints: 5, // 0.05% royalties
    price: sol(0.0001), // 0.0001 SOL
    itemsAvailable: toBigNumber(5), // 5 items available
  });

  console.log(`Candy Machine ID - ${candyMachine.address.toString()}`);

  // deleting the candy machine
  const { response } = await metaplex.candyMachinesV2().delete({
    candyMachine,
  });

  console.log(`Delete Candy Machine signature - ${response.signature}`);
};

deleteCandyMachine();

Paano makahanap ng Candy Machine sa pamamagitan ng awtoridad

Upang mahanap ang lahat ng Candy Machine na ang awtoridad ay isang partikular na pampublikong key, ginamit namin ang function na findAllByopen in new window. na may parameter na type bilang authority

Press </> button to view full source
import { Connection, PublicKey } from "@solana/web3.js";
import { Metaplex } from "@metaplex-foundation/js";

const findCandyMachineViaAuthority = async () => {
  const connection = new Connection(
    "https://api.devnet.solana.com/",
    "confirmed"
  );
  const metaplex = new Metaplex(connection);
  const authority = new PublicKey(
    "9pr8wNxphx2PhBRbHKuH7YhPs5zbDuxx62UcDiayXxrw"
  );

  const candyMachines = await metaplex.candyMachinesV2().findAllBy({
    type: "authority",
    publicKey: authority,
  });

  candyMachines.map((candyMachine, index) => {
    console.log(`#${index + 1} Candy Machine ID - ${candyMachine.address}`);
  });

  /**
   * #1 Candy Machine ID - HSZxtWx6vgGWGsWu9SouXkHA2bAKCMtMZyMKzF2dvhrR
   */
};

findCandyMachineViaAuthority();

Paano makahanap ng Candy Machine gamit ang address ng wallet

Upang kunin ang object ng Candy Machine sa pamamagitan ng wallet address nito, ginamit namin ang function na findAllByopen in new window kasama ng type na parameter bilang wallet. Makukuha mo ang wallet address ng Candy Machine mula sa tab na "Anchor data" sa explorer.

Press </> button to view full source
import { Connection, PublicKey } from "@solana/web3.js";
import { Metaplex } from "@metaplex-foundation/js";

const findCandyMachineViaWallet = async () => {
  const connection = new Connection(
    "https://api.devnet.solana.com/",
    "confirmed"
  );
  const metaplex = new Metaplex(connection);
  const wallet = new PublicKey("9pr8wNxphx2PhBRbHKuH7YhPs5zbDuxx62UcDiayXxrw");

  const candyMachines = await metaplex.candyMachinesV2().findAllBy({
    type: "wallet",
    publicKey: wallet,
  });

  candyMachines.map((candyMachine, index) => {
    console.log(`#${index + 1} Candy Machine ID - ${candyMachine.address}`);
  });

  /**
   * #1 Candy Machine ID - HSZxtWx6vgGWGsWu9SouXkHA2bAKCMtMZyMKzF2dvhrR
   */
};

findCandyMachineViaWallet();

Paano mahahanap ang Candy Machine gamit ang address nito

Upang makahanap ng Candy Machine gamit ang address nito, kailangan nating gamitin ang function na findByAddressopen in new window.

Press </> button to view full source
import { Connection, PublicKey } from "@solana/web3.js";
import { Metaplex } from "@metaplex-foundation/js";

const findCandyMachineViaAddress = async () => {
  const connection = new Connection(
    "https://api.devnet.solana.com/",
    "confirmed"
  );
  const metaplex = new Metaplex(connection);
  const candyMachineId = new PublicKey(
    "HSZxtWx6vgGWGsWu9SouXkHA2bAKCMtMZyMKzF2dvhrR"
  );

  const candyMachine = await metaplex.candyMachinesV2().findByAddress({
    address: candyMachineId,
  });
};

findCandyMachineViaAddress();

How to find minted NFTs from a Candy Machine

Press </> button to view full source
import { Connection, PublicKey } from "@solana/web3.js";
import { Metaplex } from "@metaplex-foundation/js";

const findCandyMachineMintedNfts = async () => {
  const connection = new Connection(
    "https://api.devnet.solana.com/",
    "confirmed"
  );
  const metaplex = new Metaplex(connection);
  const candyMachineId = new PublicKey(
    "HSZxtWx6vgGWGsWu9SouXkHA2bAKCMtMZyMKzF2dvhrR"
  );

  const candyMachine = await metaplex.candyMachinesV2().findMintedNfts({
    candyMachine: candyMachineId,
  });
};

findCandyMachineMintedNfts();

How to insert items into a Candy Machine

Press </> button to view full source
import { Connection, PublicKey } from "@solana/web3.js";
import { Metaplex } from "@metaplex-foundation/js";

const insertItems = async () => {
  const connection = new Connection(
    "https://api.devnet.solana.com/",
    "confirmed"
  );
  const metaplex = new Metaplex(connection);
  const candyMachineId = new PublicKey(
    "HSZxtWx6vgGWGsWu9SouXkHA2bAKCMtMZyMKzF2dvhrR"
  );

  await metaplex.candyMachines().insertItems({
    candyMachineId,
    items: [
      { name: "My NFT #1", uri: "https://example.com/nft1" },
      { name: "My NFT #2", uri: "https://example.com/nft2" },
      { name: "My NFT #3", uri: "https://example.com/nft3" },
    ],
  });
};

insertItems();

Paano mag-mint ng NFT mula sa isang Candy Machine

Bilang default, ang may-ari ng minted NFT ay magiging metaplex.identity().publicKey. Kung gusto mong i-mint ang NFT sa ibang wallet, ipasa ang public key na iyon kasama ng parameter na newOwner

Press </> button to view full source
import { Connection, PublicKey } from "@solana/web3.js";
import { Metaplex } from "@metaplex-foundation/js";

const mintNft = async () => {
  const connection = new Connection(
    "https://api.devnet.solana.com/",
    "confirmed"
  );
  const metaplex = new Metaplex(connection);
  const candyMachineId = new PublicKey(
    "HSZxtWx6vgGWGsWu9SouXkHA2bAKCMtMZyMKzF2dvhrR"
  );

  // by default, the owner of the minted nft would be `metaplex.identity().publicKey`. if you want to mint the nft to some other wallet, pass that public key along with the `newOwner` parameter
  const candyMachine = await metaplex.candyMachinesV2().mint({
    candyMachine: candyMachineId,
    // newOwner: new PublicKey("some-other-public-key");
  });
};

mintNft();
Last Updated:
Contributors: mh