[Solana] nft 민팅 사이트 만들기 3탄 (캔디머신 컴포넌트)

0xDave·2022년 7월 24일
0

Solana

목록 보기
3/4

🚨 본 글은 잘못된 정보를 포함할 수 있습니다. 공부하면서 정리한 내용을 글로 작성한 것이니 너그러운 양해 부탁드립니다.

3탄에 들어서면서 점점 난이도가 높아짐을 체감한다. 아직 모르는 것이 많고 이해되지 않는 것들 투성이다. 잘못된 해석을 할까봐 두렵지만 하나씩 천천히 이해해보려고 한다.


.env 파일 만들기


app 폴더에 .env 파일을 하나 만든다.

REACT_APP_CANDY_MACHINE_ID= //캔디머신 주소 입력
REACT_APP_SOLANA_NETWORK= devnet
REACT_APP_SOLANA_RPC_HOST= https://explorer-api.devnet.solana.com

env파일은 환경변수 파일이라고 부르는데, 보통 오픈 소스에 업로드 하면 안되는 민감한 정보나 api key 값을 env 파일에 입력한다. 이렇나 정보들을 환경변수에 정의해서 보안과 유지보수에 용이하다.


useEffect() 추가


import React, { useEffect } from 'react';

...

const CandyMachine = ({ walletAddress }) => {

  ...
  
  useEffect(() => {
    getCandyMachineState();
  }, []);	
}

index.js 파일에 CandyMachine을 가져올 useEffect를 추가하고 그 밑에 솔라나 네트워크에 연결할 getProvider() 함수를 추가한다.

const getProvider = () => {
  const rpcHost = process.env.REACT_APP_SOLANA_RPC_HOST;
  // Create a new connection object
  const connection = new Connection(rpcHost);
  
  // Create a new Solana provider object
  const provider = new Provider(
    connection,
    window.solana,
    opts.preflightCommitment
  );

  return provider;
};

getCandyMachineState() 추가

useEffect에서 추가했던 getCandyMachineState() 함수를 작성한다. 여기서 봐야하는 것은 idl과 program이다. idl은 웹앱이 캔디머신과 상호작용하기 위해 필요한 정보들을 담고 있고, program은 캔디머신과 실제로 상호작용하기 위한 객체라고 볼 수 있다. 사실 아직도 이해하기 힘들다..

// Declare getCandyMachineState as an async method
const getCandyMachineState = async () => {
  const provider = getProvider();
  
  // Get metadata about your deployed candy machine program
  const idl = await Program.fetchIdl(candyMachineProgram, provider);

  // Create a program that you can call
  const program = new Program(idl, candyMachineProgram, provider);

  // Fetch the metadata from your candy machine
  const candyMachine = await program.account.candyMachine.fetch(
    process.env.REACT_APP_CANDY_MACHINE_ID
  );
  
  // Parse out all our metadata and log it out
  const itemsAvailable = candyMachine.data.itemsAvailable.toNumber();
  const itemsRedeemed = candyMachine.itemsRedeemed.toNumber();
  const itemsRemaining = itemsAvailable - itemsRedeemed;
  const goLiveData = candyMachine.data.goLiveDate.toNumber();
  const presale =
    candyMachine.data.whitelistMintSettings &&
    candyMachine.data.whitelistMintSettings.presale &&
    (!candyMachine.data.goLiveDate ||
      candyMachine.data.goLiveDate.toNumber() > new Date().getTime() / 1000);
  
  // We will be using this later in our UI so let's generate this now
  const goLiveDateTimeString = `${new Date(
    goLiveData * 1000
  ).toGMTString()}`

  console.log({
    itemsAvailable,
    itemsRedeemed,
    itemsRemaining,
    goLiveData,
    goLiveDateTimeString,
    presale,
  });
};

UseState() 추가


추가적으로 캔디머신의 상태를 입력받을 useState()를 만들어준다.

import React, { useEffect, useState } from 'react';
const CandyMachine({walletAddress}) => {
  // Add state property inside your component like this
  const [candyMachine, setCandyMachine] = useState(null);

  ...
  
  setCandyMachine({
      id: process.env.REACT_APP_CANDY_MACHINE_ID,
      program,
      state: {
        itemsAvailable,
        itemsRedeemed,
        itemsRemaining,
        goLiveData,
        goLiveDateTimeString,
        isSoldOut: itemsRemaining === 0,
        isActive:
          (presale ||
            candyMachine.data.goLiveDate.toNumber() < new Date().getTime() / 1000) &&
          (candyMachine.endSettings
            ? candyMachine.endSettings.endSettingType.date
              ? candyMachine.endSettings.number.toNumber() > new Date().getTime() / 1000
              : itemsRedeemed < candyMachine.endSettings.number.toNumber()
            : true),
        isPresale: presale,
        goLiveDate: candyMachine.data.goLiveDate,
        treasury: candyMachine.wallet,
        tokenMint: candyMachine.tokenMint,
        gatekeeper: candyMachine.data.gatekeeper,
        endSettings: candyMachine.data.endSettings,
        whitelistMintSettings: candyMachine.data.whitelistMintSettings,
        hiddenSettings: candyMachine.data.hiddenSettings,
        price: candyMachine.data.price,
      },
    });

그리고 마지막 return 부분에 보여주고 싶은 정보들을 담아서 컴포넌트를 완성한다.

return (
  // Only show this if machineStats is available
  candyMachine && (
    <div className="machine-container">
      <p>{`Drop Date: ${candyMachine.state.goLiveDateTimeString}`}</p>
      <p>{`Items Minted: ${candyMachine.state.itemsRedeemed} / ${candyMachine.state.itemsAvailable}`}</p>
      <button className="cta-button mint-button" onClick={null}>
          Mint NFT
      </button>
    </div>
  )
);

캔디머신 컴포넌트 가져오기


이제 대부분의 작업은 끝났다. App.js에 캔디머신 컴포넌트를 임포트해오고 팬텀 지갑이 연결됐을 때 캔디머신 컴포넌트가 나오도록 해준다.

import CandyMachine from './CandyMachine';
return (
    <div className="App">
      <div className="container">
        <div className="header-container">
          <p className="header">🍭 Candy Drop</p>
          <p className="sub-text">NFT drop machine with fair mint</p>
          {!walletAddress && renderNotConnectedContainer()}
        </div>
        {/* Check for walletAddress and then pass in walletAddress */}
      {walletAddress && <CandyMachine walletAddress={window.solana} />}
        <div className="footer-container">
          <img alt="Twitter Logo" className="twitter-logo" src={twitterLogo} />
          <a
            className="footer-text"
            href={TWITTER_LINK}
            target="_blank"
            rel="noreferrer"
          >{`built on @${TWITTER_HANDLE}`}</a>
        </div>
      </div>
    </div>
  );

민팅 페이지 완성


지갑을 연결하면 위 화면이 보이면서 민팅할 수 있게 나온다. 아직 민트 기능을 추가하지 않았기 때문에 Mint NFT를 눌러도 아무런 반응이 없지만 다음편에 민팅 기능에 대해 다룰 예정이다.

profile
Just BUIDL :)

0개의 댓글