execution_kind.gno
2.92 Kb · 73 lines
1package commondao
2
3import (
4 "errors"
5 "time"
6)
7
8// executionKindName is the name of the arbitrary-execution kind.
9const executionKindName = "execution"
10
11var ErrExecutionFuncRequired = errors.New("execution proposal requires a non-nil Fn")
12
13// defaultExecutionVotingPeriod is the voting period of execution proposals.
14const defaultExecutionVotingPeriod = 7 * 24 * time.Hour
15
16// ExecutionArgs are the args for the execution kind (ExecutionKind): a
17// title, a body, and the ExecFunc to run on approval. The closure must be
18// authored in a persistent realm so it survives Propose→Execute; a
19// closure created by a `maketx run` script does not persist and cannot be
20// executed later.
21type ExecutionArgs struct {
22 Title string
23 Body string
24 Fn ExecFunc
25}
26
27// ExecutionKind is the package's one concrete proposal kind: a stateless,
28// reusable arbitrary-execution kind that runs an ExecFunc supplied by the
29// proposer on approval. It is /p/-typed so any realm can register it with
30// WithProposalKind(ExecutionKind{}) or RegisterKind without defining its
31// own execution kind.
32//
33// The executor moves value only through the DAO-scoped sub the host
34// passes (see ExecFunc): the host mints and passes that sub, so the
35// executor receives whichever DAO's sub the host decides (its own DAO's by
36// default). The closure is frozen at Propose (vote-integrity: the exact
37// code is fixed before the vote).
38//
39// This kind applies NO policy check to the closure beyond a non-nil Fn: it
40// runs the arbitrary code as-is. A realm that has treasury constraints (e.g.
41// a freeze flag) should NOT catalog this kind directly; instead it should
42// author its own execution kind whose definition wraps the closure with a
43// Validable check that enforces those constraints (blocking execution while
44// frozen, etc.), so arbitrary execution cannot bypass them. The reference
45// realm gno.land/r/nt/commondao/v0 does exactly this.
46type ExecutionKind struct{}
47
48// Name returns the execution kind's registry name.
49func (ExecutionKind) Name() string { return executionKindName }
50
51// New validates ExecutionArgs and builds an execution definition. It is a
52// pure factory: it receives only a readonly view and captures no mutable
53// handle.
54func (ExecutionKind) New(_ ReadonlyCommonDAO, args any) (ProposalDefinition, error) {
55 a, ok := args.(ExecutionArgs)
56 if !ok || a.Fn == nil {
57 return nil, ErrExecutionFuncRequired
58 }
59 return executionDef{title: a.Title, body: a.Body, fn: a.Fn}, nil
60}
61
62// executionDef is the definition produced by ExecutionKind.
63type executionDef struct {
64 title string
65 body string
66 fn ExecFunc
67}
68
69func (d executionDef) Title() string { return d.title }
70func (d executionDef) Body() string { return d.body }
71func (executionDef) VotingPeriod() time.Duration { return defaultExecutionVotingPeriod }
72func (executionDef) Threshold() Threshold { return ThresholdSupermajority }
73func (d executionDef) Executor() ExecFunc { return d.fn }