As part of my learning path of smart contract/blockchain/web3 development I took Cyfrin Updraft course. This repository is a result of me learning Foundry fundamentals lesson. Thank you Patrick and the team for putting together such an amazing learning resource!
The core of the application is a Raffle
smart contract. The idea of this application is to have an automatic on-chain raffle application that allows users to enter raffle by sending funds to the application. Then after enough time has passed the raffle is supposed to figure figure out who is going to be the winner among users who enetered the raffle since last round was finished.
In this application I needed to generate random numbers to choose the winners, as well as be able to run the raffle automatically on schedule. To achieve this I've made use of Chainlink's VRF capability and Automation service.
As part of lesson I've learned a bunch of things:
- Chainlink VRF service to generate random numbers on-chain.
- Chainlink Automation service to be able to trigger smart contract function calls on schedule.
- Better naming conventions for variable names, events, errors. Better organization of smart conract variables and functions within the file.
- Using enums.
- Emitting and reading from events data. Indexing.
- Reverting errors with parameters.
- Uisng inherited constructors with parameters in the child smart contracts (
VRFConsumerBaseV2Plus
). - Using mocks to work with ERC20 token (deploying
LINK
token locally). - Using
abstract contract
to make contracts more modular. - Using
vm.startBroadcast()
with different accounts. - Using Chainlink brownie contracts mocks for VRF coordinator.
- Learned
vm.warp()
andvm.roll()
. - Setting
vm.expectRevert()
with specific error codes and parameters passed to the error. - Setting expectations for specific events using
vm.expectEmit()
. - Learned how to use
vm.recordLogs()
to read from logs data.
- Run
git clone https://github.com/accurec/CyfrinUpdraftCourseFoundryRaffle.git
- Run
make install
to install required dependencies. - Run
make build
to build the project. - Add
.env
file with the following variables:SEPOLIA_RPC_URL
- could take this from Alchemy;ETHERSCAN_API_KEY
- needed for automatic verification, can get it from Etherscan account. - Make sure that in
HelperConfig.s.sol
the following values are properly setup for your subscription and account ingetSepoliaEthConfig
function:subscriptionId
andaccount
. - Make sure you have encrypted and saved your Sepolia private key using
cast wallet import --interactive sepoliaKey
for the account that you have setup in the previous step inHelperConfig.s.sol
file. - Make sure you have some testnet ETH and LINK balance on the account that you have specified in step #5 above. These are good faucets to use to get some: ETH Sepolia faucet and LINK and ETH Sepolia faucet.
- Make sure you've created subscription for VRF using this link and funded it with enough LINK. Use the subscription ID that you get from it and replace in
HelperConfig.s.sol
file forgetSepoliaEthConfig()
function,subscriptionId
field. - You can now deploy to Sepolia using
make deploy-sepolia
command. - Alternatively, can deploy locally and run
make deploy-local
. Make sure to encrypt Anvil's key for the address0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
usingcast wallet import
command. After deployment we can wait for30 seconds
(interval time) and then runmake local-enter-raffle
. Then we can runmake local-perform-upkeep
and thenlocal-vrf-coordinator-fulfill-random-words
to simulate Chainlink's Automation and VRF request fulfillments. After that we can observe that the winner of the raffle has been set by runningmake get-local-recent-winner
.
NOTE 1: A little hacky way, but I have not been able to figure out quicker way for now to fix the problem with 0 blocks blockchain when running anvil
is to go directly to lib/chainlink-brownie-contracts/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol
and modify the line where the subscription ID is set based on the block - 1
logic by removing the -1
part before running make deploy-local
:
keccak256(abi.encodePacked(msg.sender, blockhash(block.number - 1), address(this), currentSubNonce))
NOTE 2: For .env
file the local values reference is:
LOCAL_RPC_URL=http://127.0.0.1:8545
LOCAL_RAFFLE_ADDRESS=0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9
LOCAL_VRF_COORDINATOR=0x5FbDB2315678afecb367f032d93F642f64180aa3
LOCAL_SEND_VALUE=50000000000000000 # 0.05 ETH
- After deploying to Sepolia we can look at the contract state variables. Example. We can see latest winner and verify that if raffle has never been run then the address will be a zero address.
- We then can register a new upkeep in Chainlink. Example.
- Once the upkeep has been registered, we can go ahead and write to our
Raffle
contract toenterRaffle
function with any value that is higher than the minimum entry fee. - Once this is done, we can wait an amount of time that has been configured in
HelperConfig.s.sol
filegetSepoliaEthConfig()
functioninterval
parameter, and see that Chainlink calledperformUpkeep()
function. - Once the
performUpkeep()
is called then the control flow is passed to VRF, which will callfulfillRandomWords
function on the contract once the random values are ready. Example can see internal call toFulfill Random Words
. - We then can check that the latest winner has been updated in our contract by reading from it and verify that the winner was indeed us.
- Write integration tests.
- Add interaction for registering an upkeep for
Raffle
contract.