Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
LABS
Guides

Setting Up On-Chain Voting for Property Upgrades

A technical guide for developers to build a secure, on-chain voting system for property management DAOs to approve and fund renovations using smart contracts.
Chainscore © 2026
introduction
INTRODUCTION

Setting Up On-Chain Voting for Property Upgrades

This guide explains how to implement a transparent and decentralized voting system for property upgrades using smart contracts.

On-chain voting enables communities to govern shared assets, like a digital property or a DAO treasury, through transparent and verifiable proposals. Unlike traditional polls, votes are recorded as transactions on a blockchain, creating an immutable ledger of community decisions. This system is trust-minimized, as the rules are enforced by smart contract code rather than a central administrator. Common use cases include allocating funds for development, approving aesthetic changes to a virtual world, or ratifying changes to a protocol's parameters.

The core technical components are a voting contract and a token contract. Typically, voting power is derived from token ownership, where one token equals one vote, though weighted or quadratic voting models are also possible. The process involves: a proposal being submitted with a description and executable calldata, a voting period where token holders cast their votes, and a final execution step if the proposal passes a predefined threshold (e.g., a majority of votes and a minimum quorum). Security considerations, such as preventing double-voting and ensuring only authorized proposals are executed, are paramount.

For example, an Ethereum-based property DAO might use OpenZeppelin's Governor contract suite. A proposal to upgrade a property's rendering contract would include the target address, the amount of ETH to send (0), and the encoded function call for the upgrade. Voters would then interact with the Governor contract using their governance tokens (like an ERC-20 or ERC-721) to cast their vote. The entire history—from proposal creation to final execution—is permanently recorded on-chain, providing full auditability.

Implementing this requires careful planning of governance parameters. You must decide on the voting delay (time between proposal submission and voting start), voting period (duration of the vote), proposal threshold (minimum tokens needed to submit a proposal), and quorum (minimum participation required for a vote to be valid). Setting these incorrectly can lead to voter apathy, governance attacks, or a system that is too slow to respond. Tools like Tally and Snapshot are often integrated for user-friendly proposal browsing and voting interfaces.

This guide will walk through building a basic on-chain voting system from scratch. We'll write a simple governance token contract, a governor contract that manages proposals, and a mock 'property' contract to be upgraded. The final section will cover deploying to a testnet, creating a proposal, and executing a successful upgrade, providing a complete, actionable foundation for decentralized property governance.

prerequisites
SETUP GUIDE

Prerequisites

Before implementing on-chain voting for property upgrades, you must establish the foundational technical environment and understand the core governance model.

To follow this guide, you need a basic understanding of blockchain fundamentals, smart contract development, and decentralized governance. You should be familiar with concepts like wallets, gas fees, and transaction signing. For development, proficiency in Solidity and experience with a framework like Hardhat or Foundry is required. This tutorial assumes you are building on an EVM-compatible chain such as Ethereum, Polygon, or Arbitrum. Ensure you have Node.js (v18 or later) and npm or yarn installed on your machine.

The core of any on-chain voting system is a governance token. You must decide on your token's distribution model—will it be earned, airdropped, or purchased? The token contract must implement the ERC-20Votes standard or a similar snapshot-compatible interface to enable vote delegation and historical balance tracking. For property-specific voting, you'll also need a Property NFT standard (like ERC-721) to represent each upgradable asset. The smart contract architecture must link voting power to token holdings and define the upgrade proposals as on-chain transactions.

You will need a development wallet with testnet ETH or the native token for your chosen chain to deploy contracts and simulate votes. We recommend using a Hardhat project initialized with npx hardhat init. Essential dependencies include @openzeppelin/contracts for secure, audited base contracts like Governor and Votes, and dotenv for managing private keys. Your hardhat.config.js should be configured for a local network and a public testnet like Sepolia or Goerli to test the full flow from proposal creation to execution.

The governance lifecycle consists of several phases: proposal creation, a voting period, a timelock delay, and finally execution. You must define key parameters: the voting delay (time between proposal and voting start), voting period (duration of the vote), proposal threshold (minimum tokens needed to propose), and quorum (minimum participation for a vote to be valid). These values are set in your Governor contract and directly impact the security and responsiveness of your system.

