A game where you need to send ETH every time you want to roll the dice. If you get a 7, you win the prize in ETH. Otherwise, your ETH acummulates for another lucky player.
I made this POC to show an Use Case for Upgradeable Proxies. First, we deploy v1 of the implementation (GiveMe7v1.sol) which has a high vulnerability bug related to the source of randomness. Hypothecialy, this bug was not detected during deployment. Hence, it was then addressed in v2 (GiveMe7v2.sol) by means of implementing a secure and decentralized source of randomness (Chainlink VRF).
Implementation v1 is based on the Dice challenge from the Speed Run Ethereum.
- The constructor can't be used, we need and "initialization" function instead that is only used for the 1st implementation.
- The function is identified by the modifier
initializer
. - For the subsequent implementations, we cannot use this function. Different access control approaches have to be used.
- Storage collisions have to be considered between the different implementations. We can't modify the order of pre-existing variables.
- We have to be carefull about function clashes as well. Potentially, 2 functions could have the same signature. This issue is addressed by the Solidity compiler only when it happens within the same contract. Thus, it won't alert us when it happens between different implementations.
- Blockchains are deterministics and, as such, they can't produce true randomness within their own context.
- Using on-chain information (e.g. block hash) to generate randomness is not secure. An attacker contract could execute the same logic at the same time and predict the resulting number.
- The best solution we have, as of today, is to a use decentralized source of randomness like Chainlink VRF, which can't be manipulated by any user, node operator, or malicious actor.
contracts/
- GiveMe7v1.sol: Implementation that has vulnerability associated with randomness.
- GiveMe7v2.sol: Implementation that solves vulnerability using Chainlink VRF.
- RiggedRoll.sol: Contract that is used to hack v1.
contracts/chainlink/
- VRFConsumerBaseV2Upgradeable.sol: VRF coordinator modified to be proxy compatible.
contracts/test/
- VRFCoordinatorV2Mock.sol: Mock to replicate behaivour of a Chailink VRF.
The test is divided in 3 steps:
- Deploy implementation v1.
- Hack implementation v1.
- Upgrade to implementation v2.
- Add a second dice and modify the patterns.
- Add different dices games.
- Build the frontend.
- EIP1976
- OpenZeppelin's Proxies
- OpenZeppelin's Writing Upgradeable Contracts
- Chainlikn VRF
- Speed Run Ethereum, Dice Challenge
Proxy: 0x360d94a879B3357304EE132212C377574737E2E5
- Nodejs
- You'll know you've installed nodejs right if you can run:
node --version
and get an ouput likevx.x.x
- You'll know you've installed nodejs right if you can run:
- Yarn instead of
npm
- You'll know you've installed yarn right if you can run:
yarn --version
And get an output likex.x.x
- You'll know you've installed yarn right if you can run:
- Run
yarn add --dev @nomiclabs/hardhat-ethers@npm:hardhat-deploy-ethers ethers @nomiclabs/hardhat-etherscan @nomiclabs/hardhat-waffle chai ethereum-waffle hardhat hardhat-deploy hardhat-gas-reporter prettier prettier-plugin-solidity solidity-coverage dotenv @openzeppelin/hardhat-upgrades @openzeppelin/contracts @openzeppelin/contracts-upgradeable @chainlink/contracts
. - Add/copy .gitignore, .prettierrc, .prettierignore, README.md, hardhat-config.js, helper-hardhat-config.js
- Fill the .env file (see Deploy to a Testnet or Mainnet).
Initiate the local node, which already deploys contracts when initiated:
hh node --network hardhat
If needed to deploy again:
hh deploy --reset
Run tests:
hh test
- Setup environment variabltes
You'll want to set below parameters in your .env
file.
PRIVATE_KEY
: The private key of your account.MAINNET_RPC_URL
: This is url of the mainnet node you're working with.GOERLI_RPC_URL
: This is url of the goerli testnet node you're working with.ETHERSCAN_API_KEY
: This is the KEY you generate from etherscan.io. To be used to verify the contracts on testnet and mainnet.COINMARKETCAP_API_KEY
: This is the KEY you generate from coinmarketcap.com. To be used to do quick USD calculations for gas usage.
- Get testnet ETH
Head over to goerlifaucet.com/ and get some tesnet ETH.
- Deploy
hh deploy --network goerli --tags proxy
If you deploy to a testnet or mainnet, you can verify it if you get an API Key from Etherscan and set it as an environemnt variable named ETHERSCAN_API_KEY
.
In it's current state, if you have your api key set, it will auto verify goerli contracts!
However, you can manual verify with:
hh verify --constructor-args arguments DEPLOYED_CONTRACT_ADDRESS
See Verifying your contracts for updated information.