NFT를 만드는 방법
작성자: Alchemy Team
이 튜토리얼에서는 Ethereum과 Inter Planetary File System (IPFS)을 사용하여 Non Fungible (ERC721) Token 스마트 컨트랙트를 작성하고 배포하는 과정을 다룹니다.
가이드 예상 소요 시간: 약 15분
바위 밑에서 살고 있었다 해도, 모든 주요 뉴스 매체가 NFT의 부상을 다루고 있다는 것을 눈치챘을 것입니다.
NFT가 블록체인을 대중의 눈앞으로 끌어낸 지금, 직접 Ethereum 블록체인에 자신만의 NFT (ERC-721 Token)를 게시해봄으로써 이 열풍을 이해해볼 좋은 기회입니다!
이 튜토리얼에서는 Metamask, Solidity, Hardhat, Pinata, Alchemy를 사용하여 Sepolia 테스트 네트워크에 ERC-721 스마트 컨트랙트를 생성하고 배포하는 과정을 살펴봅니다 (아직 이 용어들이 무엇을 의미하는지 몰라도 괜찮습니다. 차차 설명하겠습니다). 이 튜토리얼의 Part II에서는 작성한 스마트 컨트랙트를 사용해 NFT를 민팅하는 방법을 다루고, Part III에서는 Metamask에서 NFT를 확인하는 방법을 다룹니다.
그리고 진행 중 궁금한 점이 있다면 언제든지 Alchemy 지원 센터를 방문하세요!
1단계: Ethereum 네트워크에 연결하기
Ethereum 블록체인에 요청을 보내는 방법은 여러 가지가 있지만, 가장 쉬운 방법으로 Alchemy의 무료 계정을 사용하겠습니다. Alchemy는 블록체인 개발자 플랫폼이자 API로, 직접 노드를 운영하지 않고도 Ethereum 체인과 통신할 수 있게 해줍니다.
이 튜토리얼에서는 스마트 컨트랙트 배포 과정에서 내부적으로 어떤 일이 일어나는지 파악하기 위해 Alchemy의 모니터링 및 분석 개발자 도구도 활용하겠습니다. 아직 Alchemy 계정이 없다면 여기에서 무료로 가입할 수 있습니다.
2단계: 앱 생성하기 (및 API 키 발급)
Alchemy 계정을 생성했다면, 앱을 만들어 API 키를 발급받을 수 있습니다. 이 키를 통해 Sepolia 테스트 네트워크에 요청을 보낼 수 있습니다. 테스트 네트워크에 대해 더 알아보고 싶다면 이 가이드를 참고하세요.
- Alchemy Dashboard의 내비게이션 바에서 "Apps"에 마우스를 올려 "Create App"을 클릭하고 "Create App" 페이지로 이동합니다

- 앱 이름을 지정하고 (여기서는 "My First NFT!"로 지정했습니다), 간단한 설명을 입력한 후 Environment로 "Staging"을 선택합니다 (앱 관리용). Network는 "Sepolia"를 선택합니다.

- "Create app"을 클릭하면 끝입니다! 아래 표에 앱이 나타날 것입니다.
3단계: Ethereum 계정 (주소) 생성하기
트랜잭션을 주고받으려면 Ethereum 계정이 필요합니다. 이 튜토리얼에서는 브라우저에서 Ethereum 계정 주소를 관리하는 가상 지갑인 Metamask를 사용합니다. Ethereum에서 트랜잭션이 어떻게 작동하는지 더 알고 싶다면 Ethereum 재단의 이 페이지를 참고하세요.
여기에서 Metamask를 무료로 다운로드하고 계정을 생성할 수 있습니다. 계정을 생성할 때 (또는 이미 계정이 있다면), 실제 자금을 다루지 않도록 Sepolia 테스트 네트워크로 전환해야 합니다.

