Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

utils.gno

6.22 Kb Β· 134 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	// Safe here only because cur is THIS realm's own, minted by this crossing
 84	// function. CallerID is not the entry-point gate: copied somewhere that
 85	// passes a realm it received from elsewhere, this becomes the donation bug
 86	// the DAO entry points exist to refuse. If you need the gate, go through
 87	// Propose/Vote/Execute.
 88	id := daoPrivate.CallerID(daoPrivate, cur)
 89	daoPrivate.Members.AddMember(id, make([]string, 0))
 90}
 91
 92// Creates a Proposal to add a new member to the DAO with specified roles.
 93// This function exist to let users try the userflow of daokit with a simple MsgCall (maketx call) instead of a MsgRun.
 94// See why a run is necessary for creating a proposal -> https://docs.gno.land/users/interact-with-gnokey#run.
 95// Parameters:
 96//   - address: The std.Address of the member to be added
 97//   - roles: Comma-separated roles (e.g., "public-relationships,finance-officer" or "finance-officer")
 98func ProposeAddMember(cur realm, address address, roles string) {
 99	rs := strings.Split(roles, ",")
100	for i, s := range rs {
101		rs[i] = strings.TrimFunc(s, unicode.IsSpace)
102	}
103	req := daokit.ProposalRequest{
104		Title: ufmt.Sprintf("Add member %s with roles %s", address, strings.Join(rs, ", ")),
105		Action: basedao.NewAddMemberAction(&basedao.ActionAddMember{
106			Address: address,
107			Roles:   rs,
108		}),
109	}
110	localDAO.Propose(req, cur)
111}
112
113func renderDemo() string {
114	s := ""
115	s += "# πŸ›οΈ Simple DAO Actions\n\n"
116	s += "Welcome to Simple DAO! This is a demonstration of basic DAO functionality.\n\n"
117	s += "## ℹ️ How it Works\n\n"
118	s += "1. **Join the DAO** using the " + md.Link("AddMember", txlink.Call("AddMember")) + " function.\n\n"
119	s += "2. **Create a pre-made Proposal** using " + md.Link("ProposeAddMember", txlink.Call("ProposeAddMember")) + "  function using this parameters:\n\n"
120	s += "- `address`: The address of the member to add\n"
121	s += "- `roles`: Comma-separated roles (e.g., \"public-relationships,finance-officer\" or \"finance-officer\")\n\n"
122	s += "3. " + md.Link("Vote", txlink.Call("Vote")) + " on proposals using their ID.\n\n"
123	s += "4. " + md.Link("Execute", txlink.Call("Execute")) + " proposals that have passed (met the required voting conditions).\n\n"
124	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"
125	s += "## πŸ“‹ Available Actions\n\n"
126	s += "### Member Management\n"
127	s += "- " + md.Link("πŸ”— Add Yourself as Member", txlink.Call("AddMember")) + " - Join the DAO to participate in governance\n"
128	s += "- " + md.Link("πŸ”— Propose Add Member", txlink.Call("ProposeAddMember")) + " - Create a proposal to add a new member with specific roles\n\n"
129	s += "### Other Demos\n"
130	s += "- " + md.Link("πŸ”— Custom Resource Example", "/r/samcrew/daodemo/custom_resource") + " - See a demo of custom resource implementation\n"
131	s += "- " + md.Link("πŸ”— Custom Condition Example", "/r/samcrew/daodemo/custom_condition") + " - See a demo of custom condition implementation\n\n"
132	s += "*This is a demonstration DAO built with gno.land and daokit*"
133	return s
134}