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

admin.gno

3.22 Kb · 133 lines
  1package admin
  2
  3import (
  4	"chain"
  5	"chain/runtime/unsafe"
  6
  7	"gno.land/p/akkadia/beta/accesscontrol"
  8)
  9
 10const (
 11	TransferAdminEvent  = "TransferAdmin"
 12	AcceptAdminEvent    = "AcceptAdmin"
 13	CancelAdminEvent    = "CancelAdmin"
 14	SetExplorerURLEvent = "SetExplorerURL"
 15)
 16
 17var (
 18	admin        address
 19	pendingAdmin address
 20	explorerURL  string = "https://app.beta.akkadia.land"
 21)
 22
 23func init() {
 24	caller := unsafe.OriginCaller()
 25	admin = caller
 26}
 27
 28func GetAdmin() address {
 29	return admin
 30}
 31
 32func GetPendingAdmin() address {
 33	return pendingAdmin
 34}
 35
 36func TransferAdmin(cur realm, newAdmin address) {
 37	assertTransferAdminCaller(0, cur)
 38	assertValidAddress(newAdmin)
 39	if pendingAdmin.IsValid() {
 40		panic("pending admin transfer already exists")
 41	}
 42
 43	pendingAdmin = newAdmin
 44
 45	chain.Emit(
 46		TransferAdminEvent,
 47		"from", admin.String(),
 48		"to", newAdmin.String(),
 49	)
 50}
 51
 52func assertTransferAdminCaller(_ int, rlm realm) {
 53	if !admin.IsValid() {
 54		// The admin realm normally initializes admin from OriginCaller during
 55		// package deployment, so a live on-chain admin should be a valid address.
 56		// An empty admin is a bootstrap-only state observed by cross-package tests:
 57		// dependent realm tests can import admin before a real deploy signer exists,
 58		// leaving admin as address(""). In that state there is no valid user address
 59		// that can satisfy direct caller authorization, so requiring AssertIsAdmin
 60		// would make those tests unable to promote a real test admin at all.
 61		//
 62		// Keep the legacy OriginCaller check only for this invalid-admin bootstrap
 63		// state. This preserves the narrow test/bootstrap path where the current
 64		// placeholder admin is address(""), while ensuring that once a real admin is
 65		// accepted every subsequent admin transfer is direct-caller-only. In other
 66		// words, code-realm relays cannot borrow a valid admin signer's authority to
 67		// change pendingAdmin; the exception exists solely to escape the empty
 68		// imported-test initialization state.
 69		accesscontrol.AssertCurrentRealm(0, rlm)
 70		accesscontrol.AssertIsAdminOrigin(IsAdmin)
 71		return
 72	}
 73
 74	accesscontrol.AssertIsAdmin(0, rlm, IsAdmin)
 75}
 76
 77func AcceptAdmin(cur realm) {
 78	if !pendingAdmin.IsValid() {
 79		panic("invalid pending admin address")
 80	}
 81	caller := mustGetPendingAdminUserCaller(0, cur)
 82
 83	prevAdmin := admin
 84	admin = caller
 85	pendingAdmin = address("")
 86
 87	chain.Emit(
 88		AcceptAdminEvent,
 89		"from", prevAdmin.String(),
 90		"to", admin.String(),
 91	)
 92}
 93
 94func CancelAdminTransfer(cur realm) {
 95	accesscontrol.AssertIsAdmin(0, cur, IsAdmin)
 96	if !pendingAdmin.IsValid() {
 97		panic("invalid pending admin address")
 98	}
 99
100	canceledAdmin := pendingAdmin
101	pendingAdmin = address("")
102
103	chain.Emit(
104		CancelAdminEvent,
105		"admin", admin.String(),
106		"pendingAdmin", canceledAdmin.String(),
107	)
108}
109
110func IsAdmin(address address) bool {
111	return address == admin
112}
113
114// SetExplorerURL sets the explorer base URL (admin only)
115func SetExplorerURL(cur realm, url string) {
116	accesscontrol.AssertIsAdmin(0, cur, IsAdmin)
117
118	normalizedURL := normalizeExplorerURL(url)
119	oldURL := explorerURL
120	explorerURL = normalizedURL
121
122	chain.Emit(
123		SetExplorerURLEvent,
124		"admin", admin.String(),
125		"oldURL", oldURL,
126		"newURL", normalizedURL,
127	)
128}
129
130// GetExplorerURL returns the explorer base URL
131func GetExplorerURL() string {
132	return explorerURL
133}