A lightweight Node.js/Express backend that interacts with the Voting.sol smart contract deployed via Hardhat. It provides REST APIs for fetching candidates, adding candidates (owner-only), casting votes, and retrieving the winner. It is the backend service for the voting_hardhat project here, and also a complete explanation of the whole project with tests and live demo are here.
This backend communicates with the blockchain using Web3.js and the contract ABI.
-
Connects to an Ethereum RPC provider (Hardhat, Ganache, Anvil, etc.)
-
Reads and writes from/to the deployed Voting smart contract
-
Owner-protected candidate creation
-
Endpoints for:
- Fetching candidates
- Adding candidates (owner only)
- Casting votes
- Getting election winner
-
Logging & centralized error handling
-
Clean route/controller structure
voting_backend/
│
├── server.js
├── abi.js
├── .env
├── .env.example
├── package.json
│
└── src/
├── config/
│ └── web3.js
├── controllers/
│ └── voting.controller.js
├── middlewares/
│ └── ownerAuth.js
├── routes/
│ └── voting.routes.js
└── utils/
└── errorHandler.js
git clone <your_repo_url>
cd voting_backendnpm installCreate a .env file:
cp .env.example .envEdit values inside .env:
PROVIDER_URL=http://127.0.0.1:8545
CONTRACT_ADDRESS=0x...
OWNER_PRIVATE_KEY=0x...
PORT=4000
Ensure the contract is deployed and CONTRACT_ADDRESS matches your Hardhat deployment.
node server.jsThe API will start on:
http://localhost:4000
GET /
Response: { "message": "Voting API v1 is live" }
GET /candidates
Response:
{
"candidates": [
{ "name": "Alice", "voteCount": 0 },
{ "name": "Bob", "voteCount": 3 }
]
}
POST /candidates
Required JSON body:
{
"candidate_name": "Charlie",
"privatekey": "<OWNER_PRIVATE_KEY>"
}Response:
{
"message": "Candidate added",
"txHash": "0x..."
}POST /vote
Required JSON body:
{
"candidate_index": 1,
"address": "0xYourWalletAddress"
}Response:
{
"message": "Vote cast",
"txHash": "0x..."
}GET /winner
Response:
{
"winner": "Alice"
}
The backend uses a simple middleware:
ownerAuth → verifies req.body.privatekey === process.env.OWNER_PRIVATE_KEY
Only the contract owner can add new candidates.
The file src/config/web3.js:
- Initializes Web3 provider
- Loads ABI
- Creates contract instance
- Loads owner wallet into Web3
const contract = new web3.eth.Contract(voting_abi, process.env.CONTRACT_ADDRESS);All errors are handled centrally by:
src/utils/errorHandler.js
Ensures clean, consistent 500 responses.
- This backend assumes your Voting smart contract is deployed and running.
- Uses Web3.js v4, which requires ESM imports (
type: module). - Ensure Hardhat node is running before calling the API.
Dhruv Charne (Dhruv4ne)
MIT