https://speedrunethereum.com/challenge/simple-nft-example
Scaffold-eth
의 기본 사항을 배우기 위해 간단한 NFT를 만들어 보세요.HardHat
을 사용하여 스마트 계약을 컴파일하고 배포합니다. 그런 다음 중요한 Ethereum 컴포넌트와 훅이 가득한React
템플릿을 사용합니다. 마지막으로, 친구들과 공유할 수 있는 공개 네트워크에 NFT를 배포합니다! 🚀
yarn install
yarn chain
yarn deploy
yarn start
준비를 마친 이후 실행한 dApp에서는 다음과 같은 화면을 확인할 수 있다. 상태가 유지되는 것을 방지하기 위해 incognito window (시크릿창)
으로 실행한다.
사용 중인 계정의 연결을 해제하고 재연결한다.
Brave 브라우저에서는 다음과 같은 UI를 제공한다. Burner Wallet
을 연결하면, 최소한의 스펙을 가진 익명의 계좌를 생성하여 연결한다.
Local Faucet
에서 localhost test funds
로부터 ETH를 자유롭게 공급받을 수 있다. 생성된 wallet
의 주소를 Destination
으로 입력하면 된다.
yarn chain
을 실행한 터미널에서는 트랜잭션을 포함하여, 실행되는 함수들을 다....
eth_sendTransaction
Transaction: 0xa0e82de60ae9ab5f16df389236701f1e645b1e6ec04f01ddc0ca4e829cdf9c3a
From: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
To: 0xab6c5086e09a0b6b0b801394f129275cf4472d50
Value: 3579.3579 ETH
Gas used: 21000 of 30000000
Block #4: 0x4ca435df9bad686a4431bddbee9aac0771f50aa33515654b5b6518dda3554ea1
Block Explorer
에서는 테스트넷에서의 트랜잭션 기록을 UI로 제공한다.Mint NFT
또한 Transaction을 수반하기 때문에, 이에 필요한 gas가 충분한지 확인해야 한다.
Block Explorer
에서 각 트랜잭션의 상세 정보를 확인할 수 있다.
소비되는 가스의 양은 네트워크의 현재 상황과 수요에 따라 동적으로 변동된다. 실제 거래에서는 사용자들은 이러한 가스 가격을 설정하여 거래의 우선 순위를 결정할 수 있다.
1.447298621 Gwei
1.392738142 Gwei
1.344602637 Gwei
1.263613049 Gwei
Scaffold-ETH
를 기반으로 deployedContracts.ts
파일을 자동 갱신한다. 이 파일에는 실행 가능한 함수의 인터페이스를 명시하는데, 이에 대한 구현으로 @openzeppelin
라이브러리를 사용한 것을 확인할 수 있었다. 이는 이더리움의 토큰 표준인 ERC20
, ERC721
인터페이스를 구현하는 계약 함수를 제공한다.새로운 브라우저 창을 실행하여 계정을 만들고, NFT를 다른 계정으로 이동시킬 수 있다. transferFrom
함수를 통해 이동된 NFT 데이터는 다음과 같다. 이 데이터가 어떤 과정으로 활용 가능하도록 변하는지 살펴보자.
0x23b872dd000000000000000000000000ab6c5086e09a0b6b0b801394f129275cf4472d500000000000000000000000001c415d68f299241654177ff4d16ed7ad0f757ea20000000000000000000000000000000000000000000000000000000000000002
transferFrom
함수는 다음 계약의 내용을 따른다.
@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol
transferFrom
& Transfer
// openzeppelin/contracts/token/ERC721/ERC721.sol
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(address from, address to, uint256 tokenId) public virtual override {
//solhint-disable-next-line max-line-length
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
_transfer(from, to, tokenId);
}
이는 일종의 래퍼 함수로서, tokenId
를 활용하여 msgSender
에 대한 인가 과정을 진행한다. 내부적으로는 _transfer
을 호출하며, 여기서는 함수의 인자로 전달된 from
에 대한 토큰 인가 과정을 진행한다. 이 두 가지가 구분된 것은 토큰에 대해 적절한 권한이 없는 주체가 함수를 실행하는 것을 차단하기 위함으로 보인다.
// @openzeppelin/contracts/token/ERC721/ERC721.sol
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/
function _transfer(address from, address to, uint256 tokenId) internal virtual {
...
}
우선 기본적으로 동작을 확인/검증하는 수준에서 실습을 진행했다. 이후 포스팅에서는 실제로 이 dApp을 배포하기 위한 준비하고, 그 과정 중 알아야 하는 개념들을 정리하여 소개한다.