Skip to content

Commit

Permalink
Merge branch 'main' into fix/refacto-form-logic-org-roles-based
Browse files Browse the repository at this point in the history
  • Loading branch information
clegirar committed Jan 14, 2025
2 parents 76ac5ef + eb8745e commit 130b9c4
Show file tree
Hide file tree
Showing 19 changed files with 981 additions and 163 deletions.
66 changes: 66 additions & 0 deletions gno/p/daocond/cond_and.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package daocond

import (
"gno.land/p/demo/json"
)

func And(left Condition, right Condition) Condition {
if left == nil || right == nil {
panic("left or right is nil")
}
return &andCond{left: left, right: right}
}

type andCond struct {
// XXX: use a slice instead of only two children?
left Condition
right Condition
}

// NewState implements Condition.
func (a *andCond) NewState() State {
return &andState{left: a.left.NewState(), right: a.right.NewState()}
}

// Render implements Condition.
func (a *andCond) Render() string {
return "[" + a.left.Render() + " AND " + a.right.Render() + "]"
}

// RenderJSON implements Condition.
func (a *andCond) RenderJSON() *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"type": json.StringNode("", "and"),
"left": a.left.RenderJSON(),
"right": a.right.RenderJSON(),
})
}

var _ Condition = (*andCond)(nil)

type andState struct {
left State
right State
}

// RenderJSON implements State.
func (a *andState) RenderJSON(votes map[string]Vote) *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"type": json.StringNode("", "and"),
"left": a.left.RenderJSON(votes),
"right": a.right.RenderJSON(votes),
})
}

// Eval implements State.
func (a *andState) Eval(votes map[string]Vote) bool {
return a.left.Eval(votes) && a.right.Eval(votes)
}

// HandleEvent implements State.
func (a *andState) HandleEvent(evt Event, votes map[string]Vote) {
a.left.HandleEvent(evt, votes)
a.right.HandleEvent(evt, votes)
}

var _ State = (*andState)(nil)
99 changes: 99 additions & 0 deletions gno/p/daocond/cond_members_threshold.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package daocond

import (
"errors"

"gno.land/p/demo/json"
"gno.land/p/demo/ufmt"
)

func MembersThreshold(threshold float64, isMemberFn func(memberId string) bool, membersCountFn func() uint64) Condition {
if threshold <= 0 || threshold > 1 {
panic(errors.New("invalid threshold"))
}
if isMemberFn == nil {
panic(errors.New("nil isMemberFn"))
}
if membersCountFn == nil {
panic(errors.New("nil membersCountFn"))
}
return &membersThresholdCond{
threshold: threshold,
isMemberFn: isMemberFn,
membersCountFn: membersCountFn,
}
}

type membersThresholdCond struct {
isMemberFn func(memberId string) bool
membersCountFn func() uint64
threshold float64
}

// NewState implements Condition.
func (m *membersThresholdCond) NewState() State {
return &membersThresholdState{
cond: m,
}
}

// Render implements Condition.
func (m *membersThresholdCond) Render() string {
return ufmt.Sprintf("%g%% of members", m.threshold*100)
}

// RenderJSON implements Condition.
func (m *membersThresholdCond) RenderJSON() *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"type": json.StringNode("", "members-threshold"),
"threshold": json.NumberNode("", m.threshold),
})
}

var _ Condition = (*membersThresholdCond)(nil)

type membersThresholdState struct {
cond *membersThresholdCond
totalYes uint64
}

// Eval implements State.
func (m *membersThresholdState) Eval(_ map[string]Vote) bool {
return float64(m.totalYes)/float64(m.cond.membersCountFn()) >= m.cond.threshold
}

// HandleEvent implements State.
func (m *membersThresholdState) HandleEvent(evt Event, votes map[string]Vote) {
switch evt := evt.(type) {
case *EventVote:
if !m.cond.isMemberFn(evt.VoterID) {
return
}
previousVote := votes[evt.VoterID]
if previousVote == VoteYes && evt.Vote != VoteYes {
m.totalYes -= 1
} else if previousVote != VoteYes && evt.Vote == VoteYes {
m.totalYes += 1
}

case *EventMemberAdded:
if votes[evt.MemberID] == VoteYes {
m.totalYes += 1
}

case *EventMemberRemoved:
if votes[evt.MemberID] == VoteYes {
m.totalYes -= 1
}
}
}

// RenderJSON implements State.
func (m *membersThresholdState) RenderJSON(_ map[string]Vote) *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"type": json.StringNode("", "members-threshold"),
"totalYes": json.NumberNode("", float64(m.totalYes)),
})
}

