Fund-Me Smart Contract: This is a minimal project allowing user to fund the contract owner with donations. The smart contract accepts ETH as donations, dominated in USD. Donations has minimum USD value , otherwise they are rejected. The value is priced using a Chainlink Price Feed , and the smart contract keeps track of the doners in case they are to be rewarded in the future.
The FundMe Project smart contract enables transparent, "decentralized crowdfunding", acting like a programmable Kickstarter on the blockchain. Its core purpose is to "securely accept native cryptocurrency donations (fund)", "track contributor data", "enforce a minimum USD value using Chainlink oracles", and allow "authorized withdrawals (withdraw)".
The FundMe contract enables decentralized fundraising with the following key features:
- Minimum funding requirement of $5 USD (converted from ETH)
- Real-time ETH/USD price conversion using Chainlink oracles
- Owner-only can withdraw functionality
- Automatic fund() execution via fallback and receive functions
It demonstrates:
- Price feed integration via AggregatorV3Interface
- Mocking Chainlink feeds for local testing
- Foundry-style unit, integration tests
Built this project to understand in-dept about:
- Oracle integration (Chainlink)
- Access control with onlyOwner
- Safe ETH withdrawal patterns.
- Gas optimizations with constant, immutable, and custom errors.
- Minimum Contribution: $5 USD equivalent in ETH
- Price Oracle Integration: Uses Chainlink ETH/USD price feeds (Sepolia testnet)
- Access Control: Only contract deployer can withdraw funds
- Fallback Support: Automatically processes direct ETH transfers as donations
- Funder Tracking: Records who sent ETH and how much
- Auto ETH Handling: receive() and fallback() support direct ETH
Think of this contract like a donation box:
- People (like e.g "Nathaniel" 🧍) can donate ETH
- But it only accepts donations worth $5 or more in real-time USD value
- You (the contract creator) are the only one allowed to withdraw the funds.
- The contract safely tracks all donors and protects against misuse.
- msg.sender, msg.value, address(this).balance
- Chainlink AggregatorV3Interface
- Price conversion using custom library (PriceConverter)
- onlyOwner modifier using immutable i_owner
- transfer, send, and call ETH withdrawal methods
- Gas-optimized NotOwner() custom error.
- receive() and fallback() to catch direct ETH transactions.
- Solidity - Smart contract programming language
- Foundry(forge, cast, anvil) - Development framework and testing suite
- Chainlink Price/Data Feeds (real + mock)
- Chainlink Brownie Contracts
- MetaMask: Ethereum wallet for transactions.
- Solidity ^0.8.18
- Foundry development framework for compiling and testing.
- Chainlink for price feed integration.
- Install the MetaMask browser extension and connect it to a test network (e.g., Sepolia).
- Apart of being able to deploy on local blockchain (like Anvil) . Access to Ethereum free testnet (Sepolia) for deployment, is needed. Which is typically similar to mainnet deployment.
-
Clone the repository:
git clone https://github.com/legendarycode3/fund-me-smart-contract
cd fund-me-smart-contract -
Install dependencies:
forge install smartcontractkit/chainlink-brownie-contracts@0.6.1
make install Or forge install
-
Build the project:
make build
A Makefile is included to streamline commands for cleaning, building, testing, updating, formatting, deployment, and more. You can use it to execute tasks without needing to remember specific commands. Just run the command you need like this:
make <command>The Makefile defines the following commands for quick project management:
- clean: Cleans up build artifacts.
- remove: Clears Git submodules and libraries, then commits the changes.
- all: Runs clean, remove, install, update, and build in sequence.
- install: Installs required packages without committing.
- update: Updates dependencies.
- build: Compiles the contracts.
- test-anvil: Runs tests in a local Anvil environment.
- test-sepolia: Runs tests on Sepolia fork using SEPOLIA_RPC_URL.
- snapshot: Generates a snapshot of contract states.
- format: Formats code according to standards.
- coverage: Runs code coverage.
- deploy-anvil: Deploys contract locally using Anvil.
- deploy-sepolia: Deploys contract to Sepolia network with verification on Etherscan.
Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.
Foundry consists of:
- Forge: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- Cast: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- Anvil: Local Ethereum node, akin to Ganache, Hardhat Network.
- Chisel: Fast, utilitarian, and verbose solidity REPL.
- Setup environment variables
You'll want to set your SEPOLIA_RPC_URL and PRIVATE_KEY as environment variables. You can add them to a .env file
- PRIVATE_KEY: The private key of your account (like from metamask. NOTE: FOR DEVELOPMENT, PLEASE USE A KEY THAT DOESN'T HAVE ANY REAL FUNDS ASSOCIATED WITH IT.
- SEPOLIA_RPC_URL: This is url of the sepolia testnet node you're working with. You can get setup with one for free from alchemy Optionally, add your ETHERSCAN_API_KEY if you want to verify your contract on Etherscan
- Get testnet ETH
Head over to cloud.google.com or faucets.chain.link and get some testnet Sepolia ETH. You should see the Sepolia ETH show up in your metamask. - Deploy(Using Script)
forge script script/DeployFundMe.s.sol --rpc-url $SEPOLIA_RPC_URL --private-key $PRIVATE_KEY --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY forge buildRun all tests:
forge testOr
make testRun tests with verbosity:
make test -vvvRun specific test:
forge test --mt testFunctionNameTest coverage:
make coverageExample test scenarios:
- Funding below minimum threshold (should revert)
- Successful funding above minimum
- Non-owner withdrawal attempt (should revert)
- Owner withdrawal functionality
- Price conversion accuracy
forge fmt forge snapshot anvil forge script script/DeployFundMe.s.sol:DeployFundMe --rpc-url <your_rpc_url> --private-key <your_private_key>Deploy to Sepolia testnet:
make deploy-sepolia
$ cast <subcommand>$ forge --help
$ anvil --help
$ cast --help- fund(): Allows users to contribute funds to the campaign. Requires the sent amount to meet the minimum USD requirement.
- getPrice(): Retrieves the latest ETH to USD conversion rate using Chainlink's AggregatorV3Interface.
- getVersion(): Retrieves the version of the Chainlink AggregatorV3Interface being used.
- getConversionRate(uint256 ethAmount): Calculates the equivalent USD amount for the provided ETH amount.
- withdraw(): Enables the contract owner to be able to pull all funds (Ether) out of the contract to their own wallet.
Create a .env file with the following variables:
SEPOLIA_RPC_URL=your_sepolia_rpc_url
ETHERSCAN_API_KEY=your_etherscan_api_key ├──script
│ ├── DeployFundMe.s.sol
│ ├── HelperConfig.s.sol
│ └── Interactions.s.sol
├── src
├── PriceConverterLibrary.sol
│ └── FundMe.sol
└── test
├── integration
│ └── FundMeTestIntegrationOrIntetractionTest.t.sol
├── mocks
│ └── MockV3Aggregator.sol
└── unit
└── FundMeTest.t.sol
├── foundry.toml
└── README.md
The contract implements several gas optimization techniques:
- Immutable owner variable
- Constant minimum USD value
- Efficient array resetting in withdrawal
- Foundry Book
- Foundry Fundamentals
By completing this project, you should be comfortable with:
- Writing Solidity contracts with external dependencies
- Using libraries and immutable variables
- Writing Foundry tests with mocks and cheats
- Debugging EVM and Foundry errors
- Understanding environment-specific behavior (local vs testnet vs fork)
Some users were having a confusion that whether Chainlink-brownie-contracts is an official Chainlink repository or not. Here is the info. Chainlink-brownie-contracts is an official repo. The repository is owned and maintained by the chainlink team for this very purpose, and gets releases from the proper chainlink release process. You can see it's still the smartcontractkit org as well. smartcontractkit
LegendaryCode
- LinkedIn: @legendarycode3
- Twitter: @legendary_code_
- Github: @legendarycode3