github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/r/x/nir1218_evaluation_proposal/committee.gno (about) 1 package evaluation 2 3 import ( 4 "std" 5 6 "gno.land/p/demo/avl" 7 "gno.land/p/demo/ufmt" 8 ) 9 10 type Committee struct { 11 members []std.Address // TODO - use avl tree or address set? 12 categories avl.Tree // A category is mapped to a list of evaluation criteria 13 evaluation *Evaluation 14 } 15 16 const ApprovedStatus = "Approved" 17 18 func NewCommittee() *Committee { 19 c := &Committee{ 20 members: []std.Address{}, 21 categories: avl.Tree{}, 22 evaluation: NewEvalutaion(), 23 } 24 return c 25 } 26 27 func (c *Committee) DesignateMembers(members []std.Address) []std.Address { 28 c.members = append(c.members, members...) 29 return c.members 30 } 31 32 func (c *Committee) DismissMembers(members []std.Address) []std.Address { 33 // TODO 34 return []std.Address{} 35 } 36 37 func (c *Committee) AddCategory(name string, criteria []string) bool { 38 // TODO error handling 39 if !c.isMember(std.GetOrigCaller()) { 40 return false 41 } 42 category := NewCategory(name, criteria) 43 c.categories.Set(name, category) 44 return true 45 } 46 47 func (c *Committee) ApproveCategory(name string, option string) bool { 48 if !c.isMember(std.GetOrigCaller()) { 49 return false 50 } 51 52 value, exists := c.categories.Get(name) 53 if !exists { 54 return false 55 } 56 category := value.(*Category) 57 if category.Status() == ApprovedStatus { 58 return false 59 } 60 61 vote := NewVote(std.GetOrigCaller(), option) 62 category.votes.Set(std.GetOrigCaller().String(), vote) 63 category.Tally() 64 65 // TODO Add threshold factor for a category approval 66 // TODO Add quorum factor for a category approval 67 // Current assumption is all members voted YES so category is approved 68 69 result, exists := category.tallyResult.results.Get(VoteYes) 70 if !exists { 71 return false 72 } 73 74 if result.(int) == len(c.members) { 75 category.Approve() 76 return true 77 } 78 79 return false 80 } 81 82 // TODO error handling 83 func (c *Committee) AddContribution(pr *PullRequest, contributor std.Address) (contributionId int, ok bool) { 84 if !c.isMember(std.GetOrigCaller()) { 85 return -1, false 86 } 87 // Check the category of the PR matches a category this committee evaluates 88 // TODO check the category is an approved category 89 if c.categories.Has(pr.category) { 90 return c.evaluation.AddContribution(pr, contributor) 91 } 92 93 return -1, false 94 } 95 96 // TODO error handling 97 func (c *Committee) ApproveContribution(id int, option string) bool { 98 if !c.isMember(std.GetOrigCaller()) { 99 return false 100 } 101 102 value, exists := c.evaluation.contributions.Get(ufmt.Sprintf("%d", id)) 103 if !exists { 104 return false 105 } 106 contribution := value.(*Contribution) 107 // Already approved 108 if contribution.status == ApprovedStatus { 109 return false 110 } 111 112 vote := NewVote(std.GetOrigCaller(), option) 113 contribution.votes = append(contribution.votes, vote) 114 contribution.Tally() 115 116 // TODO Add threshold factor for a contribution approval 117 // TODO Add quorum factor for a contribution approval 118 // Current assumption is all members voted YES so contribution is approved 119 120 result, exists := contribution.tallyResult.results.Get(VoteYes) 121 if !exists { 122 return false 123 } 124 125 if result.(int) == len(c.members) { 126 contribution.Approve() 127 return true 128 } 129 130 return false 131 } 132 133 func (c *Committee) isMember(m std.Address) bool { 134 for _, member := range c.members { 135 if m == member { 136 return true 137 } 138 } 139 return false 140 }