Smart contracts are foundational to decentralized applications on blockchain platforms like Ethereum. Solidity, the most widely used language for writing these contracts, enables developers to implement complex logic with transparency and immutability. In this guide, we explore several practical Solidity contract examples—ranging from voting systems and auctions to payment channels and modular design patterns—that demonstrate core concepts such as state management, access control, cryptographic signatures, and secure fund handling.
Whether you're building a decentralized finance (DeFi) protocol or experimenting with Web3 tools, understanding real-world implementations is key. We'll walk through each example in detail, highlighting best practices and critical security considerations.
Voting Contracts with Delegation
One of the most illustrative Solidity examples is a voting system that supports delegation. This contract allows a chairperson to assign voting rights to specific addresses. Voters can either cast their vote directly or delegate it to someone they trust.
The system ensures automatic and fully transparent vote counting. At the end of the voting period, the winningProposal() function returns the index of the proposal with the highest number of votes.
Key features:
- Weighted voting via
Voterstruct storingweight,voted,delegate, andvote. - Proposal tracking using dynamic arrays and mappings.
- Delegation logic prevents loops and double-voting.
struct Voter {
uint weight;
bool voted;
address delegate;
uint vote;
}
struct Proposal {
bytes32 name;
uint voteCount;
}👉 Discover how blockchain voting can revolutionize digital governance
Why Delegation Matters
Delegation empowers users who may lack time or expertise to make informed decisions. By allowing trusted parties to vote on their behalf, participation increases while maintaining decentralization.
However, challenges remain—such as ensuring only eligible participants receive voting rights and preventing manipulation. While this contract doesn’t solve identity verification, it lays the groundwork for secure, transparent decision-making.
Open and Blind Auctions
Auction contracts are another powerful use case for Solidity smart contracts. Let’s examine two types: open bidding and blind bidding.
Simple Open Auction
In an open auction, all bids are visible. Participants send Ether along with their bid. If outbid, the previous highest bidder can withdraw funds later.
Critical mechanisms:
- Time-bound auction via
auctionEndTime. - Refund system using
pendingReturnsmapping. - Events like
HighestBidIncreasednotify frontends.
function bid() external payable {
require(block.timestamp <= auctionEndTime, "Auction already ended");
require(msg.value > highestBid, "Bid not high enough");
if (highestBid != 0) {
pendingReturns[highestBidder] += highestBid;
}
highestBidder = msg.sender;
highestBid = msg.value;
emit HighestBidIncreased(msg.sender, msg.value);
}Blind Auction: Enhanced Privacy
To prevent last-minute sniping, a blind auction hides bid values during the bidding phase. Users submit hashed bids (keccak256(value, fake, secret)). Afterward, they reveal their details.
This approach:
- Prevents strategic bidding based on visible amounts.
- Ensures fairness through cryptographic commitments.
- Uses modifiers like
onlyBeforeandonlyAfterto enforce timing.
modifier onlyBefore(uint time) {
require(block.timestamp < time);
_;
}👉 Learn how decentralized auctions are reshaping NFT markets
Secure Remote Purchase
Buying goods remotely involves trust issues—how do we ensure both buyer and seller fulfill obligations?
This remote purchase contract uses escrow-like mechanics:
- Both parties deposit twice the item’s value.
- Upon confirmation of delivery, the buyer gets half back; the seller receives three times the value.
- Motivates honest behavior—funds are locked until resolution.
States include:
CreatedLockedReleaseInactive
Using enums and modifiers like inState() ensures transitions happen correctly.
modifier inState(State state_) {
require(state == state_);
_;
}Events such as ItemReceived and SellerRefunded keep interactions traceable.
Micro-Payment Channels
For high-frequency, low-cost transactions (e.g., streaming payments), on-chain fees are impractical. Payment channels solve this by enabling off-chain transfers secured by cryptography.
How It Works
- Alice deploys a contract funded with Ether.
- She signs messages specifying payment amounts.
- Bob redeems them by submitting the signature to the contract.
Security relies on:
- ECDSA signature recovery via
ecrecover. - Nonce and contract address inclusion to prevent replay attacks.
- Expiration timeouts so funds aren’t stuck forever.
function claimPayment(uint256 amount, uint256 nonce, bytes memory signature) external {
require(!usedNonces[nonce]);
bytes32 message = prefixed(keccak256(abi.encodePacked(msg.sender, amount, nonce, this)));
require(recoverSigner(message, signature) == owner);
payable(msg.sender).transfer(amount);
}This model enables instant, feeless microtransactions—ideal for pay-per-use services.
Modular Contract Design
As contracts grow in complexity, modularity becomes essential. Libraries allow reusable code without duplication.
Using Libraries for Balance Management
The Balances library isolates balance operations:
library Balances {
function move(mapping(address => uint256) storage balances, address from, address to, uint amount) internal {
require(balances[from] >= amount);
require(balances[to] + amount >= balances[to]); // Overflow check
balances[from] -= amount;
balances[to] += amount;
}
}By attaching this library to a token contract with using Balances for *;, developers ensure consistent, auditable balance changes across all functions.
Benefits:
- Reduced code redundancy.
- Easier testing and auditing.
- Clear separation of concerns.
Frequently Asked Questions
What is a Solidity contract?
A Solidity contract is a collection of code (functions) and data (state variables) that resides at a specific address on the Ethereum blockchain. It defines rules for asset transfers, access control, and business logic in decentralized applications.
How does delegation work in voting contracts?
Delegation allows one user to assign their voting power to another. The delegate can accumulate weight from multiple voters and cast votes on their behalf, increasing efficiency without sacrificing representation.
Can anyone create a blind auction?
Yes. Anyone with basic Solidity knowledge can deploy a blind auction. However, proper testing and security audits are crucial to prevent exploits like front-running or incorrect fund distribution.
Why use payment channels instead of regular transactions?
Payment channels reduce gas costs and latency by moving repeated transactions off-chain. Only two on-chain transactions (opening and closing) are needed regardless of how many payments occur in between.
How do modifiers improve contract security?
Modifiers like onlyOwner, inState, or onlyAfter centralize access control logic. They prevent unauthorized state changes and enforce business rules consistently across functions.
What are common pitfalls when writing Solidity contracts?
Common issues include reentrancy attacks, integer overflow/underflow (mitigated in Solidity 0.8+), incorrect visibility settings, and improper handling of Ether transfers. Always follow known secure patterns and test thoroughly.
Final Thoughts
These Solidity contract examples showcase the language’s versatility—from democratic governance to private auctions and scalable payments. By mastering these patterns, developers can build robust, trustless systems that power the next generation of decentralized applications.
Understanding core principles like state management, cryptographic verification, and modular design is essential for creating secure and maintainable smart contracts.
👉 Start building your own smart contracts today with advanced tools