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