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  }