On-chain governance is the mechanism by which a decentralized protocol's stakeholders collectively decide on its evolution. For risk management systems, this is critical: new market conditions, asset types, and attack vectors necessitate regular updates to parameters like loan-to-value (LTV) ratios, liquidation thresholds, and oracle configurations. A well-designed governance proposal system formalizes this process, moving from informal discussion to executable on-chain code. This guide focuses on the architectural components required to build such a system, applicable to protocols using frameworks like Compound's Governor Bravo or a custom implementation built with OpenZeppelin Governor contracts.
Setting Up a Governance Proposal System for New Risk Models
Introduction
This guide details the technical process for establishing a decentralized governance system to propose and ratify new risk models for a DeFi protocol.
The core lifecycle of a governance proposal follows a standard path: 1) Temperature Check – an off-chain forum discussion to gauge community sentiment; 2) Proposal Creation – an on-chain transaction submitting the executable code (e.g., a call to a RiskManager contract); 3) Voting Period – token holders cast votes weighted by their stake; 4) Execution – the successful proposal's payload is executed after a timelock delay. The timelock is a security-critical component, providing a buffer for users to react to or exit from system changes before they take effect. We'll examine each stage, including the smart contract interfaces and the data structures needed to encode a new risk model.
A new risk model proposal typically involves updating parameters in a dedicated RiskParameters contract. For example, a proposal payload might call setCollateralFactor(address asset, uint256 newLTV). The governance contract must be authorized as the owner or admin of this risk contract. We will outline the steps to deploy the governance infrastructure, connect it to the protocol's contracts, and create a front-end interface for proposal submission and voting. The goal is to create a transparent, secure, and efficient system that aligns protocol risk management with the collective will of its stakeholders.
Prerequisites
Before deploying a new risk model, you must establish the technical and governance framework that will evaluate and enact it.
A governance proposal system for risk models requires a secure, on-chain execution environment and a defined stakeholder group. You will need a smart contract framework like OpenZeppelin Governor or Compound's Governor Bravo, deployed on your target chain (e.g., Ethereum Mainnet, Arbitrum). This contract manages the proposal lifecycle: creation, voting, and execution. Your system must also integrate a token or NFT-based voting mechanism to represent governance power. Ensure your token's distribution and delegation logic aligns with your desired security model, whether it's token-weighted, delegate-based, or uses a novel system like ve-tokenomics.
The core technical prerequisite is a risk parameter smart contract that the governance system can upgrade. This is typically a separate, upgradeable contract (using a proxy pattern like TransparentProxy or UUPS) that stores key risk variables: collateral factors, liquidation thresholds, oracle addresses, and asset whitelists. Governance proposals will call functions on this contract. You must write and thoroughly test these functions, such as setCollateralFactor(address asset, uint256 factor) or pauseMarket(address asset), ensuring they include proper access control modifiers like onlyGovernance.
For off-chain components, you need a proposal creation frontend and indexing service. Developers often use a framework like Tally or build a custom interface that interacts with the governance contract's propose function. You will also need to index proposal and vote data from the blockchain. Services like The Graph (subgraphs) or Covalent can provide this data to your frontend. Setting up a discourse forum or similar platform for temperature checks and community discussion before on-chain submission is a critical best practice to gauge sentiment.
Finally, establish clear documentation for proposal creators. This includes a template specifying required sections: Problem Statement, Risk Model Specification (e.g., liquidationIncentive = 1050000000000000000 for 5%), Technical Implementation (smart contract diff), Security Considerations, and Voting Options. Provide example code snippets for interacting with your contracts, such as a script to simulate a proposal's effects using Foundry's forge or Hardhat. This preparation ensures proposals are actionable and minimizes governance overhead.
Setting Up a Governance Proposal System for New Risk Models
A modular, on-chain governance framework is essential for DAOs to securely propose, debate, and implement updates to their financial risk parameters.
A governance proposal system for risk models is a specialized smart contract architecture that manages the lifecycle of protocol parameter changes. Unlike simple token voting, it must handle complex, time-gated processes to ensure safety. Core components typically include a proposal factory for creating new risk model submissions, a timelock controller to enforce a mandatory delay before execution, and an executor contract that applies the approved changes to the target protocol, such as a lending market's Comptroller or an AMM's PoolManager. This separation of powers prevents instant, potentially malicious upgrades.
The proposal lifecycle follows a strict sequence: 1) Submission where a proposal with encoded calldata is created, 2) Voting where token holders cast votes during a defined period, 3) Queuing where a successful proposal is placed in the timelock, and 4) Execution where the action is performed after the delay. For risk models, the proposal payload often calls a function like _setMarketBorrowCaps(address[] markets, uint256[] caps) or _setCollateralFactor(CToken cToken, uint256 newCollateralFactorMantissa). Using a timelock is non-negotiable; it provides a final safety window for users to exit or for governance to cancel a proposal if flaws are discovered.
Implementation commonly leverages battle-tested frameworks like OpenZeppelin's Governor contracts. A standard setup involves deploying a GovernorContract (e.g., GovernorCompatibilityBravo), a TimelockController, and connecting them so the Governor is the Timelock's sole "proposer" and "executor". The proposal's target is the Timelock address, which will later relay the call. Critical configuration includes setting the voting delay (blocks before voting starts), voting period (blocks voting is open), proposal threshold (minimum tokens to propose), and quorum (minimum votes for validity).
When designing proposals for new risk models, the calldata must be meticulously constructed. This involves off-chain simulation using tools like Tenderly or Foundry's cast to ensure the function calls behave as intended. For example, a proposal to update liquidation thresholds on Aave V3 would encode a call to the PoolConfigurator contract. All parameters—asset addresses, new values, and underlying contract ABIs—must be verified. A best practice is to publish the full simulation script and results alongside the proposal for community vetting.
Security considerations are paramount. The governance contract should have a guardian or pause mechanism for emergencies, though its powers should be severely limited. All privileged roles (e.g., Timelock admin) should be held by a multi-signature wallet or a decentralized entity. Furthermore, the system should be upgradeable via a transparent proxy pattern (like UUPS) to fix bugs, but the upgrade mechanism itself must also be governed by the timelock to avoid centralization risks. This creates a recursive security model.
Finally, successful deployment requires thorough testing on a testnet with a token faucet, followed by a trial governance period on mainnet with low-stakes proposals. Tools like Snapshot can be used for sentiment signaling before on-chain votes. Documentation, such as a clear proposal template in the DAO's forum, is critical for standardization. The end goal is a transparent, secure process where any community member can confidently propose adjustments to the protocol's risk parameters, ensuring its long-term resilience.
Key System Components
A robust governance proposal system requires specific technical components to manage risk model updates securely and transparently. These are the core building blocks.
Risk Parameter Registry
A dedicated, upgradeable smart contract that stores the current active risk models and their parameters. It acts as the single source of truth for the protocol's risk settings.
- Stores mappings for asset-specific parameters like Loan-to-Value (LTV) ratios, liquidation thresholds, and oracle addresses.
- Emits events on every parameter change, creating an immutable audit trail.
- Is owned by the Timelock, ensuring only successfully executed governance proposals can modify its state. This pattern is used by Aave and Compound.
Communication & Notification Layer
Systems to disseminate proposal information and engage stakeholders, which is crucial for participation.
- Governance Forum: A Discourse or Commonwealth forum where proposals are drafted and discussed in RFC (Request for Comments) format before an on-chain vote.
- Notification Bots: Discord or Telegram bots that alert community members to new proposals, voting periods, and execution deadlines. Tools like Collab.Land integrate token-gated channels.
- Governance Frontend: A dedicated UI (e.g., built with Governor Bravo UI components) that abstracts the complexity of interacting directly with the smart contracts.
Security & Monitoring
Continuous oversight mechanisms to protect the governance system itself from attacks or failures.
- Emergency Multisig: A fallback, time-limited multisig wallet (e.g., 6/9 signers) with the power to pause the system or veto malicious proposals in extreme scenarios, as seen in MakerDAO's PSM module governance.
- Governance Monitoring: Services like Forta Network that deploy bots to detect unusual voting patterns, such as sudden large token delegations or flash loan attacks aimed at manipulating votes.
- Post-Mortem Analysis: A formal process for reviewing executed proposals to assess their real-world impact versus projections, creating feedback for future proposals.
Step 1: Define the Proposal Template
The proposal template is the structured data schema that defines what information is required to submit a new risk model for on-chain governance approval.
A well-defined proposal template acts as a validation layer and standardization tool. It ensures every submitted risk model contains the necessary data for proper evaluation, preventing incomplete or malformed proposals from entering the governance queue. This template is typically implemented as a Solidity struct within your governance contract, specifying the exact parameters that proposers must provide. For example, a basic template for a lending protocol's collateral risk model would require fields like assetAddress, loanToValueRatio, liquidationThreshold, and liquidationPenalty.
The template must balance completeness with usability. Requiring excessive data can deter participation, while omitting critical fields makes risk assessment impossible. Essential components include: the target contract address for the new model, the risk parameters themselves (encoded as key-value pairs or a data hash), a justification document URI (often an IPFS hash linking to a detailed risk assessment report), and an execution payload—the encoded function call that will modify the protocol's state if the proposal passes. This payload is what gets executed upon successful vote completion.
Implementation involves defining the struct and integrating it with your proposal submission function. Below is a simplified example using a generic governance contract pattern:
soliditystruct RiskModelProposal { address targetAsset; uint256 ltv; // Loan-to-Value ratio (in basis points) uint256 liquidationThreshold; // (in basis points) uint256 liquidationBonus; // (in basis points) string ipfsHash; // Reference to full risk report bytes executionPayload; // Calldata for `setRiskParameters()` } function submitRiskProposal(RiskModelProposal calldata proposal) public { // Validate basic inputs require(proposal.ltv < proposal.liquidationThreshold, "Invalid risk params"); require(bytes(proposal.ipfsHash).length > 0, "Missing documentation"); // Create proposal in governor governor.propose( address(this), // Target: this contract 0, // Value abi.encodeWithSignature("executeRiskProposal(bytes)", abi.encode(proposal)), // Payload string(abi.encodePacked("Risk Model Update: ", proposal.ipfsHash)) // Description ); }
This code defines the data structure and a submission wrapper that performs initial sanity checks before forwarding a proposal to a governor contract (like OpenZeppelin's Governor).
Finally, the template should be documented for the community. Publish the exact struct definition and field explanations in your protocol's documentation, such as on GitHub or a dedicated docs site. Clear documentation reduces submission errors and sets consistent expectations for the quality and format of the supporting risk analysis, which is often stored off-chain via IPFS or Arweave. This step transforms ad-hoc suggestions into standardized, executable governance actions.
Step 2: Build the Proposal Manager Smart Contract
This step involves implementing the on-chain logic for creating, voting on, and executing proposals to modify the protocol's risk parameters.
The Proposal Manager is the central smart contract that governs the lifecycle of a risk model update. Its primary functions are to: create proposals with new risk parameter sets, manage a voting period, tally votes from governance token holders, and finally execute approved proposals to update the live risk model. This contract must be upgradeable to allow for future improvements to the governance process itself, and it will interact with both the GovernanceToken (for voting power) and the RiskModelRegistry (to apply changes).
Start by defining the core data structures. A Proposal struct should include fields like: a unique id, the proposer's address, a description hash (storing metadata off-chain via IPFS), the target riskModelId to update, the new parameters array, and status flags (Active, Succeeded, Executed). You'll also need to track voting data: forVotes, againstVotes, abstainVotes, and a mapping of which addresses have already voted to prevent double-counting.
The key function is createProposal(uint256 riskModelId, bytes32 descriptionHash, RiskParameter[] calldata newParameters). This function should validate that the riskModelId exists in the RiskModelRegistry and that the caller holds a minimum proposal threshold of governance tokens. Upon success, it stores a new Proposal with an Active status and emits an event. It's critical to use a timelock pattern: proposals that pass should enter a waiting period before they can be executed, giving users time to react to parameter changes.
Voting logic is implemented in castVote(uint256 proposalId, uint8 support), where support is an enum for For, Against, or Abstain. The function must check the proposal is active and that the voter hasn't voted before. Voting power should be calculated using a snapshot mechanism—typically the token balance at the block when the proposal was created—to prevent manipulation. This can be done by querying a snapshot from the GovernanceToken contract or implementing an internal snapshot within the manager.
After the voting period ends, anyone can call queueProposal(uint256 proposalId) to move a successful proposal to a queued state, starting the timelock delay. Finally, executeProposal(uint256 proposalId) can be called after the delay expires. This function calls RiskModelRegistry.updateRiskModel(proposal.riskModelId, proposal.parameters) to enact the change on-chain. Always include comprehensive event emissions (ProposalCreated, VoteCast, ProposalQueued, ProposalExecuted) for off-chain indexing and frontend integration.
Step 3: Integrate On-Chain Voting
This step details how to implement an on-chain voting system to approve or reject new risk models, ensuring protocol changes are transparent and community-driven.
On-chain governance provides a transparent and immutable record of all decisions. For a risk model registry, this means each new model's parameters—such as collateral factors, liquidation thresholds, and oracle configurations—must be ratified by a vote of token holders or their delegates. The core contract is typically a Governor contract, often based on OpenZeppelin's Governor implementation, which manages proposal creation, voting, and execution. This contract interacts with your RiskModelRegistry to execute the addRiskModel function upon a successful vote.
A proposal lifecycle begins when a proposer, who must hold a minimum voting power threshold, submits a transaction that calls propose on the Governor contract. The proposal payload contains the target (the registry contract address), value (usually 0), and calldata encoding the call to addRiskModel with the new model's parameters. After a review period, the voting phase opens. Voters cast their votes using tokens, often with options like For, Against, and Abstain, with weight determined by their token balance at a specific snapshot block.
The voting mechanism must be carefully designed. Common patterns include token-weighted voting (one token, one vote) or delegation via systems like Compound's Governor Bravo. For critical risk parameters, you may implement a timelock between vote conclusion and execution. This delay, enforced by a TimelockController contract, gives users a safety window to exit positions if they disagree with an approved model change. The execution step is permissionless; any account can trigger the execute function on the Governor to apply the new model to the registry.
Here is a simplified code example for a proposal's calldata using ethers.js and a Governor Alpha-style contract:
javascriptconst registryAddress = '0x...'; const registryInterface = new ethers.utils.Interface(['function addRiskModel(uint256 id, bytes calldata config)']); const calldata = registryInterface.encodeFunctionData('addRiskModel', [proposedModelId, modelConfigBytes]); // Targets, values, and calldata are arrays for a single proposal action const targets = [registryAddress]; const values = [0]; const calldatas = [calldata]; const description = 'IPFS hash of proposal description'; await governor.propose(targets, values, calldatas, description);
Security considerations are paramount. The proposer threshold prevents spam. The quorum requirement ensures sufficient participation for legitimacy. It's critical that the RiskModelRegistry's addRiskModel function is only callable by the Timelock or Governor contract, which is achieved by using OpenZeppelin's AccessControl. Furthermore, the model configuration data (bytes calldata config) should be verified off-chain by delegates and documented in the proposal's description, which is typically an IPFS hash pointing to a detailed specification.
After implementation, you must provide clear interfaces for users. This includes a front-end to create proposals, view active votes, and cast votes. Tools like Tally and Sybil aggregate delegate platforms. Monitoring tools should track proposal state and execution. Successful integration means protocol risk can evolve in a decentralized manner, aligning long-term security with stakeholder consensus, as seen in systems like Aave and Uniswap.
Proposal Lifecycle States and Requirements
Required actions, timings, and quorum thresholds for each stage of a governance proposal.
| State | Duration | Required Quorum | Voting Threshold | Actions Required |
|---|---|---|---|---|
Draft | Unlimited | Forum discussion, temperature check | ||
Pending | 2 days | Submit on-chain, deposit security | ||
Active | 5 days | 4% of veTOKEN |
| Delegate voting, cast votes |
Queued | 2 days | Met in Active phase | Met in Active phase | Time lock execution |
Executed | N/A | Met in Active phase | Met in Active phase | Proposal logic runs |
Canceled | N/A | Proposer cancels before Active | ||
Defeated | N/A | <4% of veTOKEN | <50% Yes votes | Quorum or threshold not met |
Step 4: Frontend and Indexer Integration
This step connects your smart contract's governance logic to a user-friendly interface and a real-time data layer, enabling proposal creation, voting, and result tracking.
With your governance smart contracts deployed, the next phase is to build the frontend application that allows stakeholders to interact with the system. This interface typically includes pages for proposal creation, active proposal listing, voting, and results display. Using a framework like React or Vue.js with a Web3 library such as wagmi or ethers.js is standard. The frontend's primary job is to encode user actions—like submitting a new risk model's parameters—into transactions that call your contract's createProposal function, and to decode on-chain data for display.
Directly querying the blockchain for every UI update is slow and inefficient. This is where an indexer becomes essential. An indexer is a service that listens to your contract's events (e.g., ProposalCreated, VoteCast) and stores the decoded data in a queryable database like PostgreSQL. You can build a custom indexer using The Graph (deploying a subgraph) or a framework like Subsquid. The indexer transforms raw event logs into structured data, such as a list of all proposals with their current vote tally, making it fast for your frontend to fetch via GraphQL or a REST API.
The frontend must connect to both the blockchain provider (e.g., via Infura or Alchemy) for sending transactions and the indexer API for reading data. For example, when a user visits the proposals page, the app queries the indexer's GraphQL endpoint for all proposals sorted by block number. When a user votes, the frontend uses the connected wallet to sign a transaction invoking the castVote function. It's crucial to handle transaction states (pending, confirmed, failed) and update the UI accordingly, often by refetching data from the indexer after a transaction is mined.
A key integration is the governance token. Your frontend needs to read the user's token balance (often from the indexer or via a balanceOf call) to determine voting power and eligibility. For snapshot voting, where votes are weighted by token balance at a specific block, the indexer must store historical token balances. The UI should clearly display voting power, proposal thresholds (e.g., quorum of 4% of total supply), and real-time vote counts for For, Against, and Abstain options.
Finally, consider security and UX patterns. Use transaction simulations via tools like Tenderly or the eth_call RPC method to estimate gas and catch revert errors before the user signs. Implement multichain support if your governance spans multiple networks, using a library like Wagmi with chain configurations. Always verify contract ABIs are up-to-date and consider using TypeChain for type-safe contract interactions. The end goal is a seamless loop: user action -> blockchain transaction -> indexer ingestion -> updated frontend display.
Resources and Tools
These tools and frameworks help teams design, deploy, and operate a governance proposal system for introducing and updating onchain risk models. Each resource focuses on a specific layer, from proposal creation and voting to execution and auditability.
Risk Proposal Specification Templates
A governance system is only as good as the proposal standards it enforces. Mature protocols define strict templates for risk model changes to reduce ambiguity and voter fatigue.
A strong risk proposal template typically includes:
- Model description: equations, assumptions, and referenced research.
- Input data: price feeds, volatility windows, oracle dependencies.
- Impact analysis: effect on liquidation thresholds, capital efficiency, and bad debt risk.
- Rollback plan: conditions under which the change should be reverted.
Protocols like Aave and MakerDAO require these elements before a proposal can proceed to voting.
Developers should encode these requirements in:
- Offchain governance processes (forum + Snapshot)
- Onchain proposal metadata validation where possible
Standardizing proposal content improves decision quality and reduces governance attack surface.
Frequently Asked Questions
Common questions and solutions for developers implementing on-chain governance for new risk models in DeFi protocols.
A robust on-chain governance system for risk models requires several key components:
- Proposal Factory Contract: A smart contract that standardizes the creation of new proposals, ensuring they contain required data fields like title, description, and executable calldata.
- Voting Token/Mechanism: A token (like a protocol's governance token) or mechanism (like ve-token locking) that determines voting power. This is critical for Sybil resistance.
- Timelock Controller: A contract that queues and executes successful proposals after a mandatory delay. This is a primary security feature, allowing users to exit if a malicious proposal passes.
- Governor Contract: The core contract that manages the proposal lifecycle (create, vote, queue, execute), often following standards like OpenZeppelin's Governor.
- Risk Model Registry: A separate, upgradeable contract that stores the official, active risk parameters. Proposals should target this registry to enact changes.
Using a battle-tested framework like OpenZeppelin Governor reduces audit surface and integrates these components securely.
Conclusion and Next Steps
You have now configured a foundational governance proposal system for introducing new risk models. This guide covered the core smart contract architecture and key processes.
The implemented system provides a structured, on-chain framework for proposing, vetting, and ratifying new risk assessment logic. By separating the proposal logic from the execution logic, you ensure that new models can be debated and approved by token holders before they are activated. This is critical for maintaining the security and stability of any protocol that relies on dynamic risk parameters, such as lending platforms like Aave or Compound. The use of a timelock contract adds a crucial security delay, allowing for a final review before any code changes take effect.
To extend this system, consider integrating with off-chain voting platforms like Snapshot for gas-free sentiment signaling before an on-chain vote. You should also implement a robust risk model interface, requiring all proposals to adhere to a specific standard—for example, a function like calculateRiskScore(address asset, uint256 amount) returns (uint256 score). This ensures compatibility and makes auditing proposed models more straightforward. For production use, you will need to establish clear guidelines in your governance documentation detailing the required data, simulations, and audit reports for a proposal to be considered valid.
The next step is to test the entire workflow end-to-end in a forked mainnet environment using tools like Foundry or Hardhat. Simulate a full governance cycle: a community member submits a proposal, delegates vote, the vote passes, the proposal queues in the timelock, and finally executes. Pay close attention to edge cases, such as proposal cancellation and quorum requirements. Furthermore, analyze the economic security of your governance by stress-testing against vote buying or flash loan attacks, potentially implementing safeguards like a vote delay or minimum voting power.
For ongoing maintenance, establish a transparent process for the community to signal the need for new risk models. This could involve a dedicated forum, regular risk parameter reviews, and incentivized bug bounties for the model submission contract. Remember that governance is iterative; the parameters of your governance system itself (like voting period duration or proposal threshold) should also be upgradeable via proposals. Continuously monitor governance participation and be prepared to adjust incentives to ensure a healthy, decentralized decision-making process.