Code on the Blockchain - Electronic Contract Scripts
Note: Almost all of the CryptoKitties contract scripts are open source and documented with inline running commentary. Thanks! The KittyCore contract script is about 2 000 lines total.
The only sooper-sekretoo contract is the GeneScienceInterface with the "magic" mixGenes function that given genes of kitten 1 & 2, return a genetic combination.
Note: The mixGenes got "reverse-engineered" from the opcode - thanks to Sean Soria (see CryptoKitties mixGenes Function, Dec 2017) -
and is now a "public" sooper-sektretoo.
See mixGenes.rb
for a ruby version
or mixGenes.py
for a python version.
Etherscan
- KittyCore (Open Source), see contract address
0x06012c8cf97bead5deae237070f9587f8e7a266d
- GeneScienceInterface (Opcode), see contract address
0xf97e0a5b616dffc913e72455fde9ea8bbe946a2b
The genetic combination algorithm is kept seperate so we can open-source all of the rest of our code without making it too easy for folks to figure out how the genetics work. Don't worry, I'm sure someone will reverse engineer it soon enough!
-- Commentary from the CryptoKitties source code
- SaleClockAuction (Open Source), see contract address
0xb1690c08e213a35ed9bab7b318de14420fb57d8c
- SiringClockAuction (Open Source), see contract address
0xc7af99fe5513eb6710e6d5f44f9989da40f27f26
The auctions are seperate since their logic is somewhat complex and there's always a risk of subtle bugs. By keeping them in their own contracts, we can upgrade them without disrupting the main contract that tracks kitty ownership.
-- Commentary from the CryptoKitties source code
Contract structure:
The day-one functionality of the contract scripts includes:
- Keep track of the genes of upcoming gen0 CryptoKitties
- Introducing the genes of gen0 CryptoKitties to the Core Contract
- Launching the auctions for gen0 CryptoKitties (including price determination)
- Combining the genotypes of two parent CryptoKitties to determine the genotype of the new CryptoKitten
- Managing the auctions of CryptoKitties (both gen-0 cats being auctioned to users and user-to-user auctions) and siring tokens
- Managing siring auctions (including initiating the breeding when successful).
All functionality for breeding, buying, selling, and transferring cats will be possible for any user by interacting directly with the contracts on the blockchain. Any auctions or sales conducted through our auction contract will include a 3.75% commission (no minimum) taken from the seller's portion.
(Source: CryptoKitties Technical Details / Contract Structure)
The contract inheritance for the main kitty contract looks like this:
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
This contract manages the various addresses and constraints for operations that can be executed only by specific roles. Namely CEO, CFO and COO.
-- Commentary from the CryptoKitties source code
This is where we define the most fundamental code shared throughout the core functionality. This includes our main data storage, constants and data types, plus internal functions for managing these items.
-- Commentary from the CryptoKitties source code
/// @dev The main Kitty struct. Every cat in CryptoKitties is represented by a copy
/// of this structure, so great care was taken to ensure that it fits neatly into
/// exactly two 256-bit words. Note that the order of the members in this structure
/// is important because of the byte-packing rules used by Ethereum.
/// Ref: http://solidity.readthedocs.io/en/develop/miscellaneous.html
struct Kitty {
// The Kitty's genetic code is packed into these 256-bits, the format is
// sooper-sekret! A cat's genes never change.
uint256 genes;
// The timestamp from the block when this cat came into existence.
uint64 birthTime;
// The minimum timestamp after which this cat can engage in breeding
// activities again. This same timestamp is used for the pregnancy
// timer (for matrons) as well as the siring cooldown.
uint64 cooldownEndBlock;
// The ID of the parents of this kitty, set to 0 for gen0 cats.
// Note that using 32-bit unsigned integers limits us to a "mere"
// 4 billion cats. This number might seem small until you realize
// that Ethereum currently has a limit of about 500 million
// transactions per year! So, this definitely won't be a problem
// for several years (even as Ethereum learns to scale).
uint32 matronId;
uint32 sireId;
// Set to the ID of the sire cat for matrons that are pregnant,
// zero otherwise. A non-zero value here is how we know a cat
// is pregnant. Used to retrieve the genetic material for the new
// kitten when the birth transpires.
uint32 siringWithId;
// Set to the index in the cooldown array (see below) that represents
// the current cooldown duration for this Kitty. This starts at zero
// for gen0 cats, and is initialized to floor(generation/2) for others.
// Incremented by one for each successful breeding action, regardless
// of whether this cat is acting as matron or sire.
uint16 cooldownIndex;
// The "generation number" of this cat. Cats minted by the CK contract
// for sale are called "gen0" and have a generation number of 0. The
// generation number of all other cats is the larger of the two generation
// numbers of their parents, plus one.
// (i.e. max(matron.generation, sire.generation) + 1)
uint16 generation;
}
(Source: KittyBase.sol)
This provides the methods required for basic non fungible token transactions, following the draft ERC-721 spec.
-- Commentary from the CryptoKitties source code
This file contains the methods necessary to breed cats together, including keeping track of siring offers, and relies on an external genetic combination contract.
-- Commentary from the CryptoKitties source code
Here we have the public methods for auctioning or bidding on cats or siring services. The actual auction functionality is handled in two sibling contracts (one for sales and one for siring), while auction creation and bidding is mostly mediated through this facet of the core contract.
-- Commentary from the CryptoKitties source code
This final facet contains the functionality we use for creating new gen0 cats. We can make up to 5000 "promo" cats that can be given away (especially important when the community is new), and all others can only be created and then immediately put up for auction via an algorithmically determined starting price. Regardless of how they are created, there is a hard limit of 50k gen0 cats. After that, it's all up to the community to breed, breed, breed!
-- Commentary from the CryptoKitties source code
// Limits the number of cats the contract owner can ever create.
uint256 public constant PROMO_CREATION_LIMIT = 5000;
uint256 public constant GEN0_CREATION_LIMIT = 45000;
(Source: KittyMinting.sol)
/// @notice Returns all the relevant information about a specific kitty.
/// @param _id The ID of the kitty of interest.
function getKitty(uint256 _id)
external
view
returns (
bool isGestating,
bool isReady,
uint256 cooldownIndex,
uint256 nextActionAt,
uint256 siringWithId,
uint256 birthTime,
uint256 matronId,
uint256 sireId,
uint256 generation,
uint256 genes
) {
Kitty storage kit = kitties[_id];
// if this variable is 0 then it's not gestating
isGestating = (kit.siringWithId != 0);
isReady = (kit.cooldownEndBlock <= block.number);
cooldownIndex = uint256(kit.cooldownIndex);
nextActionAt = uint256(kit.cooldownEndBlock);
siringWithId = uint256(kit.siringWithId);
birthTime = uint256(kit.birthTime);
matronId = uint256(kit.matronId);
sireId = uint256(kit.sireId);
generation = uint256(kit.generation);
genes = kit.genes;
}
(Source: KittyCore.sol)
See How to Code Your Own CryptoKitties-Style Game on Ethereum by James Martin Duffy, Dec 2017 -- for an in-depth analysis / write-up about the machinery,
Documentation from the Official CryptoKitty Bounty Program (github: axiomzen/cryptokitties-bounty), Nov 2017
CryptoKitties is composed of 4 public facing contracts. Below we'll provide an overview on these contracts:
Also referred as the main contract, is where Kitties and their ownership are stored. This also mediates all the main operations, such as breeding, exchange, and part of auctions.
For this release, the actual bytecode released for the contract is
KittyCoreRinkeby.sol
, explained below.Where users are expected to acquire their gen0 kitten. It is also a marketplace where anyone can post their kitten for auction. See Dutch/Clock auction - note we also accept an increasing price. ps: CryptoKitties auctions take an initial time and duration, and after duration is over they are not closed. Instead they hold the final price indefinitely
A marketplace where any user can offer their Kitty as a potential sire for any takers.
It's a mystery! Not public for this release.
[...]
Here's what we expect to be the most usual flow, and what function are to be called.
- COO will periodically put a kitten to gen0 auction (Main
createGen0Auction()
)- user go an buy gen0 kittens (Sale Auction
bid()
)- user can get kitty data (Main
getKitty()
)- user can breed their own kittens (Main
breedWith()
orbreedWithAuto()
)- after cooldown is passed, any user can have a pregnant kitty giving birth (Main
giveBirth()
)- user can offer one of their kitties as sire via auction (Main
createSiringAuction()
)- user can offer their kitty as sire to another user (Main
approveSiring()
)- user can bid on an active siring auction (Main
createSiringAuction()
)- user can put their kitty for sale on auction (Main
createSaleAuction()
)- user can buy a kitty that is on auction from another user (Sale Auction
bid()
)- user can check info of a kitty that is to auction (Sale/Siring Auction
getAuction()
)- user can cancel an auction they started (Sale/Siring Auction
cancelAuction()
)- user can transfer a kitty they own to another user (Main
transfer()
)- user can allow another user to take ownership of a kitty they own (Main
approve()
)- once an user has a kitty ownership approved, they can claim a kitty (Main
transferFrom()
)- CEO is the only one that may replace COO or CTO (Main
setCEO()
setCFO()
setCOO()
)- COO can mint and distribute promotional kittens (Main
createPromoKitty()
)- COO can transfer the balance from auctions (Main
withdrawAuctionBalances()
)- CFO can drain funds from main contract (Main
withdrawBalance()
)
CryptoKitties provides a practical use case for digital scarcity and digital collectibles by pioneering ERC-721, a non-fungible token protocol
A standard interface allows any Non Fungible Token (NFTs) on Ethereum to be handled by general-purpose applications. In particular, it will allow for Non Fungible Token (NFTs) to be tracked in standardized wallets and traded on exchanges.
Compatibility Functions for Ethereum Request for Comments #20 (ERC-20)
- function name() constant returns (string name)
- function symbol() constant returns (string symbol)
- function totalSupply() constant returns (uint256 totalSupply)
- function balanceOf(address _owner) constant returns (uint256 balance)
Basic Ownership Functions
- function ownerOf(uint256 _tokenId) constant returns (address owner)
- function approve(address _to, uint256 _tokenId)
- function takeOwnership(uint256 _tokenId)
- function transfer(address _to, uint256 _tokenId)
- function tokenOfOwnerByIndex(address _owner, uint256 _index) constant returns (uint tokenId)
Metadata Functions
- function tokenMetadata(uint256 _tokenId) constant returns (string infoUrl)
Events
- event Transfer(address indexed _from, address indexed _to, uint256 _tokenId)
- event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId)