Governance & Voting
The Governance Registry

The Governance Registry

The Registry is the single entry point to æternity governance. It keeps the index of every poll ever registered, and it holds the global delegation map. It does not hold votes (those live on each individual Poll contract), and it does not compute results, which happens off-chain in the governance backend.

One registry per network, deployed once, with no admin entrypoint and no upgrade path.

Addresses

NetworkRegistry address
Mainnetct_ouZib4wT9cNwgRA1pxgA63XEUd8eQRrG8PcePDEYogBc1VYTq
Testnetct_2nritSnqW6zooEL4g2SMW5pf12GUbrNyZ17osTLrap7wXiSSjf

The Superhero app ships these as GOVERNANCE_CONTRACT_ADDRESS. The agent skill's CLI defaults to the mainnet address and accepts an override through the AE_GOVERNANCE_REGISTRY environment variable, which is how you point it at testnet.

State

Registry.state = { polls          : map(int, Registry.poll_data)
                 , seq_id         : int
                 , delegations    : map(address, address)
                 , created_height : int }

Registry.poll_data = { poll         : Poll
                     , is_listed    : bool
                     , title        : string
                     , close_height : option(int) }

poll_data caches the title and close height, which also live on the poll contract, so a client can render a full poll list from one contract call instead of one call per poll, which is what the app and the CLI do.

delegations is a plain address-to-address map, which is why an account can have at most one outgoing delegation and any number of incoming ones. See Delegation.

seq_id is the counter behind poll ids: add_poll assigns the next one, so ids are dense, sequential and permanent. created_height records when the registry was deployed; the governance backend starts scanning for Delegation and RevokeDelegation events from that height when it reconstructs a historic delegation graph.

Entrypoints

EntrypointSignaturePurpose
init()No parameters. The registry is deployed empty.
add_poll(poll: Poll, is_listed: bool) : intRegister a deployed poll; returns its id. Stateful.
polls() : map(int, poll_data)Every poll, listed and unlisted
poll(poll_id: int) : poll_dataOne poll's summary
delegate(delegatee: address)Set or replace your delegation. Stateful.
revoke_delegation()Remove your delegation. Stateful.
delegations() : map(address, address)The complete delegation map
delegatee(account: address) : option(address)Who that account delegates to
delegators(account: address) : map(address, address)Direct delegators to that account
created_height() : intDeployment height
version() : intContract version

The complete list of state-changing entrypoints is add_poll, delegate and revoke_delegation. There is no way to remove a poll, change its is_listed flag, or edit its cached title, and there is no owner, admin, pause or migration hook.

add_poll can be called by any account for any deployed poll, including one the caller did not author, and the caller chooses is_listed. The call reverts if the argument cannot answer title() and close_height(). The same poll can be registered more than once under different ids. A registration is permanent; listing decisions happen in clients.

polls() returns everything, unlisted included, because is_listed is a display hint rather than an access control. See Polls.

Contract versions

Sourceversion()Notes
Registry.aes1Builds with aesophia up to 5.0.0
Registry_Compiler_v6.aes2@compiler >= 6; contract interface Poll and main contract Registry syntax. Builds 6.0.0 through 8.0.0

The two have the same state, entrypoints and events, so the ACI is the same either way. Read version() on the address you are calling if you need to know which build a network runs.

Events

EventFields
AddPollthe poll contract, its id
Delegationdelegator, delegatee
RevokeDelegationdelegator

These three are the registry's whole activity stream. AddPoll lets an indexer discover new polls without re-reading polls(); the delegation events let it maintain the delegation graph incrementally.

Vote and RevokeVote are emitted by each Poll contract, not by the registry, so an indexer subscribes per poll, discovering polls through AddPoll first and then following them individually. See Contract events.

Call it

From the agent skill's CLI, which initialises the registry for you:

node scripts/superhero-governance.mjs list           # Registry.polls(), listed only
node scripts/superhero-governance.mjs list 50 --all  # include unlisted
node scripts/superhero-governance.mjs info-by-id 42  # Registry.poll(42), then the poll itself
node scripts/superhero-governance.mjs delegatee      # Registry.delegatee(you)
node scripts/superhero-governance.mjs delegators     # Registry.delegators(you)

To point any of them at testnet, override both the node and the registry:

export AE_NODE_URL=https://testnet.aeternity.io
export AE_GOVERNANCE_REGISTRY=ct_2nritSnqW6zooEL4g2SMW5pf12GUbrNyZ17osTLrap7wXiSSjf

From your own client, initialise a contract instance against the registry ACI and the address for your network. The agent skill ships the ACI as RegistryWithEventsACI.json; the event variant declared in it is what lets a client decode AddPoll, Delegation and RevokeDelegation without a separate schema.

The governance API

The registry gives you structure; the backend gives you weighted results.

NetworkGovernance API base URL
Mainnethttps://governance-server-mainnet.prd.service.aepps.com/
Testnethttps://governance-server-testnet.prd.service.aepps.com/
EndpointReturns
GET versionBackend version
GET pollOrdering?closed=true,falsePoll ordering with per-poll totals, vote counts and a score
GET pollOverview/:pollAddressFull poll state, per-account stakes at height, per-option stakes
GET votesState/:addressThe same overview shape; the source of the official result
GET delegatedPower/:address?poll=:pollAddressDelegated power and delegation tree, optionally scoped to one poll
GET accountPollVoterAuthor/:addressPolls an account voted in, authored, or was represented in by its delegatee
POST contractEventNudge the backend to re-index, with a topic and an optional poll address

The Superhero app combines the two sources for its poll list: it reads titles from Registry.polls() and ordering, stake totals and vote counts from pollOrdering, then merges them by poll id.

The agent skill's CLI defaults to https://governance-server-mainnet.prd.aepps.com for mainnet, overridable with AE_GOVERNANCE_BACKEND_URL. If one host does not answer, try the other.

Superhero's own backend also indexes governance transactions at /api/governance/votes and /api/governance/delegations. They are useful for history rather than for live results. See Polls.

Related