← Back to Realms

Realm

gno.land/r/samcrew/memba_reviews_v2

Overview

Realm Path
gno.land/r/samcrew/memba_reviews_v2
Exported Functions
23
State Entries
20
Source Files
5
Total Package Entries
70

Exported Functions

23 exported functions

State

20 state entries

Source Code

FILES
admin.gno
go
1package memba_reviews_v2
2
3// Moderator authority and its rotation path.
4//
5// No moderator is compiled in: `moderator` below is seeded at package load from
6// the publishing transaction's signer (on gnoland-1 the samcrew namespace
7// multisig, the stamped creator at enable time), and assertModerator reads the
8// mutable `moderator`, so the address holding moderation can be changed after
9// deployment.
10//
11// WHY THIS MATTERS ON MAINNET. Realms are immutable once published, there is no
12// faucet, and mainnet genesis locks ugnot transfers under Constitution §126 — so
13// a compile-time moderator cannot be corrected after the fact: a testnet key
14// compiled in would permanently disable HideTarget/UnhideTarget/ClearFlags,
15// leaving this realm with no way to act on a flagged review ever again.
16//
17// TWO-STEP BY DESIGN: the successor must claim the role with its own transaction,
18// so moderation can never be handed to an address that cannot transact (a typo,
19// or an unfunded address under §126) with no way back.
20//
21// CALLER AUTH here uses `cur.IsCurrent()` + `cur.Previous().Address()`, per
22// contract-review checklist #9, matching memba_arcade_leaderboard_v1 /
23// memba_points_v1. The realm's existing assertModerator keeps its older
24// frame-unverified caller read (grandfathered in
25// antipattern-prevrealm-baseline.txt); only the value it compares against
26// changed, which is the smallest edit that removes the immutability.
27
28import "chain"
29
30var (
31	// moderator is the LIVE authority, seeded with the publisher at package load.
32	// Initialized at declaration so there is no init-ordering question about
33	// gates that read it.
34	moderator address = publisherAtLoad()
35
36	// pendingModerator is the staged successor; "" when none is in flight.
37	pendingModerator address
38)
39
40// TransferOwnership stages a handoff of the moderator role. Moderator only; it
41// takes effect only once newModerator calls AcceptOwnership. Calling it again
42// before acceptance replaces the staged address, which is how a mistyped
43// proposal is corrected.
44func TransferOwnership(cur realm, newModerator address) {
45	assertModeratorCur(cur)
46	if newModerator == "" {
47		panic("newModerator must be non-empty")
48	}
49	if !newModerator.IsValid() {
50		panic("invalid address: " + newModerator.String())
51	}
52	if newModerator == moderator {
53		panic("newModerator is the current moderator")
54	}
55	pendingModerator = newModerator
56	chain.Emit("OwnershipTransferStarted", "pending", newModerator.String())
57}
58
59// AcceptOwnership completes the handoff. Only the staged pendingModerator may
60// call it — including against the outgoing moderator, so the two steps cannot be
61// collapsed into one by the party giving up the role.
62func AcceptOwnership(cur realm) {
63	if !cur.IsCurrent() {
64		panic("spoofed realm")
65	}
66	if pendingModerator == "" {
67		panic("no pending ownership transfer")
68	}
69	if cur.Previous().Address() != pendingModerator {
70		panic("unauthorized: only the pending moderator may accept")
71	}
72	moderator = pendingModerator
73	pendingModerator = ""
74	chain.Emit("OwnershipTransferAccepted", "moderator", moderator.String())
75}
76
77// CancelOwnershipTransfer clears a staged handoff. Moderator only, so a
78// proposal can be aborted without the proposed address cooperating.
79func CancelOwnershipTransfer(cur realm) {
80	assertModeratorCur(cur)
81	if pendingModerator == "" {
82		panic("no pending ownership transfer")
83	}
84	cancelled := pendingModerator
85	pendingModerator = ""
86	chain.Emit("OwnershipTransferCancelled", "cancelled", cancelled.String())
87}
88
89// GetModerator returns the address that currently holds moderation.
90func GetModerator() string { return moderator.String() }
91
92// GetPendingModerator returns the staged successor ("" when none).
93func GetPendingModerator() string { return pendingModerator.String() }
94
95// assertModeratorCur is the gate for this file's entrypoints. Named apart from
96// the realm's existing assertModerator so the older call sites keep their
97// signature and semantics untouched.
98func assertModeratorCur(cur realm) {
99	if !cur.IsCurrent() {
100		panic("spoofed realm")
101	}
102	if cur.Previous().Address() != moderator {
103		panic("unauthorized: moderator multisig only")
104	}
105}
106

Raw Package Data

Raw JSON data