1package upgradeable23import "strings"45// 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 the8// realm holding the Proxy. When a transaction is sent straight to that realm9// the caller is a user: pkgPath is empty and addr is the signer. When the10// call arrives through another realm, say a DAO executing a proposal, pkgPath11// names that realm and addr is the realm's own address.12//13// Both halves are passed because the two authorization styles on gno.land14// read different ones: an owner check compares addresses, a governance check15// compares realm paths. An implementation must read the half it means and16// ignore the other. In particular an empty pkgPath is not a realm -- it is17// every user call -- so a path check must reject it explicitly.18type Authority interface {19 Authorized(addr address, pkgPath string) bool20 String() string21}2223// AddrAuthority authorizes exactly one address: the signer of a direct call,24// or a realm acting at that address.25type AddrAuthority struct {26 addr address27}2829// 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}3637func (a *AddrAuthority) Authorized(addr address, _ string) bool {38 return a != nil && addr.IsValid() && addr == a.addr39}4041// Address returns the authorized address.42func (a *AddrAuthority) Address() address {43 if a == nil {44 return ""45 }46 return a.addr47}4849func (a *AddrAuthority) String() string {50 if a == nil {51 return "addr:<nil>"52 }53 return "addr:" + a.addr.String()54}5556// RealmAuthority authorizes a fixed set of realm paths, the shape r/gov/dao57// uses: a governance realm executes the upgrade, and the proxy recognizes it58// 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 []string65}6667// NewRealmAuthority returns an Authority holding paths. It panics on an empty68// list rather than authorizing nobody, and on a blank or padded entry rather69// 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}8485func (a *RealmAuthority) Authorized(_ address, pkgPath string) bool {86 if a == nil || pkgPath == "" {87 return false88 }89 for _, p := range a.paths {90 if p == pkgPath {91 return true92 }93 }94 return false95}9697// Paths returns a copy of the authorized realm paths.98func (a *RealmAuthority) Paths() []string {99 if a == nil {100 return nil101 }102 dup := make([]string, len(a.paths))103 copy(dup, a.paths)104 return dup105}106107func (a *RealmAuthority) String() string {108 if a == nil {109 return "realms:<nil>"110 }111 return "realms:" + strings.Join(a.paths, ",")112}113114// AnyOf authorizes a caller that any of its members authorizes. It is the115// handover shape for the common case: hold an address authority while you are116// still deploying, add the governance realm, drop the address later.117type AnyOf struct {118 auths []Authority119}120121// NewAnyOf returns an Authority satisfied by any of auths. It panics on an122// empty list or a nil member, both of which would silently weaken or void123// 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}137138func (a *AnyOf) Authorized(addr address, pkgPath string) bool {139 if a == nil {140 return false141 }142 for _, sub := range a.auths {143 if sub.Authorized(addr, pkgPath) {144 return true145 }146 }147 return false148}149150func (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}160Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.