Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: r/gov/dao v2 + r/sys/vars #2581

Open
wants to merge 70 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
4dd7c58
Add standard govdao types
zivkovicmilos Jul 13, 2024
aad859b
Initial simpledao implementation
zivkovicmilos Jul 13, 2024
81396bf
Add membstore tests
zivkovicmilos Jul 13, 2024
dd5d64b
Add propstore tests
zivkovicmilos Jul 13, 2024
c342741
Add testing stubs
zivkovicmilos Jul 13, 2024
3d16ba6
Update examples/gno.land/p/gov/dao/types.gno
zivkovicmilos Jul 14, 2024
8f2e3ac
Move /nt/simpledao -> /demo/simpledao
zivkovicmilos Jul 14, 2024
ae0639a
Move DAO API to dao.gno
zivkovicmilos Jul 14, 2024
3a7ba00
Move vote API to vote.gno
zivkovicmilos Jul 14, 2024
00056a5
Add GetVoteByMember to proposal API
zivkovicmilos Jul 14, 2024
209ee06
Drop name from dao.Member
zivkovicmilos Jul 14, 2024
54c555d
Add limit to number of proposals returned
zivkovicmilos Jul 14, 2024
84aeb30
Add Size() to MembStore API
zivkovicmilos Jul 14, 2024
322bc8c
Apply Yoda wisdom to MemberStore API
zivkovicmilos Jul 14, 2024
794a353
Add execution failed ProposalStatus
zivkovicmilos Jul 14, 2024
8c45039
Drop unused PropStore method
zivkovicmilos Jul 14, 2024
268021d
Drop RemoveMember, add removal in UpdateMember
zivkovicmilos Jul 14, 2024
43e5c66
Add Size() to PropStore API
zivkovicmilos Jul 14, 2024
e1cd617
Add pagination to MembStore
zivkovicmilos Jul 14, 2024
67e4535
Rename proposal.gno -> proposals.gno
zivkovicmilos Jul 14, 2024
8fbbd5e
Start cleaning up r/gov/dao
zivkovicmilos Jul 14, 2024
fd13d02
Clean house for the govdao executor
zivkovicmilos Jul 14, 2024
ebfd3d2
Add remaining simpledao tests
zivkovicmilos Jul 15, 2024
b3856c7
Remove unsafe ctx executor usage
zivkovicmilos Jul 15, 2024
4d3d94e
Fixup prop filetests
zivkovicmilos Jul 15, 2024
1f1d5d7
Fixup prop filetests
zivkovicmilos Jul 15, 2024
7fa7530
Remove faulty test
zivkovicmilos Jul 15, 2024
ef299bd
Add pagination for vote fetching
zivkovicmilos Jul 15, 2024
3d0c056
Tidy mod
zivkovicmilos Jul 15, 2024
4396c48
Update update method
zivkovicmilos Jul 15, 2024
24e0b08
Add r/sys/vars
zivkovicmilos Jul 15, 2024
4827d0b
Version packages, add unit tests
zivkovicmilos Jul 15, 2024
26f21d8
Start integrating r/sys/vars into EndBlocker
zivkovicmilos Jul 15, 2024
71e8644
Add moniker to r/gnoland/valopers
zivkovicmilos Jul 16, 2024
93d2b70
Resolve freaky import
zivkovicmilos Jul 16, 2024
efe35cc
Restore Endblocker
zivkovicmilos Jul 16, 2024
63cf23f
Make tidy
zivkovicmilos Jul 16, 2024
4520593
Make tidy
zivkovicmilos Jul 16, 2024
af65764
Fixup vars tests
zivkovicmilos Jul 16, 2024
f567394
Merge branch 'master' into dev/zivkovicmilos/govdao
zivkovicmilos Jul 16, 2024
4ec9f3b
Export errors
zivkovicmilos Jul 16, 2024
30ac5ff
Update comment
zivkovicmilos Jul 16, 2024
c05289f
Drop useless voters methods
zivkovicmilos Jul 16, 2024
d8e5b7d
Drop excess field
zivkovicmilos Jul 16, 2024
d320493
Update voting power
zivkovicmilos Jul 16, 2024
d33b0df
Please the standards police
zivkovicmilos Jul 16, 2024
79be838
Slim down the DAO API
zivkovicmilos Jul 16, 2024
8c52893
Revert "Slim down the DAO API"
zivkovicmilos Jul 16, 2024
74948fc
Add Executor to proposal
zivkovicmilos Jul 16, 2024
c9b4cc4
Fix up old API
zivkovicmilos Jul 17, 2024
93ca6a8
Mod tidy
zivkovicmilos Jul 17, 2024
ee77102
Make the PropStore part of the DAO API
zivkovicmilos Jul 17, 2024
dbf0966
Fixup prop test
zivkovicmilos Jul 17, 2024
2f337a6
Move out memberstore
zivkovicmilos Jul 17, 2024
31d265f
Add Render to proposal
zivkovicmilos Jul 18, 2024
908b949
Add govdao executor wrapper
zivkovicmilos Jul 18, 2024
6b3b81c
Remove unused code
zivkovicmilos Jul 18, 2024
480a287
Add new prop test
zivkovicmilos Jul 18, 2024
06fe4fe
Move out memberstore
zivkovicmilos Jul 20, 2024
dba0379
Move p/gov/dao -> p/demo/dao
zivkovicmilos Jul 20, 2024
873ba9b
Drop voting fetchers from the propstore
zivkovicmilos Jul 21, 2024
6ceb72a
Rename VotingStats -> Stats
zivkovicmilos Jul 21, 2024
8198c7f
Add key name to r/sys/vars emit event
zivkovicmilos Jul 21, 2024
8a51452
Merge branch 'master' into dev/zivkovicmilos/govdao
zivkovicmilos Jul 22, 2024
b0fa6b7
Merge branch 'master' into dev/zivkovicmilos/govdao
zivkovicmilos Aug 15, 2024
676b202
Make the executor not panic due to wrong caller
zivkovicmilos Aug 15, 2024
852291c
isCallerGOVDAO -> isCallerDAORealm
zivkovicmilos Aug 15, 2024
ae650d2
Resolve nitpick
zivkovicmilos Aug 15, 2024
aa4f9ef
Fix faulty test assert
zivkovicmilos Aug 15, 2024
33343d7
Merge branch 'master' into dev/zivkovicmilos/govdao
zivkovicmilos Sep 18, 2024
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
32 changes: 32 additions & 0 deletions examples/gno.land/p/demo/dao/dao.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package dao
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a package-level comment to explain the role of this p/


