Skip to content

Actioning and Expiring Initiatives

Board owners have two key functions to manage initiative lifecycle: accepting successful proposals and expiring inactive ones. Both actions are permanent and trigger different outcomes for supporters.

Initiative States

enum InitiativeState {
    Proposed,    // Initial state when created
    Accepted,    // Approved via acceptInitiative
    Cancelled,   // Reserved for future use
    Expired      // Owner expired due to inactivity
}

State Transitions

Valid Transitions

Proposed → Accepted  (via acceptInitiative)
Proposed → Expired   (via expireInitiative)

Invalid Transitions

  • Cannot expire an Accepted initiative
  • Cannot accept an Expired initiative
  • Cannot transition to Cancelled state (reserved for future use)
  • Cannot reverse Accepted or Expired back to Proposed
All state transitions are ONE-WAY and PERMANENT.

Actioning an Initiative

Actioning an initiative means officially approving it, transitioning it from Proposed to Accepted state. This records the acceptance timestamp and makes locked tokens redeemable after any release timelock.

Access Control

Access control is determined by the board's AcceptanceCriteria:

struct AcceptanceCriteria {
    AcceptancePermissions permissions;    // Permissionless or OnlyOwner
    ThresholdOverride thresholdOverride;  // None or OnlyOwner
    uint256 thresholdPercentTotalSupplyWAD;
    uint256 minThreshold;
}

Permission Settings

permissionsthresholdOverrideWho Can AcceptThreshold Check
OnlyOwnerNoneOwner onlyRequired
OnlyOwnerOnlyOwnerOwner onlyOwner bypasses
PermissionlessNoneAnyoneRequired for all
PermissionlessOnlyOwnerAnyoneOwner bypasses, others required

Pre-conditions

  1. Initiative must exist - initiativeId <= initiativeCount
  2. Initiative must be in Proposed state - Cannot accept already Accepted or Expired initiatives
  3. Caller must have permission - Based on permissions setting
  4. Threshold must be met - Unless caller is owner with ThresholdOverride.OnlyOwner

Threshold Calculation

The acceptance threshold is dynamically calculated:

threshold = max(
    totalSupply * thresholdPercentTotalSupplyWAD / 1e18,
    minThreshold
)

At least one of these values must be non-zero.

What Happens When Accepting

When an initiative is accepted:

  1. State changes to Accepted (irreversible)
  2. Acceptance timestamp is recorded (acceptanceTimestamp = block.timestamp)
  3. Supporters can redeem their locked tokens (after release timelock)

Automatic Integrations

Incentives

If an incentives pool is configured, rewards are calculated and paid when supporters redeem their locks after acceptance.

Impact on Token Locks When Accepted

Redemption Timeline

Locked tokens become redeemable based on releaseLockDuration:

Immediate Release (releaseLockDuration = 0): Supporters can redeem immediately.

Timelocked Release: Supporters must wait for acceptanceTimestamp + releaseLockDuration before redeeming.

Board Cancellation: If the board is cancelled via cancelBoard(), the release timelock is bypassed and all locks become immediately redeemable.


Expiring an Initiative

Expiring an initiative terminates an inactive proposal that has failed to gain sufficient support. No additional support can be added, and the initiative is removed from active consideration. Tokens locked in support of an expired initiative can be redeemed immediately.

Access Control

Owner-only - Uses onlyOwner modifier. Only the board owner can expire initiatives.

Pre-conditions

  1. Initiative must exist
  2. Initiative must be in Proposed state - Cannot expire Accepted initiatives
  3. Initiative must be inactive for > inactivityTimeout (default 60 days)
Activity tracking:
  • lastActivity updates when:
    • Initiative is created
    • Any supporter locks tokens
  • Default timeout: 60 days (configurable via board config)

What Happens When Expiring

  1. State changes to Expired
  2. Emits InitiativeExpired event
  3. Supporters can redeem their locked tokens immediately (no waiting period)
  4. No incentive rewards are distributed for expired initiatives

Events

event InitiativeAccepted(uint256 indexed initiativeId, address indexed actor)
event InitiativeExpired(uint256 indexed initiativeId, address indexed actor)