doc.gno
4.80 Kb · 81 lines
1// v0 - Unaudited: This is an initial version that has not yet been formally audited.
2// A fully audited version will be published as a subsequent release.
3// Use in production at your own risk.
4//
5// Package commondao provides governance primitives following the Common
6// DAO Spec (docs/CONSTITUTION.md, Appendix): a CommonDAO is a Council (a
7// set of addresses with equal voting power), a proposal lifecycle decided
8// by the constitution's default voting rules, and an optional sub-DAO
9// tree.
10//
11// Proposal types are registered per DAO: a ProposalKind couples a
12// registry name with a definition factory New(dao ReadonlyCommonDAO,
13// args), and Propose(creator, kind, args) accepts exactly the kinds
14// registered on the DAO. New receives only a readonly view, so it cannot
15// mutate the DAO before the vote; a kind that must mutate state on
16// execution captures its target *CommonDAO from args (populated only by
17// trusted callers) and mutates in its executor. RegisterKind /
18// DeregisterKind / HasKind / KindNames and the WithProposalKind option
19// are the registry primitives; the package ships one concrete kind,
20// ExecutionKind (arbitrary execution), and no governance meta-kinds —
21// managing a DAO's kind set through governance is the consuming realm's
22// job.
23//
24// Proposals snapshot the council as their electorate at creation and
25// are decided the moment the outcome is mathematically settled: with
26// integer math over D = |electorate| - abstains, a supermajority
27// (3*yes >= 2*D) passes, a NO majority (2*no > D) dismisses, and
28// proposals still undecided at their voting deadline are dismissed.
29//
30// A DAO may carry a treasury address and frozen flag; the package only
31// stores them - hosting realms derive the address and move the funds.
32//
33// A *CommonDAO is a mutable handle for the realm that owns it: never
34// accept one from, or return one to, an untrusted realm - readonly views
35// (CommonDAO.Readonly) are the only safe handles to cross a realm
36// boundary. See the package README for details.
37//
38// # Extending commondao in your own realm
39//
40// This package is mostly mechanism: it ships the ExecutionKind concrete kind
41// (with a default voting policy) and the registry primitives, and leaves the
42// rest of governance policy — which kinds a DAO accepts, how it manages them,
43// and any per-kind constraints such as a treasury freeze — to the consuming
44// realm. To add a proposal type of your own:
45//
46// - Author a ProposalKind: a type with Name() string and
47// New(dao ReadonlyCommonDAO, args any) (ProposalDefinition, error). Make
48// the definition Executable (Executor() returns an ExecFunc) if it
49// mutates state on approval. If its executor moves funds from a DAO other
50// than the proposal's host, have the HOST realm consume a Funded-style
51// contract (FundingDAOID() uint64) — minting a DAO sub needs the host's
52// cur, so this contract is host-consumed, not package-dispatched; define
53// it in your realm, as the reference realm does.
54// - Apply your own policy. ExecutionKind runs the closure as-is (no check
55// beyond a non-nil Fn), so if your realm has treasury constraints (e.g. a
56// freeze flag) do NOT catalog ExecutionKind directly: author your own
57// execution kind whose definition wraps the closure with a Validable
58// check (Validate() error) enforcing those constraints, so arbitrary
59// execution cannot bypass them. The reference realm does this so a frozen
60// DAO cannot drain its own treasury through an execution proposal.
61// - Seed it. The owning realm holds the DAO handle, so no proposal is
62// needed: pass commondao.New(WithProposalKind(YourKind{}), …) at
63// construction, or call dao.RegisterKind(YourKind{}) directly.
64// - Author a typed, CLI-friendly wrapper
65// CreateYourProposal(cur realm, daoID uint64, …params…): council-gate the
66// caller, build the args struct, and call Propose. This is the only
67// public entry, so the args-capture trust boundary holds.
68// - Optionally add a runtime governance toggle. If the council should
69// register/deregister kinds by vote (rather than only at construction),
70// author a manage-kinds-style ProposalKind whose executor calls
71// RegisterKind/DeregisterKind, and keep that managing kind itself
72// un-deregisterable so the DAO can always recover.
73//
74// Trust boundary: New receives only a ReadonlyCommonDAO, so a kind — even an
75// externally authored one — cannot mutate the host at Propose time. The
76// mutable *CommonDAO reaches a definition only through args, which your
77// trusted wrapper populates (an external proposer cannot obtain one). On
78// execution the host passes the DAO's terminal, RealmSend-only sub, so a
79// fund-moving executor is bounded to that one DAO address. See the reference
80// realm gno.land/r/nt/commondao/v0 for a full worked example.
81package commondao