많이 살수록 커진다고요?NFT「merge.」기술 구조

개막사

  • 이 글은 특정 NFC와 가상화폐의 구매를 촉진하는 글이 아니다.
  • 개시하다


    2021년 12월, 디지털 아티스트'팩'이 제작한 NFC 컬렉션'메르지'48시간 만에 104억이 팔려 매진됐다는 소식이 전해졌다.이 "merge"NFFT의 기술 구조가 흥미롭기 때문에 이번에는 그 구조를 해독해 보겠습니다.

    merge. 무엇



    참조 소스: Pak의 NFC'메르지'를 합쳐 약 104억엔이 매진됐다.
    디지털 아티스트 Pak의 NFC 프로젝트
    48시간 만에 약 104억엔이 팔려 매진됐다.이틀 동안 28984명이 참가했다
    메르지는'마스(Mass)'로 불리는 NFC를 판매하고,'마스'를 여러 개 구매한 컬렉터가'마스'간'합병'을 할 수 있도록 했다."Mass"를 대량으로 구매하면 NFC 크기를 늘릴 수 있는 메커니즘
    이로써 송어의 총량은 어느 정도 총수를 줄였다
    수집가들이 2차 시장에서 송어를 구매할 때마다 새로 구입한 송어와 기존 송어는 하나의 NFFT로'합병'된다
    https://niftygateway.com/collections/pakmerge
    NFC 사이즈 확대?
    2차 유통에서 송어를 구매할 때마다 하나의 NFFT로 통합되는 것은 무엇일까?
    신경 쓰이는 부분이 많지만 실제 메르지.코치님의 소스 코드가 공개됐기 때문에 제가 바로 가볼게요.
    https://etherscan.io/address/0xc3f8a0f5841abff777d3eefa5047e8d413a1c9ab#code

    해독하다


    신경 쓰이는 곳


    우선 마음에 드는 곳을 대충 조사해 보자
  • 언제 "Mass"가 합병됩니까?
  • 송어의 초기치는?
  • 송어의'총량'이 어느 정도'총수'를 줄인 것은 무엇일까?
  • 어떻게 그립니까?
  • 하나하나 보다

    "Mass"를 병합할 시기는 언제입니까?


    송어를 어떻게 합칩니까?NFFT 사이를 합성할 수 있습니까?어떻게 된 거야?
    ERC 721은 NFC를 다른 사람에게 전달할 때transfer 방법이라고 한다.수신할 때 호출되는 함수 (기본값) 가 존재하지 않습니다.
    이로써 transfer 방법 내에 합병 처리가 있을 것으로 예상된다.
    // Merge.sol
    function _transfer(address owner, address from, address to, uint256 tokenId) internal notFrozen {
            require(owner == from, "ERC721: transfer of token that is not own");
            require(to != address(0), "ERC721: transfer to the zero address");
            require(!_blacklistAddress[to], "Merge: transfer attempt to blacklist address");
    	
    	// ... 省略
    	
                    } else {
                        uint256 sentTokenId = tokenId;
    
                        // ここがmerge処理
                        uint256 deadTokenId = _merge(currentTokenId, sentTokenId);
                        emit Transfer(to, address(0), deadTokenId);
    
                        uint256 aliveTokenId = currentTokenId;
                        if (currentTokenId == deadTokenId) {
                            aliveTokenId = sentTokenId;
                        }
    
                        delete _owners[deadTokenId];
    
        // ... 
    
    메르지 처리 자체가 _merge 방법으로 나뉘어진 것 같아요.
    // Merge.sol
        function _merge(uint256 tokenIdRcvr, uint256 tokenIdSndr) internal returns (uint256 tokenIdDead) {
            require(tokenIdRcvr != tokenIdSndr, "Merge: Illegal argument identical tokenId.");
    
            // 既に持っているマスの値
            uint256 massRcvr = decodeMass(_values[tokenIdRcvr]);
    	// 購入した or 送られてきたマスの値
            uint256 massSndr = decodeMass(_values[tokenIdSndr]);
            
    	// どちらが大きいマスか比較する -------->>>
            uint256 massSmall = massRcvr;
            uint256 massLarge = massSndr;
    
            uint256 tokenIdSmall = tokenIdRcvr;
            uint256 tokenIdLarge = tokenIdSndr;
    
            if (massRcvr >= massSndr) {
    
                massSmall = massSndr;
                massLarge = massRcvr;
    
                tokenIdSmall = tokenIdSndr;
                tokenIdLarge = tokenIdRcvr;
            }
    	// << ------------------------------
    
            // 大きい方のマスに小さい方のマスの値を加算する
    	// ⭐ _valuesに全てのマスの大きさが格納されていることがわかる
            _values[tokenIdLarge] += massSmall;
    
            uint256 combinedMass = massLarge + massSmall;
    
            if(combinedMass > _alphaMass) {
                _alphaId = tokenIdLarge;
                _alphaMass = combinedMass;
                emit AlphaMassUpdate(_alphaId, combinedMass);
            }
            
            _mergeCount[tokenIdLarge]++;
            
    	// 小さい方のマスの値データ削除
            delete _values[tokenIdSmall];
    
            _countToken -= 1;
    
            emit MassUpdate(tokenIdSmall, tokenIdLarge, combinedMass);
    
            return tokenIdSmall;
        }
    
    중요한 부분은 평론으로 쓰여 있다.
    요점은 _values[tokenIdLarge] += massSmall;여기입니다.큰 칸의 값에 작은 칸의 값을 더하다.
    그 후 작은 네모난 칸이 번에게 넘어갔다.

    송어의 초기값은?


    나는 아까 코드를 보고 송어 자체가 가치가 있다는 것을 알았다.
    나는 그 초기값이 1이라고 생각하지만 신중을 기하기 위해 코드를 보자.
    우선, NFC 생성 처리로서Merge.solmint 방법을 읽는다
    // Merge.sol
    
    // ...
    function mint(uint256[] calldata values_) external onlyValidSender {
    	require(!_mintingFinalized, "Merge: Minting is finalized.");        
    
    	uint256 index = _nextMintId;                
    	uint256 alphaId = _alphaId;
    	uint256 alphaMass = _alphaMass;
    	address omnibus = _omnibus;
    
    	uint256 massAdded = 0;
    	uint256 newlyMintedCount = 0;
    	uint256 valueIx = 0;
    
    	while (valueIx < values_.length) {            
    
    	    if (isSentinelMass(values_[valueIx])) {
    		// SKIP FLAG SET - DON'T MINT
    	    } else {
    		newlyMintedCount++;
    
    		// _values に値を入れている
    		// 値はこのメソッドの引数である values_ からとっている
    		_values[index] = values_[valueIx];            
    		_owners[index] = omnibus;
    
    		(/* uint256 class */, uint256 mass) = decodeClassAndMass(values_[valueIx]);
    
    		if (alphaMass < mass){
    		    alphaMass = mass;
    		    alphaId = index;
    		}
    
    		massAdded += mass;
    
    		emit Transfer(address(0), omnibus, index);
    	    }
    
    	    // update counters for loop
    	    valueIx++;
    	    index++;
    	}
    
    // ...
    
    실제 값은 하드코딩을 거친 것이 아니기 때문에 코드에서 읽을 수 없습니다.
    구조기에서 질량치getValueOf를 볼 수 있는 방법이 실현되었다.
    적정merge(1)이 된 한 번도 병합되지 않은 마스의 토큰IDgetValueOf 호출 방법에 따라 수치를 본 곳100000001이 표시됨에 따라 초기값100000001이 설정됐다.
    https://opensea.io/assets/0xc3f8a0f5841abff777d3eefa5047e8d413a1c9ab/17814

    왜 1000000001?100000000001+100000001 하고 있어요?


    계산하는 게 아니라100000001+100000001._merge 방법에 이런 처리가 있다고 생각해요.
    // Merge.sol
    // 既に持っているマスの値
    uint256 massRcvr = decodeMass(_values[tokenIdRcvr]);
    // 購入した or 送られてきたマスの値
    uint256 massSndr = decodeMass(_values[tokenIdSndr]);
    
    decodeMass 방법은 다음과 같습니다.
    // Merge.sol
    
    // ...
    
    uint256 constant private CLASS_MULTIPLIER = 100 * 1000 * 1000; // 100 million
    
    // ...
    
    function decodeMass(uint256 value) public pure returns (uint256 mass) {
    	mass = value % CLASS_MULTIPLIER; // integer modulo is ‘checked’ in Solidity 0.8.x
    	ensureValidMass(mass);
    }
    
  • mass = value % CLASS_MULTIPLIER
  • 100 * 1000 * 1000 -> 100000000
  • 100000001100000000로 나눈 나머지 수(이 경우1를 질의 실제값으로 하는 것이다
    이것은 품질치オーバーフロー・アンダーフロー対策이다.자세한 내용은 googleSafeMath 참조
    이러한 디지털 처리에서 알 수 있듯이 계산할 때1+1처럼 간단하고 알기 쉬운 디지털 안전 계산만 값100000001100000002과 같은 수치로 유지되고 있다.

    송어의 총량이 어느 정도 줄어드는 총수는 무엇입니까?


    총량과 총수는 비슷해 보이지만 뜻은 조금 다르다.
    총량NFTの最大発行枚数, 총량NFTの最大発行枚数 - burnされた数은 이해하기 쉬울 것이다.
    최대 발행 장수는 어떻게 결정합니까?그것은 어디에서 보증을 받습니까?가봐.mint 처리 방법을 살펴보겠습니다.
    // Merge.sol
    
    
    bool public _mintingFinalized;
    
    // ...
    
    function mint(uint256[] calldata values_) external onlyValidSender {
    	// _mintingFinalizedがtrueの場合、mintができない
    	require(!_mintingFinalized, "Merge: Minting is finalized.");        
    	/// ...
    }
         
    // ...
    
    // _mintingFinalizedをtrueにする。 falseにするメソッドは無い
    function finalize() external onlyPak {
    	thaw();        
    	_mintingFinalized = true;        
    }
        
    // ...
    
    _mintingFinalized의 표지의 상태 제어 여부는mint가 최대 발행 장수를 제어하는 것이 아니다._mintingFinalized는 진짜일 수 있지만 가짜일 수는 없기 때문에 방법을 호출할 때 최대 발행 장수를 결정한다.
    이로부터 알 수 있듯이 총량은 일정함을 유지한다.
    또 합병 후의 시간점 때문에 두 값이 비교적 작은 네모난 칸이 burn에 의해 줄어들기 때문에 총수는 줄어든다.

    드로잉 처리는 어떻습니까?



    송어를 합쳐 점점 커지는 구조인 것 같다.이게 어떻게 된 일입니까? 오픈sea에 표시된 이미지 데이터를 보겠습니다.

    svg 파일인 것 같습니다.NFFT의 이미지 메타데이터 중 실제finalize(),png,jpeg,mp4 이외에 HTML 파일과 SVG 파일을 저장할 수도 있고base 64 인코딩의 원시 데이터를 URL 대신 저장할 수도 있다.(원시 데이터라면 가스요금이 높아진다. 또 시장 가격에 따라 표시할 수 있느냐 없느냐에 따라 달라진다.)
    URL은 Opensea의 것입니다. 그러나 이것은 Opensea가svg 파일을 저장한 것이 아니라 Opensea가 저장한 캐시 파일입니다.
    실체는 어디에 있습니까?
    그거 gif에 써있어요.
    svg 데이터는 구조기에서 생성되며 이를 바탕으로 하는 메타데이터입니다.json을 만들어서 베이스 64 인코딩된 물건을 토큰 URI로 돌려줍니다.
    이른바 풀 체인인 NFFT의 부분이지만, 여기서 자세한 설명은 길어지기 때문에 생략한다.참고 자료

    총결산

  • 많이 살수록 큰 NFC merge.의 기술 사양
  • 마음에 드는 곳 4개 해설
  • 송어의 초기치는?
  • 언제 "Mass"가 합병됩니까?
  • '마스'의'총량'이 어느 정도'총량'을 줄인 것은 무엇일까?
  • 드로잉 처리는?
  • 최후


    프레임에 더 세밀한 통제 처리라고 쓰여 있는데 이번에는 생략하겠습니다.
    관심 있는 사람은 아래부터 구조기의 코드를 읽어 보세요.
    https://etherscan.io/address/0xc3f8a0f5841abff777d3eefa5047e8d413a1c9ab#code

    etc


    Solidity 무선 학습에 관한 커뮤니티'solidity-jp'를 만들었습니다!
    지금부터 배우고 싶어요/공부하는 중에 일본어 정보가 적어요/낡고 시간이 많이 걸리는 분들, 같이 공부하세요~!!
    https://discord.gg/8MsgnHCRud
    또 트위터에 솔리시티의 기술 부분을 게시했다.가능하면 팔로우 해주세요!

    좋은 웹페이지 즐겨찾기