Skip to main content
FlowGuard governance is composed of two contracts: ProposalCovenant (manages spending proposal lifecycle) and VoteLockCovenant (locks governance tokens as immutable vote commitments).

Proposal Lifecycle

ProposalCovenant Status Codes

StatusValueDescription
PENDING0Awaiting approvals
APPROVED1Quorum reached, waiting for execution timelock
EXECUTED2Proposal carried out, NFT burned
CANCELLED3Withdrawn by M-of-N signers
EXPIRED4Voting deadline passed without quorum

ProposalCovenant NFT State (40 bytes)

[0]:    version
[1]:    status
[2]:    approval_count (uint8)
[3]:    required_approvals (uint8)
[4-8]:  voting_end_timestamp (5 bytes)
[9-13]: execution_timelock (5 bytes)
[14-33]: payout_hash (bytes20)
[34-39]: reserved

Vote Locking

VoteLockCovenant locks governance FTs with an immutable vote choice. The UTXO model on BCH makes double-voting cryptographically impossible: spending the lock UTXO IS the vote cast. The same tokens cannot exist in two places simultaneously.

VoteLockCovenant Parameters

ParameterDescription
proposalIdLinks vote to specific proposal (bytes32)
voteChoiceImmutable: 0=AGAINST, 1=FOR, 2=ABSTAIN
voterHashhash160 of voter pubkey — prevents theft
unlockTimestampWhen tokens can be reclaimed

VoteLockCovenant NFT State (32 bytes)

[0]:    version
[1-4]:  proposal_id_prefix (first 4 bytes of proposalId)
[5]:    vote_choice
[6-7]:  reserved
[8-12]: lock_timestamp (5 bytes)
[13-17]: unlock_timestamp (5 bytes)
[18-31]: reserved

Early Reclaim

After a proposal reaches EXECUTED, CANCELLED, or EXPIRED, voters no longer need to wait for unlockTimestamp. They can call earlyReclaim() and supply the proposalFinalStatus to prove the proposal is done.
Because there is no cross-UTXO read on BCH, the voter must supply proposalFinalStatus as a parameter. The caller is responsible for providing the correct status. The covenant validates it falls within the set .