N合約分析
什么是LOOT?
在官網,只用了兩行簡短的英語對其進行介紹:
Loot is randomized adventurer gear generated and stored on chain. Stats, images, and other functionality are intentionally omitted for others to interpret.Feel free to use Loot in any way you want.
Loot是隨機生成的冒險者裝備,并存盤在區塊鏈上,統計數字、影像和其他功能被有意省略,供他人解釋,
請自由地以任何方式使用Loot,
通俗一點,Loot 是一種黑色背景,只包含文本的鏈上 NFT,任何人都可以參與鑄造,將會隨機獲得一組奇幻冒險家裝備,當然是以文本的形式,這些裝備具有隨機分布的稀缺特征,Loot是一個幾乎空白的畫布,卻賦有巨大的吸引力來讓人共同創作、建設和傳播,
基于此,本文想對一個最簡單的loot合約代碼以及每個loot發行出來的價值進行分析,為學習loot提供參考,
代碼地址:https://github.com/WeLightProject/tai-shang-nft-contracts/blob/feat/basic_n/N.sol
該loot合約發行的NFT是包含0-14的8行數字,下面來分析一下主要的函式功能:
1.random
傳進一個string型別的引數,然后對其a bi編碼,在對其keccak256哈希運算,最后轉成int256回傳,
function random(string memory input) internal pure returns (uint256) {
return uint256(keccak256(abi.encodePacked(input)));
}
2.pluck
可以看到,獲取每行的數字內容,關鍵是呼叫pluck函式,需要給他傳進三個引數,tokenId, keyPrefix,sourceArray,一二兩個引數可以來構造生成隨機,這樣可以確保每個NFT的8行數字里面沒有相同的數字,同時保證生成的8888個NFT的唯一性,sourceArray則是為數字提供資料集,后面會對從資料集里面選出的數字output,下一步進行if匹配條件再進行相應的加工,例如+1,+2等,最后回傳出去就是每行得到的最終數字
function getFirst(uint256 tokenId) public view returns (uint256) {
return pluck(tokenId, "FIRST", units);
}
function getSecond(uint256 tokenId) public view returns (uint256) {
return pluck(tokenId, "SECOND", units);
}
.......
function pluck(
uint256 tokenId,
string memory keyPrefix,
uint8[] memory sourceArray
) internal view returns (uint256) {
//傳進tokenId和例如"FIRST"這樣的字符,然后回傳一個亂數
uint256 rand = random(string(abi.encodePacked(keyPrefix, toString(tokenId))));
//對rand % sourceArray.length取余,獲取sourceArray里面的一個值
uint256 output = sourceArray[rand % sourceArray.length];
//對亂數進行取余
uint256 luck = rand % 21;
if (luck > 14) {
//output+1或output+2
output += suffixes[rand % suffixes.length];
}
if (luck >= 19) {
if (luck == 19) {
//(output*1或output*0)再+1或+2
output = (output * multipliers[rand % multipliers.length]) + suffixes[rand % suffixes.length];
} else {
//output*1或output*0
output = (output * multipliers[rand % multipliers.length]);
}
}
return output;
}
3.tokenURI
此函式的作用是回傳一個將8個數字以一種黑底白字的svg格式的圖片,主要是通過拼接字串的方式
function tokenURI(uint256 tokenId) public view override returns (string memory) {
string[17] memory parts;
//svg圖片格式的前綴
parts[
0
] = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: white; font-family: serif; font-size: 14px; }</style><rect width="100%" height="100%" fill="black" /><text x="10" y="20" class="base">';
//數字1
parts[1] = toString(getFirst(tokenId));
parts[2] = '</text><text x="10" y="40" class="base">';
//數字2
parts[3] = toString(getSecond(tokenId));
parts[4] = '</text><text x="10" y="60" class="base">';
//數字3
parts[5] = toString(getThird(tokenId));
parts[6] = '</text><text x="10" y="80" class="base">';
//數字4
parts[7] = toString(getFourth(tokenId));
parts[8] = '</text><text x="10" y="100" class="base">';
//數字5
parts[9] = toString(getFifth(tokenId));
parts[10] = '</text><text x="10" y="120" class="base">';
//數字6
parts[11] = toString(getSixth(tokenId));
parts[12] = '</text><text x="10" y="140" class="base">';
//數字7
parts[13] = toString(getSeventh(tokenId));
parts[14] = '</text><text x="10" y="160" class="base">';
//數字8
parts[15] = toString(getEight(tokenId));
parts[16] = "</text></svg>";
//接下來就是對上面的各部分進行拼接,9個一組
string memory output = string(
abi.encodePacked(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8])
);
output = string(
abi.encodePacked(
output,
parts[9],
parts[10],
parts[11],
parts[12],
parts[13],
parts[14],
parts[15],
parts[16]
)
);
//拼接完畢,使用Base64編碼庫函式進行整體編碼,方便傳輸
string memory json = Base64.encode(
bytes(
string(
abi.encodePacked(
'{"name": "N #',
toString(tokenId),
'", "description": "N is just numbers.", "image": "data:image/svg+xml;base64,',
//這里對于圖片的內容單獨進行了一次Base64編碼
Base64.encode(bytes(output)),
'"}'
)
)
)
);
output = string(abi.encodePacked("data:application/json;base64,", json));
return output;
}
這里我們可以使用remix傳入引數1呼叫一下看一下具體回傳格式究竟是什么樣子:
data:application/json;base64,eyJuYW1lIjogIk4gIzEiLCAiZGVzY3JpcHRpb24iOiAiTiBpcyBqdXN0IG51bWJlcnMuIiwgImltYWdlIjogImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIQnlaWE5sY25abFFYTndaV04wVW1GMGFXODlJbmhOYVc1WlRXbHVJRzFsWlhRaUlIWnBaWGRDYjNnOUlqQWdNQ0F6TlRBZ016VXdJajQ4YzNSNWJHVStMbUpoYzJVZ2V5Qm1hV3hzT2lCM2FHbDBaVHNnWm05dWRDMW1ZVzFwYkhrNklITmxjbWxtT3lCbWIyNTBMWE5wZW1VNklERTBjSGc3SUgwOEwzTjBlV3hsUGp4eVpXTjBJSGRwWkhSb1BTSXhNREFsSWlCb1pXbG5hSFE5SWpFd01DVWlJR1pwYkd3OUltSnNZV05ySWlBdlBqeDBaWGgwSUhnOUlqRXdJaUI1UFNJeU1DSWdZMnhoYzNNOUltSmhjMlVpUGpVOEwzUmxlSFErUEhSbGVIUWdlRDBpTVRBaUlIazlJalF3SWlCamJHRnpjejBpWW1GelpTSStORHd2ZEdWNGRENDhkR1Y0ZENCNFBTSXhNQ0lnZVQwaU5qQWlJR05zWVhOelBTSmlZWE5sSWo0M1BDOTBaWGgwUGp4MFpYaDBJSGc5SWpFd0lpQjVQU0k0TUNJZ1kyeGhjM005SW1KaGMyVWlQak04TDNSbGVIUStQSFJsZUhRZ2VEMGlNVEFpSUhrOUlqRXdNQ0lnWTJ4aGMzTTlJbUpoYzJVaVBqazhMM1JsZUhRK1BIUmxlSFFnZUQwaU1UQWlJSGs5SWpFeU1DSWdZMnhoYzNNOUltSmhjMlVpUGpnOEwzUmxlSFErUEhSbGVIUWdlRDBpTVRBaUlIazlJakUwTUNJZ1kyeGhjM005SW1KaGMyVWlQalk4TDNSbGVIUStQSFJsZUhRZ2VEMGlNVEFpSUhrOUlqRTJNQ0lnWTJ4aGMzTTlJbUpoYzJVaVBqTThMM1JsZUhRK1BDOXpkbWMrIn0=
我們通過在線網站進行解碼:https://tool.ip138.com/base64
將data:application/json;base64,之后的內容復制進去,得到一次解碼后的內容:
{"name": "N #1", "description": "N is just numbers.", "image": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaW5ZTWluIG1lZXQiIHZpZXdCb3g9IjAgMCAzNTAgMzUwIj48c3R5bGU+LmJhc2UgeyBmaWxsOiB3aGl0ZTsgZm9udC1mYW1pbHk6IHNlcmlmOyBmb250LXNpemU6IDE0cHg7IH08L3N0eWxlPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9ImJsYWNrIiAvPjx0ZXh0IHg9IjEwIiB5PSIyMCIgY2xhc3M9ImJhc2UiPjU8L3RleHQ+PHRleHQgeD0iMTAiIHk9IjQwIiBjbGFzcz0iYmFzZSI+NDwvdGV4dD48dGV4dCB4PSIxMCIgeT0iNjAiIGNsYXNzPSJiYXNlIj43PC90ZXh0Pjx0ZXh0IHg9IjEwIiB5PSI4MCIgY2xhc3M9ImJhc2UiPjM8L3RleHQ+PHRleHQgeD0iMTAiIHk9IjEwMCIgY2xhc3M9ImJhc2UiPjk8L3RleHQ+PHRleHQgeD0iMTAiIHk9IjEyMCIgY2xhc3M9ImJhc2UiPjg8L3RleHQ+PHRleHQgeD0iMTAiIHk9IjE0MCIgY2xhc3M9ImJhc2UiPjY8L3RleHQ+PHRleHQgeD0iMTAiIHk9IjE2MCIgY2xhc3M9ImJhc2UiPjM8L3RleHQ+PC9zdmc+"}
此時我們就可以看到真的內容,還有base64格式的圖片,讓我接著再一次決議data:image/svg+xml;base64,之后的內容:
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: white; font-family: serif; font-size: 14px; }</style><rect width="100%" height="100%" fill="black" /><text x="10" y="20" class="base">5</text><text x="10" y="40" class="base">4</text><text x="10" y="60" class="base">7</text><text x="10" y="80" class="base">3</text><text x="10" y="100" class="base">9</text><text x="10" y="120" class="base">8</text><text x="10" y="140" class="base">6</text><text x="10" y="160" class="base">3</text></svg>
最終我們得到了,最后s v g圖片的代碼,展示圖如下:

