[ERC721A] 우주에서 가장 저렴하게 NFT를 발행하는 방법
Azuki는 ERC721A가 우주에서 가장 저렴하게 NFT를 발행하는 방법이라고 주장한다. 이번 포스트에서는 ERC721A가 무엇인지에 대해 알아보고, ERC721A가 가스비용을 절약할 수 있었던 원리에 대해 알아본다.
Azuki는 ERC721A가 우주에서 가장 저렴하게 NFT 발행하는 방법이라 주장한다.
정확히는 다수의 NFT를 발행하는 데 드는 가스 비용이 우주에서 가장 저렴하다고 한다.
현재 우주에서 가장 저렴하다는 Azuki의 이 주장은 사실인 것으로 보인다.
다수의 NFT를 발행하려면, 기존에는 발행하고자하는 NFT의 개수만큼 트랜잭션을 발생시켜야 했고 따라서 그만큼 많은 가스비용이 발생했다.
하지만 이번에 소개하고자하는 ERC721A는 단일 트랜잭션으로 다수의 NFT를 발행할 수 있으며, 여러개의 NFT를 발행하더라도 단 1개의 NFT를 발행하는 가스비용만 발생한다.
이번 포스트에서는 ERC721A가 어떻게 단일 트랜잭션으로 다수의 NFT를 발행했는지 그 원리에 대해 알아보도록 하자.
ERC721Enumerable vs ERC721A
먼저, 실제로 ERC721A가 가스비용을 줄여주는지 확인해보자.
비교대상은 기존의 많은 NFT 프로젝트에서 사용하고 있는 OpenZeppelin의 ERC721Enumerable이다.
다음 표는 OpenZeppelin의 ERC721Enumerable을 활용하였을 때와 Azuki의 ERC721A를 사용하였을 때, 다수의 NFT를 발행하는 상황에서의 가스비용을 비교한 것이다.
ERC721Enumerable을 활용한 경우 NFT의 수가 하나씩 늘어날 때마다 거의 2배, 3배씩 가스비용이 증가하는 것을 볼 수 있다. 이것은 트랜잭션을 여러번 수행하였기 때문에 발생하는 현상이다.
반면에 ERC721A는 가스비용의 증가가 적은 것을 확인할 수 있다. NFT의 수가 하나씩 늘어나더라도, 몇배씩 가스비용이 증가하는 것이 아닌, 일정량의 가스비용만 증가하는 것을 보인다.
물론 NFT의 개수가 무수히 많아지면 ERC721A의 가스비용도 증가하겠지만, 전자와 비교하면 ERC721A의 가스비용이 매우 적을 것이다.
단일 트랜잭션으로 다수의 NFT를 발행하는 원리
Azuki는 이러한 ERC721A를 오픈소스로 공개하면서, ERC721A가 단일 트랜잭션으로 다수의 NFT를 발행하는 원리를 밝혔다.
ERC721A는 다음과 같은 최적화를 통해 구현되었다.
- 최적화 1 : NFT Metadata 저장공간의 중복을 제거한다.
- 최적화 2 : 다수의 NFT 발행 시, Owner의 Balance를 한번만 업데이트 한다.
- 최적화 3 : 다수의 NFT 발행 시, Owner를 한번만 데이터를 업데이트 한다.
여기서 ERC721A는 ERC721Enumerable과 같이 순차적이고 연속적인 NFT를 발행하는데 초점이 맞추어져있다는 것을 알아야한다.
ERC721A는 OpenZeppelin의 ERC721Enumerable의 단점을 최적화 한 것으로, 소수의 NFT 발행을 위함이 아니라 대량으로 순차적인 NFT를 발행하는데 있어서 효과적이다. 즉 소량의 순차적이지 않은 NFT를 발행하는데에는 ERC721A를 쓸 이유가 전혀 없다.
다음으로 각각의 최적화 원리에 대해서 알아보도록 하자.
최적화 1 : NFT Metadata 저장공간의 중복을 제거한다.
최적화 1은 NFT 각각의 NFT Metadata를 저장함으로서 얻는 이점이 낮아 그것을 포기하여 가스비용을 최적화한다는 것이다.
주로 Meatadata가 ipfs://something.../0
과 같은 형태로 0, 1, 2, 3, ... 과 같이 숫자만 바뀌기 때문에 최적화가 가능한 것이다
최적화 2 : 다수의 NFT 발행 시, Owner의 Balance를 한번만 업데이트 한다.
NFT 발행 시, Onwer A가 100번부터 150번까지의 NFT를 구매하려고 한다고 가정하자.
ERC721Enumerable의 경우
100번을 구매할 때 Owner A의 Balance를 1 더한다. / 101번을 구매할 때, Owner A의 Balance를 1 더한다. / . . . / 150번을 구매할 때, Owner A의 Balance를 1 더한다.
각각의 NFT마다 Balance를 업데이트 시켜, 트랜잭션이 51번 발생한다. 가스비용이 많이 든다.
ERC721A의 경우
Owenr A의 Balance를 한번에 51 더한다.
Balance를 한번에 업데이트 시켜 트랜잭션이 1번 발생한다. 가스비용이 절약된다.
최적화 3 : 다수의 NFT 발행 시, Owner를 한번만 데이터를 업데이트 한다.
NFT 발행 시, Owner A가 100 ~ 102번의 NFT를 구매하고, Owner B가 103 ~ 104번의 NFT를 구매하려고 한다고 가정하자.
ERC721Enumerable의 경우
100번 NFT를 발행하고, Owner를 A로 변경한다. / 101번 NFT를 발행하고, Owner를 A로 변경한다. / 102번 NFT를 발행하고, Owner를 A로 변경한다.
103번 NFT를 발행하고, Owner를 B로 변경한다. / 104번 NFT를 발행하고, Owner를 B로 변경한다.
총 5번 NFT를 발행하고, 5번 Owner를 변경한다.
ERC721A의 경우
100번 NFT를 발행하고, Owner를 A로 변경한다.
103번 NFT를 발행하고, Owner를 B로 변경한다.
총 2번 NFT Owner를 변경한다.
발행되는 NFT의 수는 같지만, Owner 변경의 횟수가 적어지므로, 가스비용을 절약할 수 있다.
Owner가 없는 NFT의 주인은 누구일까?
세번째 최적화에서 Owner를 설정하지 않아서 가스비용을 절약할 수 있었는데, 그렇다면 Owner가 설정되지 않은 NFT의 Owner를 어떻게 알 수 있을까?
ERC721A는 101번, 102번 NFT는 A가 Owner이고, 104번 NFT는 B가 Owner가 될 수 있도록 다음과 같이 구현해냈다.
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
require(_exists(tokenId), "ERC721A: owner query for nonexistent token");
uint256 lowestTokenToCheck;
if (tokenId >= maxBatchSize) {
lowestTokenToCheck = tokenId - maxBatchSize + 1;
}
for (uint256 curr = tokenId; curr >= lowestTokenToCheck; curr--) {
address owner = _owners[curr];
if (owner != address(0)) {
return owner;
}
}
revert("ERC721A: unable to determine the owner of token");
}
Owner가 설정되지 않은 NFT의 Owner를 찾기 위해서는, Owner가 있는 NFT를 찾을때까지 tokenId를 하나씩 줄여가며 Owner를 확인해보는 것이다.
103번의 Owner를 찾는 과정
- 103번의 NFT Owner → 없음
- 102번의 NFT Owner → 없음
- 101번의 NFT Owner → A
따라서, 103번의 Onwer는 A이다
Summary
이번 포스트에서는 ERC721A와 ERC721Enumerable을 비교해보며, ERC721A가 어떻게 획기적으로 가스비용을 줄였는지 알아보았다.
추후 다른 포스트로, ERC721A를 활용한 NFT발행과 같이 ERC721A의 실제 활용을 알아볼 것이다.