types.gno
5.19 Kb ยท 227 lines
1package dao
2
3import (
4 "errors"
5 "std"
6
7 "gno.land/p/demo/avl"
8 "gno.land/p/demo/seqid"
9 "gno.land/p/demo/ufmt"
10)
11
12type ProposalID int64
13
14func (pid ProposalID) String() string {
15 return ufmt.Sprintf("%v", int64(pid))
16}
17
18// VoteOption is the limited voting option for a DAO proposal
19// New govDAOs can create their own VoteOptions if needed in the
20// future.
21type VoteOption string
22
23const (
24 AbstainVote VoteOption = "ABSTAIN" // Side is not chosen
25 YesVote VoteOption = "YES" // Proposal should be accepted
26 NoVote VoteOption = "NO" // Proposal should be rejected
27)
28
29type VoteRequest struct {
30 Option VoteOption
31 ProposalID ProposalID
32 Metadata interface{}
33}
34
35func NewProposalRequest(title string, description string, executor Executor) ProposalRequest {
36 return ProposalRequest{
37 title: title,
38 description: description,
39 executor: executor,
40 }
41}
42
43func NewProposalRequestWithFilter(title string, description string, executor Executor, filter Filter) ProposalRequest {
44 return ProposalRequest{
45 title: title,
46 description: description,
47 executor: executor,
48 filter: filter,
49 }
50}
51
52type Filter interface{}
53
54type ProposalRequest struct {
55 title string
56 description string
57 executor Executor
58 filter Filter
59}
60
61func (p *ProposalRequest) Title() string {
62 return p.title
63}
64
65func (p *ProposalRequest) Description() string {
66 return p.description
67}
68
69func (p *ProposalRequest) Filter() Filter {
70 return p.filter
71}
72
73type Proposal struct {
74 author std.Address
75
76 title string
77 description string
78
79 executor Executor
80 allowedDAOs []string
81}
82
83func (p *Proposal) Author() std.Address {
84 return p.author
85}
86
87func (p *Proposal) Title() string {
88 return p.title
89}
90
91func (p *Proposal) Description() string {
92 return p.description
93}
94
95func (p *Proposal) ExecutorString() string {
96 if p.executor != nil {
97 return p.executor.String()
98 }
99
100 return ""
101}
102
103func (p *Proposal) AllowedDAOs() []string {
104 return p.allowedDAOs
105}
106
107type Proposals struct {
108 seq seqid.ID
109 *avl.Tree // *avl.Tree[ProposalID]*Proposal
110}
111
112func NewProposals() *Proposals {
113 return &Proposals{Tree: avl.NewTree()}
114}
115
116func (ps *Proposals) SetProposal(p *Proposal) ProposalID {
117 pid := ProposalID(int64(ps.seq))
118 updated := ps.Set(pid.String(), p)
119 if updated {
120 panic("fatal error: Override proposals is not allowed")
121 }
122
123 ps.seq = ps.seq.Next()
124
125 return pid
126}
127
128func (ps *Proposals) GetProposal(pid ProposalID) *Proposal {
129 pv, ok := ps.Get(pid.String())
130 if !ok {
131 return nil
132 }
133
134 return pv.(*Proposal)
135}
136
137type Executor interface {
138 Execute() error
139 String() string
140}
141
142func NewSimpleExecutor(callback func() error, description string) *SimpleExecutor {
143 return &SimpleExecutor{
144 callback: callback,
145 desc: description,
146 }
147}
148
149// SimpleExecutor implements the Executor interface using
150// a callback function and a description string.
151type SimpleExecutor struct {
152 callback func() error
153 desc string
154}
155
156func (e *SimpleExecutor) Execute() error {
157 return e.callback()
158}
159
160func (e *SimpleExecutor) String() string {
161 return e.desc
162}
163
164func NewSafeExecutor(e Executor) *SafeExecutor {
165 return &SafeExecutor{
166 e: e,
167 }
168}
169
170// SafeExecutor wraps an Executor to only allow its execution
171// by allowed govDAOs.
172type SafeExecutor struct {
173 e Executor
174}
175
176func (e *SafeExecutor) Execute() error {
177 // Verify the caller is an adequate Realm
178 if !InAllowedDAOs(std.CurrentRealm().PkgPath()) {
179 return errors.New("execution only allowed by validated govDAOs")
180 }
181
182 return e.e.Execute()
183}
184
185func (e *SafeExecutor) String() string {
186 return e.e.String()
187}
188
189type DAO interface {
190 // PreCreateProposal is called just before creating a new Proposal
191 // It is intended to be used to get the std.Address of the proposal, that
192 // may vary depending on the DAO implementation, and to validate that
193 // the requester is allowed to do a proposal
194 PreCreateProposal(r ProposalRequest) (std.Address, error)
195
196 // PostCreateProposal is called after creating the Proposal. It is
197 // intended to be used as a way to store a new proposal status, that
198 // depends on the actuall govDAO implementation
199 PostCreateProposal(r ProposalRequest, pid ProposalID)
200
201 // VoteOnProposal will send a petition to vote for a specific proposal
202 // to the actual govDAO implementation
203 VoteOnProposal(r VoteRequest) error
204
205 // PreGetProposal is called when someone is trying to get a proposal by ID.
206 // Is intended to be used to validate who can query proposals, just in case
207 // the actual govDAO implementation wants to limit the access.
208 PreGetProposal(pid ProposalID) error
209
210 // PostGetProposal is called after the proposal has been obtained. Intended to be
211 // used by govDAO implementations if they need to check Proposal data to know if
212 // the caller is allowed to get that kind of Proposal or not.
213 PostGetProposal(pid ProposalID, p *Proposal) error
214
215 // PreExecuteProposal is called when someone is trying to execute a proposal by ID.
216 // Is intended to be used to validate who can trigger the proposal execution.
217 PreExecuteProposal(pid ProposalID) (bool, error)
218
219 // Render will return a human-readable string in markdown format that
220 // will be used to show new data through the dao proxy entrypoint.
221 Render(pkgpath string, path string) string
222}
223
224type UpdateRequest struct {
225 DAO DAO
226 AllowedDAOs []string
227}