Contract · Payments
Crowdfunding
Time-boxed ETH fundraising. Contributors are refunded automatically if the soft cap is not met.
Fundraise
~1.4M gas
Ethereum
Post-deploy checklist
- Double-check soft/hard caps and deadline timezone (Unix UTC)
- Test contribute + refund paths on a testnet
- Publish the verified source so contributors can read the rules
- Plan who can withdraw if the soft cap is met
Configure & deploy
Minimum raise for success. Below this, contributors should be able to refund. 1e18 = 1 ETH.
Maximum ETH the contract will accept. Must be ≥ softCap.
Campaign end in Unix seconds (UTC). Use the Timestamp tool if you need conversion help.
Use cases
- Community fundraising
- Charity campaigns
- Product presales
Crowdfunding.solsolidity
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0 (Wizard / Contracts MCP patterns)
// Compiled with Solidity ^0.8.24 — Ethereum Toolset browser solc
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
// Time-boxed ETH fundraising with refunds if soft cap is missed.
contract Crowdfunding is Ownable, ReentrancyGuard {
uint256 public immutable softCap;
uint256 public immutable hardCap;
uint64 public immutable deadline;
uint256 public totalRaised;
mapping(address => uint256) public contributions;
bool public finalized;
error CampaignEnded();
error HardCapReached();
error NotEnded();
error SoftCapMet();
constructor(address initialOwner, uint256 _soft, uint256 _hard, uint64 _deadline)
Ownable(initialOwner)
{
softCap = _soft; hardCap = _hard; deadline = _deadline;
}
receive() external payable {
if (block.timestamp > deadline) revert CampaignEnded();
if (totalRaised + msg.value > hardCap) revert HardCapReached();
contributions[msg.sender] += msg.value;
totalRaised += msg.value;
}
function withdraw() external onlyOwner {
if (block.timestamp <= deadline) revert NotEnded();
require(totalRaised >= softCap, "soft cap not met");
finalized = true;
payable(owner()).transfer(address(this).balance);
}
function refund() external nonReentrant {
if (block.timestamp <= deadline) revert NotEnded();
if (totalRaised >= softCap) revert SoftCapMet();
uint256 amt = contributions[msg.sender];
contributions[msg.sender] = 0;
payable(msg.sender).transfer(amt);
}
}
