utils.gno
5.88 Kb Β· 129 lines
1package simple_dao
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/daocond"
12 "gno.land/p/samcrew/daokit"
13)
14
15// Creates a number of initial proposals and votes.
16// It divides the proposals into 4 parts: AddMember, RemoveMember, AssignRole, EditProfile.
17// It initializes votes for each proposal type.
18func initProposals(cur realm, nb int) {
19 const financeOfficer = "g1demo1234567890abcdefghijklmnopqrstuvwxyz"
20 const nbTypes = 4
21 proposalsPerType := nb / nbTypes
22 offsets := []int{0, proposalsPerType, 2 * proposalsPerType, 3 * proposalsPerType, nb} // AddMember, Remove, AssignRole, EditProfile
23
24 lastAddr := financeOfficer
25
26 for t, start := range offsets[:nbTypes] {
27 end := offsets[t+1]
28 for i := start; i < end; i++ {
29 addr := ufmt.Sprintf("g1fakemember000000000000000000000000000%02d", i)
30 var action daokit.Action
31 var title string
32 var description string
33
34 // CREATE
35 switch t {
36 case 0: // AddMember
37 action = basedao.NewAddMemberAction(&basedao.ActionAddMember{Address: address(addr), Roles: []string{}})
38 title = ufmt.Sprintf("Add member %s with no role", addr)
39 description = ufmt.Sprintf("This proposal will add %s as a new member of the DAO without any specific roles. They will be able to participate in governance and vote on proposals.", addr)
40 case 1: // RemoveMember
41 action = basedao.NewRemoveMemberAction(address(addr))
42 title = ufmt.Sprintf("Remove member %s", addr)
43 description = ufmt.Sprintf("This proposal will remove %s from the DAO membership. They will no longer be able to participate in governance or vote on proposals.", addr)
44 case 2: // AssignRole
45 role := "public-relationships"
46 action = basedao.NewAssignRoleAction(&basedao.ActionAssignRole{Address: address(financeOfficer), Role: role})
47 title = ufmt.Sprintf("Assign role %s for %s", role, addr)
48 description = ufmt.Sprintf("This proposal will assign the '%s' role to the finance officer. This role grants additional responsibilities and permissions within the DAO.", role)
49 case 3: // EditProfile
50 action = basedao.NewEditProfileAction([2]string{"Bio", "A demo DAO showcasing governance and community decision-making."})
51 title = "Edit the DAO's profile"
52 description = "This proposal will update the DAO's bio with a simple description of our purpose as a demonstration DAO."
53 }
54 req := daokit.ProposalRequest{
55 Title: title,
56 Action: action,
57 Description: description,
58 }
59 id := daoPrivate.Core.Propose(lastAddr, req)
60
61 // VOTE
62 quart := i * 4 / nb
63 switch quart {
64 case 0: // VoteNo
65 daoPrivate.Core.Vote(financeOfficer, id, daocond.VoteNo)
66 case 1: // VoteYes
67 daoPrivate.Core.Vote(financeOfficer, id, daocond.VoteYes)
68 case 2: // VoteAbstain
69 daoPrivate.Core.Vote(financeOfficer, id, daocond.VoteAbstain)
70 case 3: // VoteYes + Execute
71 daoPrivate.Core.Vote(financeOfficer, id, daocond.VoteYes)
72 daoPrivate.Core.Execute(id, cur)
73 }
74
75 lastAddr = addr
76 }
77 }
78}
79
80// Bypass limitation by adding yourself to the DAO.
81// It is necessary to be part of the DAO to create a Proposal.
82func AddMember(cur realm) {
83 id := daoPrivate.CallerID()
84 daoPrivate.Members.AddMember(id, make([]string, 0))
85}
86
87// Creates a Proposal to add a new member to the DAO with specified roles.
88// This function exist to let users try the userflow of daokit with a simple MsgCall (maketx call) instead of a MsgRun.
89// See why a run is necessary for creating a proposal -> https://docs.gno.land/users/interact-with-gnokey#run.
90// Parameters:
91// - address: The std.Address of the member to be added
92// - roles: Comma-separated roles (e.g., "public-relationships,finance-officer" or "finance-officer")
93func ProposeAddMember(cur realm, address address, roles string) {
94 rs := strings.Split(roles, ",")
95 for i, s := range rs {
96 rs[i] = strings.TrimFunc(s, unicode.IsSpace)
97 }
98 req := daokit.ProposalRequest{
99 Title: ufmt.Sprintf("Add member %s with roles %s", address, strings.Join(rs, ", ")),
100 Action: basedao.NewAddMemberAction(&basedao.ActionAddMember{
101 Address: address,
102 Roles: rs,
103 }),
104 }
105 localDAO.Propose(req)
106}
107
108func renderDemo() string {
109 s := ""
110 s += "# ποΈ Simple DAO Actions\n\n"
111 s += "Welcome to Simple DAO! This is a demonstration of basic DAO functionality.\n\n"
112 s += "## βΉοΈ How it Works\n\n"
113 s += "1. **Join the DAO** using the " + md.Link("AddMember", txlink.Call("AddMember")) + " function.\n\n"
114 s += "2. **Create a pre-made Proposal** using " + md.Link("ProposeAddMember", txlink.Call("ProposeAddMember")) + " function using this parameters:\n\n"
115 s += "- `address`: The address of the member to add\n"
116 s += "- `roles`: Comma-separated roles (e.g., \"public-relationships,finance-officer\" or \"finance-officer\")\n\n"
117 s += "3. " + md.Link("Vote", txlink.Call("Vote")) + " on proposals using their ID.\n\n"
118 s += "4. " + md.Link("Execute", txlink.Call("Execute")) + " proposals that have passed (met the required voting conditions).\n\n"
119 s += " π **Note**: Only proposals that have met the governance conditions can be executed. You need both **40% of member approval** AND at least **1 finance-officer** to execute a proposal.\n\n"
120 s += "## π Available Actions\n\n"
121 s += "### Member Management\n"
122 s += "- " + md.Link("π Add Yourself as Member", txlink.Call("AddMember")) + " - Join the DAO to participate in governance\n"
123 s += "- " + md.Link("π Propose Add Member", txlink.Call("ProposeAddMember")) + " - Create a proposal to add a new member with specific roles\n\n"
124 s += "### Other Demos\n"
125 s += "- " + md.Link("π Custom Resource Example", "/r/samcrew/daodemo/custom_resource") + " - See a demo of custom resource implementation\n"
126 s += "- " + md.Link("π Custom Condition Example", "/r/samcrew/daodemo/custom_condition") + " - See a demo of custom condition implementation\n\n"
127 s += "*This is a demonstration DAO built with gno.land and daokit*"
128 return s
129}