CryptoKitties(中文名:迷戀貓)是一款在以太坊區(qū)塊鏈上的虛擬養(yǎng)貓游戲屏轰,一經(jīng)推出就以病毒式的快速擴(kuò)散杈笔,橫掃整個(gè)以太坊市場(chǎng)野哭。而這款可愛的游戲于2018年 2 月 16 日(農(nóng)歷大年初一)登陸 iOS國(guó)區(qū)挂滓,中文名稱的 “迷戀貓”妆档,皆因 “迷戀” 與 “密鏈” 同音膀懈,亦有 “加密區(qū)塊鏈” 的意思富岳,而且為了慶祝中國(guó)農(nóng)歷新年入篮,所有在節(jié)日期間出生的新貓咪都將會(huì)有中國(guó)的背景故事陈瘦。
迷戀貓是一款由 Axiom Zen 和以太坊智能合作開發(fā)的區(qū)塊鏈寵物養(yǎng)成游戲。在游戲中潮售,玩家使用以太幣(ETH)進(jìn)行電子貓的購(gòu)買痊项、喂食、照料與交配等酥诽,但其最為核心是玩法是將以太坊區(qū)塊鏈中的電子貓進(jìn)行出售线婚。撇開眾人對(duì)虛擬小貓的狂熱不談,畢竟絕對(duì)不只是貓很可愛這種原因盆均,這個(gè)游戲已造成過(guò)大流量塞弊,甚至因流量太大導(dǎo)致游戲困難,讓很多交易耗費(fèi)比原本更長(zhǎng)的時(shí)間,官方甚至為此讓生育費(fèi)漲價(jià)以提供礦工更高的誘因游沿。目前 CryptoKitties 已經(jīng)成為以太坊最流行的智能合約饰抒,數(shù)量約莫是第二名的兩倍。
輝哥系統(tǒng)整合出了ERC721從理論到實(shí)踐的文章诀黍,可按需查看:
(1)第十七課 【ERC721實(shí)踐】迷戀貓從玩耍到開發(fā)
(2)第三十三課 如何創(chuàng)建自己的ERC721非同質(zhì)化資產(chǎn)生物商店袋坑?
(3)第三十四課 采用TRUFFLE框架如何創(chuàng)建自己的ERC721非同質(zhì)化資產(chǎn)生物商店?
(4)第三十五課 如何配置Metadata以便裝飾你的ERC721非同質(zhì)化資產(chǎn)眯勾?
1. 迷戀貓注冊(cè)/玩法攻略
玩迷戀貓游戲枣宫,玩家需要在以太坊區(qū)塊鏈上下載到這款游戲的APP,游戲開始系統(tǒng)會(huì)贈(zèng)送玩家一只喵吃环。剛推出時(shí)是送貓的也颤,現(xiàn)在只有活動(dòng)時(shí)才贈(zèng)送。它讓你沉迷于吸貓郁轻,然后當(dāng)你無(wú)法自拔后翅娶,就會(huì)自愿掏出大把的以太幣去氪金了,滿滿的套路昂梦ā竭沫!
1.1 在谷歌瀏覽器中安裝MetaMask
1.1.1 下載安裝谷歌瀏覽器(Chrome)
百度搜索"谷歌瀏覽器"即可進(jìn)行下載安裝(谷歌瀏覽器可以完美支持第三方插件和擴(kuò)展程序)。
1.1.2 安裝MetaMask錢包插件
MetaMask是一款運(yùn)行穩(wěn)定的以太坊錢包骑篙,我們和其他交易所的區(qū)別之一在于在這里您可以自主管理您的錢包蜕提,并且錢包所有的資產(chǎn)變動(dòng)都會(huì)上區(qū)塊鏈確認(rèn),完全是開放和透明的靶端,而在其他交易所贯溅,您的錢包實(shí)際是平臺(tái)在管理,無(wú)法完全杜絕資金風(fēng)險(xiǎn)以及被限制充幣提幣等行為躲查。
1)國(guó)內(nèi)用戶可使用 MetaMask_v3.9.11.crx下載MetaMask并解壓它浅,然后在擴(kuò)展程序設(shè)置頁(yè)面chrome://extensions/將下載好的文件拖進(jìn)來(lái)即可安裝,安裝后點(diǎn)擊啟用镣煮,即可在瀏覽器右上角看到MetaMask圖標(biāo)姐霍。如下圖:
2)翻墻或者國(guó)外的用戶可以點(diǎn)擊 這里在谷歌插件商店進(jìn)行安裝。
1.2 創(chuàng)建MetaMask賬號(hào)
1)接下來(lái)典唇,點(diǎn)擊MetaMask圖標(biāo)創(chuàng)建自己的賬戶镊折。
2)對(duì)MetaMask錢包插件進(jìn)行設(shè)置,首先需要鏈接到主網(wǎng)介衔。點(diǎn)擊MetaMask界面的左上角恨胚,選擇Main Ethereum Network
1.3 購(gòu)買迷戀貓
打開官方網(wǎng)站(www.cryptokitties.co ),用MetaMask的錢包地址登錄炎咖,然后到市場(chǎng)上用ETH去購(gòu)買貓赃泡,新手登錄將免費(fèi)獲得一只寒波。需要擁有以太幣(ETH),用于養(yǎng)貓的花費(fèi)升熊,沒有的話要先去交易所買點(diǎn)以太幣ETH俄烁。
然后到你的貓咪個(gè)人頁(yè)面去喂養(yǎng)、培育级野、銷售它页屠。每一個(gè)貓咪都可以選擇扮演母親或者父親的角色,和其他異性貓咪組成家庭蓖柔,最后按繁殖按鈕生下小貓咪辰企。如果想和其他人的貓咪繁育,則需要支付其他玩家相應(yīng)的ETH况鸣。生下的小貓咪則可以去市場(chǎng)上交易牢贸。貓咪每多繁殖一次,培育小貓咪所需時(shí)間都會(huì)相應(yīng)增長(zhǎng)懒闷,目前官網(wǎng)上每5分鐘就誕生一個(gè)小貓咪。主人可以將自己的貓咪打扮各種風(fēng)格的花式貓栈幸。由于區(qū)塊鏈?zhǔn)欠稚⒌姆吖溃總€(gè)交易都是通過(guò)多臺(tái)計(jì)算機(jī)分配的,而不是中央服務(wù)器速址,所以玩家支付的ETH相當(dāng)于區(qū)塊鏈網(wǎng)絡(luò)中支持交易或合約的成本玩焰。
當(dāng)你已在瀏覽器安裝MetaMask插件并手握MetaMask賬號(hào)后,擼貓的一切準(zhǔn)備工作已經(jīng)完畢芍锚,登陸迷戀貓(CryptoKitties)官網(wǎng)昔园,準(zhǔn)備選購(gòu)你的第一只貓咪吧。
在以太貓這款游戲中并炮,玩家必須至少擁有一只貓才可進(jìn)行游戲默刚,而獲得貓主要可以通過(guò)以下三種方式:
1.測(cè)試玩家,獲贈(zèng)免費(fèi)的貓
2.普通玩家逃魄,在游戲內(nèi)市場(chǎng)購(gòu)買自己的第一只貓
3.普通玩家荤西,在Twitch、Reddit等平臺(tái)等待主播或其他玩家贈(zèng)送(適合體驗(yàn)游戲)
在這里我們僅介紹第2種伍俘,通過(guò)在市場(chǎng)中購(gòu)買貓的方式開始游玩:
當(dāng)您已在瀏覽器上安裝并登陸MetaMask錢包邪锌,迷戀貓官網(wǎng)會(huì)自動(dòng)同步您的登陸信息。在此過(guò)程中您可能會(huì)遇到賬號(hào)被鎖定的阻礙癌瘾,這是正趁俜幔現(xiàn)象,輸入密碼就可解鎖妨退。
初始頁(yè)面妇萄,左上為您的個(gè)人信息蜕企,右側(cè)頂部的三個(gè)標(biāo)簽欄依次為:“我的貓咪”(My Kitties)、“市場(chǎng)”(Marketplace)還有“邀請(qǐng)”(Invite)嚣伐。但由于上圖中的賬號(hào)未擁有貓糖赔,所以頁(yè)面中顯示的是市場(chǎng)推薦。
讓我們點(diǎn)進(jìn)“市場(chǎng)”看看具體情況轩端。
玩家可以在市場(chǎng)中交易或給自己的貓配種放典。頁(yè)面中上的四個(gè)標(biāo)簽分別為:“正在售賣”(For Sale)、“提供配種”(Siring)基茵、“零代貓”(Gen 0)以及“全部”(All Kitts)奋构。
顧名思義,通過(guò)“正在售賣”標(biāo)簽玩家可以快速查看可以購(gòu)買的對(duì)象拱层。
“提供配種”標(biāo)簽下顯示的全是可以用來(lái)與自己貓交配的“公貓”對(duì)象弥臼。
“零代貓”的概念比較特殊,在2018年11月前根灯,系統(tǒng)每隔15分鐘都會(huì)產(chǎn)出一批零代貓径缅,它們擁有最短的初始生殖間隔。新零代貓的初始價(jià)格比最近市場(chǎng)中售賣出的五只貓的價(jià)格平均值高50%烙肺。
通過(guò)“全部”標(biāo)簽纳猪,玩家可以查看游戲里的所有貓。無(wú)論是“市場(chǎng)”還是“我的貓咪”頁(yè)面桃笙,玩家都可通過(guò)右側(cè)下拉框簡(jiǎn)單篩選顯示規(guī)則氏堤。規(guī)則大體為“最新一代”、“最初始一代”以及“最便宜”和“最貴”搏明。
購(gòu)買貓時(shí)鼠锈,玩家除要選擇帶有“For sale”(正在售賣)標(biāo)簽的對(duì)象,還需仔細(xì)查該對(duì)象的各項(xiàng)屬性星著。
這里要注意幾點(diǎn)购笆,包括貓的代數(shù),貓的交配間隔以及它的外觀和屬性虚循。
通常來(lái)說(shuō)添诉,零代貓擁有最短的初始交配間隔梧疲,但隨著玩家讓其配種次數(shù)的增多岖是,貓咪的交配間隔會(huì)愈發(fā)延長(zhǎng)轴咱。
以今天創(chuàng)下新交易記錄的4號(hào)貓“Fluffy”為例,它的交配間隔已經(jīng)降至第二檔剪廉,意味著它只能每隔2-5分鐘交配一次娃循。
由玩家培育出的貓咪的交配間隔不會(huì)低于它的父母。目前最慢一檔的交配間隔為一周一次斗蒋。而僅在目前看來(lái)捌斧,交配間隔越短的貓咪在市場(chǎng)上的價(jià)值也就越高笛质。
已有不少玩家把迷戀貓當(dāng)成“生殖農(nóng)場(chǎng)”,所以如果您是初次進(jìn)入游戲捞蚂,一定要觀察購(gòu)買對(duì)象是否處在交配CD妇押,以及它的交配欲望。
除了交配相關(guān)姓迅,貓的外觀敲霍、性狀以及父母和子女可能都是買貓者要考慮在內(nèi)的問(wèn)題。
從眼睛到尾巴再到花色甚至是背景丁存,這些都是能夠直觀觀察到的肩杈。而同過(guò)“Cattributes”一欄,你還可以進(jìn)一步看到更多關(guān)于這只貓咪由基因排列體現(xiàn)出的性狀特征解寝。
題外話扩然,迷戀貓里的貓咪均由256位基因編碼組成,父母的基因在一定程度上會(huì)決定孩子的特征聋伦。零代貓由于是系統(tǒng)生成夫偶,無(wú)父母一欄。
看到了吧觉增,在迷戀貓里買貓的門道非常多兵拢,入坑需謹(jǐn)慎。
在選擇好想要購(gòu)買的貓咪后抑片,點(diǎn)擊“Buy now”按鈕并使用以太幣購(gòu)買貓咪卵佛。
以上就是就是以太坊買貓攻略杨赤。需要注意的是敞斋,游戲中玩家自行配種以及更多涉及市場(chǎng)的操作均需向平臺(tái)提交手續(xù)費(fèi)。所以不僅是想在迷戀貓里賺錢疾牲,就算想要維持持續(xù)運(yùn)作也不是一件容易事植捎。當(dāng)然,如果你手握一大堆以太幣那就簡(jiǎn)單了阳柔。
2. 謎戀貓?jiān)创a詳解
要想快速了解這個(gè)游戲的工作原理焰枢,最好的方法就是直接閱讀源代碼。
CryptoKitties 的源代碼大部分是開源的(也有小部分沒有開源舌剂,主要是是交配基因更新這部分)济锄。CryptoKitties 源碼大約有2000行,本文將主要講解其中相對(duì)重要的部分霍转。
CryptoKitties游 戲的源代碼分成了一個(gè)個(gè)的子合約荐绝,而非一個(gè)包含所有邏輯的單一文件。
子合約通過(guò)下述方式繼承主合約:
contract KittyAccessControl
contract KittyBase is KittyAccessControl
contract KittyOwnership is KittyBase, ERC721
contract KittyBreeding is KittyOwnership
contract KittyAuction is KittyBreeding
contract KittyMinting is KittyAuction
contract KittyCore is KittyMinting
最終應(yīng)用程序指向的合約是 KittyCore 合約避消,這個(gè)合約繼承了前面所有合約的屬性和方法低滩。接下來(lái)召夹,讓我們一個(gè)一個(gè)地來(lái)分析這些合約。
2.1 KittyAccessControl:誰(shuí)控制合約恕沫?
該合約負(fù)責(zé)管理各種不同的地址监憎,同時(shí)定義了各種僅限于特定角色執(zhí)行的限制性操作,這些角色被命名為“CEO”婶溯、“CFO”和“COO”鲸阔。
KittyAccessControl 合約主要功能是管理其他合約,所以它不涉及游戲的具體邏輯爬虱。該合約定義了以太坊地址“CEO”隶债、“CFO”和“COO”的使用方法,它們對(duì)該合約有著特殊的所有權(quán)以及控制權(quán)限跑筝。
KittyAccessControl 合約還定義了一些函數(shù)修飾符死讹,如 onlyCEO (該函數(shù)只有“CEO”才能執(zhí)行),同時(shí)該合約還定義了一些暫停/恢復(fù)合約的方法以及提現(xiàn)方法曲梗。
modifier onlyCLevel() {
require(
msg.sender == cooAddress ||
msg.sender == ceoAddress ||
msg.sender == cfoAddress
);
_;
}
//...some other stuff
// Only the CEO, COO, and CFO can execute this function:
function pause() external onlyCLevel whenNotPaused {
paused = true;
}
pause() 函數(shù)主要是方便開發(fā)人員進(jìn)行版本更新赞警,以防那些預(yù)見不到的 bug。但我同事 Luke 指出虏两,這個(gè)方法可以讓開發(fā)人員有權(quán)完全凍結(jié)合約愧旦,令所有人都無(wú)法轉(zhuǎn)讓、出售或繁殖他們的貓咪定罢!當(dāng)然笤虫,開發(fā)人員并不想這么做。但真正有趣的地方確實(shí)祖凫,大多數(shù)人僅僅因?yàn)樵撚螒蜻\(yùn)行在以太坊上琼蚯,就會(huì)以為它是一款完全是去中心化的游戲。
我們接著來(lái)看其他合約惠况。
2.1 KittyBase:數(shù)字貓是什么貓遭庶?
KittyBase 合約是我們定義最底層的代碼的地方,這些代碼會(huì)用到整個(gè)游戲的所有核心功能上稠屠,包括數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)峦睡、相關(guān)常量與數(shù)據(jù)類型,以及管理這些數(shù)據(jù)的內(nèi)部函數(shù)权埠。
KittyBase 合約定義了應(yīng)用程序的很多核心數(shù)據(jù)榨了。首先它將Kitty定義為結(jié)構(gòu)體類型:
struct Kitty {
uint256 genes;
uint64 birthTime;
uint64 cooldownEndBlock;
uint32 matronId;
uint32 sireId;
uint32 siringWithId;
uint16 cooldownIndex;
uint16 generation;
}
從這里可以看到,一只貓咪的本質(zhì)就是一長(zhǎng)串的無(wú)符號(hào)整數(shù)攘蔽。
接下來(lái)一一介紹貓咪的每個(gè)屬性的具體參數(shù):
genes — 是256位的整數(shù)龙屉,主要作為貓的遺傳密碼,是決定貓外貌的核心數(shù)據(jù)秩彤;
birthTime — 貓出生時(shí)所打包的區(qū)塊的時(shí)間戳叔扼;
cooldownEndBlock — 貓可以再次繁殖的最小時(shí)間事哭;
matronId&sireId — 貓母親的ID號(hào)和貓父親的ID號(hào);
siringWithId — 如果貓懷孕了瓜富,則設(shè)置為父親的ID鳍咱,否則為零;
cooldownIndex — 貓繁殖所需的冷卻時(shí)間(貓需要等待多久才能繁殖)与柑;
generation — 貓的“世代號(hào)”(指明這是第幾代貓)谤辜。合約創(chuàng)造的第一只貓是0代,新一代貓的“世代號(hào)”是其父母中較大的一代再加1价捧。
需要注意的是丑念,在 CryptoKitties 游戲中,貓是無(wú)性別之分的结蟋,任意2只貓都可以一起繁殖脯倚。
KittyBase 合約聲明了一個(gè)“貓”結(jié)構(gòu)的數(shù)組,如下所示:
該數(shù)組包含了所有貓咪的數(shù)據(jù)嵌屎,所以它就像一個(gè)貓咪數(shù)據(jù)庫(kù)一般推正。無(wú)論什么時(shí)候生成一個(gè)新的貓咪,它都會(huì)被添加到該數(shù)組內(nèi)宝惰,數(shù)組的索引就是貓咪的 ID 號(hào)植榕。下圖顯示的是創(chuàng)世貓,其 ID 號(hào)為“1”尼夺。Kitty[] kitties;
該合約中還包含有從貓咪 ID 號(hào)到其所有者地址的一個(gè)映射尊残,主要用于追蹤貓咪的所有者。
mapping (uint256 => address) public kittyIndexToOwner;
合約中還定義了其他一些映射淤堵,但此處不再深究每一個(gè)細(xì)節(jié)寝衫。
當(dāng)貓咪的所有者從一個(gè)人轉(zhuǎn)移到另外一個(gè)人時(shí),kittyIndexToOwner 映射就會(huì)更新粘勒,從而識(shí)別新的所有者竞端。
/// @dev Assigns ownership of a specific Kitty to an address.
function _transfer(address _from, address _to, uint256 _tokenId) internal {
// Since the number of kittens is capped to 2^32 we can't overflow this
ownershipTokenCount[_to]++;
// transfer ownership
kittyIndexToOwner[_tokenId] = _to;
// When creating new kittens _from is 0x0, but we can't account that address.
if (_from != address(0)) {
ownershipTokenCount[_from]--;
// once the kitten is transferred also clear sire allowances
delete sireAllowedToAddress[_tokenId];
// clear any previously approved ownership exchange
delete kittyIndexToApproved[_tokenId];
}
// Emit the transfer event.
Transfer(_from, _to, _tokenId);
}
現(xiàn)在我們來(lái)看看當(dāng)一個(gè)新的貓咪生成時(shí)都發(fā)生了些什么:
function _createKitty(
uint256 _matronId,
uint256 _sireId,
uint256 _generation,
uint256 _genes,
address _owner
)
internal
returns (uint)
{
// These requires are not strictly necessary, our calling code should make
// sure that these conditions are never broken. However! _createKitty() is already
// an expensive call (for storage), and it doesn't hurt to be especially careful
// to ensure our data structures are always valid.
require(_matronId == uint256(uint32(_matronId)));
require(_sireId == uint256(uint32(_sireId)));
require(_generation == uint256(uint16(_generation)));
// New kitty starts with the same cooldown as parent gen/2
uint16 cooldownIndex = uint16(_generation / 2);
if (cooldownIndex > 13) {
cooldownIndex = 13;
}
Kitty memory _kitty = Kitty({
genes: _genes,
birthTime: uint64(now),
cooldownEndBlock: 0,
matronId: uint32(_matronId),
sireId: uint32(_sireId),
siringWithId: 0,
cooldownIndex: cooldownIndex,
generation: uint16(_generation)
});
uint256 newKittenId = kitties.push(_kitty) - 1;
// It's probably never going to happen, 4 billion cats is A LOT, but
// let's just be 100% sure we never let this happen.
require(newKittenId == uint256(uint32(newKittenId)));
// emit the birth event
Birth(
_owner,
newKittenId,
uint256(_kitty.matronId),
uint256(_kitty.sireId),
_kitty.genes
);
// This will assign ownership, and also emit the Transfer event as
// per ERC721 draft
_transfer(0, _owner, newKittenId);
return newKittenId;
}
從上面這段代碼中可以看出屎即,這個(gè)函數(shù)傳遞了母親和父親的 ID 號(hào)庙睡、貓咪的世代號(hào)、256位遺傳密碼和所有者的地址技俐。然后創(chuàng)建貓咪乘陪,并將其加入到 Kitty 數(shù)組中,最后調(diào)用 _transfer() 將其分配給新的所有者雕擂。
是不是很酷啡邑!現(xiàn)在我們已經(jīng)知道 CryptoKitties 游戲如何將一只貓咪定義為一種數(shù)據(jù)類型,如何將所有貓咪都存儲(chǔ)在區(qū)塊鏈中井赌,以及如何跟蹤這些貓咪的所有者谤逼。
2.3 KittyOwnership:作為通證的貓咪
CryptoKitties 游戲遵循 ERC721 通證標(biāo)準(zhǔn)贵扰,這是一種不可替代通證,它可以很好地追蹤數(shù)字收藏品的所有權(quán)流部,比如數(shù)字撲克牌或 MMORPG(大型多人在線角色扮演游戲)中的稀有物品戚绕。
關(guān)于可互換性的說(shuō)明:Ether 是可互換的通證,因?yàn)槿我?個(gè) ETH 都與其他5個(gè) ETH 一樣有著同樣的價(jià)值枝冀。但是像 CryptoKitties 這樣的通證是不可替代通證舞丛,每只貓咪的外觀都各不相同,它們不能生而相同果漾,所以無(wú)法相互交換球切。
你可以從合約的定義中看出,KittyOwnership 繼承的是 ERC721 合約绒障。
contract KittyOwnership is KittyBase, ERC721 {
而所有是 ERC721 通證都遵循同樣的標(biāo)準(zhǔn)吨凑。下一章節(jié)分析ERC721標(biāo)準(zhǔn)。
3. 非同質(zhì)化代幣ERC721分析
3.1 ERC721是什么
和ERC20一樣户辱,ERC721同樣是一個(gè)代幣標(biāo)準(zhǔn)怀骤,ERC721官方簡(jiǎn)要解釋是Non-Fungible Tokens,簡(jiǎn)寫為NFTs焕妙,多翻譯為非同質(zhì)代幣蒋伦。
ERC721 是由Dieter Shirley 在2017年9月提出。Dieter Shirley 正是謎戀貓CryptoKitties背后的公司Axiom Zen的技術(shù)總監(jiān)焚鹊。因此謎戀貓也是第一個(gè)實(shí)現(xiàn)了ERC721 標(biāo)準(zhǔn)的去中心化應(yīng)用痕届。ERC721號(hào)提議已經(jīng)被以太坊作為標(biāo)準(zhǔn)接受,但該標(biāo)準(zhǔn)仍處于終結(jié)Final階段末患。本文介紹的ERC721標(biāo)準(zhǔn)基于最新(2018/03/23)官方提議研叫。
那怎么理解非同質(zhì)代幣呢?
非同質(zhì)代表獨(dú)一無(wú)二,謎戀貓為例璧针,每只貓都被賦予擁有基因嚷炉,是獨(dú)一無(wú)二的(一只貓就是一個(gè)NFTs),貓之間是不能置換的探橱。這種獨(dú)特性使得某些稀有貓具有收藏價(jià)值申屹,也因此受到追捧。
ERC20代幣是可置換的隧膏,且可細(xì)分為N份(1 = 10 * 0.1), 而ERC721的Token最小的單位為1哗讥,無(wú)法再分割。
如果同一個(gè)集合的兩個(gè)物品具有不同的特征胞枕,這兩個(gè)物品是非同質(zhì)的杆煞,而同質(zhì)是某個(gè)部分或數(shù)量可以被另一個(gè)同等部分或數(shù)量所代替。
非同質(zhì)性其實(shí)廣泛存在于我們的生活中,如圖書館的每一本决乎,寵物商店的每一只寵物队询,歌手所演唱的歌曲,花店里不同的花等等构诚,因此ERC721合約必定有廣泛的應(yīng)用場(chǎng)景娘摔。通過(guò)這樣一個(gè)標(biāo)準(zhǔn),也可建立跨功能的NFTs管理和銷售平臺(tái)(就像有支持ERC20的交易所和錢包一樣)唤反,使生態(tài)更加強(qiáng)大凳寺。
3.2 ERC721標(biāo)準(zhǔn)
ERC721最為一個(gè)合約標(biāo)準(zhǔn),提供了在實(shí)現(xiàn)ERC721代幣時(shí)必須要遵守的協(xié)議彤侍,要求每個(gè)ERC721標(biāo)準(zhǔn)合約需要實(shí)現(xiàn)ERC721及ERC165接口肠缨,接口定義如下:
pragma solidity ^0.4.20;
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
/// Note: the ERC-165 identifier for this interface is 0x80ac58cd
interface ERC721 /* is ERC165 */ {
/// @dev This emits when ownership of any NFT changes by any mechanism.
/// This event emits when NFTs are created (`from` == 0) and destroyed
/// (`to` == 0). Exception: during contract creation, any number of NFTs
/// may be created and assigned without emitting Transfer. At the time of
/// any transfer, the approved address for that NFT (if any) is reset to none.
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
/// @dev This emits when the approved address for an NFT is changed or
/// reaffirmed. The zero address indicates there is no approved address.
/// When a Transfer event emits, this also indicates that the approved
/// address for that NFT (if any) is reset to none.
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
/// @dev This emits when an operator is enabled or disabled for an owner.
/// The operator can manage all NFTs of the owner.
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param _owner An address for whom to query the balance
/// @return The number of NFTs owned by `_owner`, possibly zero
function balanceOf(address _owner) external view returns (uint256);
/// @notice Find the owner of an NFT
/// @dev NFTs assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @param _tokenId The identifier for an NFT
/// @return The address of the owner of the NFT
function ownerOf(uint256 _tokenId) external view returns (address);
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT. When transfer is complete, this function
/// checks if `_to` is a smart contract (code size > 0). If so, it calls
/// `onERC721Received` on `_to` and throws if the return value is not
/// `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
/// @param data Additional data with no specified format, sent in call to `_to`
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev This works identically to the other function with an extra data parameter,
/// except this function just sets data to ""
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
/// THEY MAY BE PERMANENTLY LOST
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
/// @notice Set or reaffirm the approved address for an NFT
/// @dev The zero address indicates there is no approved address.
/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
/// operator of the current owner.
/// @param _approved The new approved NFT controller
/// @param _tokenId The NFT to approve
function approve(address _approved, uint256 _tokenId) external payable;
/// @notice Enable or disable approval for a third party ("operator") to manage
/// all of `msg.sender`'s assets.
/// @dev Emits the ApprovalForAll event. The contract MUST allow
/// multiple operators per owner.
/// @param _operator Address to add to the set of authorized operators.
/// @param _approved True if the operator is approved, false to revoke approval
function setApprovalForAll(address _operator, bool _approved) external;
/// @notice Get the approved address for a single NFT
/// @dev Throws if `_tokenId` is not a valid NFT
/// @param _tokenId The NFT to find the approved address for
/// @return The approved address for this NFT, or the zero address if there is none
function getApproved(uint256 _tokenId) external view returns (address);
/// @notice Query if an address is an authorized operator for another address
/// @param _owner The address that owns the NFTs
/// @param _operator The address that acts on behalf of the owner
/// @return True if `_operator` is an approved operator for `_owner`, false otherwise
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
接口說(shuō)明:
- balanceOf(): 返回由_owner 持有的NFTs的數(shù)量。
- ownerOf(): 返回tokenId代幣持有者的地址盏阶。
- approve(): 授予地址_to具有_tokenId的控制權(quán)晒奕,方法成功后需觸發(fā)Approval 事件。
- setApprovalForAll(): 授予地址_operator具有所有NFTs的控制權(quán)名斟,成功后需觸發(fā)ApprovalForAll事件脑慧。
- getApproved()、isApprovedForAll(): 用來(lái)查詢授權(quán)砰盐。
-
safeTransferFrom():
轉(zhuǎn)移NFT所有權(quán)闷袒,一次成功的轉(zhuǎn)移操作必須發(fā)起 Transfer 事件。函數(shù)的實(shí)現(xiàn)需要做一下幾種檢查:
1] 調(diào)用者msg.sender應(yīng)該是當(dāng)前tokenId的所有者或被授權(quán)的地址
2] _from 必須是 _tokenId的所有者
3] _tokenId 應(yīng)該是當(dāng)前合約正在監(jiān)測(cè)的NFTs 中的任何一個(gè)
4] _to 地址不應(yīng)該為 0岩梳,如果_to 是一個(gè)合約應(yīng)該調(diào)用其onERC721Received方法, 并且檢查其返回值囊骤,如果返回值不為bytes4(keccak256("onERC721Received(address,uint256,bytes)"))則拋出異常。 - transferFrom(): 用來(lái)轉(zhuǎn)移NFTs, 方法成功后需觸發(fā)Transfer事件冀值。調(diào)用者自己確認(rèn)_to地址能正常接收NFT也物,否則將丟失此NFT。此函數(shù)實(shí)現(xiàn)時(shí)需要檢查上面條件的前4條列疗。
3.3 ERC165 標(biāo)準(zhǔn)
ERC721標(biāo)準(zhǔn)同時(shí)要求必須符合ERC165標(biāo)準(zhǔn) 滑蚯,其接口如下:
interface ERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
ERC165同樣是一個(gè)合約標(biāo)準(zhǔn),這個(gè)標(biāo)準(zhǔn)要求合約提供其實(shí)現(xiàn)了哪些接口抵栈,這樣再與合約進(jìn)行交互的時(shí)候可以先調(diào)用此接口進(jìn)行查詢告材。
interfaceID為函數(shù)選擇器,計(jì)算方式有兩種竭讳,如:bytes4(keccak256('supportsInterface(bytes4)'));
或ERC165.supportsInterface.selector
创葡,多個(gè)函數(shù)的接口ID為函數(shù)選擇器的異或值浙踢。
3.4 可選實(shí)現(xiàn)接口:ERC721Metadata
ERC721Metadata 接口用于提供合約的元數(shù)據(jù):name , symbol 及 URI(NFT所對(duì)應(yīng)的資源)绢慢。
其接口定義如下:
interface ERC721Metadata /* is ERC721 */ {
function name() external pure returns (string _name);
function symbol() external pure returns (string _symbol);
function tokenURI(uint256 _tokenId) external view returns (string);
}
接口說(shuō)明:
- name(): 返回合約名字,盡管是可選,但強(qiáng)烈建議實(shí)現(xiàn)胰舆,即便是返回空字符串骚露。
- symbol(): 返回合約代幣符號(hào),盡管是可選缚窿,但強(qiáng)烈建議實(shí)現(xiàn)棘幸,即便是返回空字符串。
- tokenURI(): 返回_tokenId所對(duì)應(yīng)的外部資源文件的URI(通常是IPFS或HTTP(S)路徑)倦零。外部資源文件需要包含名字误续、描述、圖片扫茅,其格式的要求如下:
{
"title": "Asset Metadata",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Identifies the asset to which this NFT represents",
},
"description": {
"type": "string",
"description": "Describes the asset to which this NFT represents",
},
"image": {
"type": "string",
"description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive.",
}
}
}
tokenURI通常是被web3調(diào)用蹋嵌,以便在應(yīng)用層做相應(yīng)的查詢和展示。
3.5 可選實(shí)現(xiàn)接口:ERC721Enumerable
ERC721Enumerable的主要目的是提高合約中NTF的可訪問(wèn)性葫隙,其接口定義如下:
interface ERC721Enumerable /* is ERC721 */ {
function totalSupply() external view returns (uint256);
function tokenByIndex(uint256 _index) external view returns (uint256);
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}
接口說(shuō)明:
- totalSupply(): 返回NFT總量
- tokenByIndex(): 通過(guò)索引返回對(duì)應(yīng)的tokenId栽烂。
- tokenOfOwnerByIndex(): 所有者可以一次擁有多個(gè)的NFT, 此函數(shù)返回_owner擁有的NFT列表中對(duì)應(yīng)索引的tokenId。
3.6 補(bǔ)充說(shuō)明
NTF IDs
NTF ID恋脚,即tokenId腺办,在合約中用唯一的uint265進(jìn)行標(biāo)識(shí),每個(gè)NFT的ID在智能合約的生命周期內(nèi)不允許改變糟描。推薦的實(shí)現(xiàn)方式有:
1. 從0開始怀喉,每新加一個(gè)NFT,NTF ID加1
2. 使用sha3后uuid 轉(zhuǎn)換為 NTF ID
與ERC-20的兼容性
ERC721標(biāo)準(zhǔn)盡可能遵循 ERC-20 的語(yǔ)義船响,但由于同質(zhì)代幣與非同質(zhì)代幣之間的根本差異磺送,并不能完全兼容ERC-20。
交易灿意、挖礦估灿、銷毀
在實(shí)現(xiàn)transter相關(guān)接口時(shí)除了滿足上面的的條件外,我們可以根據(jù)需要添加自己的邏輯缤剧,如加入黑名單等馅袁。
同時(shí)挖礦、銷毀盡管不是標(biāo)準(zhǔn)的一部分荒辕,我們可以根據(jù)需要實(shí)現(xiàn)汗销。
4. 彩貝社區(qū)介紹
彩貝鏈?zhǔn)加诓守惿鐓^(qū),它致力于為全世界的繪畫創(chuàng)作者提供最好用的繪畫工具抵窒,建立最繁榮活躍的繪畫興趣社區(qū)弛针,并通過(guò)區(qū)塊鏈社區(qū)方式,構(gòu)建全球統(tǒng)一的數(shù)字版權(quán)交易標(biāo)準(zhǔn)和交易支付工具李皇,跨越各國(guó)版權(quán)交易法律及支付結(jié)算的鴻溝削茁,成為全球商業(yè)級(jí)的作品發(fā)表、存儲(chǔ)、檢索和版權(quán)交易服務(wù)茧跋,數(shù)字藝術(shù)作品的創(chuàng)作生態(tài)慰丛、版權(quán)交易及衍生品服務(wù)平臺(tái)。
彩貝DAPP是彩貝鏈生態(tài)第一個(gè)落地去中心化應(yīng)用瘾杭,它是全球領(lǐng)先的數(shù)字繪畫社區(qū)畫吧的國(guó)際區(qū)塊鏈版本诅病。畫吧已有注冊(cè)用戶600萬(wàn),原創(chuàng)數(shù)字繪畫資產(chǎn)900萬(wàn)幅粥烁,畫吧完全自主開發(fā)全球領(lǐng)先的數(shù)字繪畫工具集贤笆,每幅數(shù)字繪畫全過(guò)程全平臺(tái)矢量回放,可實(shí)現(xiàn)2D讨阻,3D數(shù)字資產(chǎn)高效率高質(zhì)量生成苏潜。彩貝DAPP利用彩貝鏈基礎(chǔ)設(shè)施,降低版權(quán)交易各國(guó)差異性和支付方式差異性变勇,大幅提高交易效率恤左,降低交易成本,同時(shí)通過(guò)彩貝鏈代幣經(jīng)濟(jì)激勵(lì)體系搀绣,進(jìn)一步提升彩貝社區(qū)全球參與者活躍度飞袋。
5. 參考文檔
1) 區(qū)塊鏈游戲玩法及攻略:謎戀貓CryptoKitties(以太貓)為例
2) 謎戀貓?jiān)创a詳解:手把手教你開發(fā)自己的養(yǎng)成類區(qū)塊鏈游戲
3) 迷戀貓官網(wǎng)
4) 剖析非同質(zhì)化代幣ERC721-全面解析ERC721標(biāo)準(zhǔn)
5) 迷戀貓智能合約和源碼
6) ERC721接口文檔
7)OpenZeppelin實(shí)現(xiàn)的ERC721合約參考
8) CryptoKittes(加密貓链患,謎戀貓)智能合約結(jié)構(gòu)和源碼解析