committee.gno

3.13 Kb ยท 140 lines
  1package evaluation
  2
  3import (
  4	"chain/runtime"
  5
  6	"gno.land/p/nt/avl"
  7	"gno.land/p/nt/ufmt"
  8)
  9
 10type Committee struct {
 11	members    []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
 16const ApprovedStatus = "Approved"
 17
 18func NewCommittee() *Committee {
 19	c := &Committee{
 20		members:    []address{},
 21		categories: avl.Tree{},
 22		evaluation: NewEvalutaion(),
 23	}
 24	return c
 25}
 26
 27func (c *Committee) DesignateMembers(members []address) []address {
 28	c.members = append(c.members, members...)
 29	return c.members
 30}
 31
 32func (c *Committee) DismissMembers(members []address) []address {
 33	// TODO
 34	return []address{}
 35}
 36
 37func (c *Committee) AddCategory(name string, criteria []string) bool {
 38	// TODO error handling
 39	if !c.isMember(runtime.OriginCaller()) {
 40		return false
 41	}
 42	category := NewCategory(name, criteria)
 43	c.categories.Set(name, category)
 44	return true
 45}
 46
 47func (c *Committee) ApproveCategory(name string, option string) bool {
 48	if !c.isMember(runtime.OriginCaller()) {
 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(runtime.OriginCaller(), option)
 62	category.votes.Set(runtime.OriginCaller().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
 83func (c *Committee) AddContribution(pr *PullRequest, contributor address) (contributionId int, ok bool) {
 84	if !c.isMember(runtime.OriginCaller()) {
 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
 97func (c *Committee) ApproveContribution(id int, option string) bool {
 98	if !c.isMember(runtime.OriginCaller()) {
 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(runtime.OriginCaller(), 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
133func (c *Committee) isMember(m address) bool {
134	for _, member := range c.members {
135		if m == member {
136			return true
137		}
138	}
139	return false
140}