The purpose of this project is to develop a platform to manage on-chain data for Spanish horse racing so these data can be used by external applications (games, dApps, etc.)
One of this applications, included in the project, is a fully on-chain thoroughbred NFTs representing real race horses that anyone can acquire. The NFTs look like a game card with SVG and horse data. The NFTs are upgradeable with the current number of victories of the horse represented.
In order to fetch horses' data, I have installed a local Chainlink node with a specific jobId that requests the data to Metaturf Spanish horse racing platform. I am partner at this company.
https://dmolinac.github.io/blockchain-developer-bootcamp-final-project/
- The contract owner checks the last races' IDs and requests the information of a horse asking for the winner of a race. The information retrieved is stored on-chain.
- Any address can mint a horse from the list of on-chain horses stored. Every horse can be minted once.
- The contract owner can periodically update the number of races winned by a horse. Token owners cannot do this.
- The number of victories is shown in the NFT (tokenURI).
In order to cover costs, the platform will apply fees when horses are sold, traits are updated and horses are used by external dApps.
I tried to keep the idea as simple as possible, so at this stage the contracts and dApp are in an early stage. Next steps are manyfold:
- Retrieve more information from horses (age, sex, etc.).
- Implement proxy contract.
- Set
MetaturfHorseRacingData
address as an argument inMetaturfNFT
constructor. - Fetch information about races. At this stage I have only developed the queries to fetch race information the oracle contract.
- Check other ways to ask the Oracle about how to retrieve horse information, rather than asking for the winner of a race.
- Users may have to pay a fee to mint horses to cover costs.
- NFTs should be better designed with more information, different colors, shapes, etc. and SVG may be pre-codified in base64.
- Anyone could use the information stored in the
MetaturfHorseRacingData
contract to build other dApps.
The dApp is backed by 3 smart contracts:
MetaturfHorseRacingData
contract stores Spanish horse racing data retrieved from a Chainlink oracle. It declares a library with structs to store Horse and Race data.
MetaturfNFT
contract mints NFTs 100% on-chain. Inspired in generative NFTs and Loot project
Oracle
Chainlink base contract for Oracles. Deployed with Remix
- Blockchain: Ethereum Kovan testnet
- Solidity Development: Truffle v5.4.18
npm i -g truffle
- Node v12.18.4
- Web3.js v1.5.3
- Wallet Support: MetaMask
- Web Client: React
- HDWallet provider ^1.0.6:
npm i @truffle/hdwallet-provider
- NFT Contract Library ^4.3.2: Open Zeppelin
npm i @openzeppelin/contracts
- Oracle Contract Library ^0.2.2: Chainlink
npm i @chainlink/contracts
- React:
npm i -g react
- Axios ^0.24.0: required to fetch off-chain data from Metaturf REST API
npm i axios
- Dotenv ^10.0.0:
npm i dotenv
client
: Project's React frontend.
contracts
: Smart contracts that are deployed in the Kovan testnet.
migrations
: Migration files for deploying contracts in contracts directory.
test
: Tests for smart contracts.
The development, test and deploy of the contracts and the React dApps have been performed in Kovan testnet, mainly to be able to integrate with the Chainlink oracle.
- Clone the repository
git clone https://github.com/dmolinac/blockchain-developer-bootcamp-final-project
- Populate the .env locally
I have included a file .env.template with the two environment variables to customise:
MNEMONIC="YOUR_MNEMONIC_PHRASE_HERE"
INFURA_API_URL="YOUR_INFURA_API_KEY_HERE"
- Install dependencies
cd blockchain-developer-bootcamp-final-project
npm install
- Compile contracts
truffle compile
- Test contracts
truffle test --network kovan
- Deploy contracts
truffle deploy --network kovan --reset
- Oracle contract
The oracle contract is inherited from Chainlink and it is fixed as it needs to call the local Chainlink node. It was deployed using Remix. The address is set in MetaturfHorseRacingData
contract.
In order for the dApp to work, we need to set the address of MetaturfHorseRacingData
contract in MetaturfNFT
contract:
First, we get the address of MetaturfHorseRacingData
address:
npx truffle console --network kovan
truffle(kovan)> let mtdata = await MetaturfHorseRacingData.deployed()
truffle(kovan)> let mtaddress = mtdata.address
Then, we register the address in MetaturfNFT
contract:
truffle(kovan)> let nft = await MetaturfNFT.deployed()
truffle(kovan)> nft.registerMetaturfHorseRacingDataAddress(mtdata.address)
Finally, we need to send LINK tokens (1 LINK per request) to the MetaturfHorseRacingContract
(i.e. using Metamask):
We can check the contract address by typing mtdata.address
in Truffle console.
Some examples:
- Calling the oracle to retrieve the winner of a race and checking the result. For this call to work, the local node must be active. In case it is not up, please write me to [email protected].
let result = await mtdata.requestOracleRaceWinner(456)
result.logs[0]
- Setting a horse without calling the oracle (only for contract owner). This operation is only for testing purposes, in mainnet this function should be removed)
mtdata.setHorseFromCSV("793,VEGIA,3")
-
Get information from a horse stored:
mtdata.getHorse(793)
-
List horses:
mtdata.listHorses()
-
Mint a horse:
nft.mint(12,"Horse_name")
-
Get NFT Info:
nft.getHorseNFTInfo(0);
-
Get number of tokens:
nft.getNumberOfTokens()
The Web Client for the dApp has been developed with React.
cd client
npm install
npm install gh-pages --save-dev
npm run predeploy
npm run deploy
The project interacts with a Chalinlink node installed locally. We have developed the project so it can be operated without this requirement by calling setHorseFromCSV
from MetaturfHorseRacingData
contract (see example above). In case the server is not running, please write to [email protected].