diff --git a/examples/gno.land/p/demo/simpledao/propstore.gno b/examples/gno.land/p/demo/simpledao/propstore.gno index 67a3ba1ed02..127f64e75b7 100644 --- a/examples/gno.land/p/demo/simpledao/propstore.gno +++ b/examples/gno.land/p/demo/simpledao/propstore.gno @@ -10,7 +10,10 @@ import ( pproposal "gno.land/p/gov/proposal" ) -var errMissingProposal = errors.New("proposal is missing") +var ( + errMissingProposal = errors.New("proposal is missing") + errMissingVote = errors.New("member has not voted") +) // proposal is the internal simpledao proposal implementation type proposal struct { @@ -36,7 +39,41 @@ func (p *proposal) GetStatus() dao.Status { } func (p *proposal) GetVotes() []dao.Vote { - return p.votes.getVotes() + var ( + voters = p.votes.getVoters() + votes = make([]dao.Vote, 0, voters.Size()) + ) + + voters.Iterate("", "", func(key string, val interface{}) bool { + option := val.(dao.VoteOption) + + vote := dao.Vote{ + Address: std.Address(key), + Option: option, + } + + votes = append(votes, vote) + + return false + }) + + return votes +} + +func (p *proposal) GetVoteByMember(address std.Address) (dao.Vote, error) { + voters := p.votes.getVoters() + + optionRaw, exists := voters.Get(address.String()) + if !exists { + return dao.Vote{}, errMissingVote + } + + vote := dao.Vote{ + Address: address, + Option: optionRaw.(dao.VoteOption), + } + + return vote, nil } // PropStore implements the dao.PropStore abstraction diff --git a/examples/gno.land/p/demo/simpledao/propstore_test.gno b/examples/gno.land/p/demo/simpledao/propstore_test.gno index e76b2fc014d..93b96c8a28b 100644 --- a/examples/gno.land/p/demo/simpledao/propstore_test.gno +++ b/examples/gno.land/p/demo/simpledao/propstore_test.gno @@ -148,6 +148,44 @@ func TestProposal_Data(t *testing.T) { } } }) + + t.Run("vote by member", func(t *testing.T) { + t.Parallel() + + var ( + members = generateMembers(t, 50) + p = &proposal{ + votes: newVotes(), + } + ) + + for _, m := range members { + urequire.NoError(t, p.votes.castVote(m, dao.YesVote)) + } + + votes := p.GetVotes() + urequire.Equal(t, len(members), len(votes)) + + vote, err := p.GetVoteByMember(members[0].Address) + urequire.NoError(t, err) + + uassert.Equal(t, dao.YesVote.String(), vote.Option.String()) + uassert.Equal(t, members[0].Address.String(), vote.Address.String()) + }) + + t.Run("missing vote by member", func(t *testing.T) { + t.Parallel() + + p := &proposal{ + votes: newVotes(), + } + + votes := p.GetVotes() + urequire.Equal(t, 0, len(votes)) + + _, err := p.GetVoteByMember(testutils.TestAddress("dummy")) + uassert.ErrorIs(t, err, errMissingVote) + }) } func TestPropStore_GetProposals(t *testing.T) { diff --git a/examples/gno.land/p/demo/simpledao/vote.gno b/examples/gno.land/p/demo/simpledao/vote.gno index 2f5fa913dd3..7d06aab3876 100644 --- a/examples/gno.land/p/demo/simpledao/vote.gno +++ b/examples/gno.land/p/demo/simpledao/vote.gno @@ -3,8 +3,6 @@ package simpledao import ( "errors" - "std" - "gno.land/p/demo/avl" "gno.land/p/gov/dao" ) @@ -55,22 +53,7 @@ func (v *votes) getTally() (uint64, uint64) { return v.yays, v.nays } -// getVotes fetches the currently active vote set -func (v *votes) getVotes() []dao.Vote { - votes := make([]dao.Vote, 0, v.voters.Size()) - - v.voters.Iterate("", "", func(key string, val interface{}) bool { - option := val.(dao.VoteOption) - - vote := dao.Vote{ - Address: std.Address(key), - Option: option, - } - - votes = append(votes, vote) - - return false - }) - - return votes +// getVoters returns the current voter set +func (v *votes) getVoters() *avl.Tree { + return v.voters } diff --git a/examples/gno.land/p/gov/dao/proposal.gno b/examples/gno.land/p/gov/dao/proposal.gno index 67339427a0c..855ce387b7e 100644 --- a/examples/gno.land/p/gov/dao/proposal.gno +++ b/examples/gno.land/p/gov/dao/proposal.gno @@ -44,4 +44,7 @@ type Proposal interface { // GetVotes returns the votes of the proposal GetVotes() []Vote + + // GetVoteByMember returns the proposal vote by the member, if any + GetVoteByMember(address std.Address) (Vote, error) }