ERC721 + Vue.js CryptoKitties-like Dapp in under 10 minutes
You might have heard of CryptoKitties, an Ethereum-based platform where you can collect, buy, sell, and even breed digital cats, and about how people have been spending a crazy amount of money in the game.
Making a CryptoKitties-like application is actually quite easy! And in this tutorial, we’ll be doing just that.
What We Are About To Build
From here onwards, we will be building a simple CryptoKitties-like dapp, which we will call CryptoVipers (vipers, because why not?). In our simple application, we will be able to buy vipers, breed vipers, and view the ones we own. Which will be something like this:
- Viper Creation — we should be able to own new vipers by buying one or breeding two of them
- View Viper Details — we should be able to retrieve our vipers’ details and display it.
Aside from that, we will also be using Git later to clone our boilerplate :)
Before proceeding with this tutorial, you should first read the following articles:
- Getting Started with MetaMask
- Compile and Deploy Using Remix IDE
- Introduction to Smart Contracts and Solidity
ERC721 is a standard that describes how non-fungible (or unique tokens) on the Ethereum blockchain should be made. With ERC721, each item or token is unique, meaning it is not equal to any other token. You could think of each one as a rare, one-of-a-kind collectible.
According to the specifications, ERC721 defines a minimum interface a smart contract must implement to allow unique tokens to be managed, owned, and traded:
- balanceOf( _owner ) — Returns the number of tokens in a specific _owner’s wallet.
- ownerOf( _tokenId ) — Returns the wallet address of the specific token’s owner.
- totalSupply() — Returns the total amount of tokens created
- transfer( _to, _tokenId ) — Transfers token with _tokenId from sender’s wallet to a specific wallet.
- takeOwnership( _tokenId ) — Claims the ownership of a given token ID
- approve( _to, _tokenId ) — Approves another address to claim for the ownership of the given token ID
Also, it defines two events: Transfer, and Approval. A Transfer event is emitted when a token is transferred from one wallet to another. On the other hand, an Approval event is emitted when an address (user) approves another address to claim the ownership of a certain token that he owns.
OpenZeppelin ERC721 Implementation
OpenZeppelin provides reusable smart contracts with implementations of standards like ERC20 and ERC721. In this case, we will be importing their ERC721 implementation so we don’t have to write it ourselves from scratch.
Making the Project
- Creating the Smart Contract
- Building the Web App
Creating the Smart Contract
Since our clone will also be based on Ethereum, our token will also be made using Solidity, one of the programming languages used for creating smart contracts.
In Remix, create a new file named ViperToken.sol and add the following code:
First, the function generateViperGenes is responsible for determining the new viper’s genes, especially when it is being created through breeding (getting both parents’ genes). This is a very simple implementation though, and in this case, we use a simple number from 1–6 to determine how the viper will look like. You could do something better if you feel like it :)
Then, we have the function createViper which basically creates a new viper and gives it to the address passed in the parameter, “viperOwner”.
The function buyViper is a payable function (accepts payments) and calls the createViper function we previously defined. The word
payable is a modifier that is used to indicate that this function can receive ether when you execute it. Now, you might have noticed this part:
require(msg.value == 0.02 ether);
The require statement checks a condition and raises an error when false. In Solidity,
msg.value holds the amount of Ether being sent by the one who called the function. In this case, we want the user to pay 0.02 ether for buying a random viper. You may change this amount, or even remove it if you wish to.
We then have the breedVipers function which takes 0.05 ether as payment, and creates a new viper based off the two parents’ genes.
Next, we have the function getViperDetails which just returns details such as genes, and parent IDs of a given viper.
Finally, we have the ownedVipers function which returns a list of viper IDs that the function caller owns. The word
msg.sender is the address of the user that executed that function.
Now, compile the ViperToken contract (make sure you select compiler version at the right side of Remix, and choose 0.5.3+commit.10d17f24 because we are using Solidity version 0.5.3) and deploy it to the Ropsten Test Network. Make sure you are compiling and deploying the ViperToken contract.
To check that our contract was deployed, you should see the following:
Building the Web App
Our smart contract now works, but there’s no fun in just looking at numbers so we’ll be making a simple web application.
To get up to speed, let’s clone a boilerplate project (found here) by doing the following in a Terminal (or Command Prompt/Powershell for Windows):
# Cloning the boilerplate from GitHub
git clone -b boilerplate --single-branch https://github.com/openberry-ac/cryptovipers.git
# Navigating to the directory and installing packages
# Installing Web3
npm install -s email@example.com
# To run the app
npm run dev
Voila! In a few minutes, you should see the app running through a browser on http://localhost:8080 looking like this (though it is not functional yet):
Connecting to Our Smart Contract Instance
To enable our web app to interact with our smart contract, we will be using web3.js. We already have the package installed, you can see how it is called in the file named web3.js inside the “contracts” folder, where we should put something like this:
It basically loads the web3 instance the MetaMask extension initializes, which we will be needing later to interact with our smart contract.
You might encounter a MetaMask pop-up window that asks for access permission. This is because we have
ethereum.enable() where the app requests for account (or wallet) access. You should just click the ‘Connect’ button right here:
Now, we need our smart contract’s ABI to connect it to our web app. To get the ABI, go back to Remix, go to the Compile tab, and click ABI beside the Details button as shown in the picture:
After getting it, open the file named abi.js in the contracts folder, then paste it as the variable contractAbi ’s value, like this:
There should be an example in the file, which you can always refer to. Then, we will have to specify the smart contract’s instance address too, which you can get by going to Remix’s Deploy tab, and clicking the copy icon on your deployed contract, as shown in this picture:
Open App.vue found inside the src folder, and paste your contract address on line 86 as the variable contractAddress’ value (there should also be comments in the file, which you can always refer to):
const contractAddress = ''; // Right here!
// Ex: const contractAddress = '0xf59c4c3c79071d3e11034a9344789bd3';
Defining the Methods
You might notice that the user interface is there, but the buttons aren’t functional. That’s because we have not defined our functions yet, which we will be doing now. Go back to App.vue, and go to line 116 where you can see methods, but everything just contains a console.log().
Our first function is for buying a viper. Let’s modify the buyViper() function to look like this:
For buying a single viper, we have a fee of 0.02 ether, so we need to pay it by sending our account details and 0.02 ether. We then call the buyViper() function from our smart contract, which returns the details of the new viper. We will save these details inside the
Next, we modify the function for viper breeding, breedVipers():
We need to pay 0.05 ether to access this function. The breedVipers() function in our smart contract requires two integer parameters, matron and sire, so we pass the two integers to the function. This function also returns the details of the new viper and we need to save it to the
Finally, we define the method for retrieving the details of vipers we own, called getVipers():
There are two functions to get the details, ownedVipers() and getViperDetails(). The first function is to get an array of our vipers then the second function is to get the details of each of the vipers. After getting the details of each viper, we save it to the
And, we’re done!
Refresh your browser to see the changes. This time, the whole web app is complete, and everything is functional! You should then be able to use it like this:
You can see the final result on this GitHub repository (master branch) which you can always refer to :)
We just finished making our simple Cryptokitties clone! Awesome!
We learned how to create our own ERC721 implementation, and define our own custom functions. We also learned how to set up our own project using Vue.js, and created a simple application.
So what’s next?
You might want to write the token code (ERC721 implementation) from scratch while referencing to OpenZeppelin’s implementation or the standard specification. Or perhaps, you’d like to expand from what we have done and add more features like trading with other users, which is a good idea too 👍
On a side note, you might want to check out openberry’s previous tutorial, creating an Instagram-like DApp with IPFS + Vue.js.
’til the next tutorial!
openberry is a tutorial marketplace, designed to allow anyone to learn blockchain programming.
openberry is a tutorial marketplace, designed to enable anyone to learn blockchain programming.www.openberry.ac