A sample Ethereum smart contract lottery built with Foundry, featuring robust testing, Chainlink VRF v2.5 support, mock infrastructure, and modular, maintainable scripts.
Chainlink VRF integration ensures cryptographically secure randomness for winner selection.
- Git
- Foundry (Forge, Cast, Anvil)
- Make (optional, for scripts)
- Node.js (optional, for scripting utilities)
Confirm your tools are installed:
git --version
forge --version
anvil --versiongit clone https://github.com/web3pavlou/foundry-smart-contract-lottery-f23
cd foundry-smart-contract-lottery-f23
forge buildStart Anvil in a separate terminal:
anvil
# or with Makefile:
make anvilWhen running locally, you might see:
[Revert] panic: arithmetic underflow or overflow (0x11)
Why?
- Some Chainlink mocks use
blockhash(block.number - 1). If the local chain is new (block.number == 0), this will underflow.
Solution:
-
Open a second terminal and run:
cast rpc evm_mine
This increments the block number so
block.number - 1is safe. -
Then re-run your deployment script.
If you see:
Error: You seem to be using Foundry's default sender. Be sure to set your own --sender.
-
This appears if you don’t provide
--senderexplicitly. -
If you use
--private-key, your script broadcasts from the correct account—the warning can be safely ignored if everything else works. -
To silence, use:
forge script script/DeployRaffle.s.sol:DeployRaffle \ --rpc-url http://localhost:8545 \ --private-key <YOUR_PRIVATE_KEY> \ --sender <YOUR_ADDRESS> \ --broadcast
-
Setup Environment Variables
Create a
.envfile based on.env.example:PRIVATE_KEY: your dev wallet (never use real funds!)SEPOLIA_RPC_URL: Sepolia testnet RPC URLETHERSCAN_API_KEY: (optional) for contract verification
-
Get Testnet ETH
Use faucets.chain.link to get Sepolia ETH.
-
Deploy
make deploy ARGS="--network sepolia"- Sets up Chainlink VRF subscription
- Adds your contract as VRF consumer
- If you have an existing sub, update in
script/HelperConfig.s.sol
-
Register Chainlink Automation Upkeep
- Read Automation docs
- Register an upkeep at automation.chain.link (choose “Custom logic” as the trigger)
Covers all four Foundry test tiers:
- Unit
- Integration
- Forked (mainnet/testnet fork)
- Staging (public testnets)
Unit & Integration:
forge test
forge test -vvv # with tracesForked:
forge test --fork-url $SEPOLIA_RPC_URLStaging (on testnet):
forge script script/StagingTest.s.sol --rpc-url $SEPOLIA_RPC_URL --broadcastforge coveragecast send <RAFFLE_CONTRACT_ADDRESS> "enterRaffle()" --value 0.1ether --private-key <PRIVATE_KEY> --rpc-url $SEPOLIA_RPC_URLmake createSubscription ARGS="--network sepolia"forge fmt- Solidity >=0.8.x (overflow protection)
- Chainlink VRF/Upkeep best practices
- Comprehensive tests, access control, events
- Never use mainnet private keys for dev/test!
Further reading: Smart Contract Security Best Practices
This project is licensed under the MIT License.
- Cyfrin Updraft – Thanks to @patrickalphaC
- Chainlink – For the VRF service
- Foundry – For the dev tools