diff --git a/gno/p/dao_core/dao_core.gno b/gno/p/dao_core/dao_core.gno index 86f9d7126..74791b8b7 100644 --- a/gno/p/dao_core/dao_core.gno +++ b/gno/p/dao_core/dao_core.gno @@ -5,9 +5,7 @@ import ( "strconv" "strings" - "gno.land/p/demo/json" dao_interfaces "gno.land/p/teritori/dao_interfaces" - "gno.land/p/teritori/jsonutil" ) // TODO: add wrapper message handler to handle multiple proposal modules messages @@ -16,7 +14,6 @@ type daoCore struct { dao_interfaces.IDAOCore votingModule dao_interfaces.IVotingModule - rolesModule dao_interfaces.IRolesModule proposalModules []dao_interfaces.ActivableProposalModule activeProposalModuleCount int realm std.Realm @@ -25,7 +22,6 @@ type daoCore struct { func NewDAOCore( votingModuleFactory dao_interfaces.VotingModuleFactory, - rolesModuleFactory dao_interfaces.RolesModuleFactory, proposalModulesFactories []dao_interfaces.ProposalModuleFactory, messageHandlersFactories []dao_interfaces.MessageHandlerFactory, ) dao_interfaces.IDAOCore { @@ -33,10 +29,6 @@ func NewDAOCore( panic("Missing voting module factory") } - if rolesModuleFactory == nil { - panic("Missing roles module factory") - } - if len(proposalModulesFactories) == 0 { panic("No proposal modules factories") } @@ -48,12 +40,6 @@ func NewDAOCore( proposalModules: make([]dao_interfaces.ActivableProposalModule, len(proposalModulesFactories)), } - // important to keep this order since voting module might depend on roles module - core.rolesModule = rolesModuleFactory(core) - if core.rolesModule == nil { - panic("roles module factory returned nil") - } - core.votingModule = votingModuleFactory(core) if core.votingModule == nil { panic("voting module factory returned nil") @@ -131,32 +117,6 @@ func (d *daoCore) VotingModule() dao_interfaces.IVotingModule { return d.votingModule } -func (d *daoCore) RolesModule() dao_interfaces.IRolesModule { - return d.rolesModule -} - -func (d *daoCore) GetMembersJSON(start, end string, limit uint64, height int64) string { - vMembers := d.votingModule.GetMembersJSON(start, end, limit, height) - nodes, err := json.Unmarshal([]byte(vMembers)) - if err != nil { - panic("failed to unmarshal voting module members") - } - vals := nodes.MustArray() - for i, val := range vals { - obj := val.MustObject() - addr := jsonutil.MustAddress(obj["address"]) - roles := d.rolesModule.GetMemberRoles(addr) - rolesJSON := make([]*json.Node, len(roles)) - for j, role := range roles { - rolesJSON[j] = json.StringNode("", role) - } - obj["roles"] = json.ArrayNode("", rolesJSON) - vals[i] = json.ObjectNode("", obj) - - } - return json.ArrayNode("", vals).String() -} - func (d *daoCore) VotingPowerAtHeight(address std.Address, height int64) uint64 { return d.VotingModule().VotingPowerAtHeight(address, height, []string{}) } @@ -169,15 +129,12 @@ func (d *daoCore) Render(path string) string { sb := strings.Builder{} sb.WriteString("# DAO Core\n") votingInfo := d.votingModule.Info() + sb.WriteString("## Voting Module: ") sb.WriteString(votingInfo.String()) sb.WriteRune('\n') sb.WriteString(d.votingModule.Render("")) - rolesInfo := d.rolesModule.Info() - sb.WriteString("# Roles Module: ") - sb.WriteString(rolesInfo.String()) - sb.WriteRune('\n') - sb.WriteString(d.rolesModule.Render("")) + sb.WriteString("## Supported Messages:\n") sb.WriteString(d.registry.Render()) diff --git a/gno/p/dao_core/dao_core_test.gno b/gno/p/dao_core/dao_core_test.gno index 2c1013d15..d3ab7a8a6 100644 --- a/gno/p/dao_core/dao_core_test.gno +++ b/gno/p/dao_core/dao_core_test.gno @@ -46,57 +46,6 @@ func (vm *votingModule) TotalPowerAtHeight(height int64) uint64 { return 0 } -type rolesModule struct { - core dao_interfaces.IDAOCore -} - -func rolesModuleFactory(core dao_interfaces.IDAOCore) dao_interfaces.IRolesModule { - return &rolesModule{core: core} -} - -func (rm *rolesModule) Info() dao_interfaces.ModuleInfo { - return dao_interfaces.ModuleInfo{ - Kind: "TestRoles", - Version: "42.21", - } -} - -func (rm *rolesModule) ConfigJSON() string { - return "{}" -} - -func (rm *rolesModule) Render(path string) string { - return "# Test Roles Module" -} - -func (rm *rolesModule) HasRole(address std.Address, role string) bool { - return false -} - -func (rm *rolesModule) NewRoleJSON(roleName, resourcesJSON string) { - panic("not implemented") -} - -func (rm *rolesModule) DeleteRole(roleName string) { - panic("not implemented") -} - -func (rm *rolesModule) GrantRole(address std.Address, role string) { - panic("not implemented") -} - -func (rm *rolesModule) RevokeRole(address std.Address, role string) { - panic("not implemented") -} - -func (rm *rolesModule) GetMemberRoles(address std.Address) []string { - return []string{} -} - -func (rm *rolesModule) GetMemberResourceVPower(address std.Address, resource string) uint64 { - return 0 -} - type proposalModule struct { core dao_interfaces.IDAOCore } @@ -151,7 +100,7 @@ func TestDAOCore(t *testing.T) { return handler } - core := NewDAOCore(votingModuleFactory, rolesModuleFactory, []dao_interfaces.ProposalModuleFactory{proposalModuleFactory}, []dao_interfaces.MessageHandlerFactory{handlerFactory}) + core := NewDAOCore(votingModuleFactory, []dao_interfaces.ProposalModuleFactory{proposalModuleFactory}, []dao_interfaces.MessageHandlerFactory{handlerFactory}) if core == nil { t.Fatal("core is nil") } @@ -169,15 +118,6 @@ func TestDAOCore(t *testing.T) { t.Fatal("voting module has wrong kind") } - rolesMod := core.RolesModule() - if rolesMod == nil { - t.Fatal("roles module is nil") - } - - if rolesMod.Info().Kind != "TestRoles" { - t.Fatal("roles module has wrong kind") - } - propMods := core.ProposalModules() if len(propMods) != 1 { t.Fatal("expected 1 proposal module") diff --git a/gno/p/dao_interfaces/core.gno b/gno/p/dao_interfaces/core.gno index 749a0ccf6..5379638ed 100644 --- a/gno/p/dao_interfaces/core.gno +++ b/gno/p/dao_interfaces/core.gno @@ -11,13 +11,10 @@ type IDAOCore interface { Render(path string) string VotingModule() IVotingModule - RolesModule() IRolesModule ProposalModules() []ActivableProposalModule ActiveProposalModuleCount() int Registry() *MessagesRegistry UpdateVotingModule(newVotingModule IVotingModule) UpdateProposalModules(toAdd []IProposalModule, toDisable []int) - - GetMembersJSON(start, end string, limit uint64, height int64) string } diff --git a/gno/p/dao_interfaces/core_testing.gno b/gno/p/dao_interfaces/core_testing.gno index a61c467bd..4d0e88175 100644 --- a/gno/p/dao_interfaces/core_testing.gno +++ b/gno/p/dao_interfaces/core_testing.gno @@ -2,6 +2,8 @@ package dao_interfaces type dummyCore struct{} +var _ IDAOCore = (*dummyCore)(nil) + func NewDummyCore() IDAOCore { return &dummyCore{} } @@ -14,10 +16,6 @@ func (d *dummyCore) VotingModule() IVotingModule { panic("not implemented") } -func (d *dummyCore) RolesModule() IRolesModule { - panic("not implemented") -} - func (d *dummyCore) ProposalModules() []ActivableProposalModule { panic("not implemented") } @@ -37,7 +35,3 @@ func (d *dummyCore) UpdateVotingModule(newVotingModule IVotingModule) { func (d *dummyCore) UpdateProposalModules(toAdd []IProposalModule, toDisable []int) { panic("not implemented") } - -func (d *dummyCore) GetMembersJSON(start, end string, limit uint64, height int64) string { - panic("not implemented") -} diff --git a/gno/p/dao_interfaces/modules.gno b/gno/p/dao_interfaces/modules.gno index 5565d9537..35b375b3a 100644 --- a/gno/p/dao_interfaces/modules.gno +++ b/gno/p/dao_interfaces/modules.gno @@ -25,7 +25,6 @@ type IVotingModule interface { type VotingModuleFactory func(core IDAOCore) IVotingModule type IProposalModule interface { - Core() IDAOCore Info() ModuleInfo ConfigJSON() string Render(path string) string @@ -37,18 +36,3 @@ type IProposalModule interface { } type ProposalModuleFactory func(core IDAOCore) IProposalModule - -type IRolesModule interface { - Info() ModuleInfo - ConfigJSON() string - Render(path string) string - GetMemberRoles(address std.Address) []string - GetMemberResourceVPower(address std.Address, resource string) uint64 - HasRole(address std.Address, role string) bool - NewRoleJSON(roleName, resourcesJSON string) - DeleteRole(roleName string) - GrantRole(address std.Address, role string) - RevokeRole(address std.Address, role string) -} - -type RolesModuleFactory func(core IDAOCore) IRolesModule diff --git a/gno/p/dao_proposal_single/dao_proposal_single.gno b/gno/p/dao_proposal_single/dao_proposal_single.gno index 19f68130e..a98024bc0 100644 --- a/gno/p/dao_proposal_single/dao_proposal_single.gno +++ b/gno/p/dao_proposal_single/dao_proposal_single.gno @@ -56,13 +56,13 @@ func (opts DAOProposalSingleOpts) ToJSON() *json.Node { } type DAOProposalSingle struct { - dao_interfaces.IProposalModule - core dao_interfaces.IDAOCore opts *DAOProposalSingleOpts proposals []*Proposal } +var _ dao_interfaces.IProposalModule = (*DAOProposalSingle)(nil) + func NewDAOProposalSingle(core dao_interfaces.IDAOCore, opts *DAOProposalSingleOpts) *DAOProposalSingle { if core == nil { panic("core cannot be nil") @@ -238,10 +238,6 @@ func (d *DAOProposalSingle) Render(path string) string { return sb.String() } -func (d *DAOProposalSingle) Core() dao_interfaces.IDAOCore { - return d.core -} - func (d *DAOProposalSingle) Info() dao_interfaces.ModuleInfo { return dao_interfaces.ModuleInfo{ Kind: "gno.land/p/teritori/dao_proposal_single", diff --git a/gno/p/dao_roles_group/roles_group.gno b/gno/p/dao_roles_group/roles_group.gno index c7d81ece4..688a2ca12 100644 --- a/gno/p/dao_roles_group/roles_group.gno +++ b/gno/p/dao_roles_group/roles_group.gno @@ -11,8 +11,6 @@ import ( ) type RolesGroup struct { - dao_interfaces.IRolesModule - rm *role_manager.RoleManager resourcesVPower *avl.Tree // roles -> ResourceVPower[] } diff --git a/gno/p/dao_roles_voting_group/roles_voting_group.gno b/gno/p/dao_roles_voting_group/roles_voting_group.gno index 40f728cb1..07c8d293e 100644 --- a/gno/p/dao_roles_voting_group/roles_voting_group.gno +++ b/gno/p/dao_roles_voting_group/roles_voting_group.gno @@ -7,6 +7,7 @@ import ( "gno.land/p/demo/json" dao_interfaces "gno.land/p/teritori/dao_interfaces" + "gno.land/p/teritori/dao_roles_group" "gno.land/p/teritori/havl" "gno.land/p/teritori/jsonutil" ) @@ -30,15 +31,15 @@ func (m *Member) FromJSON(ast *json.Node) { } type RolesVotingGroup struct { - dao_interfaces.IVotingModule - powerByAddr *havl.Tree // std.Address -> uint64 totalPower *havl.Tree // "" -> uint64 memberCount *havl.Tree // "" -> uint32 - rolesModule dao_interfaces.IRolesModule + rolesModule *dao_roles_group.RolesGroup } -func NewRolesVotingGroup(rm dao_interfaces.IRolesModule) *RolesVotingGroup { +var _ dao_interfaces.IVotingModule = (*RolesVotingGroup)(nil) + +func NewRolesVotingGroup(rm *dao_roles_group.RolesGroup) *RolesVotingGroup { return &RolesVotingGroup{ powerByAddr: havl.NewTree(), totalPower: havl.NewTree(), diff --git a/gno/p/dao_roles_voting_group/roles_voting_group_test.gno b/gno/p/dao_roles_voting_group/roles_voting_group_test.gno index 39eb14d08..b6baa9c1b 100644 --- a/gno/p/dao_roles_voting_group/roles_voting_group_test.gno +++ b/gno/p/dao_roles_voting_group/roles_voting_group_test.gno @@ -15,7 +15,7 @@ var ( func TestRolesVotingGroup(t *testing.T) { rm := dao_roles_group.NewRolesGroup() - var j dao_interfaces.IRolesModule + var j *dao_roles_group.RolesGroup j = rm rv := NewRolesVotingGroup(j) var i dao_interfaces.IVotingModule diff --git a/gno/p/havl/havl.gno b/gno/p/havl/havl.gno index 2be4a4a0a..61c7b2480 100644 --- a/gno/p/havl/havl.gno +++ b/gno/p/havl/havl.gno @@ -13,7 +13,7 @@ type Tree struct { initialHeight int64 } -var Latest = int64(0) +const Latest = int64(0) // FIXME: this is not optimized at all, we make a full copy on write diff --git a/gno/r/dao_realm/dao_realm.gno b/gno/r/dao_realm/dao_realm.gno index fc2d02814..c9be11cc4 100644 --- a/gno/r/dao_realm/dao_realm.gno +++ b/gno/r/dao_realm/dao_realm.gno @@ -38,11 +38,6 @@ func init() { return group } - rolesModuleFactory := func(core dao_interfaces.IDAOCore) dao_interfaces.IRolesModule { - roles = dao_roles_group.NewRolesGroup() - return roles - } - // TODO: consider using factories that return multiple modules and handlers proposalModulesFactories := []dao_interfaces.ProposalModuleFactory{ @@ -82,7 +77,7 @@ func init() { }, } - daoCore = dao_core.NewDAOCore(votingModuleFactory, rolesModuleFactory, proposalModulesFactories, messageHandlersFactories) + daoCore = dao_core.NewDAOCore(votingModuleFactory, proposalModulesFactories, messageHandlersFactories) // Register the DAO profile profile.SetStringField(profile.DisplayName, "DAO Realm") @@ -148,3 +143,7 @@ func getProposalJSON(moduleIndex int, proposalIndex int) string { module := dao_core.GetProposalModule(daoCore, moduleIndex) return module.Module.ProposalJSON(proposalIndex) } + +func getMembersJSON(start, end string, limit uint64) string { + return daoCore.VotingModule().GetMembersJSON(start, end, limit, std.GetHeight()) +} diff --git a/gno/r/dao_roles_realm.gno/dao_roles_realm.gno b/gno/r/dao_roles_realm.gno/dao_roles_realm.gno index 6319c3ff6..f44253c37 100644 --- a/gno/r/dao_roles_realm.gno/dao_roles_realm.gno +++ b/gno/r/dao_roles_realm.gno/dao_roles_realm.gno @@ -6,12 +6,14 @@ import ( "std" "time" + "gno.land/p/demo/json" dao_core "gno.land/p/teritori/dao_core" dao_interfaces "gno.land/p/teritori/dao_interfaces" proposal_single "gno.land/p/teritori/dao_proposal_single" "gno.land/p/teritori/dao_roles_group" roles_voting_group "gno.land/p/teritori/dao_roles_voting_group" "gno.land/p/teritori/dao_utils" + "gno.land/p/teritori/jsonutil" "gno.land/r/demo/profile" "gno.land/r/teritori/dao_registry" "gno.land/r/teritori/social_feeds" @@ -28,20 +30,17 @@ var ( ) func init() { - rolesModuleFactory := func(core dao_interfaces.IDAOCore) dao_interfaces.IRolesModule { - roles = dao_roles_group.NewRolesGroup() - roles.NewRoleJSON("admin", "[{\"resource\": \"social_feed\", \"power\": \"25\"}, {\"resource\": \"organizations\", \"power\": \"100\"}]") - roles.NewRoleJSON("moderator", "[{\"resource\": \"social_feed\", \"power\": \"10\"}]") - roles.NewRoleJSON("member", "[]") - roles.GrantRole("g1747t5m2f08plqjlrjk2q0qld7465hxz8gkx59c", "admin") - roles.GrantRole("g108cszmcvs4r3k67k7h5zuhm4el3qhlrxzhshtv", "moderator") - roles.GrantRole("g14u5eaheavy0ux4dmpykg2gvxpvqvexm9cyg58a", "member") - roles.GrantRole("g1ckn395mpttp0vupgtratyufdaakgh8jgkmr3ym", "member") - return roles - } + roles = dao_roles_group.NewRolesGroup() + roles.NewRoleJSON("admin", "[{\"resource\": \"social_feed\", \"power\": \"25\"}, {\"resource\": \"organizations\", \"power\": \"100\"}]") + roles.NewRoleJSON("moderator", "[{\"resource\": \"social_feed\", \"power\": \"10\"}]") + roles.NewRoleJSON("member", "[]") + roles.GrantRole("g1747t5m2f08plqjlrjk2q0qld7465hxz8gkx59c", "admin") + roles.GrantRole("g108cszmcvs4r3k67k7h5zuhm4el3qhlrxzhshtv", "moderator") + roles.GrantRole("g14u5eaheavy0ux4dmpykg2gvxpvqvexm9cyg58a", "member") + roles.GrantRole("g1ckn395mpttp0vupgtratyufdaakgh8jgkmr3ym", "member") votingModuleFactory := func(core dao_interfaces.IDAOCore) dao_interfaces.IVotingModule { - group = roles_voting_group.NewRolesVotingGroup(core.RolesModule()) + group = roles_voting_group.NewRolesVotingGroup(roles) group.SetMemberPower("g1747t5m2f08plqjlrjk2q0qld7465hxz8gkx59c", 1) group.SetMemberPower("g108cszmcvs4r3k67k7h5zuhm4el3qhlrxzhshtv", 1) group.SetMemberPower("g14u5eaheavy0ux4dmpykg2gvxpvqvexm9cyg58a", 1) @@ -89,7 +88,7 @@ func init() { }, } - daoCore = dao_core.NewDAOCore(votingModuleFactory, rolesModuleFactory, proposalModulesFactories, messageHandlersFactories) + daoCore = dao_core.NewDAOCore(votingModuleFactory, proposalModulesFactories, messageHandlersFactories) // Register the DAO profile profile.SetStringField(profile.DisplayName, "DAO Realm") @@ -155,3 +154,25 @@ func getProposalJSON(moduleIndex int, proposalIndex int) string { module := dao_core.GetProposalModule(daoCore, moduleIndex) return module.Module.ProposalJSON(proposalIndex) } + +func getMembersJSON(start, end string, limit uint64) string { + vMembers := daoCore.VotingModule().GetMembersJSON(start, end, limit, std.GetHeight()) + nodes, err := json.Unmarshal([]byte(vMembers)) + if err != nil { + panic("failed to unmarshal voting module members") + } + vals := nodes.MustArray() + for i, val := range vals { + obj := val.MustObject() + addr := jsonutil.MustAddress(obj["address"]) + roles := roles.GetMemberRoles(addr) + rolesJSON := make([]*json.Node, len(roles)) + for j, role := range roles { + rolesJSON[j] = json.StringNode("", role) + } + obj["roles"] = json.ArrayNode("", rolesJSON) + vals[i] = json.ObjectNode("", obj) + + } + return json.ArrayNode("", vals).String() +} diff --git a/networks.json b/networks.json index f0a178c5a..b782b9260 100644 --- a/networks.json +++ b/networks.json @@ -4579,7 +4579,7 @@ "daoProposalSinglePkgPath": "gno.land/p/teritori/dao_proposal_single", "daoInterfacesPkgPath": "gno.land/p/teritori/dao_interfaces", "daoCorePkgPath": "gno.land/p/teritori/dao_core", - "daoUtilsPkgPath": "gno.land/r/teritori/dao_utils", + "daoUtilsPkgPath": "gno.land/p/teritori/dao_utils", "toriPkgPath": "gno.land/r/teritori/tori", "profilePkgPath": "gno.land/r/demo/profile", "txIndexerURL": "https://indexer.portal-loop.gno.testnet.teritori.com" diff --git a/packages/hooks/dao/useDAOMembers.ts b/packages/hooks/dao/useDAOMembers.ts index 3e857088f..a605f9915 100644 --- a/packages/hooks/dao/useDAOMembers.ts +++ b/packages/hooks/dao/useDAOMembers.ts @@ -16,7 +16,7 @@ import { extractGnoJSONString } from "@/utils/gno"; type GnoDAOMember = { address: string; power: number; - roles: string[]; + roles?: string[]; }; export const useDAOMembers = (daoId: string | undefined) => { @@ -55,13 +55,13 @@ export const useDAOMembers = (daoId: string | undefined) => { const res: GnoDAOMember[] = extractGnoJSONString( await provider.evaluateExpression( daoAddress, - `daoCore.GetMembersJSON("", "", 0, 0)`, + `getMembersJSON("", "", 0)`, ), ); return res.map((member) => ({ addr: member.address, weight: member.power, - roles: member.roles, + roles: member.roles || [], })); } } diff --git a/packages/networks/gno-portal/index.ts b/packages/networks/gno-portal/index.ts index 767f1a3fb..d53469683 100644 --- a/packages/networks/gno-portal/index.ts +++ b/packages/networks/gno-portal/index.ts @@ -39,7 +39,7 @@ export const gnoPortalNetwork: GnoNetworkInfo = { daoProposalSinglePkgPath: "gno.land/p/teritori/dao_proposal_single", daoInterfacesPkgPath: "gno.land/p/teritori/dao_interfaces", daoCorePkgPath: "gno.land/p/teritori/dao_core", - daoUtilsPkgPath: "gno.land/r/teritori/dao_utils", + daoUtilsPkgPath: "gno.land/p/teritori/dao_utils", toriPkgPath: "gno.land/r/teritori/tori", profilePkgPath: "gno.land/r/demo/profile", txIndexerURL: "https://indexer.portal-loop.gno.testnet.teritori.com", diff --git a/packages/scripts/generateDAOSource.ts b/packages/scripts/generateDAOSource.ts new file mode 100644 index 000000000..0a96871f5 --- /dev/null +++ b/packages/scripts/generateDAOSource.ts @@ -0,0 +1,60 @@ +import { program } from "commander"; +import { z } from "zod"; + +import { gnoDevNetwork } from "@/networks/gno-dev"; +import { GnoDAOConfig } from "@/utils/gnodao/deploy"; +import { generateMembershipDAOSource } from "@/utils/gnodao/generateMembershipDAOSource"; +import { generateRolesDAOSource } from "@/utils/gnodao/generateRolesDAOSource"; + +// example usage: `npx tsx packages/scripts/generateDAOSource.ts roles | gofmt > my_dao.gno` + +const kindSchema = z.union([z.literal("membership"), z.literal("roles")]); + +const main = () => { + const [kindArg] = program.argument("").parse().args; + const kind = kindSchema.parse(kindArg); + + const network = gnoDevNetwork; + + const config: GnoDAOConfig = { + name: "my_dao", + displayName: "My DAO", + description: "Some DAO", + imageURI: + "https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?w=1080&fit=max", + maxVotingPeriodSeconds: 60 * 60 * 24 * 42, // 42 days + roles: [ + { name: "fooer", color: "#111111", resources: ["fooing"] }, + { name: "barer", color: "#777777", resources: ["baring", "bazing"] }, + ], + initialMembers: [ + { + address: "g1fakeaddr", + weight: 42, + roles: ["fooer", "barer"], + }, + { + address: "g1fakeaddr2", + weight: 21, + roles: [], + }, + ], + thresholdPercent: 0.66, + quorumPercent: 0.33, + }; + + let source: string; + switch (kind) { + case "membership": + source = generateMembershipDAOSource(network.id, config); + break; + case "roles": + source = generateRolesDAOSource(network.id, config); + break; + default: + throw new Error("unknown dao structure"); + } + console.log(source); +}; + +main(); diff --git a/packages/utils/gnodao/generateMembershipDAOSource.ts b/packages/utils/gnodao/generateMembershipDAOSource.ts index 8e0fe7542..b9d3ae7e9 100644 --- a/packages/utils/gnodao/generateMembershipDAOSource.ts +++ b/packages/utils/gnodao/generateMembershipDAOSource.ts @@ -10,12 +10,12 @@ export const generateMembershipDAOSource = ( return `package ${conf.name} import ( + "std" "time" dao_core "${network.daoCorePkgPath}" dao_interfaces "${network.daoInterfacesPkgPath}" proposal_single "${network.daoProposalSinglePkgPath}" - "${network.rolesGroupPkgPath}" "${network.daoUtilsPkgPath}" "${network.profilePkgPath}" voting_group "${network.votingGroupPkgPath}" @@ -23,35 +23,26 @@ export const generateMembershipDAOSource = ( "${network.socialFeedsPkgPath}" ) -var ( - daoCore dao_interfaces.IDAOCore - group *voting_group.VotingGroup - roles *dao_roles_group.RolesGroup - registered bool -) - -func init() { - votingModuleFactory := func(core dao_interfaces.IDAOCore) dao_interfaces.IVotingModule { - group = voting_group.NewVotingGroup() - ${conf.initialMembers - .map( - (member) => - `group.SetMemberPower("${member.address}", ${member.weight})`, - ) - .join("\n\t")} - return group - } - - rolesModuleFactory := func(core dao_interfaces.IDAOCore) dao_interfaces.IRolesModule { - roles = dao_roles_group.NewRolesGroup() - ${(conf.roles ?? []).map((role) => `roles.NewRole("${role}", "");`).join("\n\t")} - ${conf.initialMembers.map((member) => member.roles.map((role) => `roles.GrantRole("${member.address}", "${role}")`).join("\n\t"))} - return roles - } + var ( + daoCore dao_interfaces.IDAOCore + group *voting_group.VotingGroup + registered bool + ) + func init() { + votingModuleFactory := func(core dao_interfaces.IDAOCore) dao_interfaces.IVotingModule { + group = voting_group.NewVotingGroup() + ${conf.initialMembers + .map( + (member) => + `group.SetMemberPower("${member.address}", ${member.weight})`, + ) + .join("\n\t")} + return group + } // TODO: consider using factories that return multiple modules and handlers - + proposalModulesFactories := []dao_interfaces.ProposalModuleFactory{ func(core dao_interfaces.IDAOCore) dao_interfaces.IProposalModule { tt := proposal_single.PercentageThresholdPercent(${Math.ceil( @@ -69,29 +60,29 @@ func init() { }) }, } - - messageHandlersFactories := []dao_interfaces.MessageHandlerFactory{ - func(core dao_interfaces.IDAOCore) dao_interfaces.MessageHandler { - return group.UpdateMembersHandler() - }, - func(core dao_interfaces.IDAOCore) dao_interfaces.MessageHandler { - // TODO: add a router to support multiple proposal modules - propMod := core.ProposalModules()[0] - return proposal_single.NewUpdateSettingsHandler(propMod.Module.(*proposal_single.DAOProposalSingle)) - }, - func(core dao_interfaces.IDAOCore) dao_interfaces.MessageHandler { - return social_feeds.NewCreatePostHandler() - }, - } - - daoCore = dao_core.NewDAOCore(votingModuleFactory, rolesModuleFactory, proposalModulesFactories, messageHandlersFactories) - - // Register the DAO profile - profile.SetStringField(profile.DisplayName, "${conf.displayName}") - profile.SetStringField(profile.Bio, "${conf.description}") - profile.SetStringField(profile.Avatar, "${conf.imageURI}") - - dao_registry.Register(func() dao_interfaces.IDAOCore { return daoCore }, "${conf.displayName}", "${conf.description}", "${conf.imageURI}") + + messageHandlersFactories := []dao_interfaces.MessageHandlerFactory{ + func(core dao_interfaces.IDAOCore) dao_interfaces.MessageHandler { + return group.UpdateMembersHandler() + }, + func(core dao_interfaces.IDAOCore) dao_interfaces.MessageHandler { + // TODO: add a router to support multiple proposal modules + propMod := core.ProposalModules()[0] + return proposal_single.NewUpdateSettingsHandler(propMod.Module.(*proposal_single.DAOProposalSingle)) + }, + func(core dao_interfaces.IDAOCore) dao_interfaces.MessageHandler { + return social_feeds.NewCreatePostHandler() + }, + } + + daoCore = dao_core.NewDAOCore(votingModuleFactory, proposalModulesFactories, messageHandlersFactories) + + // Register the DAO profile + profile.SetStringField(profile.DisplayName, "${conf.displayName}") + profile.SetStringField(profile.Bio, "${conf.description}") + profile.SetStringField(profile.Avatar, "${conf.imageURI}") + + dao_registry.Register(func() dao_interfaces.IDAOCore { return daoCore }, "${conf.displayName}", "${conf.description}", "${conf.imageURI}") } func Render(path string) string { @@ -139,5 +130,9 @@ func init() { module := dao_core.GetProposalModule(daoCore, moduleIndex) return module.Module.ProposalJSON(proposalIndex) } + + func getMembersJSON(start, end string, limit uint64) string { + return daoCore.VotingModule().GetMembersJSON(start, end, limit, std.GetHeight()) + } `; }; diff --git a/packages/utils/gnodao/generateRolesDAOSource.ts b/packages/utils/gnodao/generateRolesDAOSource.ts index 93d30f392..2dfafa384 100644 --- a/packages/utils/gnodao/generateRolesDAOSource.ts +++ b/packages/utils/gnodao/generateRolesDAOSource.ts @@ -9,6 +9,7 @@ export const generateRolesDAOSource = ( return `package ${conf.name} import ( + "std" "time" dao_core "${network.daoCorePkgPath}" @@ -16,10 +17,12 @@ export const generateRolesDAOSource = ( proposal_single "${network.daoProposalSinglePkgPath}" "${network.rolesGroupPkgPath}" "${network.daoUtilsPkgPath}" + "gno.land/p/teritori/jsonutil" "${network.profilePkgPath}" voting_group "${network.rolesVotingGroupPkgPath}" "${network.daoRegistryPkgPath}" "${network.socialFeedsPkgPath}" + "gno.land/p/demo/json" ) var ( @@ -30,32 +33,29 @@ var ( ) func init() { - rolesModuleFactory := func(core dao_interfaces.IDAOCore) dao_interfaces.IRolesModule { - roles = dao_roles_group.NewRolesGroup() - ${(conf.roles ?? []) - .map( - (role) => - `roles.NewRoleJSON("${role.name}", "[${(role.resources ?? []) - .map( - (resource) => - `{\\"resource\\": \\"${resource}\\", \\"power\\": \\"999\\"}`, - ) - .join(", ")}]")`, - ) - .join("\n\t")} - ${conf.initialMembers - .filter((member) => member.roles.length > 0) - .map((member) => - member.roles - .map((role) => `roles.GrantRole("${member.address}", "${role}")`) - .join("\n\t"), - ) - .join("\n\t")} - return roles - } + roles = dao_roles_group.NewRolesGroup() + ${(conf.roles ?? []) + .map( + (role) => + `roles.NewRoleJSON("${role.name}", "[${(role.resources ?? []) + .map( + (resource) => + `{\\"resource\\": \\"${resource}\\", \\"power\\": \\"999\\"}`, + ) + .join(", ")}]")`, + ) + .join("\n\t")} + ${conf.initialMembers + .filter((member) => member.roles.length > 0) + .map((member) => + member.roles + .map((role) => `roles.GrantRole("${member.address}", "${role}")`) + .join("\n\t"), + ) + .join("\n\t")} votingModuleFactory := func(core dao_interfaces.IDAOCore) dao_interfaces.IVotingModule { - group = voting_group.NewRolesVotingGroup(core.RolesModule()) + group = voting_group.NewRolesVotingGroup(roles) ${conf.initialMembers .map( (member) => @@ -100,7 +100,7 @@ func init() { }, } - daoCore = dao_core.NewDAOCore(votingModuleFactory, rolesModuleFactory, proposalModulesFactories, messageHandlersFactories) + daoCore = dao_core.NewDAOCore(votingModuleFactory, proposalModulesFactories, messageHandlersFactories) // Register the DAO profile profile.SetStringField(profile.DisplayName, "${conf.displayName}") @@ -155,5 +155,28 @@ func init() { module := dao_core.GetProposalModule(daoCore, moduleIndex) return module.Module.ProposalJSON(proposalIndex) } + + + func getMembersJSON(start, end string, limit uint64) string { + vMembers := daoCore.VotingModule().GetMembersJSON(start, end, limit, std.GetHeight()) + nodes, err := json.Unmarshal([]byte(vMembers)) + if err != nil { + panic("failed to unmarshal voting module members") + } + vals := nodes.MustArray() + for i, val := range vals { + obj := val.MustObject() + addr := jsonutil.MustAddress(obj["address"]) + roles := roles.GetMemberRoles(addr) + rolesJSON := make([]*json.Node, len(roles)) + for j, role := range roles { + rolesJSON[j] = json.StringNode("", role) + } + obj["roles"] = json.ArrayNode("", rolesJSON) + vals[i] = json.ObjectNode("", obj) + + } + return json.ArrayNode("", vals).String() + } `; };