For a functional front-end, you will need to interact with your contracts using a library like ethers.js or viem. This involves connecting a user's wallet (e.g., via MetaMask), reading token balances and voting power, and submitting signed transactions for creating proposals and casting votes. You should plan to index proposal and vote events using a service like The Graph or Covalent for efficient querying. Testing is critical; write comprehensive unit tests for all voting logic and integration tests that simulate a full governance cycle with multiple participants.

system-architecture
ON-CHAIN GOVERNANCE

System Architecture Overview

This guide details the technical architecture for implementing a secure, transparent on-chain voting system to manage property upgrades within a decentralized community.

The core of the system is a smart contract deployed on a blockchain like Ethereum, Arbitrum, or Polygon. This contract serves as the single source of truth, holding the governance logic, tracking property states, and recording all votes immutably. Each property is represented as a unique token (an NFT or a token ID within a contract) that confers voting rights. The contract's state machine defines property statuses—such as Proposed, Voting, Approved, or Rejected—and enforces the rules for transitioning between them. This on-chain foundation ensures transparency and tamper-resistance, as every action is publicly verifiable.

Voting is initiated through a governance proposal. A community member submits a transaction to the contract, specifying the target property token ID and a description of the proposed upgrade (e.g., "Install solar panels on roof"). This transaction creates a new proposal struct stored on-chain, kicking off a predefined voting period, typically 3-7 days. To prevent spam, proposals often require the proposer to stake a bond or be made exclusively by token holders above a certain threshold. The proposal metadata, which can be stored on IPFS or Arweave for cost-efficiency, includes detailed specifications, cost estimates, and visual plans linked via a decentralized URI.

During the voting period, token holders cast their votes directly by interacting with the smart contract. The most common patterns are token-weighted voting, where voting power is proportional to the number of property tokens held, and one-token-one-vote. A typical contract function for voting looks like:

solidity
function castVote(uint256 proposalId, bool support) external {
    require(votingToken.balanceOf(msg.sender) > 0, "No voting rights");
    // ... logic to record vote
}

Votes are tallied on-chain, and once the period ends, the contract automatically executes the outcome based on predefined quorum and majority thresholds, updating the property's state accordingly.

To execute approved upgrades, the system utilizes a multisig wallet or a timelock controller. Funds for the upgrade are held in a community treasury contract. After a successful vote, a transaction to release funds to a contractor's address can be queued in the timelock, which introduces a mandatory delay (e.g., 48 hours). This delay provides a final safety window for the community to review and potentially cancel the transaction if issues are discovered, adding a critical layer of security against malicious proposals or rapid fund drainage.

Integrating oracles like Chainlink is essential for connecting off-chain outcomes to on-chain execution. For instance, an upgrade involving a contractor's work can be set to release payment only upon verification. A decentralized oracle network can be tasked to confirm work completion based on predefined data feeds (e.g., a notary's confirmation or IoT sensor data) before triggering the final payment transaction from the treasury. This creates a trust-minimized execution layer for real-world agreements.

The final architecture creates a closed-loop system: Proposal → Transparent Voting → Secure Execution → Verifiable Outcome. This model, inspired by protocols like Compound and Uniswap, empowers communities with direct ownership over their shared assets. The immutable audit trail on the blockchain provides unparalleled accountability for all upgrade decisions and financial flows.

core-contracts
ON-CHAIN GOVERNANCE

Core Smart Contracts

Implementing a secure and transparent voting system for property upgrades requires specific smart contract patterns. These are the foundational components you'll need to build.

06

Security & Audit Considerations

Common vulnerabilities in on-chain governance and how to mitigate them.

  • Proposal Spam: Mitigate with high proposal creation costs or a proposal threshold.
  • 51% Attacks: Implement a quorum and potentially a veto guardian role for emergencies.
  • Timelock Bypass: Ensure the Timelock is the sole admin of all core contracts.
  • Always audit: Use services like Trail of Bits or CertiK. Compound's Governor Bravo audit is a key reference.
$3.8B+
Lost to Governance Exploits (2022-2023)
step-proposal-creation
ON-CHAIN GOVERNANCE

