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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

authority.gno

4.27 Kb · 159 lines
  1package upgradeable
  2
  3import "strings"
  4
  5// Authority decides who may change what a [Proxy] points at.
  6//
  7// It is handed the identity of the caller -- the realm that crossed into the
  8// realm holding the Proxy. When a transaction is sent straight to that realm
  9// the caller is a user: pkgPath is empty and addr is the signer. When the
 10// call arrives through another realm, say a DAO executing a proposal, pkgPath
 11// names that realm and addr is the realm's own address.
 12//
 13// Both halves are passed because the two authorization styles on gno.land
 14// read different ones: an owner check compares addresses, a governance check
 15// compares realm paths. An implementation must read the half it means and
 16// ignore the other. In particular an empty pkgPath is not a realm -- it is
 17// every user call -- so a path check must reject it explicitly.
 18type Authority interface {
 19	Authorized(addr address, pkgPath string) bool
 20	String() string
 21}
 22
 23// AddrAuthority authorizes exactly one address: the signer of a direct call,
 24// or a realm acting at that address.
 25type AddrAuthority struct {
 26	addr address
 27}
 28
 29// NewAddrAuthority returns an Authority holding addr.
 30func NewAddrAuthority(addr address) *AddrAuthority {
 31	if !addr.IsValid() {
 32		panic(ErrBadAddress)
 33	}
 34	return &AddrAuthority{addr: addr}
 35}
 36
 37func (a *AddrAuthority) Authorized(addr address, _ string) bool {
 38	return a != nil && addr.IsValid() && addr == a.addr
 39}
 40
 41// Address returns the authorized address.
 42func (a *AddrAuthority) Address() address {
 43	if a == nil {
 44		return ""
 45	}
 46	return a.addr
 47}
 48
 49func (a *AddrAuthority) String() string {
 50	if a == nil {
 51		return "addr:<nil>"
 52	}
 53	return "addr:" + a.addr.String()
 54}
 55
 56// RealmAuthority authorizes a fixed set of realm paths, the shape r/gov/dao
 57// uses: a governance realm executes the upgrade, and the proxy recognizes it
 58// by the path it was deployed at rather than by an address.
 59//
 60// More than one path is allowed so that authority can be moved without a gap:
 61// list both the old and the new governance realm, let the new one take over,
 62// then narrow the list.
 63type RealmAuthority struct {
 64	paths []string
 65}
 66
 67// NewRealmAuthority returns an Authority holding paths. It panics on an empty
 68// list rather than authorizing nobody, and on a blank or padded entry rather
 69// than storing one that can never match a caller -- or, for a blank one,
 70// matches every user call.
 71func NewRealmAuthority(paths ...string) *RealmAuthority {
 72	if len(paths) == 0 {
 73		panic(ErrNoAuthority)
 74	}
 75	out := make([]string, 0, len(paths))
 76	for _, p := range paths {
 77		if p == "" || p != strings.TrimSpace(p) {
 78			panic(ErrBadRealmPath)
 79		}
 80		out = append(out, p)
 81	}
 82	return &RealmAuthority{paths: out}
 83}
 84
 85func (a *RealmAuthority) Authorized(_ address, pkgPath string) bool {
 86	if a == nil || pkgPath == "" {
 87		return false
 88	}
 89	for _, p := range a.paths {
 90		if p == pkgPath {
 91			return true
 92		}
 93	}
 94	return false
 95}
 96
 97// Paths returns a copy of the authorized realm paths.
 98func (a *RealmAuthority) Paths() []string {
 99	if a == nil {
100		return nil
101	}
102	dup := make([]string, len(a.paths))
103	copy(dup, a.paths)
104	return dup
105}
106
107func (a *RealmAuthority) String() string {
108	if a == nil {
109		return "realms:<nil>"
110	}
111	return "realms:" + strings.Join(a.paths, ",")
112}
113
114// AnyOf authorizes a caller that any of its members authorizes. It is the
115// handover shape for the common case: hold an address authority while you are
116// still deploying, add the governance realm, drop the address later.
117type AnyOf struct {
118	auths []Authority
119}
120
121// NewAnyOf returns an Authority satisfied by any of auths. It panics on an
122// empty list or a nil member, both of which would silently weaken or void
123// the check.
124func NewAnyOf(auths ...Authority) *AnyOf {
125	if len(auths) == 0 {
126		panic(ErrNoAuthority)
127	}
128	out := make([]Authority, 0, len(auths))
129	for _, a := range auths {
130		if a == nil {
131			panic(ErrNoAuthority)
132		}
133		out = append(out, a)
134	}
135	return &AnyOf{auths: out}
136}
137
138func (a *AnyOf) Authorized(addr address, pkgPath string) bool {
139	if a == nil {
140		return false
141	}
142	for _, sub := range a.auths {
143		if sub.Authorized(addr, pkgPath) {
144			return true
145		}
146	}
147	return false
148}
149
150func (a *AnyOf) String() string {
151	if a == nil {
152		return "anyOf:<nil>"
153	}
154	parts := make([]string, 0, len(a.auths))
155	for _, sub := range a.auths {
156		parts = append(parts, sub.String())
157	}
158	return "anyOf(" + strings.Join(parts, " ") + ")"
159}