區塊鏈淺談12 - 區塊鏈盲盒研究

契機

一年前朋友在玩一個NFT社群,項目方透過盲盒發售NFT,有不少稀有的NFT還未開出。因我之前在前公司有做過區塊鏈的樂透機制Demo,那時的研究了解到單憑區塊鏈是無法做到真正的隨機,一定要仰賴第三方做隨機數。所以朋友就邀我一起研究一下他們的NFT開盲盒機制,看能不能有甚麼方法提高中獎機率。

智能合約研究(ERC721)

找到該項目NFT的智能合約,為ERC721的應用,其中解盲時產生NFT token_id隨機數的程式碼如下

function XXXXXXX(uint256 tokenId_) internal returns (uint256) {
        require(_remaining > 0, "there are no available token id");
        uint256 tempRemaining = _remaining;

        // PRG:
        uint256 value = uint256(
            keccak256(
                abi.encodePacked(
                    tokenId_,
                    block.difficulty,
                    block.timestamp,
                    msg.sender
                )
            )
        ) % tempRemaining;

        // Durstenfeld-Fisher–Yates shuffle
        uint256 tokenId = value;
        uint256 tempRecordValue = _cache[value];
        if (tempRecordValue != 0) {
            tokenId = tempRecordValue;
        }
        uint256 remainingIndex = tempRemaining - 1;
        uint256 tempLastValue = _cache[remainingIndex];
        if (tempLastValue == 0) {
            tempLastValue = remainingIndex;
        }
        _cache[value] = tempLastValue;
        _remaining = remainingIndex;
        return tokenId + _startingIndex;
    }

最主要是中間那段程式碼在計算盲盒的隨機數

  uint256 value = uint256(
    keccak256(
      abi.encodePacked(
        tokenId_,
        block.difficulty,
        block.timestamp,
        msg.sender
      )
    )
  ) % tempRemaining;
  • tokenId_ : 盲盒ID
  • block.difficulty : 區塊鏈難度
  • block.timestamp : 區塊時間戳
  • sender : 交易發送者

由以上4者算Hash值後再對剩餘NFT發行量取Mod。

至於Funtion底下的「//Durstenfeld-Fisher–Yates shuffle…」,這段是假如開出同樣號碼的處理,不在我們要鎖定中獎的目標中,畢竟稀有NFT是還沒被開出的,不會重複。

解析與初步設想

tokenId_在購買盲盒後就已知,Sender也是已知,剩下的就是開盲盒當下的區塊鏈難度與區塊時間戳。朋友寫了一個預測「難度 + 時間戳」對應所開出NFT的程式,以此模擬。只要接下來一段時間內開出稀有的NFT機率大於80%,就發送交易開盲盒。但實際跑了一段時間後,開出稀有NFT機率大於80%的時間段比預期的少很多,難度變化頻繁更增加失敗機率。但在這段嘗試中,又發現了可以更準確開出盲盒的變數。

交易流程中的可控因子validBefore(timestamp)

開啟盲盒流程中,會需要給使用者簽署交易,最後確認簽署交易後才會給出對應的NFT。這部分的智能合約設計有給使用者一個緩衝時間,也就是validBefore,一旦開啟盲盒的流程超過某個時間就無法再簽署完成交易。有點像是我們平常登入銀行的自動登出機制,一旦超過validBefore這個時間,則操作就會無效。這本來是一個安全機制,但在此時卻成為可以更準確控制時間戳的一個方法。

實際解盲流程操作

  1. 程式預測出某難度在未來固定時間(validBefore)有大獎
  2. 開始解盲盒流程到簽署前
  3. 監控難度是否與預測一致
  4. 若在validBefore前幾秒難度一致,則簽署交易發送
  5. 若在validBefore前幾秒難度不對,則不簽署交易,讓交易超出時間

以上方法的成本為交易失敗的手續費,基本上成功率可以接近100%

發行方如何避免此提高機率的方法

  1. 提高手續費,增加試誤的成本
  2. 不以Token_id為參數,而是以像是Chainlink VRF產生的隨機數當參數
  3. 以區塊上不可預測的參數增加輸入變數,如區塊頭Hash值。但這樣可能會變成讓礦工可以操控結果

結語

與隨機相關的智能合約開發需要多花時間研究撰寫,最簡單的方法可能是串接Chainlink VRF,但這也可能是成本最高的方法,畢竟每次隨機數產生都要一筆手續費。其餘方法都有不是真隨機的缺點,可能會被花時間研究破解或提高預測的機率。






Search

    Post Directory