actions.gno
3.96 Kb · 138 lines
1package daokit
2
3// Defines executable operations that proposals can perform.
4// Each action has a type and handler functions that implements the actual logic.
5//
6// Example: Adding a member, transferring funds, or updating configuration.
7
8import (
9 "errors"
10
11 "gno.land/p/moul/md"
12 "gno.land/p/nt/ufmt/v0"
13)
14
15// Interface storing Action's data.
16type Action interface {
17 // Returns human-readable description of the action.
18 String() string
19 // Returns unique identifier for the action type.
20 Type() string
21}
22
23// Interface storing executable function that processes Action's data.
24type ActionHandler interface {
25 // Executes the given action's logic. The rlm realm is threaded so
26 // handlers can perform cross-realm calls during execution.
27 Execute(action Action, rlm realm)
28 // Returns the action type this handler processes.
29 Type() string
30}
31
32// Generic action implementation that stores a type and a payload.
33// Payload contains the data parameters that will be processed by the handler.
34// Example: {kind="/p/demo/transfer.Transfer", payload={amount: 1000, recipient: "user123"}}
35type genericAction struct {
36 kind string
37 payload interface{}
38}
39
40// Generic action handler that executes a function with a given payload.
41// Example: A transfer handler that processes {amount, recipient} to move funds.
42// {kind="transfer", executor=transferFunds}
43type genericActionHandler struct {
44 kind string
45 executor func(payload interface{}, rlm realm)
46}
47
48func NewAction(kind string, payload interface{}) Action {
49 return &genericAction{kind: kind, payload: payload}
50}
51
52// Returns string representation of the action's payload.
53func (g *genericAction) String() string {
54 return ufmt.Sprintf("%v", g.payload)
55}
56
57// Returns the action's type identifier.
58func (g *genericAction) Type() string {
59 return g.kind
60}
61
62func NewActionHandler(kind string, executor func(interface{}, realm)) ActionHandler {
63 return &genericActionHandler{kind: kind, executor: executor}
64}
65
66// Executes the action by calling the executor function with the payload.
67func (g *genericActionHandler) Execute(iaction Action, rlm realm) {
68 action, ok := iaction.(*genericAction)
69 if !ok {
70 panic(errors.New("invalid action type"))
71 }
72 g.executor(action.payload, rlm)
73}
74
75// Returns the action's type identifier.
76func (g *genericActionHandler) Type() string {
77 return g.kind
78}
79
80// Creates a new empty action instance.
81func (g *genericActionHandler) Instantiate() Action {
82 return &genericAction{
83 kind: g.kind,
84 }
85}
86
87// //////////////////////////////////////////////////////////
88// ActionExecuteLambdaKind
89//
90// Built-in action type for executing lambda functions.
91const ActionExecuteLambdaKind = "gno.land/p/samcrew/daokit.ExecuteLambda"
92
93func NewExecuteLambdaHandler() ActionHandler {
94 return NewActionHandler(ActionExecuteLambdaKind, func(i interface{}, _ realm) {
95 cb, ok := i.(func())
96 if !ok {
97 panic(errors.New("invalid action type"))
98 }
99 cb()
100 })
101}
102
103func NewExecuteLambdaAction(cb func()) Action {
104 return NewAction(ActionExecuteLambdaKind, cb)
105}
106
107// //////////////////////////////////////////////////////////
108// ActionInstantExecuteKind
109//
110// Built-in action type for instantly executing sub-proposals.
111const ActionInstantExecuteKind = "gno.land/p/samcrew/daokit.InstantExecute"
112
113type actionInstantExecute struct {
114 dao DAO // Target DAO to execute on
115 req ProposalRequest // Proposal to execute instantly
116}
117
118func (a *actionInstantExecute) String() string {
119 // XXX: find a way to be explicit about the subdao
120 s := ""
121 s += md.Paragraph(md.Blockquote(a.req.Action.Type()))
122 s += md.Paragraph(a.req.Action.String())
123 return s
124}
125
126func NewInstantExecuteHandler() ActionHandler {
127 return NewActionHandler(ActionInstantExecuteKind, func(i interface{}, rlm realm) {
128 action, ok := i.(*actionInstantExecute)
129 if !ok {
130 panic(errors.New("invalid action type"))
131 }
132 InstantExecute(action.dao, action.req, rlm)
133 })
134}
135
136func NewInstantExecuteAction(dao DAO, req ProposalRequest) Action {
137 return NewAction(ActionInstantExecuteKind, &actionInstantExecute{dao: dao, req: req})
138}