Step 1: Creating the Proposal Contract

This step involves deploying the smart contract that formalizes a property upgrade proposal and manages the voting lifecycle on-chain.

The core of any on-chain governance system is the proposal contract. This is a smart contract that acts as a self-contained, executable proposal. For property upgrades, this contract defines the specific changes (e.g., a new amenity, a fee adjustment) and holds the logic for the voting process. Deploying this contract to the blockchain (like Ethereum, Arbitrum, or Polygon) creates an immutable, transparent record of the proposal that all token holders can interact with. Key parameters, such as the proposal description, voting duration, and quorum requirements, are set in the contract's constructor upon deployment.

A standard proposal contract inherits from governance frameworks like OpenZeppelin's Governor contracts. This provides battle-tested functionality for creating proposals, casting votes, and executing passed proposals. The contract's state tracks the proposal's lifecycle: Pending, Active, Succeeded/Defeated, Queued, and Executed. The voting mechanism is typically implemented using a token-weighted system, where one governance token equals one vote. This ensures that voting power is directly tied to a member's stake in the property or DAO.

Here is a simplified example of a proposal contract constructor using Solidity and OpenZeppelin's Governor:

solidity
import "@openzeppelin/contracts/governance/Governor.sol";

contract PropertyUpgradeProposal is Governor {
    string public proposalDescription;
    address public targetContract;
    bytes public upgradeCalldata;

    constructor(
        string memory _description,
        address _target,
        bytes memory _calldata
    ) Governor("PropertyGovernor") {
        proposalDescription = _description;
        targetContract = _target;
        upgradeCalldata = _calldata;
    }
    // ... Voting and execution logic
}

This skeleton shows how the proposal encapsulates the what (_description), the where (_target), and the how (_calldata) of the intended upgrade.

Before deployment, the proposal's calldata must be carefully constructed. This is the encoded function call that will be executed if the vote passes. For example, if the proposal is to upgrade a property's rental management contract to set a new maintenance fee to 5%, the calldata would encode a function call like setMaintenanceFee(uint256) with the argument 5. Generating this data off-chain and verifying its correctness is critical, as an error here could lead to the execution of unintended transactions.

Once deployed, the contract address becomes the canonical reference for the proposal. Governance front-ends and block explorers will use this address to display proposal details, track vote totals, and monitor state changes. The act of deployment also emits events that indexers can capture, making the proposal discoverable by the community. This establishes a single source of truth on the blockchain, eliminating disputes over proposal wording or terms that can occur in off-chain discussions.

The creation of the proposal contract is the foundational technical step that transitions an idea from informal discussion to a formal, executable on-chain object. It ensures transparency, immutability, and programmability for the entire governance process that follows.

step-governor-integration
ON-CHAIN GOVERNANCE

Integrating the Governor Contract

Deploy and configure a governance contract to manage proposals and voting for property upgrades.

