Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
NAMESPACE ?= gnome
CHAIN_ID ?= dev
REMOTE ?= 127.0.0.1:26657
KEY_NAME ?=
KEY_PASSWORD ?=

ifndef KEY_NAME
KEY_NAME := $(shell bash -c 'read -p "Key Name: " name; echo $$name')
endif

ifndef KEY_PASSWORD
KEY_PASSWORD := $(shell bash -c 'read -s -p "Key Password: " pwd; echo $$pwd')
endif

deploy: deploy_realms

deploy_realms: deploy_realm_dao

deploy_realm_dao:
@echo "\nDeploying DAO realm..."
@gnokey maketx addpkg $(KEY_NAME) \
--pkgpath "gno.land/r/$(NAMESPACE)/dao" \
--pkgdir "./gno.land/r/gnome/dao" \
--gas-fee "50000ugnot" \
--gas-wanted "50000000" \
--broadcast \
--chainid "$(CHAIN_ID)" \
--remote "$(REMOTE)" \
--quiet \
--insecure-password-stdin <<< "$(KEY_PASSWORD)"
16 changes: 16 additions & 0 deletions gno.land/r/gnome/dao/dao.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package dao

import (
"gno.land/p/demo/avl"
"gno.land/p/nt/commondao"
)

var (
gnomeDAO *commondao.CommonDAO
locked bool
notice string
parameters struct {
// VotingPeriods contains the voting period for different proposal types.
VotingPeriods avl.Tree // string(param name) -> time.Duration
}
)
56 changes: 56 additions & 0 deletions gno.land/r/gnome/dao/format.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package dao

import (
"math"
"time"

"gno.land/p/demo/ufmt"
)

func formatDuration(d time.Duration) string {
if d == 0 {
return ""
}

if sec := d.Seconds(); sec < 60 {
return ufmt.Sprintf("%d seconds", int(sec))
}

if m := d.Minutes(); m < 60 {
sec := math.Mod(d.Seconds(), 60)
if sec < 1 {
return ufmt.Sprintf("%d minutes", int(m))
}
return ufmt.Sprintf("%d minutes %d seconds", int(m), int(sec))
}

if hs := d.Hours(); hs < 24 {
m := math.Mod(d.Minutes(), 60)
if m < 1 {
return ufmt.Sprintf("%d hours", int(hs))
}

sec := math.Mod(d.Seconds(), 60)
if sec < 1 {
return ufmt.Sprintf("%d hours %d minutes", int(hs), int(m))
}
return ufmt.Sprintf("%d hours %d minutes %d seconds", int(hs), int(m), int(sec))
}

days := d.Hours() / 24
hs := math.Mod(d.Hours(), 24)
if hs < 1 {
return ufmt.Sprintf("%d days", int(days))
}

m := math.Mod(d.Minutes(), 60)
if m < 0 {
return ufmt.Sprintf("%d days %d hours", int(days), int(hs))
}

sec := math.Mod(d.Seconds(), 60)
if sec < 1 {
return ufmt.Sprintf("%d days %d hours %d minutes", int(days), int(hs), int(m))
}
return ufmt.Sprintf("%d days %d hours %d minutes %d seconds", int(days), int(hs), int(m), int(sec))
}
84 changes: 84 additions & 0 deletions gno.land/r/gnome/dao/genesis.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package dao

import (
"time"

"gno.land/r/nt/commondao"
)

// TODO: Add DAO descriptions when supported by CommonDAO
// TODO: Add proposal review deadline parameter when supported by CommonDAO
// TODO: Group members by role when supported, see gnolang/gno#4287

const Day = time.Hour * 24

const (
paramPropTypeBudget = "budget-approval"
paramPropTypeLocking = "realm-locking"
paramPropTypeParams = "params-update"
)

func init() {
// Configure initial realm parameter values
initParams()

// Initialize genesis Gno.me community DAO tree
//
// Gnome DAO
// └── Ecosystem
// ├── Space
// └── Community
// └── Tutorials
initDAO()
}

