Search Apps Documentation Source Content File Folder Download Copy Actions Download

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() }