A secure, transparent smart contract for Swedish association (förening) governance processes including Annual General Meetings and Special Meetings.
# 1. Set up environment
cp env.example .env
# Edit .env with your values
# 2. Deploy to Amoy testnet (newer, recommended)
forge script scripts/deploy/DeployAmoy.s.sol \
--rpc-url https://rpc-amoy.polygon.technology \
--broadcast \
--verify \
--private-key $PRIVATE_KEY
# 3. Test functionality
forge script scripts/test/TestAmoy.s.sol \
--rpc-url https://rpc-amoy.polygon.technology \
--broadcast \
--private-key $PRIVATE_KEY📖 Full Guides:
- Quick Start:
docs/user-guides/QUICK_START.md- 5-minute setup - Comprehensive Guide:
docs/user-guides/POLYGON_TESTNETS_GUIDE.md- Complete deployment guide - Design Documentation:
docs/technical/DESIGN_SUMMARY.md- Technical specifications - Navigation Guide:
NAVIGATION.md- Repository structure & quick links
This contract enables Swedish associations to conduct secure, transparent voting on governance matters with the following key features:
- Secure Voting: One vote per member per question, non-transferable
- Session Management: Create voting sessions with multiple questions
- Privacy Controls: Configurable privacy settings per question
- Batch Operations: Gas-efficient batch voting and member registration
- Emergency Controls: Pause functionality for crisis situations
- Immutable Results: Hash-based result verification
- KISS Compliance: Simple, focused functionality
- Security First: Comprehensive access controls and validation
- Gas Optimization: Organization pays all gas costs
- Transparency: All operations emit events for off-chain verification
createVotingSession()- Create new voting sessions with multiple questionspauseSession()- Pause voting sessions under extenuating circumstancesfinalizeSession()- Record final results and close voting sessionsaddMembers()- Add verified members to the on-chain registry
castVote()- Cast vote on a specific question (yes/no/abstain)batchVote()- Vote on multiple questions in a single transaction
getSessionInfo()- Get voting session detailsgetVoteCounts()- Get current vote counts for questionsisMember()- Check if address is a registered membergetSessionCount()- Get total number of voting sessionshasVoted()- Check if member has voted on specific question
struct Session {
uint256 startTime;
uint256 endTime;
uint256 questionCount;
bool isPaused;
bool isFinalized;
bytes32 resultsHash;
mapping(uint256 => Question) questions;
mapping(uint256 => mapping(address => bool)) hasVoted;
mapping(uint256 => mapping(uint8 => uint256)) voteCounts;
bool exists;
}
struct Question {
string text;
bool isPrivate;
bool exists;
}
struct VoteCounts {
uint256 abstainCount;
uint256 yesCount;
uint256 noCount;
}- Immutable Admin: Single admin address set at deployment
- Role-Based: OpenZeppelin AccessControl for admin functions
- Member Verification: Off-chain verification with on-chain registration
- Session Duration: 30 minutes to 2 hours
- Vote Values: 0 (abstain), 1 (yes), 2 (no)
- Question Count: Must match privacy settings array
- Member Addresses: No zero addresses allowed
- Reentrancy Protection: CEI pattern implementation
- Vote Integrity: One vote per member per question
- Session Security: Immutable parameters once created
- Emergency Controls: Pause functionality for crisis situations
- Foundry (latest version)
- Node.js (for additional tooling)
# Clone the repository
git clone <repository-url>
cd voting
# Install dependencies
forge install
# Build the project
forge buildCreate a .env file with the following variables:
# Polygon Testnet Configuration
AMOY_RPC_URL="https://rpc-amoy.polygon.technology"
MUMBAI_RPC_URL="https://rpc-mumbai.maticvigil.com/"
# API Keys (Get free from https://polygonscan.com/apis)
POLYGONSCAN_API_KEY="your_polygonscan_api_key_here"
# Deployment Configuration
PRIVATE_KEY="your_private_key_here"
ADMIN_ADDRESS="your_admin_address_here"forge test# Unit tests
forge test --match-test test_CastVote
# Security tests
forge test --match-test test_Security
# Gas optimization tests
forge test --match-test test_Gasforge coverage# Start local node
anvil
# Deploy to local network
forge script scripts/Deploy.s.sol --rpc-url http://localhost:8545 --broadcast# Deploy to Amoy testnet (recommended)
forge script scripts/DeployAmoy.s.sol \
--rpc-url https://rpc-amoy.polygon.technology \
--broadcast \
--verify \
--private-key $PRIVATE_KEY
# Deploy to Mumbai testnet
forge script scripts/DeployMumbai.s.sol \
--rpc-url https://rpc-mumbai.maticvigil.com/ \
--broadcast \
--verify \
--private-key $PRIVATE_KEY# Deploy to Polygon mainnet
forge script scripts/Deploy.s.sol \
--rpc-url https://polygon-rpc.com \
--broadcast \
--verify \
--private-key $PRIVATE_KEY// Admin creates a voting session
string[] memory questions = new string[](3);
questions[0] = "Should we increase membership fees?";
questions[1] = "Should we organize a summer event?";
questions[2] = "Should we update the bylaws?";
bool[] memory isPrivate = new bool[](3);
isPrivate[0] = false; // Public
isPrivate[1] = true; // Private
isPrivate[2] = false; // Public
uint256 sessionId = votingContract.createVotingSession(questions, isPrivate, 1 hours);// Admin adds verified members
address[] memory members = new address[](3);
members[0] = member1;
members[1] = member2;
members[2] = member3;
votingContract.addMembers(members);// Individual vote
votingContract.castVote(sessionId, 0, 1); // Yes vote on question 0
// Batch vote
uint256[] memory questionIds = new uint256[](2);
questionIds[0] = 0;
questionIds[1] = 2;
uint8[] memory votes = new uint8[](2);
votes[0] = 1; // Yes
votes[1] = 2; // No
votingContract.batchVote(sessionId, questionIds, votes);// Admin finalizes session with results hash
bytes32 resultsHash = keccak256(abi.encodePacked("final_results_data"));
votingContract.finalizeSession(sessionId, resultsHash);- Batch Voting: Vote on multiple questions in one transaction
- Batch Member Addition: Add multiple members efficiently
- Gas Sponsorship: Organization pays all gas costs
- Packed Structs: Efficient data storage
- Minimal On-chain Data: Only essential data stored
- Event-based History: Use events for historical data
- Admin Key Management: Secure admin private key storage
- Member Verification: Robust off-chain verification process
- Emergency Procedures: Plan for pause functionality usage
- Wallet Security: Secure member wallet management
- Vote Verification: Verify votes through events
- Result Verification: Verify final result hashes
├── contracts/ # Smart contracts
│ ├── SwedishVotingContract.sol
│ └── interfaces/
│ └── ISwedishVoting.sol
├── scripts/ # Deployment & testing scripts
│ ├── deploy/ # Deployment scripts
│ │ ├── DeployAmoy.s.sol
│ │ ├── DeployMumbai.s.sol
│ │ └── Deploy.s.sol
│ ├── test/ # Testing scripts
│ │ ├── TestAmoy.s.sol
│ │ ├── SimpleTestAmoy.s.sol
│ │ └── TestMumbai.s.sol
│ └── utils/ # Utility scripts
│ └── setup-mumbai.sh
├── docs/ # Documentation
│ ├── user-guides/ # User-focused guides
│ │ ├── QUICK_START.md
│ │ └── POLYGON_TESTNETS_GUIDE.md
│ ├── technical/ # Technical documentation
│ │ ├── DESIGN_SUMMARY.md
│ │ ├── SECURITY_FIXES_SUMMARY.md
│ │ └── IMPLEMENTATION_SUMMARY.md
│ └── reference/ # Reference materials
│ ├── design/
│ └── architecture/
├── test/ # Foundry test files
│ └── SwedishVotingContract.t.sol
├── NAVIGATION.md # Repository navigation guide
└── README.md # Project overview
📖 See NAVIGATION.md for detailed directory structure and quick links.
- Follow the existing code style and patterns
- Add comprehensive tests for new features
- Update documentation for any changes
- Ensure all tests pass before submitting
- Static Analysis: Run Slither for security analysis
- Gas Optimization: Monitor gas usage in tests
- Documentation: Maintain comprehensive NatSpec comments
MIT License - see LICENSE file for details.
For questions or support, please refer to the documentation in the docs/ directory or create an issue in the repository.
This contract has been designed with security best practices and includes comprehensive testing. For production use, consider:
- External Audit: Professional security audit
- Formal Verification: Mathematical proof of correctness
- Bug Bounty: Community security testing
- Gradual Deployment: Start with small-scale testing
Disclaimer: This software is provided "as is" without warranty. Use at your own risk and ensure proper testing before production deployment.