utils.gno
4.83 Kb · 124 lines
1package custom_condition
2
3import (
4 "strings"
5 "unicode"
6
7 "gno.land/p/mason/md"
8 "gno.land/p/moul/txlink"
9 "gno.land/p/nt/ufmt/v0"
10 "gno.land/p/samcrew/basedao"
11 "gno.land/p/samcrew/daokit"
12)
13
14// initDemoProposals creates initial proposals to demonstrate custom condition functionality
15func initDemoProposals() {
16 demoProposals := []struct {
17 address string
18 roles []string
19 proposer string
20 title string
21 desc string
22 }{
23 {
24 "g1demomember001234567890abcdefghijklmnopqr1",
25 []string{},
26 "g1demo1234567890abcdefghijklmnopqrstuvwxy2",
27 "Add Alice as member with no role",
28 "This proposal will add Alice to our DAO without roles.",
29 },
30 {
31 "g1demomember001234567890abcdefghijklmnopqr2",
32 []string{"Role"},
33 "g1demo1234567890abcdefghijklmnopqrstuvwxy3",
34 "Add Bob as member with Role",
35 "This proposal will add Bob to our DAO with the 'Role' role.",
36 },
37 {
38 "g1demomember001234567890abcdefghijklmnopqr3",
39 []string{},
40 "g1demo1234567890abcdefghijklmnopqrstuvwxy2",
41 "Add Charlie as member with no role",
42 "This proposal will add Charlie to our DAO without roles.",
43 },
44 }
45
46 for _, prop := range demoProposals {
47 action := basedao.NewAddMemberAction(&basedao.ActionAddMember{
48 Address: address(prop.address),
49 Roles: prop.roles,
50 })
51
52 req := daokit.ProposalRequest{
53 Title: prop.title,
54 Description: prop.desc,
55 Action: action,
56 }
57 daoPrivate.Core.Propose(prop.proposer, req)
58 }
59}
60
61// Bypass limitation by adding yourself to the DAO.
62// It is necessary to be part of the DAO to create a Proposal.
63func AddMember(cur realm) {
64 // Safe here only because cur is THIS realm's own, minted by this crossing
65 // function. CallerID is not the entry-point gate: copied somewhere that
66 // passes a realm it received from elsewhere, this becomes the donation bug
67 // the DAO entry points exist to refuse. If you need the gate, go through
68 // Propose/Vote/Execute.
69 id := daoPrivate.CallerID(daoPrivate, cur)
70 daoPrivate.Members.AddMember(id, make([]string, 0))
71}
72
73// Creates a Proposal to add a new member to the DAO with specified roles.
74// This function exist to let users try the userflow of daokit with a simple MsgCall (maketx call) instead of a MsgRun.
75// See why a run is necessary for creating a proposal -> https://docs.gno.land/users/interact-with-gnokey#run.
76// Parameters:
77// - address: The std.Address of the member to be added
78// - roles: Comma-separated string of roles to assign to the member (e.g., "admin,moderator" or "voter")
79func ProposeAddMember(cur realm, address address, roles string) {
80 rs := strings.Split(roles, ",")
81 for i, s := range rs {
82 rs[i] = strings.TrimFunc(s, unicode.IsSpace)
83 }
84
85 payload := basedao.ActionAddMember{
86 Address: address,
87 Roles: rs,
88 }
89 action := basedao.NewAddMemberAction(&payload)
90
91 proposal := daokit.ProposalRequest{
92 Title: ufmt.Sprintf("Add member %s with roles %s", address, strings.Join(rs, ", ")),
93 Description: ufmt.Sprintf("This proposal will add %s as a member with roles: %s", address, strings.Join(rs, ", ")),
94 Action: action,
95 }
96
97 Propose(cur, proposal)
98}
99
100func renderDemo() string {
101 s := ""
102 s += "# ⚙️ Custom Condition Demo\n\n"
103 s += "This showcases how to create custom governance rules.\n\n"
104 s += "## ℹ️ How it Works\n\n"
105 s += "1. **Join the DAO** using the " + md.Link("AddMember", txlink.Call("AddMember")) + " function.\n\n"
106 s += "2. **Create a Proposal** using " + md.Link("ProposeAddMember", txlink.Call("ProposeAddMember")) + " function with these parameters:\n\n"
107 s += "- `address`: The address of the member to add\n"
108 s += "- `roles`: Comma-separated roles (e.g., \"Role\")\n\n"
109 s += "3. " + md.Link("Vote", txlink.Call("Vote")) + " on proposals using their ID.\n\n"
110 s += "4. " + md.Link("Execute", txlink.Call("Execute")) + " proposals that have passed (met the required voting conditions).\n\n"
111 s += " 📝 **Note**: Only proposals that have met the governance conditions can be executed. You need at least 1 vote from members with no roles to execute a proposal.\n\n"
112 s += "## 🎯 Custom Condition: NoRole\n\n"
113 s += "This DAO uses a initial custom condition called **NoRole** that requires:\n"
114 s += "- At least **1 vote** from members who have **no assigned roles**\n"
115 s += "## 📋 Available Actions\n\n"
116 s += "### Member Management\n"
117 s += "- " + md.Link("🔗 Add Yourself as Member", txlink.Call("AddMember")) + " - Join the DAO to participate in governance\n"
118 s += "- " + md.Link("🔗 Propose Add Member", txlink.Call("ProposeAddMember")) + " - Create a proposal to add a new member with specific roles\n\n"
119 s += "### Other Demos\n"
120 s += "- " + md.Link("🔗 Simple DAO Demo", "/r/samcrew/daodemo/simple_dao") + " - Basic DAO functionality\n"
121 s += "- " + md.Link("🔗 Custom Resource Demo", "/r/samcrew/daodemo/custom_resource") + " - Custom DAO actions\n\n"
122 s += "*This is a demonstration DAO built with gno.land and daokit*"
123 return s
124}