types.gno
5.39 Kb ยท 233 lines
1package dao
2
3import (
4 "chain/runtime"
5 "errors"
6
7 "gno.land/p/nt/avl"
8 "gno.land/p/nt/seqid"
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) AllowedDAOs() []string {
103 return append([]string(nil), p.allowedDAOs...)
104}
105
106type Proposals struct {
107 seq seqid.ID
108 *avl.Tree // *avl.Tree[ProposalID]*Proposal
109}
110
111func NewProposals() *Proposals {
112 return &Proposals{Tree: avl.NewTree()}
113}
114
115func (ps *Proposals) SetProposal(p *Proposal) ProposalID {
116 pid := ProposalID(int64(ps.seq))
117 updated := ps.Set(pid.String(), p)
118 if updated {
119 panic("fatal error: Override proposals is not allowed")
120 }
121 ps.seq = ps.seq.Next()
122 return pid
123}
124
125func (ps *Proposals) GetProposal(pid ProposalID) *Proposal {
126 pv, ok := ps.Get(pid.String())
127 if !ok {
128 return nil
129 }
130
131 return pv.(*Proposal)
132}
133
134type Executor interface {
135 Execute(cur realm) error
136 String() string
137}
138
139func NewSimpleExecutor(callback func(realm) error, description string) *SimpleExecutor {
140 if callback == nil {
141 panic("executor callback must not be nil")
142 }
143
144 return &SimpleExecutor{
145 callback: callback,
146 desc: description,
147 }
148}
149
150// SimpleExecutor implements the Executor interface using
151// a callback function and a description string.
152type SimpleExecutor struct {
153 callback func(realm) error
154 desc string
155}
156
157func (e *SimpleExecutor) Execute(cur realm) error {
158 // Check if executor was created using the constructor func
159 if e.callback == nil {
160 return nil
161 }
162
163 return e.callback(cross)
164}
165
166func (e *SimpleExecutor) String() string {
167 return e.desc
168}
169
170func NewSafeExecutor(e Executor) *SafeExecutor {
171 return &SafeExecutor{
172 e: e,
173 }
174}
175
176// SafeExecutor wraps an Executor to only allow its execution
177// by allowed govDAOs.
178type SafeExecutor struct {
179 e Executor
180}
181
182func (e *SafeExecutor) Execute(cur realm) error {
183 // Verify the caller is an adequate Realm
184 if !InAllowedDAOs(runtime.PreviousRealm().PkgPath()) {
185 return errors.New("execution only allowed by validated govDAOs")
186 }
187
188 return e.e.Execute(cross)
189}
190
191func (e *SafeExecutor) String() string {
192 return e.e.String()
193}
194
195type DAO interface {
196 // PreCreateProposal is called just before creating a new Proposal
197 // It is intended to be used to get the address of the proposal, that
198 // may vary depending on the DAO implementation, and to validate that
199 // the requester is allowed to do a proposal
200 PreCreateProposal(r ProposalRequest) (address, error)
201
202 // PostCreateProposal is called after creating the Proposal. It is
203 // intended to be used as a way to store a new proposal status, that
204 // depends on the actuall govDAO implementation
205 PostCreateProposal(r ProposalRequest, pid ProposalID)
206
207 // VoteOnProposal will send a petition to vote for a specific proposal
208 // to the actual govDAO implementation
209 VoteOnProposal(r VoteRequest) error
210
211 // PreGetProposal is called when someone is trying to get a proposal by ID.
212 // Is intended to be used to validate who can query proposals, just in case
213 // the actual govDAO implementation wants to limit the access.
214 PreGetProposal(pid ProposalID) error
215
216 // PostGetProposal is called after the proposal has been obtained. Intended to be
217 // used by govDAO implementations if they need to check Proposal data to know if
218 // the caller is allowed to get that kind of Proposal or not.
219 PostGetProposal(pid ProposalID, p *Proposal) error
220
221 // PreExecuteProposal is called when someone is trying to execute a proposal by ID.
222 // Is intended to be used to validate who can trigger the proposal execution.
223 PreExecuteProposal(pid ProposalID) (bool, error)
224
225 // Render will return a human-readable string in markdown format that
226 // will be used to show new data through the dao proxy entrypoint.
227 Render(pkgpath string, path string) string
228}
229
230type UpdateRequest struct {
231 DAO DAO
232 AllowedDAOs []string
233}