var _ State = (*membersThresholdState)(nil)
91 changes: 91 additions & 0 deletions gno/p/daocond/cond_members_threshold_few_votes.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package daocond

import (
"errors"

"gno.land/p/demo/json"
"gno.land/p/demo/ufmt"
)

func MembersThresholdFewVotes(threshold float64, isMemberFn func(memberId string) bool, membersCountFn func() uint64) Condition {
if threshold <= 0 || threshold > 1 {
panic(errors.New("invalid threshold"))
}
if isMemberFn == nil {
panic(errors.New("nil isMemberFn"))
}
if membersCountFn == nil {
panic(errors.New("nil membersCountFn"))
}
return &membersThresholdFewVotesCond{
threshold: threshold,
isMemberFn: isMemberFn,
membersCountFn: membersCountFn,
}
}

type membersThresholdFewVotesCond struct {
isMemberFn func(memberId string) bool
membersCountFn func() uint64
threshold float64
}

// NewState implements Condition.
func (m *membersThresholdFewVotesCond) NewState() State {
return &membersThresholdFewVotesState{
cond: m,
}
}

// Render implements Condition.
func (m *membersThresholdFewVotesCond) Render() string {
return ufmt.Sprintf("%g%% of members", m.threshold*100)
}

// RenderJSON implements Condition.
func (m *membersThresholdFewVotesCond) RenderJSON() *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"type": json.StringNode("", "members-threshold"),
"threshold": json.NumberNode("", m.threshold),
})
}

var _ Condition = (*membersThresholdFewVotesCond)(nil)

type membersThresholdFewVotesState struct {
cond *membersThresholdFewVotesCond
}

func (m *membersThresholdFewVotesState) totalYes(votes map[string]Vote) uint64 {
totalYes := uint64(0)
for userId, vote := range votes {
if vote != VoteYes {
continue
}
if !m.cond.isMemberFn(userId) {
continue
}
totalYes += 1
}
return totalYes
}

// Eval implements State.
func (m *membersThresholdFewVotesState) Eval(votes map[string]Vote) bool {
return float64(m.totalYes(votes))/float64(m.cond.membersCountFn()) >= m.cond.threshold
}

// HandleEvent implements State.
func (m *membersThresholdFewVotesState) HandleEvent(_ Event, _ map[string]Vote) {
panic(errors.New("not implemented"))
}

// RenderJSON implements State.
func (m *membersThresholdFewVotesState) RenderJSON(votes map[string]Vote) *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"type": json.StringNode("", "members-threshold"),
"totalYes": json.NumberNode("", float64(m.totalYes(votes))),
})
}

var _ State = (*membersThresholdFewVotesState)(nil)
66 changes: 66 additions & 0 deletions gno/p/daocond/cond_or.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package daocond

import (
"gno.land/p/demo/json"
)

func Or(left Condition, right Condition) Condition {
if left == nil || right == nil {
panic("left or right is nil")
}
return &orCond{left: left, right: right}
}

type orCond struct {
// XXX: use a slice instead of only two children?
left Condition
right Condition
}

// NewState implements Condition.
func (a *orCond) NewState() State {
return &orState{left: a.left.NewState(), right: a.right.NewState()}
}

// Render implements Condition.
func (a *orCond) Render() string {
return "[" + a.left.Render() + " OR " + a.right.Render() + "]"
}

// RenderJSON implements Condition.
func (a *orCond) RenderJSON() *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"type": json.StringNode("", "or"),
"left": a.left.RenderJSON(),
"right": a.right.RenderJSON(),
})
}

var _ Condition = (*andCond)(nil)

type orState struct {
left State
right State
}

// Eval implements State.
func (a *orState) Eval(votes map[string]Vote) bool {
return a.left.Eval(votes) || a.right.Eval(votes)
}

// HandleEvent implements State.
func (a *orState) HandleEvent(evt Event, votes map[string]Vote) {
a.left.HandleEvent(evt, votes)
a.right.HandleEvent(evt, votes)
}

// RenderJSON implements State.
func (a *orState) RenderJSON(votes map[string]Vote) *json.Node {
return json.ObjectNode("", map[string]*json.Node{
"type": json.StringNode("", "and"),
"left": a.left.RenderJSON(votes),
"right": a.right.RenderJSON(votes),
})
}

var _ State = (*orState)(nil)
Loading

0 comments on commit 130b9c4

Please sign in to comment.