func initDAO() {
gnomeDAO = commondao.New("Gnome DAO")
gnomeDAO.Members().Add("g1hy6zry03hg5d8le9s2w4fxme6236hkgd928dun")
gnomeDAO.Members().Add("g1778y2yphxs2wpuaflsy5y9qwcd4gttn4g5yjx5")
options := configureDAO(gnomeDAO.ID())
options.SetAllowListing(true)

ecosystemDAO := commondao.NewSubDAO("Ecosystem", gnomeDAO.ID())
ecosystemDAO.Members().Add("g1hy6zry03hg5d8le9s2w4fxme6236hkgd928dun")
ecosystemDAO.Members().Add("g1778y2yphxs2wpuaflsy5y9qwcd4gttn4g5yjx5")
ecosystemDAO.Members().Add("g1lavlav7zwsjqlzzl3qdl3nl242qtf638vnhdjh")
configureDAO(ecosystemDAO.ID())

spaceDAO := commondao.NewSubDAO("Gnome Space", ecosystemDAO.ID())
spaceDAO.Members().Add("g1hy6zry03hg5d8le9s2w4fxme6236hkgd928dun")
spaceDAO.Members().Add("g1778y2yphxs2wpuaflsy5y9qwcd4gttn4g5yjx5")
spaceDAO.Members().Add("g18cwpdpsqd8mywj8skpsqsg9tn9hudkkpa6ycpe")
spaceDAO.Members().Add("g1lavlav7zwsjqlzzl3qdl3nl242qtf638vnhdjh")
configureDAO(spaceDAO.ID())

communityDAO := commondao.NewSubDAO("Community", ecosystemDAO.ID())
communityDAO.Members().Add("g1hy6zry03hg5d8le9s2w4fxme6236hkgd928dun")
communityDAO.Members().Add("g1778y2yphxs2wpuaflsy5y9qwcd4gttn4g5yjx5")
communityDAO.Members().Add("g1lavlav7zwsjqlzzl3qdl3nl242qtf638vnhdjh")
communityDAO.Members().Add("g1dnllrdzwfhxv3evyk09y48mgn5phfjvtyrlzm7")
configureDAO(communityDAO.ID())

tutorialsDAO := commondao.NewSubDAO("Tutorials", communityDAO.ID())
tutorialsDAO.Members().Add("g1hy6zry03hg5d8le9s2w4fxme6236hkgd928dun")
tutorialsDAO.Members().Add("g1778y2yphxs2wpuaflsy5y9qwcd4gttn4g5yjx5")
tutorialsDAO.Members().Add("g1lavlav7zwsjqlzzl3qdl3nl242qtf638vnhdjh")
tutorialsDAO.Members().Add("g1dnllrdzwfhxv3evyk09y48mgn5phfjvtyrlzm7")
configureDAO(tutorialsDAO.ID())
}

func initParams() {
parameters.VotingPeriods.Set(paramPropTypeBudget, Day*7)
parameters.VotingPeriods.Set(paramPropTypeLocking, Day*2)
parameters.VotingPeriods.Set(paramPropTypeParams, Day)
}

func configureDAO(daoID uint64) *commondao.Options {
// TODO: Allow CommonDAO proposals too
options := commondao.GetOptions(daoID)
options.SetAllowRender(true)
options.SetAllowVoting(true)
options.SetAllowChildren(true)
options.SetAllowExecution(true)
return options
}
2 changes: 2 additions & 0 deletions gno.land/r/gnome/dao/gnomod.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module = "gno.land/r/gnome/dao"
gno = "0.9"
56 changes: 56 additions & 0 deletions gno.land/r/gnome/dao/proposal_budget.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package dao

import (
"errors"
"time"

"gno.land/p/moul/md"
"gno.land/p/moul/mdtable"
commondao "gno.land/p/nt/commondao"
)

type budgetPropType struct {
dao *commondao.CommonDAO
budget string
description string
}

func (budgetPropType) Title() string {
return "Budget Approval"
}

func (budgetPropType) VotingPeriod() time.Duration {
v, _ := parameters.VotingPeriods.Get(paramPropTypeBudget)
return v.(time.Duration)
}

func (p budgetPropType) Body() string {
table := mdtable.Table{Headers: []string{"Parameter", "Value"}}
table.Append([]string{md.Bold("DAO"), daoLink(p.dao)})
table.Append([]string{md.Bold("Budget"), p.budget})
table.Append([]string{md.Bold("Description"), p.description})
return table.String()
}

func (p budgetPropType) Validate() error {
if p.dao.IsDeleted() {
return errors.New("DAO has been dissolved")
}
return nil
}

func (budgetPropType) Tally(r commondao.ReadonlyVotingRecord, m commondao.MemberSet) (bool, error) {
if !commondao.IsQuorumReached(commondao.QuorumThreeFourths, r, m) {
return false, commondao.ErrNoQuorum
}

c, success := commondao.SelectChoiceByAbsoluteMajority(r, m.Size())
if success {
return c == commondao.ChoiceYes, nil
}
return false, nil
}

func daoLink(dao *commondao.CommonDAO) string {
return md.Link(dao.Name(), daoURL(dao.ID()))
}
56 changes: 56 additions & 0 deletions gno.land/r/gnome/dao/proposal_params.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package dao

import (
"time"

"gno.land/p/demo/avl"
"gno.land/p/moul/md"
"gno.land/p/moul/mdtable"
"gno.land/p/nt/commondao"
)

type paramsPropType struct {
votingPeriods avl.Tree
}

func (paramsPropType) Title() string {
return "Parameters Update"
}

func (paramsPropType) VotingPeriod() time.Duration {
v, _ := parameters.VotingPeriods.Get(paramPropTypeParams)
return v.(time.Duration)
}

func (p paramsPropType) Body() string {
table := mdtable.Table{Headers: []string{"Parameter", "Value"}}
p.votingPeriods.Iterate("", "", func(name string, v any) bool {
table.Append([]string{
md.Bold("Voting period for: " + name),
formatDuration(v.(time.Duration)), // TODO: Use gno.land/p/jeronimoalbi/str when available
})
return false
})

return table.String()
}

func (paramsPropType) Tally(r commondao.ReadonlyVotingRecord, m commondao.MemberSet) (bool, error) {
if !commondao.IsQuorumReached(commondao.QuorumHalf, r, m) {
return false, commondao.ErrNoQuorum
}

c, success := commondao.SelectChoiceByPlurality(r)
if success {
return c == commondao.ChoiceYes, nil
}
return false, nil
}

func (p paramsPropType) Execute() error {
p.votingPeriods.Iterate("", "", func(name string, v any) bool {
parameters.VotingPeriods.Set(name, v)
return false
})
return nil
}
Loading