Pre-launch. The protocol is not publicly live yet. This documentation describes the contracts as implemented; deployed addresses are published at launch.

CTOVoteTemplate

Voting logic for a single Community Takeover. Cloned per vote by the hook or graduation manager, initialized atomically in the same transaction.

Contract Type

Minimal proxy (EIP-1167). One instance per vote attempt. Holds voters' deposited tokens until voting closes. No owner.

Voting

vote(amount: uint256, support: bool) external

Cast a vote by depositing tokens. Requires prior approve() to this contract. One position per address — you cannot vote twice or on both sides.

Reverts
  • "Not initialized"
  • "Voting ended" / "Vote period expired"
  • "Amount must be > 0"
  • "Already voted" — use add_votes
  • "Transfer failed"
Emits

VoteCast(voter, amount, support)

add_votes(amount: uint256) external

Add tokens to an existing position, in the same direction as your original vote. Does not increment the distinct-voter count.

Reverts
  • "Must vote first", plus the same state checks as vote

Vote Lifecycle

end_vote() external

Close voting after the full duration. Anyone can call. Computes the outcome once and stores it in vote_passed; also records voting_ended_block.

The quorum denominator is read live during voting — buying to win is legitimate — but once closed the result must not be re-litigated by later balance changes, so it is frozen here.

Reverts
  • "Not initialized", "Already ended", "Vote still active"
Emits

VoteEnded(yes_votes, no_votes, passed)

end_vote_early() external

Close voting before the full duration when quorum and majority already hold. Anyone can call. Available only after 3,600 s (1 hour) of the vote being open.

Reverts
  • "Too early to end early"
  • "Quorum not met"
  • "Majority not achieved"
finalize() external

Execute a passed vote — calls back into the hook to transfer the deployer role to the initiator. Anyone can call. Reads the stored outcome rather than re-checking live state.

Reverts
  • "Vote not ended"
  • "Already finalized"
  • "Vote did not pass"
Emits

VoteFinalized(new_deployer)

withdraw_tokens() external

Reclaim deposited tokens after voting closes, regardless of outcome. Locked until a block strictly after voting_ended_block, so a flash-funded buy → vote → end → withdraw → repay cannot complete in one transaction.

Reverts
  • "Vote not ended"
  • "Withdraw next block"
  • "No tokens to withdraw"
Emits

TokensWithdrawn(voter, amount)

Initialization

initialize(_token: address, _hook_address: address, _initiator: address) external

Hook only — the hook clones and initializes atomically. Reads the stake already transferred in and registers it as the initiator's YES vote, making them voter number one.

Reverts
  • "Already initialized"
  • "Only hook"
  • "Invalid token" / "Invalid hook" / "Invalid initiator"
  • "Initiator needs 5% of supply"
Emits

CTOInitialized(token, initiator, initiator_stake) and VoteCast(initiator, stake, True)

View Functions

FunctionReturns
is_takeover_successful() -> boolLive standing while open; the frozen outcome once closed
get_vote_stats()(yes, no, total, circulating, passing)
get_circulating_supply() -> uint256Total supply minus LP-custodied minus burned
get_yes_quorum_percentage() -> uint256YES as a percentage of circulating — the quorum metric
get_participation_percentage() -> uint256All votes as a percentage of circulating
get_yes_percentage() -> uint256YES as a percentage of votes cast
get_voter_info(voter)(balance, choice, has_voted)
time_remaining() -> uint256Seconds until vote_end, or 0
voter_count() -> uint256Distinct accounts that have voted
yes_votes() / no_votes()Weighted tallies
voting_ended() / vote_passed() / vote_finalized()Lifecycle flags
voting_ended_block() -> uint256Block voting closed — the withdrawal gate
quorum_percentage() / vote_duration()Constants
Weighted tally vs stored balance

yes_votes and no_votes are weighted — the incumbent deployer's stake counts 2×. voter_balances always stores the real deposited amount, so withdrawals are unaffected. Do not use the tallies to compute what a voter can withdraw.

Constants

ConstantValue
QUORUM_PERCENTAGE40% YES of circulating
MIN_VOTERS10
VOTE_DURATION259,200 s (3 days)
MIN_EARLY_END_DELAY3,600 s (1 hour)
DEPLOYER_VOTE_MULTIPLIER
Majority ruleYES ≥ 1.1 × NO
TOTAL_SUPPLY1,200,000,000 × 10⁹ (1.2B)
INITIATOR_THRESHOLD60,000,000 × 10⁹ (60M, 5% of supply)
LP_CUSTODIANPer chain — the contract that custodies pooled tokens. Resolved via the V3 factory on Gnosis.