admin.gno
3.28 Kb · 100 lines
1package memba_nft_market_v3_2
2
3// Admin operations — multisig-gated controls.
4//
5// assertAdmin() is the single authorization gate; caller = unsafe.PreviousRealm().Address().
6// AdminDelist is pause-exempt (moderation can always remove content).
7// SetFeeRecipient changes where platform fees flow (default = AdminAddress).
8
9import (
10 "chain"
11 "chain/runtime/unsafe"
12
13 "gno.land/p/samcrew/grc721"
14)
15
16func assertAdmin() {
17 if unsafe.PreviousRealm().Address() != owner {
18 panic("admin only")
19 }
20}
21
22// Pause halts new trade operations (ListNFT, BuyNFT, MakeOffer, AcceptOffer).
23// Value-exit paths (DelistNFT, CancelOffer, ClaimExpiredOffer) remain available.
24func Pause(cur realm) {
25 assertAdmin()
26 paused = true
27 chain.Emit("MarketPaused", "by", unsafe.PreviousRealm().Address().String())
28}
29
30// Unpause resumes normal operations.
31func Unpause(cur realm) {
32 assertAdmin()
33 paused = false
34 chain.Emit("MarketUnpaused", "by", unsafe.PreviousRealm().Address().String())
35}
36
37// AdminDelist force-removes any listing. Pause-exempt (moderation).
38func AdminDelist(cur realm, collectionID string, tid grc721.TokenID) {
39 assertAdmin()
40 key := listingKey(collectionID, string(tid))
41 if _, exists := listings.Get(key); !exists {
42 panic("not listed: " + key)
43 }
44 listings.Remove(key)
45 removeFromOrder(key)
46 chain.Emit("AdminDelisted",
47 "collection", collectionID,
48 "tokenId", string(tid),
49 "admin", unsafe.PreviousRealm().Address().String(),
50 )
51}
52
53// SetFeeRecipient updates the address that receives platform fees. Rejects the
54// empty address: resolveFee falls back to feeRecipient when the DAO config
55// treasury is unset, and a fee send to "" panics — with both unset, every
56// trade with a nonzero fee would revert (fat-finger brick, pre-deploy review).
57func SetFeeRecipient(cur realm, addr address) {
58 assertAdmin()
59 if addr == "" {
60 panic("fee recipient must be non-empty")
61 }
62 feeRecipient = addr
63 chain.Emit("FeeRecipientChanged", "newRecipient", addr.String())
64}
65
66// ── Ownership (2-step, pre-deploy review) ─────────────────────────────────────
67//
68// The admin used to be a hard-coded constant — on an immutable realm that means
69// the engine could never be handed to a DAO executor without a full redeploy.
70// 2-step transfer (stage + accept) so a typo can't brick admin.
71
72// TransferOwnership stages a new owner; it takes effect only after AcceptOwnership
73// is called BY that address.
74func TransferOwnership(cur realm, newOwner address) {
75 assertAdmin()
76 if newOwner == "" {
77 panic("newOwner must be non-empty")
78 }
79 pendingOwner = newOwner
80 chain.Emit("OwnershipTransferStarted", "pending", newOwner.String())
81}
82
83// AcceptOwnership completes the handoff. Only the staged pendingOwner may call it.
84func AcceptOwnership(cur realm) {
85 if pendingOwner == "" {
86 panic("no pending ownership transfer")
87 }
88 if unsafe.PreviousRealm().Address() != pendingOwner {
89 panic("unauthorized: only the pending owner may accept")
90 }
91 owner = pendingOwner
92 pendingOwner = ""
93 chain.Emit("OwnershipTransferAccepted", "owner", owner.String())
94}
95
96// GetOwner returns the current admin address.
97func GetOwner() string { return owner.String() }
98
99// GetPendingOwner returns the staged owner ("" when no transfer is pending).
100func GetPendingOwner() string { return pendingOwner.String() }