#はじめに
CryptoKittiesというEthereum上で行う猫育成ゲームが2017年の末頃に流行りました。
https://www.cryptokitties.co/
ERC721を採用する事で、猫をNon-Fungible Tokenとし、猫1匹ずつにアイデンティティを持たせて、どの猫も世界に一つしかいない代替不可なものとしています。
猫は配合する事で、新しい猫が産むことが出来、レアな猫はなんと数百万円で取引されています。
CryptoKittiesのコードは公開されているため、そのコードから配合ロジックを探りたいと思います。
#配合ロジックを探る
コードはいくつかのコントラクトから成り立ち、最終的にkittyCoreがコントラクトを継承しています。
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
配合についてはKittyBreedingのcontractに記載されてます。
function setGeneScienceAddress(address _address) external onlyCEO {
GeneScienceInterface candidateContract = GeneScienceInterface(_address);
// NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
require(candidateContract.isGeneScience());
// Set the new contract address
geneScience = candidateContract;
}
function giveBirth(uint256 _matronId)
external
whenNotPaused
returns(uint256)
{
// Grab a reference to the matron in storage.
Kitty storage matron = kitties[_matronId];
// Check that the matron is a valid cat.
require(matron.birthTime != 0);
// Check that the matron is pregnant, and that its time has come!
require(_isReadyToGiveBirth(matron));
// Grab a reference to the sire in storage.
uint256 sireId = matron.siringWithId;
Kitty storage sire = kitties[sireId];
// Determine the higher generation number of the two parents
uint16 parentGen = matron.generation;
if (sire.generation > matron.generation) {
parentGen = sire.generation;
}
// Call the sooper-sekret gene mixing operation.
uint256 childGenes = geneScience.mixGenes(matron.genes, sire.genes, matron.cooldownEndBlock - 1);
// Make the new kitten!
address owner = kittyIndexToOwner[_matronId];
uint256 kittenId = _createKitty(_matronId, matron.siringWithId, parentGen + 1, childGenes, owner);
// Clear the reference to sire from the matron (REQUIRED! Having siringWithId
// set is what marks a matron as being pregnant.)
delete matron.siringWithId;
// Every time a kitty gives birth counter is decremented.
pregnantKitties--;
// Send the balance fee to the person who made birth happen.
msg.sender.send(autoBirthFee);
// return the new kitten's ID
return kittenId;
}
}
注目するのはここ
uint256 childGenes = geneScience.mixGenes(matron.genes, sire.genes, matron.cooldownEndBlock - 1);
ここで子供の遺伝子が決定されますが、geneScienceが外部のコントラクトを参照し、コードが公開されていないため、残念ながらmixGenesの内容までは分かりません。(分かってしまったらゲーム性が無くなりますよね^^;)
ただし引数として父、母の遺伝子、母のcooldownEndBlock
が利用される事が分かります。
geneScienceはCEOしかコントラクトアドレスを設定出来ないようにしてます。
ちなみにgeneScienceのコントラクトアドレスまでは分かりますので興味ある方はこちらから。
https://etherscan.io/address/0xf97e0a5b616dffc913e72455fde9ea8bbe946a2b#code
海外では猫の配合サンプルから解析したり、bytecodeから解析してるツワモノもいるみたいです。
https://medium.com/@kaigani/the-cryptokitties-genome-project-68582016f687
https://medium.com/@alexhegyi/cryptokitties-genescience-1f5b41963b0d
https://medium.com/@sean.soria/cryptokitties-mixgenes-function-69207883fc80
配合ロジックは分かりませんでしたが、Dappを作る上で、クローズにしたい実装が学べました。
#参考にさせて頂きました。
CryptoKittiesコード解説
仮想仔猫ゲーム CryptoKitties のコントラクト解読その2