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

config.gno

4.20 Kb · 115 lines
  1// Package config is the one realm moul's other realms read their settings
  2// from: a key/value store plus the manager list that decides who may write it.
  3//
  4// # Why a realm and not a constant
  5//
  6// A value shared by several contracts, hardcoded in each, is changed by
  7// redeploying each. On mainnet a public realm cannot even be redeployed at its
  8// own path, so "changing it" means a new version and a new path for every
  9// consumer. Here it is a transaction.
 10//
 11// # Bump rarely, and never for a new setting
 12//
 13// This realm IS public and versioned, so its path moves on every bump. That
 14// makes a bump expensive, which is exactly why the settings API is generic: a
 15// new setting is a new KEY, and a key costs one transaction. Only a change to
 16// the shape of this realm (a new function, a changed signature) is worth a
 17// version.
 18//
 19// # When a bump does happen, the state does not move
 20//
 21// A later version imports this one and relays to it rather than holding
 22// anything of its own, so v1, v2 and v3 all read and write the same settings,
 23// the same pause and the same member list. Delegation only runs backwards in
 24// time, which is why the root is the oldest version that has the state and not
 25// the newest. See proxy.gno.
 26//
 27// # What lives here
 28//
 29// settings.gno  the key/value store, and the mygnoscan accessors over it
 30// keys.gno      the key grammar: a name, optionally scoped to one realm
 31// blocks.gno    the notice a realm renders above and below its content
 32// pause.gno     the switch a realm checks before it acts
 33// proxy.gno     the relay that lets a later version share this state
 34// config.gno    the member list, unchanged from v0
 35//
 36// # Governance
 37//
 38// init seeds the authority with the deploying EOA. Everything that writes goes
 39// through Authorizer, so transferring authority to a DAO transfers the
 40// settings with it: there is no address hardcoded on the write path.
 41package config
 42
 43import (
 44	"errors"
 45
 46	"gno.land/p/moul/authz/v0"
 47)
 48
 49var Authorizer *authz.Authorizer
 50
 51func init(cur realm) {
 52	if !cur.Previous().IsUserCall() {
 53		panic("r/moul/config must be initialized by an EOA")
 54	}
 55	Authorizer = authz.NewWithMembers(cur.Previous().Address())
 56}
 57
 58// AddManager adds a new address to the list of authorized managers.
 59// This only works if the current authority is a MemberAuthority.
 60// The caller must be authorized by the current authority.
 61func AddManager(cur realm, addr address) error {
 62	memberAuth, ok := Authorizer.Authority().(*authz.MemberAuthority)
 63	if !ok {
 64		return errors.New("current authority is not a MemberAuthority, cannot add manager directly")
 65	}
 66	return memberAuth.AddMember(0, cur, addr)
 67}
 68
 69// RemoveManager removes an address from the list of authorized managers.
 70// This only works if the current authority is a MemberAuthority.
 71// The caller must be authorized by the current authority.
 72func RemoveManager(cur realm, addr address) error {
 73	memberAuth, ok := Authorizer.Authority().(*authz.MemberAuthority)
 74	if !ok {
 75		return errors.New("current authority is not a MemberAuthority, cannot remove manager directly")
 76	}
 77	return memberAuth.RemoveMember(0, cur, addr)
 78}
 79
 80// TransferManagement transfers the authority to manage keys to a new authority.
 81// The caller must be authorized by the current authority.
 82func TransferManagement(cur realm, newAuthority authz.Authority) error {
 83	if newAuthority == nil {
 84		return errors.New("new authority cannot be nil")
 85	}
 86	return Authorizer.Transfer(0, cur, newAuthority)
 87}
 88
 89// ListManagers returns a slice of all managed keys.
 90func ListManagers(cur realm) []address {
 91	var keyList []address
 92	memberAuth, ok := Authorizer.Authority().(*authz.MemberAuthority)
 93	if !ok {
 94		return keyList
 95	}
 96	tree := memberAuth.Tree()
 97	if !ok || tree == nil {
 98		return keyList // Return empty list if tree is not as expected or nil
 99	}
100	tree.Iterate("", "", func(key string, _ any) bool {
101		keyList = append(keyList, address(key))
102		return false
103	})
104	return keyList
105}
106
107func HasManager(cur realm, addr address) bool {
108	memberAuth, ok := Authorizer.Authority().(*authz.MemberAuthority)
109	if !ok {
110		return false // Return false if not a MemberAuthority or doesn't exist
111	}
112	// Use the MemberAuthority's specific RemoveMember method,
113	// which internally performs the authorization check.
114	return memberAuth.Has(addr)
115}