본 포스팅은 2022.08.26에 작성된 이전 블로그의 포스팅을 아카이빙 용으로 가져온 것입니다.
https://myumyu-ming.tistory.com/105
Quinoa 프로토콜에서는 Vault와 연관된 펀드 상품을 구매할 때, 구매한 증거로 NFT를 발급해 준다. 이 NFT의 이미지는 단순한 정적인 이미지가 아니라 Vault의 현재 상태나 Vault의 특징을 반영하는 이미지이다. 즉, on-chain 상에 있는 Vault의 정보를 NFT에 반영하게 해서 자동적으로 NFT 이미지를 만드는 것이다. 이를 위해 SVG 이미지를 이용하기로 했는데, SVG가 뭔지도 잘 모르고 써본 적도 없기 때문에 연습이 필요했다. 아직 NFT 디자인이 나오기 전이기 때문에, 디자인이 나오면 바로 Quinoa 컨트랙트의 코드를 수정할 수 있도록 임시로 만든 ERC-721 컨트랙트를 통해 연습을 진행했다.
오늘 한 첫번째 일은, NFT를 민팅할 때 집어 넣은 파라미터들(실제 Quinoa 컨트랙트에서는 Vault의 parameter들을 불러와서 이미지에 넣을 것이다)을 이용해서 자동으로 SVG 데이터를 만드는 것이었다. 이후 이 SVG 데이터를 Opensea의 metadata 표준에 맞도록 json으로 만들고, data uri로 만들어서 NFT를 실제 발행하였다. 마지막으로 mumbai 네트워크 상에 발행한 NFT를 Opensea testnet에서 확인할 수 있는지 살펴보았다.
[SVG]
SVG는 Scalable Vector Graphics의 약자로, 픽셀이 아니라 벡터를 기반으로 이미지를 표현하는 것이다. 따라서 아무리 확대해도 이미지가 깨지지 않는다. <벡터를 기반으로> 이미지를 표현한다는 것이 조금 이해하기 어려웠는데, 실제 SVG 파일을 보니 일종의 html과 같이 태그 형식의 코드로 이미지가 구현되어 있었다.
즉, 중간의 text나 color 값들을 조정해서(더 나아가서는 도형 같은 것도 그릴 수 있다) 새로운 이미지를 만들어 낼 수 있는 것이다.
Quinoa의 NFT 디자인에서는 기본적인 NFT 베이스가 있고, Vault마다 그 성질에 따라서 문구와 색상 정도가 바뀔 예정이라 위와 같은 단순한 이미지를 만들어 연습을 했다.
[Opensea에서 확인하기]
ERC721에서는 각각의 token마다 URI를 넣을 수 있다.
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
_requireMinted(tokenId);
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
기본적으로 token의 URI는 <[baseURI]/1>과 같은 형태가 되는데, 여기서 '1'은 토큰의 ID를 의미한다.
예를 들면 <https://quinoa/vault/nft/1>, <https://quinoa/vault/nft/2>...와 같은 형태로 계속해서 URI가 만들어 지고, 이 URI에 접속하게 되면, token의 meta data가 뜨게 되는 것이다. Opensea에서 이미지나 NFT의 이름 등을 원하는 대로 뜨게 하고 싶으면 이 metadata를 규격에 맞춰서 json 형식으로 만들어 주어야 한다.
Opensea의 규격은 개발자 문서를 통해 확인할 수 있는데, 간단히 살펴보면 다음과 같다.
{
"description": "Friendly OpenSea Creature that enjoys long swims in the ocean.",
"external_url": "https://openseacreatures.io/3",
"image": "https://storage.googleapis.com/opensea-prod.appspot.com/puffs/3.png",
"name": "Dave Starbelly",
"attributes": [
{
"trait_type": "Base",
"value": "Starfish"
},
{
"trait_type": "Eyes",
"value": "Big"
},
{
"trait_type": "Mouth",
"value": "Surprised"
}
]
}
이를 Opensea의 NFT 화면에서 살펴보면 아래와 같이 매칭할 수 있다.
보통은 위와 같은 json을 IPFS나 Pinata를 이용해 pinning 하거나 AWS와 같은 서버를 이용해 나온 URI를 tokenURI 값으로 집어 넣는다. 하지만 우리는 프로토콜 캠프까지의 시간이 약 10일 밖에 안남았고, 원래부터 서버를 넣지 않을 생각이었기 때문에(지금은 절실하다) 모든걸 On-chain 상에서 진행해야 한다. 그래서 SVG 역시 컨트랙트 내부에서 만들어 바로바로 URI를 만들어 보여주기로 했다.
즉, 무언가 URI를 만들어서 ERC721 상에 저장하는 것이 아니라,
(1) ERC721 상에서 tokenURI를 반환할 때에 즉석으로 SVG를 만들고
(2) SVG를 포함한 json을 만들고
(3) 이어서 URI까지 만들어 반환하도록 했다.
URI는 Data uri를 활용해 만들었는데, 이걸 이용하면 별 다른 노력 없이 base64 인코딩 만으로도 uri를 만들 수 있다.
ex. 아래 글을 복사해 주소창에 붙여넣기 하면, 위의 Opensea 규격 json을 확인할 수 있다.
data:application/json;base64,ew0KICAiZGVzY3JpcHRpb24iOiAiRnJpZW5kbHkgT3BlblNlYSBDcmVhdHVyZSB0aGF0IGVuam95cyBsb25nIHN3aW1zIGluIHRoZSBvY2Vhbi4iLCANCiAgImV4dGVybmFsX3VybCI6ICJodHRwczovL29wZW5zZWFjcmVhdHVyZXMuaW8vMyIsIA0KICAiaW1hZ2UiOiAiaHR0cHM6Ly9zdG9yYWdlLmdvb2dsZWFwaXMuY29tL29wZW5zZWEtcHJvZC5hcHBzcG90LmNvbS9wdWZmcy8zLnBuZyIsIA0KICAibmFtZSI6ICJEYXZlIFN0YXJiZWxseSIsDQogICJhdHRyaWJ1dGVzIjogWw0KICAgIHsNCiAgICAgICJ0cmFpdF90eXBlIjogIkJhc2UiLCANCiAgICAgICJ2YWx1ZSI6ICJTdGFyZmlzaCINCiAgICB9LCANCiAgICB7DQogICAgICAidHJhaXRfdHlwZSI6ICJFeWVzIiwgDQogICAgICAidmFsdWUiOiAiQmlnIg0KICAgIH0sIA0KICAgIHsNCiAgICAgICJ0cmFpdF90eXBlIjogIk1vdXRoIiwgDQogICAgICAidmFsdWUiOiAiU3VycHJpc2VkIg0KICAgIH0NCiAgXSANCn0=
json을 만드는 데에 아주 애를 먹었지만 (쉼표 하나 따옴표 하나 때문에 출력이 안되는 경우가 많았다) 그래도 어찌어찌 해냈다.
그리고 이번에도 Uniswap의 SVG 관련 코드들을 보고 굉장히 큰 도움을 받았다.
'Blockchain' 카테고리의 다른 글
Babylon Finance (0) | 2023.04.27 |
---|---|
Proxy Pattern & Upgradeable Contract (0) | 2023.04.23 |
Error Report | Balancer에서 joinPool 할 때 <BAL#103> 에러 해결 (0) | 2023.04.18 |
Hardhat Test | 테스트 중간에 Hardhat network를 reset 하기 (0) | 2023.04.13 |
Smart contract의 code size를 줄이는 방법 (0) | 2023.04.10 |
댓글