solscript-cli 0.1.1

CLI for SolScript - compile Solidity-style contracts to Solana
// Voting - Decentralized voting system
// Demonstrates enums, structs, and time-based logic

contract Voting {
    // Proposal structure
    struct Proposal {
        string description;
        uint256 forVotes;
        uint256 againstVotes;
        uint256 deadline;
        bool executed;
    }

    // Voter structure
    struct Voter {
        uint256 weight;
        bool registered;
    }

    // Vote choice
    enum Vote { For, Against }

    // State
    mapping(uint256 => Proposal) public proposals;
    mapping(address => Voter) public voters;
    mapping(uint256 => mapping(address => bool)) public hasVoted;

    uint256 public proposalCount;
    address public admin;
    uint256 public totalVoters;

    // Events
    event ProposalCreated(uint256 indexed id, string description, uint256 deadline);
    event Voted(uint256 indexed proposalId, address indexed voter, Vote vote, uint256 weight);
    event VoterRegistered(address indexed voter, uint256 weight);
    event ProposalExecuted(uint256 indexed id, bool passed);

    // Errors
    error NotAdmin();
    error NotRegistered();
    error AlreadyVoted();
    error VotingEnded();
    error VotingNotEnded();
    error AlreadyExecuted();
    error ProposalNotFound();
    error AlreadyRegistered();

    // Modifiers
    modifier onlyAdmin() {
        if (msg.sender != admin) revert NotAdmin();
        _;
    }

    modifier onlyRegistered() {
        if (!voters[msg.sender].registered) revert NotRegistered();
        _;
    }

    // Constructor
    constructor() {
        admin = msg.sender;
    }

    // Register a voter with voting weight
    function registerVoter(address voter, uint256 weight) public onlyAdmin {
        require(weight > 0, "Weight must be positive");
        if (voters[voter].registered) revert AlreadyRegistered();

        voters[voter] = Voter({
            weight: weight,
            registered: true
        });

        totalVoters++;
        emit VoterRegistered(voter, weight);
    }

    // Create a new proposal
    function createProposal(string memory description, uint256 durationSeconds)
        public
        onlyAdmin
        returns (uint256)
    {
        proposalCount++;

        proposals[proposalCount] = Proposal({
            description: description,
            forVotes: 0,
            againstVotes: 0,
            deadline: block.timestamp + durationSeconds,
            executed: false
        });

        emit ProposalCreated(proposalCount, description, block.timestamp + durationSeconds);
        return proposalCount;
    }

    // Vote on a proposal
    function vote(uint256 proposalId, Vote choice) public onlyRegistered {
        Proposal storage p = proposals[proposalId];

        if (bytes(p.description).length == 0) revert ProposalNotFound();
        if (block.timestamp >= p.deadline) revert VotingEnded();
        if (hasVoted[proposalId][msg.sender]) revert AlreadyVoted();

        hasVoted[proposalId][msg.sender] = true;
        uint256 weight = voters[msg.sender].weight;

        if (choice == Vote.For) {
            p.forVotes += weight;
        } else {
            p.againstVotes += weight;
        }

        emit Voted(proposalId, msg.sender, choice, weight);
    }

    // Execute a proposal after voting ends
    function execute(uint256 proposalId) public onlyAdmin {
        Proposal storage p = proposals[proposalId];

        if (bytes(p.description).length == 0) revert ProposalNotFound();
        if (block.timestamp < p.deadline) revert VotingNotEnded();
        if (p.executed) revert AlreadyExecuted();

        p.executed = true;
        bool passed = p.forVotes > p.againstVotes;

        emit ProposalExecuted(proposalId, passed);
    }

    // View functions
    function getProposal(uint256 proposalId) public view returns (
        string memory description,
        uint256 forVotes,
        uint256 againstVotes,
        uint256 deadline,
        bool executed
    ) {
        Proposal storage p = proposals[proposalId];
        return (p.description, p.forVotes, p.againstVotes, p.deadline, p.executed);
    }

    function isVotingActive(uint256 proposalId) public view returns (bool) {
        Proposal storage p = proposals[proposalId];
        return block.timestamp < p.deadline && !p.executed;
    }
}