Finalizing Proposals (TWAPs)

Time-Weighted Average Prices (TWAPs) are the mechanism that converts market activity into governance decisions. Instead of using a single snapshot price — which could be easily manipulated — NovaDAO computes a weighted average over the entire trading period. This page explains how TWAPs work, why they resist manipulation, and how they determine proposal outcomes.

TWAPs Decide Pass or Fail

When a proposal's trading period ends, the DAO contract computes two TWAPs:

  • Pass TWAP: The time-weighted average price of pNOVA (the pass token) over the trading period.
  • Fail TWAP: The time-weighted average price of fNOVA (the fail token) over the trading period.

The decision rule is straightforward: if the Pass TWAP exceeds the Fail TWAP (adjusted for any applicable threshold), the proposal passes. Otherwise, it fails.

Why averages, not spot prices? A spot price reflects a single moment in time. A trader with enough capital could temporarily push the price in either direction right before the deadline. A time-weighted average over days or weeks of trading is orders of magnitude more expensive to manipulate, because the attacker must sustain the distorted price for the entire observation window.

Lagged Price Observations

NovaDAO's TWAP implementation uses lagged observations to further increase manipulation resistance. Here is how it works:

Periodic Sampling

The AMM contract records the current pool price at regular intervals (every slot or on every trade, whichever comes first). Each observation is stored on-chain with its timestamp.

Cumulative Price Tracking

Rather than storing individual price snapshots, the contract maintains a cumulative price sum. The TWAP for any time window is computed as:
TWAP = (cumulative_price_end - cumulative_price_start) / (time_end - time_start)
This approach is gas-efficient and resistant to single-block manipulation.

Lag Window

Observations are lagged — the price recorded at time T reflects the pool state from a previous checkpoint, not the current instant. This means an attacker cannot manipulate the price and have it immediately affect the TWAP. By the time the manipulated price enters the average, arbitrageurs have had time to correct it.

The economics of manipulation: To move a TWAP by 1% over a 7-day window, an attacker would need to sustain a price distortion across the entire period. The constant product AMM means larger distortions require exponentially more capital, and every moment the price is distorted creates a profit opportunity for arbitrageurs to push it back. The cost of manipulation grows with the square of the desired distortion.

The 24-Hour Grace Period

After the main trading period ends, a 24-hour grace period begins before the TWAP is finalized. This grace period serves several purposes:

  • Final corrections: If late-breaking information emerges (e.g., a technical flaw is discovered in the proposal), traders have 24 hours to adjust prices before the decision is locked in.
  • Manipulation detection: If someone attempted to manipulate the price at the end of the trading period, the grace period gives the market time to identify and correct the distortion.
  • Time zone fairness: A 24-hour window ensures that participants in all time zones have an opportunity to react to the final state of the market before the outcome is determined.
Note: Trading continues during the grace period and still contributes to the TWAP. The grace period is not a freeze — it is an extension that provides a buffer against last-minute manipulation or information asymmetry.

Pass Thresholds

The pass/fail decision is not always a simple comparison. NovaDAO applies different thresholds depending on the proposer:

Proposer TypePass ConditionExample
Non-team memberPass TWAP > Fail TWAPIf Pass TWAP = $1.05 and Fail TWAP = $1.03, the proposal passes because $1.05 > $1.03.
Team memberPass TWAP > Fail TWAP + 5%If Pass TWAP = $1.05 and Fail TWAP = $1.03, the adjusted threshold is $1.03 * 1.05 = $1.0815. Since $1.05 < $1.0815, the proposal fails despite the pass market being higher. The market must demonstrate stronger conviction for team-originated proposals.

This mechanism protects against insider self-dealing. A team member proposing their own compensation increase must demonstrate that the market strongly believes the proposal is net positive — not just marginally so.

Complete Proposal Timeline

Here is the full timeline for a typical proposal, from submission to final resolution:

PhaseDurationWhat Happens
PendingVariableProposal is submitted. Proposer and supporters stake NOVA toward the 200,000 NOVA activation threshold. No markets are open.
ActivationInstantThreshold is met. The Conditional Vault is initialized and the AMM creates pass/fail trading pools. Markets open for trading.
Trading Period7 days (default)Traders buy and sell pNOVA and fNOVA. The AMM records price observations for the TWAP calculation. This is the primary price discovery window.
Grace Period24 hoursTrading continues. Final opportunity for price corrections and manipulation detection. TWAP observations continue to accumulate.
FinalizationInstantAnyone can call the finalize function. The DAO contract computes final TWAPs, applies the pass threshold, and marks the proposal as Passed or Failed. If passed, the on-chain action is executed atomically.
RedemptionOpen-endedHolders of the winning conditional token redeem 1:1 for NOVA. Staked tokens are returned to proposer and supporters. There is no deadline for redemption.

Technical Implementation on Stellar

NovaDAO's TWAP oracle is implemented directly in the Futarchy AMM Soroban contract. Here are the key technical details:

On-Chain Price Accumulator

The AMM maintains a cumulative price variable that is updated on every trade. The accumulator stores the sum of price * time_elapsed since the market opened. To compute the TWAP over any interval, the contract simply divides the difference in accumulator values by the time elapsed:

// Pseudo-code for TWAP calculation
let twap = (accumulator_at_end - accumulator_at_start)
         / (timestamp_end - timestamp_start);

Observation Storage

Price observations are stored in contract storage as a series of checkpoints. Each checkpoint records the cumulative price and timestamp. The contract uses Soroban's persistent storage to ensure observations survive across ledger boundaries and cannot be tampered with.

Finalization Call

Finalization is permissionless — any account can call the finalize function after the grace period ends. The function:

  1. Verifies the grace period has elapsed
  2. Computes the Pass TWAP and Fail TWAP from stored observations
  3. Applies the appropriate pass threshold based on proposer type
  4. Updates the proposal state to Passed or Failed
  5. If passed, executes the proposal's on-chain action
  6. Unlocks staked tokens for return to their owners
Gas considerations: On Stellar, the finalization transaction's compute cost is bounded because the TWAP is computed from cumulative accumulators (a constant-time operation) rather than iterating over individual price samples. This keeps the transaction lightweight regardless of how many trades occurred during the market period.

Back to: Governance Overview | Trading Proposals | Creating Proposals