4단계: 파우셋에서 ether 받기
스마트 컨트랙트를 테스트 네트워크에 배포하려면 가짜 Eth가 필요합니다. Eth를 받으려면 Sepolia 파우셋으로 이동하여 Sepolia 계정 주소를 입력하고 Sepolia Eth를 요청하면 됩니다. 곧 Metamask 계정에 Eth가 표시될 것입니다!
5단계: 잔액 확인하기
잔액이 제대로 들어왔는지 확인하기 위해, Alchemy의 composer 도구를 사용해 eth_getBalance 요청을 보내봅시다. 이 요청은 우리 지갑에 있는 Eth 양을 반환합니다. Metamask 계정 주소를 입력하고 "Send Request"를 클릭하면 다음과 같은 응답을 볼 수 있습니다:
{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}
참고: 이 결과는 eth가 아니라 wei 단위입니다. Wei는 ether의 가장 작은 단위로 사용됩니다. wei에서 eth로의 변환은 다음과 같습니다: 1 eth = 10¹⁸ wei. 따라서 0xde0b6b3a7640000을 10진수로 변환하면 1*10¹⁸이 되며, 이는 1 eth와 같습니다.
좋습니다! 가짜 돈이 모두 들어왔군요! 🤑
6단계: 프로젝트 초기화하기
먼저, 프로젝트를 위한 폴더를 생성해야 합니다. 명령줄로 이동하여 다음을 입력합니다:
프로젝트 폴더 안에 들어왔다면, npm init을 사용하여 프로젝트를 초기화합니다. npm이 아직 설치되어 있지 않다면 다음 안내를 따르세요 (Node.js도 필요하니 함께 다운로드하세요!).
설치 질문에 어떻게 답하든 크게 상관없지만, 참고용으로 저희가 답한 방식은 다음과 같습니다:
package.json을 승인하면 준비가 끝납니다!
7단계: Hardhat 다운로드하기
Hardhat은 Ethereum 소프트웨어를 컴파일, 배포, 테스트, 디버깅하기 위한 개발 환경입니다. 실제 체인에 배포하기 전 로컬에서 스마트 컨트랙트와 앱을 빌드할 때 개발자에게 도움을 줍니다.
터미널로 이동해서 my-nft 프로젝트 폴더 안에 있는지 확인한 다음, 다음을 실행합니다:
설치 안내에 대한 자세한 내용은 이 페이지를 참고하세요.
8단계: Hardhat 프로젝트 생성하기
프로젝트 폴더 안에서 다음을 실행합니다:
그러면 환영 메시지와 함께 무엇을 하고 싶은지 선택할 수 있는 옵션이 나타납니다. "create an empty hardhat.config.js"를 선택합니다:
이렇게 하면 hardhat.config.js 파일이 생성되며, 여기에 프로젝트에 필요한 모든 설정을 지정하게 됩니다 (13단계에서).
9단계: 프로젝트 폴더 추가하기
프로젝트를 정리하기 위해 새로운 폴더 두 개를 만들겠습니다. 명령줄에서 프로젝트의 루트 디렉토리로 이동하여 다음을 입력합니다:
**contracts/**는 NFT 스마트 컨트랙트 코드를 보관할 곳입니다
scripts/는 스마트 컨트랙트를 배포하고 상호작용하는 스크립트를 보관할 곳입니다
10단계: 컨트랙트 작성하기
환경 설정이 끝났으니, 이제 더 흥미로운 작업, 즉 스마트 컨트랙트 코드 작성으로 넘어갑니다!
선호하는 에디터로 my-nft 프로젝트를 엽니다 (VSCode를 추천합니다). 스마트 컨트랙트는 Solidity라는 언어로 작성되며, 이를 사용해 MyNFT.sol 스마트 컨트랙트를 작성하겠습니다.
-
"contracts" 폴더로 이동하여 MyNFT.sol이라는 새 파일을 생성합니다
-
아래는 OpenZeppelin 라이브러리의 ERC721 구현을 기반으로 한 NFT 스마트 컨트랙트 코드입니다. 아래 내용을 복사하여 MyNFT.sol 파일에 붙여넣으세요.
참고: 스마트 컨트랙트를 통해 NFT에 가격을 붙이고 싶다면 이 튜토리얼을 참고하세요.
- OpenZepplin 컨트랙트 라이브러리에서 클래스를 상속받고 있으므로, 명령줄에서 다음을 실행해 라이브러리를 폴더에 설치합니다:
textnpm install @openzeppelin/contracts@3.1.0-solc-0.7
그렇다면 이 코드는 정확히 무엇을 하는 걸까요? 한 줄씩 살펴보겠습니다.
5-7번째 줄에서, 우리 코드는 세 개의 OpenZepplin 스마트 컨트랙트 클래스를 상속받습니다:
-
@openzeppelin/contracts/token/ERC721/ERC721.sol에는 ERC721 표준 구현이 들어 있으며, 우리 NFT 스마트 컨트랙트가 이를 상속받습니다 (유효한 NFT가 되려면 스마트 컨트랙트가 ERC721 표준의 모든 메서드를 구현해야 합니다). 상속받은 ERC721 함수에 대해 더 알고 싶다면 여기에서 인터페이스 정의를 확인하세요.
-
@openzeppelin/contracts/utils/Counters.sol은 1씩만 증가하거나 감소할 수 있는 카운터를 제공합니다. 우리 스마트 컨트랙트는 이 카운터를 사용해 민팅된 NFT의 총 개수를 추적하고, 새 NFT에 고유 ID를 부여합니다. 스마트 컨트랙트로 민팅되는 각 NFT에는 고유 ID가 부여되어야 하는데, 여기서는 고유 ID가 단순히 현재까지 존재하는 NFT의 총 개수로 결정됩니다. 예를 들어, 스마트 컨트랙트로 민팅하는 첫 번째 NFT는 ID가 "1"이고, 두 번째 NFT는 ID가 "2"가 되는 식입니다.
-
@openzeppelin/contracts/access/Ownable.sol은 스마트 컨트랙트에 접근 제어를 설정하여, 스마트 컨트랙트의 소유자(즉, 여러분)만 NFT를 민팅할 수 있도록 합니다. 참고로 접근 제어를 포함할지는 전적으로 선택사항입니다. 누구나 여러분의 스마트 컨트랙트로 NFT를 민팅할 수 있게 하려면, 10번째 줄의 Ownable과 17번째 줄의 onlyOwner를 제거하세요.
10-28번째 줄에는 우리의 커스텀 NFT 스마트 컨트랙트가 있는데, 놀랍도록 짧습니다 — 카운터, 생성자, 함수 하나만 포함되어 있습니다! 이는 상속받은 OpenZepplin 컨트랙트가 NFT를 생성하는 데 필요한 대부분의 메서드, 예를 들어 ownerOf (NFT의 소유자를 반환)와 transferFrom (NFT의 소유권을 이전) 등을 이미 구현해두었기 때문입니다.
14번째 줄을 보면 "MyNFT"와 "NFT"라는 두 개의 문자열을 ERC721 생성자에 전달하는 것을 볼 수 있습니다. 첫 번째 변수는 스마트 컨트랙트의 이름이고, 두 번째는 심볼입니다. 이 변수들의 이름은 원하는 대로 지정할 수 있습니다!
마지막으로, 16번째 줄부터 시작하는 mintNFT() 함수를 통해 NFT를 민팅할 수 있습니다! 이 함수는 두 개의 변수를 받습니다:
-
address recipient는 새로 민팅된 NFT를 받을 주소를 지정합니다
-
string memory tokenURI는 NFT의 메타데이터를 설명하는 JSON 문서로 연결되어야 하는 문자열입니다. NFT의 메타데이터는 NFT에 생명을 불어넣는 핵심 요소로, 이름, 설명, 이미지 등 추가적인 속성을 부여할 수 있게 해줍니다. 이 튜토리얼의 2부에서 이 메타데이터를 구성하는 방법을 설명하겠습니다.
mintNFT는 상속받은 ERC721 라이브러리의 몇몇 메서드를 호출하며, 최종적으로 새로 민팅된 NFT의 ID를 나타내는 숫자를 반환합니다.
11단계: MetaMask와 Alchemy를 프로젝트에 연결하기
Metamask 지갑과 Alchemy 계정을 생성하고 스마트 컨트랙트도 작성했으니, 이제 이 세 가지를 연결할 차례입니다.
가상 지갑에서 전송되는 모든 트랜잭션에는 고유한 개인 키를 이용한 서명이 필요합니다. 프로그램에 이 권한을 부여하기 위해, 개인 키(및 Alchemy API 키)를 환경 파일에 안전하게 저장할 수 있습니다.
트랜잭션 전송에 대해 더 알고 싶다면, web3를 사용한 트랜잭션 전송에 관한 이 튜토리얼을 참고하세요.
먼저, 프로젝트 디렉토리에 dotenv 패키지를 설치합니다:
그런 다음 프로젝트 루트 디렉토리에 .env 파일을 생성하고, Metamask 개인 키와 HTTP Alchemy API URL을 추가합니다.
참고: .env 파일의 이름은 반드시 .env여야 합니다! xx.env 등으로 이름을 바꾸지 마세요
-
Metamask에서 개인 키를 내보내는 방법은 다음 안내를 따르세요
-
HTTP Alchemy API URL을 얻어 클립보드에 복사하려면 아래를 참고하세요

.env 파일은 다음과 같은 형태여야 합니다:
12단계: Ethers.js 설치하기
Ethers.js는 표준 JSON-RPC 메서드를 더 사용하기 쉬운 메서드로 감싸서 Ethereum과의 상호작용 및 요청을 더 쉽게 만들어주는 라이브러리입니다.
Hardhat은 추가적인 도구와 확장 기능을 위한 Plugins 통합을 매우 쉽게 해줍니다. 여기서는 컨트랙트 배포를 위해 Ethers plugin을 활용하겠습니다 (Ethers.js에는 매우 깔끔한 컨트랙트 배포 메서드들이 있습니다).
프로젝트 디렉토리에서 다음을 입력합니다:
다음 단계에서 hardhat.config.js에도 ethers를 require해야 합니다.
13단계: hardhat.config.js 업데이트하기
지금까지 여러 의존성과 플러그인을 추가했으니, 이제 hardhat.config.js가 이들을 모두 인식하도록 업데이트해야 합니다.
hardhat.config.js를 다음과 같이 업데이트합니다:
14단계: 컨트랙트 컴파일하기
지금까지 잘 진행되고 있는지 확인하기 위해, 컨트랙트를 컴파일해봅시다. compile 태스크는 Hardhat에 내장된 태스크 중 하나입니다.
명령줄에서 다음을 실행합니다:
소스 파일에 SPDX 라이선스 식별자가 제공되지 않았다는 경고가 나타날 수 있지만, 이는 걱정할 필요 없습니다 — 그 외에는 모두 문제없을 것입니다! 만약 그렇지 않다면 Alchemy Dashboard에서 지원 티켓을 열 수 있습니다.
15단계: 배포 스크립트 작성하기
컨트랙트 작성과 설정 파일 준비가 끝났으니, 이제 컨트랙트 배포 스크립트를 작성할 차례입니다.
scripts/ 폴더로 이동하여 deploy.js라는 새 파일을 생성하고, 다음 내용을 추가합니다:
Hardhat은 Contracts 튜토리얼에서 이 각 코드 줄이 하는 일을 훌륭하게 설명하고 있으며, 여기서는 그 설명을 그대로 가져왔습니다.
ethers.js의 ContractFactory는 새로운 스마트 컨트랙트를 배포하는 데 사용되는 추상화이므로, 여기서 MyNFT는 우리 NFT 컨트랙트의 인스턴스를 만드는 팩토리입니다. hardhat-ethers 플러그인을 사용할 때 ContractFactory와 Contract 인스턴스는 기본적으로 첫 번째 signer에 연결됩니다.
ContractFactory에서 **deploy()**를 호출하면 배포가 시작되고, Contract로 해소되는 Promise가 반환됩니다. 이 객체는 우리 스마트 컨트랙트의 각 함수에 대응하는 메서드를 가지고 있습니다.
16단계: 컨트랙트 배포하기
드디어 스마트 컨트랙트를 배포할 준비가 되었습니다! 프로젝트 디렉토리의 루트로 돌아가서, 명령줄에서 다음을 실행합니다:
그러면 다음과 같은 결과가 나타날 것입니다:
Sepolia Etherscan으로 이동하여 컨트랙트 주소를 검색하면 성공적으로 배포된 것을 확인할 수 있습니다. 트랜잭션은 다음과 같은 모습일 것입니다:

From 주소는 여러분의 Metamask 계정 주소와 일치해야 하며, To 주소에는 "Contract Creation"이라고 표시될 것입니다. 트랜잭션을 클릭해 들어가면, To 필드에서 컨트랙트 주소를 확인할 수 있습니다:

내부적으로 어떤 일이 일어나는지 확인하려면 Alchemy dashboard의 Explorer 탭으로 이동해봅시다. Alchemy 앱이 여러 개 있다면 앱별로 필터링하여 "MyNFT"를 선택해야 합니다.

여기서 .deploy() 함수를 호출했을 때 Hardhat/Ethers가 내부적으로 만든 여러 JSON-RPC 호출들을 볼 수 있습니다.
여기서 주목할 만한 두 가지는 실제로 Sepolia 체인에 스마트 컨트랙트를 기록하는 요청인 **eth_sendRawTransaction**과, 해당 해시를 기반으로 트랜잭션 정보를 조회하는 요청인 **eth_getTransactionByHash**입니다 (트랜잭션 전송 시 일반적인 패턴입니다).
트랜잭션 전송에 대해 더 알고 싶다면, Web3를 사용한 트랜잭션 전송에 관한 이 튜토리얼을 참고하세요.
이것으로 이 튜토리얼의 Part I을 마칩니다. Part II에서는 스마트 컨트랙트를 사용해 실제로 NFT를 민팅해보고, Part III에서는 Metamask에서 NFT를 확인하는 방법을 설명하겠습니다! 🤑
Alchemy 뉴스레터
출시 소식을 가장 먼저 받아보세요
뉴스레터 구독하기
Alchemy의 최신 제품 업데이트와 리소스 받기
이메일 주소를 입력하면 마케팅 커뮤니케이션 및 제품 업데이트 수신에 동의하게 됩니다. Alchemy는 저희 개인정보 처리방침에 따라 수집한 정보를 처리합니다. 언제든지 구독을 취소할 수 있습니다.
관련 아티클

Glamsterdam: Ethereum 개발자를 위한 완전 가이드
Glamsterdam이 Sepolia에서 가동 중입니다. 개발자에게 무엇을 의미하는지, 그리고 Alchemy가 네트워크 업그레이드에 어떻게 준비했는지를 담은 완전 가이드입니다.

도쿄에서 구축한다면 어떤 RPC 제공업체를 선택해야 할까
도쿄를 서비스하는 RPC 제공업체 다섯 곳을 다섯 개 체인에서 벤치마크했습니다. 비교 결과와, 지연 시간에 민감한 팀에게 차이가 어디서 나는지 정리합니다.

업계 최고 수준의 속도와 안정성을 위한 Solana RPC 읽기 아키텍처
Alchemy는 가장 낮은 Solana 읽기 지연 시간을 제공합니다: 9.21ms로, 차순위 제공업체보다 약 26% 빠릅니다.