On-Chain Governance: Propose and Vote
Tenzro's GovernanceEngine is stake-weighted and deposit-gated. Any address can create a proposal by posting a 10,000 TNZO deposit, voting weight comes from direct TNZO stake plus inbound delegations, and a proposal passes once it meets quorum (20% participation, 50% approval, 1,000 TNZO minimum). This tutorial walks the full lifecycle.
What You'll Build
- A parameter-change proposal with a 7-day voting period
- Voting power lookup against the on-chain StakingManager
- Casting For / Against / Abstain votes
- Delegating voting power to another address
Proposal Types
Supported proposal types
parameter_change — tune on-chain parameters; requires `parameter` and `new_value` fields
treasury_grant — spend from NetworkTreasury; requires `grant_amount` field
protocol_upgrade — schedule a binary upgrade; requires `version` and 32-byte `code_hash` (SHA-256 hex)
text — non-binding signalling vote (default if proposal_type omitted)Tally Rules
Tally rules (GovernanceEngine defaults — QuorumRequirements)
minimum_participation = 20% of total stake-weighted supply
minimum_approval = 50% of (votes_for + votes_against)
minimum_votes = 1000 TNZO absolute floor
proposer_stake (CLI minimum) = 10,000 TNZO
When the voting period ends and the tally meets all three thresholds,
the proposal transitions to Passed. ParameterChange / TreasuryGrant /
ProtocolUpgrade payloads are recorded on the proposal; node operators
and downstream subsystems consume them — there is no public
"executeProposal" RPC.
Sources of voting weight on a vote:
* direct TNZO stake via StakingManager.get_stake(voter)
* delegations received from other addresses (recorded via
tenzro_delegateVotingPower)Step 1: Create a Proposal
tenzro_createProposal({
"title": "Raise network fee from 0.5% to 0.75%",
"description": "Rationale: validator yield has compressed below target...",
"proposer": "0xabc123...", // Ed25519 address (proposer)
"proposal_type": "parameter_change", // parameter_change | treasury_grant | protocol_upgrade | text
"parameter": "settlement.network_fee_bps",
"new_value": "75",
"voting_duration_ms": 604800000, // 7 days
"proposer_stake": 10000 // TNZO deposit
})
-> {
proposal_id: "prop-01HR...",
title: "Raise network fee from 0.5% to 0.75%",
description: "Rationale...",
proposer: "0xabc123...",
status: "Active"
}Step 2: List Proposals
tenzro_listProposals({})
-> [
{
proposal_id: "prop-01HR...",
title: "Raise network fee from 0.5% to 0.75%",
type: "parameter_change",
status: "Active", // Pending | Active | Passed | Rejected | Executed | Expired
proposer: "0xabc123...",
votes_for: "4521000",
votes_against: "1803000",
ends_at: "2026-04-27T12:00:00Z"
}
]Step 3: Check Voting Power
tenzro_getVotingPower({
"address": "0xabc123..." // Ed25519 address
})
-> {
address: "0xabc123...",
voting_power: "152340500000000000000000" // raw u128 wei (TNZO * 1e18)
}
# Voting power is read from the StakingManager — sum of bonded TNZO stake
# at the queried address. Delegated voting power (set via
# tenzro_delegateVotingPower) is accounted for during tally inside the
# GovernanceEngine.Step 4: Cast a Vote
Each address gets one vote per proposal as long as it's still Active. Voting power is captured from your stake at the time the vote is cast:
tenzro_vote({
"proposal_id": "prop-01HR...",
"voter": "0xabc123...", // Ed25519 address
"vote": "For" // For | Against | Abstain
})
-> {
success: true,
proposal_id: "prop-01HR...",
voter: "0xabc123...",
voting_power: "152340500000000000000000"
}
# Alias: tenzro_voteOnProposal accepts the same params.Step 5: Delegate (Optional)
If you don't want to vote directly, delegate to a trusted address. The delegatee's effective voting power on subsequent votes increases by the delegated amount:
tenzro_delegateVotingPower({
"delegator": "0xabc123...", // your address
"delegatee": "0xdef456...", // who receives the delegation
"voting_power": "100000000000000000000000" // u128 wei (100,000 TNZO)
})
-> { success: true, delegator: "0xabc123...", delegatee: "0xdef456..." }Step 6: CLI
# Create a proposal (default deposit 10,000 TNZO, 14-day voting period)
tenzro governance propose \
"Raise network fee from 0.5% to 0.75%" \
"Rationale: validator yield has compressed below target..." \
--type parameter_change \
--duration-days 7 \
--deposit 10000
# List all proposals (table view)
tenzro governance list
# List with details
tenzro governance list --detailed
# Vote on a proposal (yes / no / abstain)
tenzro governance vote prop-01HR... yes --reason "Restores validator yield."
# Vote (alias)
tenzro governance vote-on prop-01HR... noStep 7: TypeScript SDK
import { TenzroClient } from "@tenzro/sdk";
const client = new TenzroClient();
// 1. Check voting power before casting
const power = await client.governance.getVotingPower({
address: "0xabc123...",
});
console.log("voting power (wei):", power.voting_power);
// 2. Walk all proposals
const proposals = await client.governance.listProposals({});
for (const p of proposals) {
console.log(`[${p.proposal_id}] ${p.title} — for ${p.votes_for} / against ${p.votes_against} (${p.status})`);
}
// 3. Vote
await client.governance.vote({
proposal_id: proposals[0].proposal_id,
voter: "0xabc123...",
vote: "For",
});
// 4. Delegate voting power to a trusted address
await client.governance.delegateVotingPower({
delegator: "0xabc123...",
delegatee: "0xdef456...",
voting_power: "100000000000000000000000", // 100,000 TNZO in wei
});What happens after a proposal passes? The GovernanceEngine records the proposal's Passed status and persists the typed payload (parameter name + new value, treasury recipient + amount, protocol version + code hash). Parameter and treasury changes are picked up by the relevant subsystem the next time it reads its config; protocol upgrades coordinate node restarts via the code_hash. Tally and status transitions are observable via tenzro_listProposals.
What You Learned
- Proposal lifecycle — Pending → Active → Passed/Rejected → Executed/Expired
- Voting weight — direct stake plus inbound delegations
- Tally thresholds — 20% participation, 50% approval, 1,000 TNZO floor
- RPC surface —
tenzro_createProposal,tenzro_listProposals,tenzro_vote,tenzro_voteOnProposal,tenzro_getVotingPower,tenzro_delegateVotingPower
Next Steps
- See the Staking TNZO tutorial — bonded stake is voting power
- See the Validator Node tutorial to stake directly
- Read the Tokenomics reference