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