4.claim
發行一個NFT,總量不超過8889個
function claim(uint256 tokenId) public nonReentrant {
require(tokenId > 0 && tokenId < 8889, "Token ID invalid");
_safeMint(_msgSender(), tokenId);
}
至于toString,還有Base64這里就不過多介紹了,
分析完合約,我們來對此合約生成的每個NFT進行分析
分析庫代碼地址:https://github.com/Anish-Agnihotri/dhof-loot
通過上面這個工具我們可以算出每個NFT的稀有度分數以及他的排名,然后通過一個腳本將json內容寫進c s v檔案中,如下部分截圖:

所以說NFT的內容是根據其token ID確定的——這意味著在最初的NFT發行之前,只要通過閱讀智能合約,任何人都可以輕而易舉地提前計算出每個NFT稀有度以及排名,由于 claim() 函式將代幣 ID 作為一個引數,所以很容易從收藏品中挑選出最稀有的物品,并趕在其他人之前立即將其鑄造完成,因為資訊的不對稱,對于每個玩家來說是極為不公平的,也與loot專案的初衷背道而馳,希望未來可以解決這個問題,讓每個NFT的珍稀度變得真正隨機,
總結:Loot是充滿想象力的,它像一個給了你畫筆的畫布,賦有巨大的吸引力來讓人共同創作、建設和傳播,但是由于每個NFT稀缺性的有規可循使得資訊不對稱,很容易破壞NFT的公平競爭環境,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/357189.html
標籤:區塊鏈
上一篇:資料中臺建設的價值及資料中臺架構
