admin.gno
2.47 Kb · 79 lines
1package memba_arcade_leaderboard_v1
2
3import "chain"
4
5// Admin surface — owner-gated. The owner is the samcrew multisig at launch and can be handed to
6// the memba_dao executor via the 2-step TransferOwnership/AcceptOwnership (never a 1-step transfer
7// to a mistyped/dead address).
8
9// AddAttester allowlists an ADDRESS (the backend verifier's dedicated low-privilege key — never the
10// deploy multisig itself) as an authorized result source. Owner only.
11func AddAttester(cur realm, addr address) {
12 assertOwner(cur)
13 if addr == "" {
14 panic("attester address must be non-empty")
15 }
16 attesters.Set(addr.String(), true)
17 chain.Emit("AttesterAdded", "addr", addr.String())
18}
19
20// RemoveAttester revokes an attester key. Owner only.
21func RemoveAttester(cur realm, addr address) {
22 assertOwner(cur)
23 attesters.Remove(addr.String())
24 chain.Emit("AttesterRemoved", "addr", addr.String())
25}
26
27// Pause freezes all attestation + receipt requests (reads stay available). Owner only.
28func Pause(cur realm, state bool) {
29 assertOwner(cur)
30 paused = state
31 chain.Emit("PauseSet", "paused", boolStr(state))
32}
33
34// TransferOwnership stages a new owner; it takes effect only after AcceptOwnership is called BY
35// that address (2-step, so a typo can't brick admin).
36func TransferOwnership(cur realm, newOwner address) {
37 assertOwner(cur)
38 if newOwner == "" {
39 panic("newOwner must be non-empty")
40 }
41 if !newOwner.IsValid() {
42 panic("invalid address: " + newOwner.String())
43 }
44 if newOwner == owner {
45 panic("newOwner is the current owner")
46 }
47 pendingOwner = newOwner
48 chain.Emit("OwnershipTransferStarted", "pending", newOwner.String())
49}
50
51// CancelOwnershipTransfer withdraws a staged handoff. Owner only.
52func CancelOwnershipTransfer(cur realm) {
53 assertOwner(cur)
54 if pendingOwner == "" {
55 panic("no pending ownership transfer")
56 }
57 cancelled := pendingOwner
58 pendingOwner = ""
59 chain.Emit("OwnershipTransferCancelled", "pending", cancelled.String())
60}
61
62// GetPendingOwner returns the staged successor, or the empty address.
63func GetPendingOwner() address { return pendingOwner }
64
65// AcceptOwnership completes the handoff. Only the staged pendingOwner may call it.
66func AcceptOwnership(cur realm) {
67 if !cur.IsCurrent() {
68 panic("spoofed realm")
69 }
70 if pendingOwner == "" {
71 panic("no pending ownership transfer")
72 }
73 if cur.Previous().Address() != pendingOwner {
74 panic("unauthorized: only the pending owner may accept")
75 }
76 owner = pendingOwner
77 pendingOwner = ""
78 chain.Emit("OwnershipTransferAccepted", "owner", owner.String())
79}