The Governor contract is the core of your DAO's on-chain governance system. It manages the lifecycle of proposals, from creation and voting to execution. For property upgrades, you will typically use OpenZeppelin's Governor contracts, which provide a modular, audited, and gas-efficient foundation. The key components you need to integrate are the Governor contract itself, a Voting Token (like your project's ERC-20 or ERC-721), and a Timelock Controller for secure, delayed execution of successful proposals.

Start by deploying your chosen Governor implementation, such as GovernorCompatibilityBravo or the newer Governor contract. You must configure several critical parameters in the constructor: the voting token address, the voting delay (time between proposal submission and voting start), the voting period (duration of the vote), the proposal threshold (minimum tokens needed to submit), and quorum requirements. For a property-focused DAO, a common setup might be a 1-day voting delay, a 3-day voting period, and a quorum of 4% of the total token supply.

The Timelock Controller is a critical security component. It acts as the executor for the Governor, introducing a mandatory delay between a proposal's approval and its execution. This delay gives token holders a final chance to exit the system if they disagree with a passed proposal. Deploy a Timelock and set the Governor contract as its sole "proposer" role and a trusted multisig or the DAO itself as the "executor." This ensures only approved proposals from the Governor can be queued for execution.

Finally, connect your property upgrade logic to this governance framework. Your property management contract—which holds the logic for upgrades—should have its privileged functions (e.g., upgradeProperty) protected by the Timelock. You do this by setting the Timelock's address as the contract's owner or admin. Once integrated, a successful governance vote will result in the upgrade transaction being queued in the Timelock. After the delay expires, anyone can execute it, applying the upgrade on-chain.

step-treasury-multisig
ON-CHAIN GOVERNANCE

Step 3: Setting Up the Treasury & Fund Release

This section details how to implement a secure, on-chain voting mechanism for property owners to propose and approve upgrades, with funds released automatically from the treasury upon successful vote execution.

The core of upgrade governance is a smart contract that manages proposal creation, voting, and fund disbursement. A typical implementation uses a Governor contract (like OpenZeppelin's Governor) paired with a Treasury contract holding the community's funds. When a property owner wants to propose an upgrade—such as a new roof or HVAC system—they submit a transaction to the Governor contract. This transaction includes the proposal details: the recipient address (e.g., the contractor's wallet), the amount of ETH or stablecoins to release from the treasury, and the encoded function call that will execute the payment.

Once a proposal is created, it enters a voting period. Voting power is typically derived from an ERC-20 token representing property ownership shares or a dedicated governance token. Token holders cast their votes for, against, or abstain. The voting logic must be configured with key parameters: the voting delay (time before voting starts), voting period (duration of the vote), and quorum (minimum participation required for validity). A common security pattern is to use timelock contracts, which queue successful proposals for a set period before execution, giving token holders a final chance to react if a malicious proposal slips through.

After the voting period ends, anyone can call the execute function on the Governor contract to process a successful proposal. If the vote passes the quorum and majority thresholds, the Governor instructs the Timelock to execute the queued transaction. The Timelock then calls the releaseFunds function on the Treasury contract, which performs a low-level .call to transfer the specified amount to the contractor's address. This entire flow is transparent and immutable on-chain, with every proposal, vote, and transfer recorded on the blockchain for auditability.

Here is a simplified code snippet illustrating a Treasury contract's core release function, which would be called via the Timelock:

solidity
contract CommunityTreasury {
    address public timelock;
    
    constructor(address _timelock) {
        timelock = _timelock;
    }
    
    function releaseFunds(address payable recipient, uint256 amount) external {
        require(msg.sender == timelock, "Unauthorized");
        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Transfer failed");
    }
}

This function ensures only the authorized timelock contract can trigger payments, preventing unilateral access to treasury funds.

For production deployment, consider integrating with existing governance platforms like Tally or Sybil for a user-friendly voting interface. Key security audits should focus on the proposal creation logic to prevent malicious transactions, the quorum calculations, and the timelock delay duration. Setting a reasonable timelock (e.g., 48-72 hours) is critical for security, as it allows the community to veto a malicious executed action by exiting the system before funds are released. This model transforms property management from a centralized, opaque process into a transparent, community-driven protocol.

step-oracle-verification
ENHANCING SECURITY

Step 4: Adding Oracle Verification (Optional)

Integrate a decentralized oracle to fetch off-chain data for validating property upgrade proposals before they are voted on.

On-chain voting for property upgrades, such as adding a new amenity or changing a fee structure, requires accurate, real-world data to make informed decisions. An oracle acts as a secure bridge between the blockchain and external data sources. For this guide, we'll implement a basic verification step using Chainlink Data Feeds to check if a proposed upgrade's estimated cost aligns with current market rates before the proposal is finalized. This prevents malicious or economically irrational proposals from consuming governance resources.

First, you need to import the Chainlink AggregatorV3Interface into your voting contract. This interface allows your smart contract to read the latest price data from a decentralized oracle network. You'll specify the data feed address for the relevant asset, such as ETH/USD for cost estimations denominated in dollars. Add a modifier or a require statement in your proposal creation function that calls latestRoundData() and compares the derived cost against a sensible threshold.

solidity
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

AggregatorV3Interface internal priceFeed;

constructor() {
    // ETH/USD feed on Ethereum Mainnet
    priceFeed = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419);
}

When a user submits a proposal with an estimatedCostUSD, the contract should verify this value. Fetch the current ETH price, convert the proposal's cost from USD to ETH (or the native gas token), and ensure it is not an order of magnitude outside expected bounds. This simple check can filter out proposals with typos or blatant spam. Remember, oracles introduce a trust assumption and minor gas costs, so this step is optional and should be weighed against the governance model's needs. For higher-value upgrades, consider using Chainlink's Proof of Reserves or a custom oracle for specialized data.

After implementing the verification, update your proposal struct to include the validated cost field and the timestamp of the oracle check. This creates an immutable audit trail on-chain. In the final voting interface, voters can see that the proposal's financial data was attested by a decentralized oracle network, increasing transparency and trust. This step moves your governance system from purely subjective voting to objective, data-informed decision making, which is critical for managing real-world asset upgrades effectively.

GOVERNANCE MODELS

Voting Parameter Comparison

Comparison of key parameters for on-chain voting mechanisms used to approve property upgrades.

ParameterSimple MajorityQuadratic VotingTime-Lock Weighted

Quorum Threshold

50% of total supply

N/A

40% of eligible votes

Vote Duration

72 hours

48 hours

168 hours

Vote Weighting

1 token = 1 vote

sqrt(tokens held)

vote weight * lock time

Proposal Bond

1000 GOV

500 GOV

2000 GOV

Execution Delay

24 hours

Immediate

48 hours after vote

Anti-Sybil

Gas Cost per Vote

$5-10

$15-25

$8-12

Use Case Fit

Basic upgrades

Community sentiment

Long-term alignment

ON-CHAIN VOTING

Frequently Asked Questions

Common technical questions and solutions for developers implementing on-chain voting for property upgrades.

A simple majority vote passes if more than 50% of the votes cast are in favor, regardless of total voter turnout. A quorum-based vote requires a minimum threshold of total voting power to participate before the result is valid.

  • Simple Majority: votesFor > totalVotes / 2. Vulnerable to low participation.
  • Quorum-Based: Requires totalVotesCast >= quorumThreshold (e.g., 30% of total supply) and a majority of those votes. This ensures broader community engagement.

For property upgrades, a quorum (e.g., using OpenZeppelin's Governor with a Votes token) is standard to prevent a small, active group from making significant changes.

conclusion-next-steps
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have successfully set up a foundational on-chain voting system for property upgrades. This guide covered the core components: a governance token, a proposal contract, and a voting mechanism.

Your deployed system now enables a community to propose upgrades—such as adding a new amenity or changing a fee structure—and vote on them using their governance tokens. The PropertyGovernance contract enforces a quorum and majority vote, ensuring decisions reflect the will of the token holders. Remember to thoroughly test all contract functions, including createProposal, vote, and executeProposal, in a local or testnet environment before considering a mainnet deployment. Use tools like Hardhat or Foundry for comprehensive unit testing.

For production readiness, several critical enhancements are necessary. Security audits are non-negotiable; engage a reputable firm to review your code for vulnerabilities. Consider implementing a timelock contract (like OpenZeppelin's TimelockController) to delay proposal execution, giving users time to react to malicious governance actions. You should also design a clear process for voter delegation (e.g., using a snapshot of token balances) and potentially a proposal threshold to prevent spam.

To extend this system, explore integrating with off-chain voting platforms like Snapshot for gas-free signaling, while keeping the execution on-chain. You could also implement more sophisticated voting mechanisms such as quadratic voting or conviction voting for long-term decision weighting. For real-world property DAOs, connecting the governance outcome to an on-chain property registry or treasury multisig is the final step to automate upgrade execution.

The next practical step is to build a frontend interface. Use a framework like Next.js with libraries such as wagmi and viem to connect to your contracts. Display active proposals, user voting power, and results. Always prioritize user experience by clearly explaining voting power, deadlines, and the implications of each proposal. Document your contract addresses and ABI for your community.

Finally, launch and maintain your governance system with transparency. Use a block explorer like Etherscan to verify and publish your source code. Establish communication channels (Discord, forums) for proposal discussion. Governance is iterative; be prepared to upgrade the system itself through the very process you've created, following best practices for upgradeable contracts using proxies or the EIP-2535 Diamond Standard for modularity.