Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

badges_host.gno

3.67 Kb · 124 lines
  1package memba_weighted_host
  2
  3import "gno.land/p/samcrew/memba_weighted_policy"
  4
  5const BadgesMaxAdmins = 10
  6
  7// Admin bits are explicit grants. The current owner's authority to appoint is
  8// separate from those bits, but target ownership always installs an admin grant.
  9type BadgesState struct {
 10	Owner, PendingOwner                                address
 11	Paused                                             bool
 12	AdminCount                                         int
 13	OwnerAdmin, DAOAdmin, SuccessorAdmin, SubjectAdmin bool
 14}
 15type badgesProposal struct {
 16	action BadgesAction
 17	before BadgesState
 18}
 19
 20func badgesCommitment(a BadgesAction, s BadgesState) string {
 21	return a.Bytes() + "|before|" + badgesStateJSON(s)
 22}
 23func (h *Host) validateBadgesAuthority(s BadgesState) {
 24	if h.badgesPolicy == nil {
 25		panic("badges actions are not configured")
 26	}
 27	if !s.Owner.IsValid() || (s.PendingOwner != "" && !s.PendingOwner.IsValid()) || !s.OwnerAdmin || s.AdminCount < 1 || s.AdminCount > BadgesMaxAdmins {
 28		panic("invalid badges authority pre-state")
 29	}
 30}
 31func (h *Host) validateBadges(a BadgesAction, s BadgesState) {
 32	h.validateBadgesAuthority(s)
 33	a.Bytes()
 34	p := h.badgesPolicy
 35	if a.Subject() == "" && s.SubjectAdmin {
 36		panic("unexpected badges subject pre-state")
 37	}
 38	if a.Kind() == BadgesAcceptOwner {
 39		if s.Owner == p.DAO() || s.PendingOwner != p.DAO() {
 40			panic("DAO is not pending badges owner")
 41		}
 42		return
 43	}
 44	if s.Owner != p.DAO() || !s.DAOAdmin {
 45		panic("DAO is not badges owner/admin")
 46	}
 47	if a.Kind() == BadgesAbortReturn {
 48		if a.Recipient() != p.Successor() || s.PendingOwner != p.Successor() {
 49			panic("badges return does not match policy")
 50		}
 51		return
 52	}
 53	if s.PendingOwner != "" {
 54		panic("badges authority transfer is pending")
 55	}
 56	switch a.Kind() {
 57	case BadgesReturnOwner:
 58		if a.Recipient() != p.Successor() {
 59			panic("badges successor does not match policy")
 60		}
 61	case BadgesAddAdmin:
 62		p.AddAdmin(a.Subject())
 63		if s.SubjectAdmin {
 64			panic("badges admin grant is a no-op")
 65		}
 66		if s.AdminCount >= BadgesMaxAdmins {
 67			panic("badges admin limit reached")
 68		}
 69	case BadgesRemoveAdmin:
 70		if a.Subject() == s.Owner {
 71			panic("cannot remove badges owner admin")
 72		}
 73		if !s.SubjectAdmin {
 74			panic("badges admin removal is a no-op")
 75		}
 76	case BadgesUnpause:
 77		if !s.Paused {
 78			panic("badges unpause is a no-op")
 79		}
 80	default:
 81		panic("unsupported badges action")
 82	}
 83}
 84func (h *Host) ProposeBadges(a BadgesAction, s BadgesState, rlm realm) uint64 {
 85	who := assertCaller(h, rlm)
 86	h.validateBadges(a, s)
 87	p := &roleProposal{proposer: who, badges: &badgesProposal{action: a, before: s}}
 88	p.ballot = h.policy.NewProposal(a.Category(), badgesCommitment(a, s))
 89	h.addProposal(p)
 90	return uint64(len(h.proposals))
 91}
 92func (h *Host) invalidateBadgesPeers(cause string, id uint64) {
 93	members := []memba_weighted_policy.Member{}
 94	for _, seat := range h.seats {
 95		members = append(members, seat.Member)
 96	}
 97	h.policy.Reconfigure(members)
 98	h.recordInvalidation(cause, id, BadgesPath)
 99}
100func (h *Host) ConsumeBadges(id uint64, s BadgesState, rlm realm) BadgesAction {
101	assertCaller(h, rlm)
102	p := h.proposal(id)
103	if p.badges == nil {
104		panic("proposal is not a badges action")
105	}
106	h.validateBadges(p.badges.action, s)
107	p.ballot.Consume(badgesCommitment(p.badges.action, s))
108	h.invalidateBadgesPeers(InvalidatedByExecution, id)
109	return p.badges.action
110}
111func (h *Host) PrepareBadgesEmergencyPause(s BadgesState, rlm realm) {
112	assertCaller(h, rlm)
113	h.validateBadgesAuthority(s)
114	if s.Owner != h.badgesPolicy.DAO() || !s.DAOAdmin {
115		panic("DAO is not badges owner/admin")
116	}
117	if s.Paused {
118		panic("badges is already paused")
119	}
120	if s.SubjectAdmin {
121		panic("unexpected badges subject pre-state")
122	}
123	h.invalidateBadgesPeers(InvalidatedByPause, 0)
124}