Tokenize Gold on Ethereum for the best security and censorship-resistant ownership to the holder.
I'm new to the Hackathon space and it's my first submission here. Hoping at least the code will be accepted as a valid submission.
The project is inspired from CacheGold's workflow which is explained in Chianlink's Tech-Talk # 15 between Max Melcher and Dias Lonappan (CTO CacheGold)
Weblink: https://www.youtube.com/watch?v=tPURU6Sq2yo
I built an MVP on the similar lines and wrote the entire code from scratch. I had to fork mainnet as the CacheGold’s Price Feed is not available on any of the testnets and as advised by Andrej on #partner-chainlink: Discord channel that mainnet forking is a valid submission.
What it does? -Basically, a user comes to a Gold-Tokenzing service provider with its Gold holding in the form of a Gold Bar to get it tokenized on Ethereum. User wants this to, maybe, trade on DeFi and do Yield Farming, etc.
1). The Contract Owner takes in User’s details and sends a transaction on the Blockchain to save those.
2). The Owner then runs 2 tests on the Gold Bar – a Purity test and a Standard Weight test. The purity has to be 24 Karat (99.9%) only and there are only 3 options for the std. wight: 10g, 100g 1000g bar.
3). Once the test is passed, the owner mints the TGOLD ERC-20 tokens to the user’s account. -If test is failed, the Gold Bar is returned to the user (in real world scenario).
4). Whenever user wants to redeem its TGOLD for Ether/Wei, it can do so anytime.
-The contract must be funded at deployment with at least 10 Ether so that the contract has some balance all the time to enable users to redeem the TGOLD so that user.call{}() does not fails. -However, to keep the contract sufficiently funded, receive() ether function is also incorporated.
TGOLD is an ERC-20 token whose decimals is 8, not 18 to mimic CacheGold’s CGT token. 1 TGOLD = 1 gram of pure Gold.
The contract uses 3 of Chainlnk’s Data Feeds all along: 1). CacheGold’s Proof of Reserve Feed: To ensure that TGOLD never gets minted more than the total off-chain reserve of Gold in custody.
To keep things easy in this MVP, I transfer/mint all the CacheGold’s reserve’s equivalent TGOLD tokens to the Owner’s account at deployment. Why? Because whenever a new user would want to tokenize its Gold, the total supply of TGOLD should increase appropriately. Should add the newly minted ones to the ones already in circulation.
2). ETH/USD Price Feed: 3). XAU/USD Price Feed: The above 2 price feeds are used in the tGOLDToWei() when a user wants to redeem TGOLD to Ether to its wallet.
I worked out a detailed Calculation of converting TGOLD to Ether/wei and explained in the Code itself right where the function tGOLDToWei() is written in contract.
Felt proud in cracking the conversion and verifying the results with real world data. :)
I also wanted to add Chainlink’s Cross-Chain Interoperability Protocol to enhance this code and not just limit it to tokenization only but I ran out of time while incorporating CCIP.
I did not want to submit a half-baked code though I’ll continue to work on it and definitely complete it for my own understanding of CCIP which I found fascinating and a game-changer.
I used Remix because it gives a decent UI to interact with the contract on the left panel as I am not a Full Stack (MERN) developer and, hence, did not want to waste any time on developing the front end UI.
Used Solidity to write both the contracts.
Used 3 of Chainlink’s Data Feeds on the mainnet, as already described in the “Description” column above:
1). CacheGold’s Proof of Reserve as a reference point, to ensure safeMint() and avoid infinite mints and never running into undercollateralized off-chain reserves.
2). ETH/USD
3). XAU(GOLD)/USD
I wrote the code from scratch and built feature by feature.
Started with single user wanting to get its Gold holding tokenized.
Moved onto adding more users for the same and, hence, updated the Data structures.
Added a feature to accommodate a returning client/user and assigned a unique “turn” to it.
e.g. User Manu came for the second time and brought more qty. of Gold to have it tokenized.
That’s where I introduced a nested mapping that maps a user->its turn->struct type UserData.
For sake of simplicity, kept Gold purity only at 24Karat.
In reality, CacheGold’s reserves belong to several customers.
Hence, I had to mint() and assign all the TGOLD token corresponding to Cache’s reserves to the owner itself so that totalSupply() holds good after any user mints its TGOLD tokens.
4 main functions the contract performs already explained in README.md file in the Github repo.
Coded few helper functions like getUserGoldPrice(), getUserData(), and most importantly tGOLDToWei() that helps users in redeeming the correct amount of Wei (Ether) when they input the amount of TGOLD balance that they want to redeem. Took some time to figure out the Maths inside tGOLDToWei() and used ETH/USD and XAU/USD price feeds.
First converted the balance TGOLD amount into equivalent $ amount using XAU/USD.
Then, converted the same $ amount into equivalent Ether / Wei to send it to user’s wallet.
For e.g.: a balance of TGOLD = 99900000000 (= 999 gram of pure Gold @ 99.9% pure 1000 gram Gold Bar) translates into 33228004341939231030 Wei (= 33.228….. Ether) when Eth/USD price feed returns 184997000000 (= US $1849.97) and XAU/USD price feed returns 191384048100 (= US $1913.84 ). XAU/USD Price feed returns the price of 1 Troy Ounce of Gold = approx. 31.103 gram