Bored Ape Yacht Club: Smart Contract Breakdown
Explaining its functionality by grouping lines of code

Bored Apes need no introduction. When I decided to do a breakdown of BAYC, I decided to answer my long-standing questions:
- What’s the utility of an Ape? What do you really get if you buy one?
- How do they actually implement their promise land of merch, exclusive access, etc?
- How is access control implemented?
- How are secondary payments (royalties) implemented?
In this article, we are answering these questions. During the exploration, we will also learn about
- The market dynamics during the NFT sale
- How much founders of BAYC earned
- A silly bug of BAYC and how other NFTs blindly copied it
Here is the outline of this article:
- ERC721 — the NFT standard
- BAYC contract source code
- What happened after contract deployment
ERC721 — the NFT standard
ERC721 is a standard used for implementing NFTs (non-fungible tokens). It’s similar to ERC20 used for fungible tokens such as Dogecoin. The main difference is that ERC20 tokens are all the same, while each ERC721 token is unique.
Here is what functions should be implemented according to ERC721:
Most functions should be straightforward as they are pretty similar to ERC20 (I have a breakdown of ERC20 if you’re interested). The differing functions are:
tokenURI
— the path to the token metadata (like the image, qualities of the token, etc)tokenByIndex
— returnstokenId
of the token at the specified indextokenOfOwnerByIndex
— same astokenByIndex
but for the specified owner
For comparison, here are the functions required by the ERC20 standard:
How BAYC implements ERC721
BAYC just uses OpenZeppelin implementation of it. OpenZeppelin is a library of implementations of the most common standards.
You can inspect the code but there are no surprises there. Everything you would expect from a standard implementation:
- They use mappings to manage ownership of tokens:

- Here is how ownership is transferred(just reassign values in the mapping):

- Mappings are also used to manage approvals and operators:

What are approvals and operators?
Approval — allow someone else to manage (transfer, sell, etc) my token
Operator — approval but for all tokens
Used by 3rd parties like OpenSea to manage my tokens
- Although not part of the standard, Openzeppelin adds
mint
/burn
functions for adding/removing tokens:

BTW, by reading this code, I finally learned the origin of the word “safe” in
safeTransfer
. It just checks whether the receiver of NFT (if it’s a contract) is aware of the ERC721 protocol to prevent tokens from being forever locked.
BAYC contract source code
BAYC contract extends OpenZeppelin’s ERC721 to add functionality specific to BAYC. The contract source code can be found on Etherscan (or Github for better readability).
The file looks long but most of it is just OpenZeppelin imports (ERC721, SafeMath, Ownable, etc). The actual BAYC code is a pretty short contract named BoredApeYachtClub:

A few things not explained in the screenshot:
- Provenance — it’s supposed to be a unique signature for the entire NFT collection (change even one image and signature won’t match). The BAYC page on provenance explains how this signature is generated:

- Unfortunately, provenance is not constant and can be changed at any time by the owner.

- The other 2 unexplained things:
baseUri
andstartingIndex
will be explained later in the article.
By examining the BAYC code, I realized that it’s far from the elegance and efficiency of Uniswap. Some examples:
- Wasting gas — BAYC computes reveal timestamp in the constructor. This can be avoided by just passing in the already computed value.

- Even though
REVEAL_TIMESTAMP
is spelled with uppercase, it’s not constant — can be changed by the owner at any time. Same forBAYC_PROVENANCE
. - Apes can be reserved by the owner in unlimited quantity👌.
A silly mistake by BAYC and how other NFTs blindly copied it
So far, we have skipped over the mysterious variable startingIndex
. Thanks to another article about BAYC smart contract, I learned about its purpose.
BAYC team tried to prevent the sniping of rare tokens during pre-sale by randomizing the order of tokens. startingIndex
is supposed to serve as a random offset to randomize the order.
The code below illustrates how startingIndex
is calculated. It’s a pretty complicated way to generate a random number!

But… this random offset is not actually used anywhere! The code doesn't use it! Despite BAYC’s claims that the order of apes is randomized, it’s actually not! And startingIndex
just wastes gas!
The article about BAYC also claims that other NFTs just blindly copy/pasted the BAYC code without understanding what it does. So they inherited this startingIndex
bug. I wanted to verify this claim but was too lazy to go beyond an “NFTs inspired by BAYC” google search. If you know of any such contracts, please leave them in the comments.
What happened after contract deployment
We saw the code. But the code is static, it doesn't tell us the dynamic picture. What happened after deploying the contract?
You can inspect the entire history of transactions of this contract on Etherscan. Let’s scroll way back to the beginning:

Click on the 1st txn: the contract was deployed on Apr 22, 2021

Around 25 hours later (the 2nd txn), 30 apes were reserved by the creator. Taking the floor price of an Ape at 82 ETH ($230K), the 30 Apes would be valued at around $6.9M today 😳.

What was the fate of the reserved apes?
BAYC team transferred them to different addresses. Not sure if some of those addresses belonged to the BAYC team.
Next txn sets the baseUri
. This is the baseUri
variable in the contract:

What is baseUri?
baseUri
is kinda like a root path where all image metadata is stored. If we check the current value of baseUri
in the contract, it shows:

So, Ape 0 metadata is at ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/0
. That metadata is:

There is theimage
field here which points to:

Indeed, all this metadata matches what’s on BAYC’s website:

Ideally, baseUri
should be constant in this contract. However, it can be changed as many times as you want by the creators.
Back to the history of transactions
After setting baseUri
, contract creators
- started the sale
- then changed their mind
- and then 16 hours later, started it again
- and the minting process started

If you look further,
- there are a lot of
mintApe
txns - then you start seeing
transferFrom
andsetApproval
txns - then, 4 days after the sale started, we see the first withdrawal of 14 ETH (175 Apes at 0.08 ETH/Ape) by the BAYC team.
After that, more Apes are minted and more ETH is withdrawn. This goes on until all Apes (10K of them) are minted. After that, there are only secondary sales (on OpenSea) which show up as transfer
events on Etherscan.
Closing thoughts
So, what does the ownership of Apes really give you? The BAYC website says that you get some kind of exclusive access to the club where you can add your own graffiti on the board. Basically, nothing useful. I think it’s mainly used as a speculative tool.
How would access control for the exclusive club be implemented? It should be straightforward as all other ownership data is stored publicly on the blockchain.
Before going into the rabbit hole of BAYC, I was under the impression that NFTs offer secondary payments (royalties) to the original creator. So, every time there is a trade of a token, a small percentage goes to the original creator. The code does not implement this functionality so seems like I was wrong. But who knows, maybe “modern” NFTs do implement it. I will find out in another smart contract breakdown:)
CORRECTION: Thanks to Isaac for pointing this out in the comments, royalties are not implemented at the NFT smart contract level. They are implemented in the marketplace. Marketplaces are like a middleman that takes a cut and forwards some to the original creator.
That’s it for the BAYC contract breakdown! I hope this was helpful. Let me know in the comments if you have any questions.
I am planning to do more breakdowns of popular smart contracts like Axie Infinity and Aave, so follow me either on Medium or Twitter to get updates.
You can also check out breakdowns of other smart contracts and more stuff for Solidity noobs at solidnoob.com.
Want to Connect?Follow me on Twitter.