const (
ProposalAddedEvent = "ProposalAdded" // emitted when a new proposal has been added
ProposalAcceptedEvent = "ProposalAccepted" // emitted when a proposal has been accepted
ProposalNotAcceptedEvent = "ProposalNotAccepted" // emitted when a proposal has not been accepted
ProposalExecutedEvent = "ProposalExecuted" // emitted when a proposal has been executed

ProposalEventIDKey = "proposal-id"
ProposalEventExecutionKey = "exec-status"
)

// ProposalRequest is a single govdao proposal request
// that contains the necessary information to
// log and generate a valid proposal
type ProposalRequest struct {
Description string // the description associated with the proposal
Executor Executor // the proposal executor
}

// DAO defines the DAO abstraction
type DAO interface {
// PropStore is the DAO proposal storage
PropStore

// Propose adds a new proposal to the executor-based GOVDAO.
// Returns the generated proposal ID
Propose(request ProposalRequest) (uint64, error)

// ExecuteProposal executes the proposal with the given ID
ExecuteProposal(id uint64) error
}
13 changes: 13 additions & 0 deletions examples/gno.land/p/demo/dao/executor.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dao

// Executor represents a minimal closure-oriented proposal design.
// It is intended to be used by a govdao governance proposal (v1, v2, etc)
type Executor interface {
// Execute executes the given proposal, and returns any error encountered
// during the execution
Execute() error

// IsExpired returns a flag indicating
// if the executor is expired
IsExpired() bool
}
1 change: 1 addition & 0 deletions examples/gno.land/p/demo/dao/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gno.land/p/demo/dao
54 changes: 54 additions & 0 deletions examples/gno.land/p/demo/dao/proposals.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package dao

import "std"

type ProposalStatus string

// ACTIVE -> ACCEPTED -> EXECUTION(SUCCEEDED/FAILED)
// ACTIVE -> NOT ACCEPTED
var (
Active ProposalStatus = "active" // proposal is still active
Accepted ProposalStatus = "accepted" // proposal gathered quorum
NotAccepted ProposalStatus = "not accepted" // proposal failed to gather quorum
ExecutionSuccessful ProposalStatus = "execution successful" // proposal is executed successfully
ExecutionFailed ProposalStatus = "execution failed" // proposal is failed during execution
)

func (s ProposalStatus) String() string {
return string(s)
}

// PropStore defines the proposal storage abstraction
type PropStore interface {
// Proposals returns the given paginated proposals
Proposals(offset, count uint64) []Proposal

// ProposalByID returns the proposal associated with
// the given ID, if any
ProposalByID(id uint64) (Proposal, error)

// Size returns the number of proposals in
// the proposal store
Size() int
}

