Kind Realm (renderable)
Name v0
Namespace gov / dao / memberstore
Exported functions 10
Module gno.land/r/gov/dao/memberstore/v0
gno 0.9 gno
memberstore.gno gno
⧉
1 package memberstore 2 3 import ( 4 "strings" 5 6 "gno.land/p/moul/md/v0" 7 "gno.land/p/nt/bptree/v0" 8 Get (int, rlm interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}) struct{BPTree *gno.land/p/nt/bptree/v0.BPTree}
GetTier (name string) (struct{BasePower float64; InvitationPoints int; MaxSize func(gno.land/r/gov/dao/memberstore/v0.MembersByTier, gno.land/r/gov/dao/memberstore/v0.TiersByName) int; MinSize func(gno.land/r/gov/dao/memberstore/v0.MembersByTier, gno.land/r/gov/dao/memberstore/v0.TiersByName) int; PowerHandler func(gno.land/r/gov/dao/memberstore/v0.MembersByTier, gno.land/r/gov/dao/memberstore/v0.TiersByName) float64}, bool)
GetTierPower (tierName string, members struct{BPTree *gno.land/p/nt/bptree/v0.BPTree}) float64
IterateTiers (fn func(string, gno.land/r/gov/dao/memberstore/v0.Tier) bool)
NewChangeTiersRequest (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, tiers map[string]gno.land/r/gov/dao/memberstore/v0.Tier) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}
NewMember (invitationPoints int) *gno.land/r/gov/dao/memberstore/v0.Member
NewMembersByTier () struct{BPTree *gno.land/p/nt/bptree/v0.BPTree}
Render (path string) string
RenderCharts (members struct{BPTree *gno.land/p/nt/bptree/v0.BPTree}) string
RenderMembers (path string, members struct{BPTree *gno.land/p/nt/bptree/v0.BPTree}) string
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.
"gno.land/p/nt/mux/v0"
9 "gno.land/p/nt/svg/v0"
10 "gno.land/p/nt/ufmt/v0"
11 "gno.land/r/gov/dao"
12 )
13
14 var (
15 members MembersByTier
16 tiers TiersByName // private to prevent external modification
17 router *mux.Router
18 )
19
20 const (
21 T1 = "T1"
22 T2 = "T2"
23 T3 = "T3"
24 )
25
26 func init() {
27 members = NewMembersByTier()
28
29 tiers = TiersByName{bptree.NewBPTree32()}
30 tiers.Set(T1, Tier{
31 InvitationPoints: 3 ,
32 MinSize: func (membersByTier MembersByTier, tiersByName TiersByName) int {
33 return 70
34 },
35 MaxSize: func (membersByTier MembersByTier, tiersByName TiersByName) int {
36 return 0
37 },
38 BasePower: 3 ,
39 PowerHandler: func (membersByTier MembersByTier, tiersByName TiersByName) float64 {
40 return 3
41 },
42 })
43
44 tiers.Set(T2, Tier{
45 InvitationPoints: 2 ,
46 MaxSize: func (membersByTier MembersByTier, tiersByName TiersByName) int {
47 return membersByTier.GetTierSize(T1) * 2
48 },
49 MinSize: func (membersByTier MembersByTier, tiersByName TiersByName) int {
50 return membersByTier.GetTierSize(T1) / 4
51 },
52 BasePower: 2 ,
53 PowerHandler: func (membersByTier MembersByTier, tiersByName TiersByName) float64 {
54 t1ms := float64 (membersByTier.GetTierSize(T1))
55 t1, _ := tiersByName.GetTier(T1)
56 t2ms := float64 (membersByTier.GetTierSize(T2))
57 t2, _ := tiersByName.GetTier(T2)
58
59 t1p := t1.BasePower * t1ms
60 t2p := t2.BasePower * t2ms
61
62 // capped to 2/3 of tier 1
63 t1ptreshold := t1p * ( 2.0 / 3.0 )
64 if t2p > t1ptreshold {
65 return t1ptreshold / t2ms
66 }
67
68 return t2.BasePower
69 },
70 })
71
72 tiers.Set(T3, Tier{
73 InvitationPoints: 1 ,
74 MaxSize: func (membersByTier MembersByTier, tiersByName TiersByName) int {
75 return 0
76 },
77 MinSize: func (membersByTier MembersByTier, tiersByName TiersByName) int {
78 return 0
79 },
80 BasePower: 1 ,
81 PowerHandler: func (membersByTier MembersByTier, tiersByName TiersByName) float64 {
82 t1ms := float64 (membersByTier.GetTierSize(T1))
83 t1, _ := tiersByName.GetTier(T1)
84 t3ms := float64 (membersByTier.GetTierSize(T3))
85 t3, _ := tiersByName.GetTier(T3)
86
87 t1p := t1.BasePower * t1ms
88 t3p := t3.BasePower * t3ms
89
90 // capped to 1/3 of tier 1
91 t1ptreshold := t1p * ( 1.0 / 3.0 )
92 if t3p > t1ptreshold {
93 return t1ptreshold / t3ms
94 }
95
96 return t3.BasePower
97 },
98 })
99
100 initRouter()
101 }
102
103 // initRouter initializes the router for the memberstore.
104 func initRouter() {
105 router = mux.NewRouter()
106 router.HandleFunc( "" , renderHome)
107 router.HandleFunc( "members" , renderMembers)
108 router.NotFoundHandler = renderNotFound
109 }
110
111 // renderHome displays the tiers data (Number of members and powers) and tiers charts.
112 func renderHome(res *mux.ResponseWriter, req *mux.Request) {
113 var sb strings.Builder
114 sb.WriteString(md.Link( "> Go to Members list <" , "/r/gov/dao/memberstore/v0:members" ) + "\n" )
115
116 members.Iterate( "" , "" , func (tn string , ti interface {}) bool {
117 tree, ok := ti.(*bptree.BPTree)
118 if !ok {
119 return false
120 }
121
122 tier, ok := tiers.GetTier(tn)
123 if !ok {
124 return false
125 }
126
127 tp := (tier.PowerHandler(members, tiers) * float64 (members.GetTierSize(tn)))
128
129 sb.WriteString(ufmt.Sprintf( "- %v Tier %v contains %v members with power: %v\n" , tierColoredChip(tn), tn, tree.Size(), tp))
130
131 return false
132 })
133
134 sb.WriteString( "\n" + RenderCharts(members))
135 res.Write(sb.String())
136 }
137
138 // renderMembers displays the members list.
139 func renderMembers(res *mux.ResponseWriter, req *mux.Request) {
140 path := strings.Replace(req.RawPath, "members" , "" , 1 ) // We have to clean the path
141 res.Write(RenderMembers(path, members))
142 }
143
144 func renderNotFound(res *mux.ResponseWriter, req *mux.Request) {
145 res.Write( "# 404\n\nThat page was not found. Would you like to [**go home**?](/r/gov/dao/memberstore/v0)" )
146 }
147
148 func tierColor(tn string ) string {
149 switch tn {
150 case T1:
151 return "#329175"
152 case T2:
153 return "#21577A"
154 case T3:
155 return "#F3D3BC"
156 default :
157 return "#FFF"
158 }
159 }
160
161 // tierColoredChip returns a colored chip svg for the given tier name.
162 func tierColoredChip(tn string ) string {
163 canvas := svg.NewCanvas( 16 , 16 )
164 canvas.Append(svg.NewRectangle( 0 , 0 , 16 , 16 , tierColor(tn)))
165 return canvas.Render(tn + " colored chip" )
166 }
167
168 func Render(path string ) string {
169 var sb strings.Builder
170 sb.WriteString(md.H1( "Memberstore Govdao v0" ))
171 sb.WriteString(router.Render(path))
172 return sb.String()
173 }
174
175 // Get gets the Members store.
176 //
177 // rlm is the cur of an in-scope crossing frame, threaded by the caller.
178 // The IsCurrent() check rejects stale or stashed realm values — a
179 // malicious realm cannot replay an old cur to claim allowed-DAO
180 // identity. After the check, rlm.PkgPath() is the authentic immediate
181 // caller's realm.
182 func Get(_ int , rlm realm) MembersByTier {
183 if !rlm.IsCurrent() {
184 panic( "memberstore.Get: rlm is not the caller's live cur (stale capture or sibling frame)" )
185 }
186 currealm := rlm.PkgPath()
187 if !dao.InAllowedDAOs(currealm) {
188 panic( "this Realm is not allowed to get the Members data: " + currealm)
189 }
190
191 return members
192 }
193
194 // GetTier returns a tier by name. This is a read-only accessor.
195 func GetTier(name string ) (Tier, bool ) {
196 return tiers.GetTier(name)
197 }
198
199 // IterateTiers iterates over all tiers in order. This is a read-only accessor.
200 // The callback receives the tier name and tier data.
201 // Return true from the callback to stop iteration.
202 func IterateTiers(fn func (name string , tier Tier) bool ) {
203 tiers.Iterate( "" , "" , func (name string , value interface {}) bool {
204 tier, ok := value.(Tier)
205 if !ok {
206 return false
207 }
208 return fn(name, tier)
209 })
210 }
211
212 // setTiers replaces the tiers configuration.
213 // This is internal and should only be called via governance proposal execution.
214 func setTiers(newTiers TiersByName) {
215 tiers = newTiers
216 }
217
218 // GetTierPower calculates the effective voting power for a tier given the current members.
219 // This is a safe accessor that uses the internal tiers configuration.
220 func GetTierPower(tierName string , members MembersByTier) float64 {
221 tier, ok := tiers.GetTier(tierName)
222 if !ok {
223 return 0
224 }
225 return tier.PowerHandler(members, tiers)
226 }
227