// Proposal is the single proposal abstraction
type Proposal interface {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: Wouldn't it be better and more secure to use a struct here? What if we define a custom struct that implements the interface for an attack?

// Author returns the author of the proposal
Author() std.Address

// Description returns the description of the proposal
Description() string

// Status returns the status of the proposal
Status() ProposalStatus

// Executor returns the proposal executor
Executor() Executor

// Stats returns the voting stats of the proposal
Stats() Stats

// Render renders the proposal in a readable format
Render() string
}
70 changes: 70 additions & 0 deletions examples/gno.land/p/demo/dao/vote.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package dao
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment to explain that the vote will be removed from this p/demo/dao package. A DAO shouldn't have to comply with or define how the voting mechanism works internally; it should be viewed as an entity that makes decisions. Therefore, we should focus on the proposal rather than the votes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to merge this PR soon, so I'm in favor of just adding the comment. However, please note that this is the biggest weakness of this implementation, and it's the only issue I see that will require us to create a v2.


import (
"std"
)

const (
VoteAddedEvent = "VoteAdded" // emitted when a vote was cast for a proposal

VoteAddedIDKey = "proposal-id"
VoteAddedAuthorKey = "author"
VoteAddedOptionKey = "option"
)

type VoteOption string

const (
YesVote VoteOption = "YES"
NoVote VoteOption = "NO"
AbstainVote VoteOption = "ABSTAIN"
)

func (v VoteOption) String() string {
return string(v)
}

// Vote encompasses a single GOVDAO vote
type Vote struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deadcode

Address std.Address // the address of the voter
Option VoteOption // the voting option
}

// Stats encompasses the proposal voting stats
type Stats struct {
YayVotes uint64
NayVotes uint64
AbstainVotes uint64
moul marked this conversation as resolved.
Show resolved Hide resolved

TotalVotingPower uint64
}

// YayPercent returns the percentage (0-100) of the yay votes
// in relation to the total voting power
func (v Stats) YayPercent() uint64 {
return (v.YayVotes / v.TotalVotingPower) * 100
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return (v.YayVotes / v.TotalVotingPower) * 100
return v.YayVotes * 100 / v.TotalVotingPower

Copy link
Member Author

@zivkovicmilos zivkovicmilos Aug 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swapped 🙃

ae650d2

}

// NayPercent returns the percentage (0-100) of the nay votes
// in relation to the total voting power
func (v Stats) NayPercent() uint64 {
return (v.NayVotes / v.TotalVotingPower) * 100
}

// AbstainPercent returns the percentage (0-100) of the abstain votes
// in relation to the total voting power
func (v Stats) AbstainPercent() uint64 {
return (v.AbstainVotes / v.TotalVotingPower) * 100
}

// MissingVotes returns the summed voting power that has not
// participated in proposal voting yet
func (v Stats) MissingVotes() uint64 {
return v.TotalVotingPower - (v.YayVotes + v.NayVotes + v.AbstainVotes)
}

// MissingVotesPercent returns the percentage (0-100) of the missing votes
// in relation to the total voting power
func (v Stats) MissingVotesPercent() uint64 {
return (v.MissingVotes() / v.TotalVotingPower) * 100
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
module gno.land/r/gov/dao
module gno.land/p/demo/membstore

require (
gno.land/p/demo/avl v0.0.0-latest
gno.land/p/demo/testutils v0.0.0-latest
gno.land/p/demo/uassert v0.0.0-latest
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/p/demo/urequire v0.0.0-latest
gno.land/p/gov/proposal v0.0.0-latest
)
38 changes: 38 additions & 0 deletions examples/gno.land/p/demo/membstore/members.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package membstore

import (
"std"
)

// MemberStore defines the member storage abstraction
type MemberStore interface {
// Members returns all members in the store
Members(offset, count uint64) []Member

// Size returns the current size of the store
Size() int

// IsMember returns a flag indicating if the given address
// belongs to a member
IsMember(address std.Address) bool

// TotalPower returns the total voting power of the member store
TotalPower() uint64

// Member returns the requested member
Member(address std.Address) (Member, error)

// AddMember adds a member to the store
AddMember(member Member) error

// UpdateMember updates the member in the store.
// If updating a member's voting power to 0,
// the member will be removed
UpdateMember(address std.Address, member Member) error
}

// Member holds the relevant member information
type Member struct {
Address std.Address // bech32 gno address of the member (unique)
VotingPower uint64 // the voting power of the member
}
Loading
Loading