Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

config.gno

4.21 Kb · 98 lines
 1// Package memba_market_config is the DAO-owned fee spine for the Memba marketplace.
 2// It is the single source of truth for the per-lane protocol fee (basis points) and
 3// the treasury that receives it. Every trade engine (NFT, services, token-OTC, agents)
 4// reads GetFeeBPS(lane) + GetTreasury() at settlement, so the DAO sets the rate ONCE
 5// and it applies everywhere — that shared read is what makes the lanes one marketplace.
 6//
 7// SAFETY (panel finding C1): the read getters are PURE and NON-FAILING — they never
 8// panic, and there is intentionally NO Pause(). A per-trade cross-realm read that
 9// could fail or halt would be a single point of failure able to brick every engine at
10// once; instead an engine always gets a usable, bounded value here and clamps locally,
11// while each engine keeps its OWN Pause() as the real kill switch. The fee is bounded
12// to [0, MaxFeeBPS] on write, so a reader can trust the bound without re-checking.
13package memba_market_config
14
15import (
16	"chain"
17	"chain/runtime/unsafe"
18
19	"gno.land/p/g1a9g8nu3m0xgx58hh36fph49e2xkqm9axlxuf5z/avl"
20)
21
22// No authority address is compiled in. The publishing transaction's signer (on
23// gnoland-1 the samcrew namespace multisig, the stamped creator at enable time)
24// is seeded as admin AND treasury at package load; the DAO takes over through the
25// two-step TransferAdmin/AcceptAdmin and repoints fees with SetTreasury.
26//
27// Under `gno test` every package is initialized with an empty origin caller, and
28// this realm is read cross-realm by every engine's test suite, so an empty seed
29// would leave the engines' fee-spine tests nothing to assert against. In that
30// one case the seed becomes unseededAuthority: a sub-address of this realm that
31// no code ever mints, so no on-chain caller can ever be it, while a test can
32// impersonate it with testing.NewUserRealm. On chain the origin caller at load
33// is never empty, so this branch is unreachable there.
34
35const (
36	// MaxFeeBPS is the 5% hard ceiling. SetFeeBPS rejects anything above it, so a
37	// fat-finger or a compromised proposal can never make a lane overcharge.
38	MaxFeeBPS = int64(500)
39	// DefaultFeeBPS is returned for an unset/unknown lane so engines always get a
40	// usable value (2.0%).
41	DefaultFeeBPS = int64(200)
42)
43
44var (
45	admin        address
46	pendingAdmin address
47	treasury     address
48	feeByLane    = avl.NewTree() // lane string -> int64 bps
49)
50
51// unseededAuthority is the test-VM stand-in for a publisher; see the note above.
52var unseededAuthority = chain.DerivePkgSubAddr("gno.land/r/g1a9g8nu3m0xgx58hh36fph49e2xkqm9axlxuf5z/memba_market_config", "unseeded")
53
54// seedAuthority makes the publisher admin and treasury. It runs once at load.
55func seedAuthority(publisher address) {
56	if publisher == "" {
57		publisher = unseededAuthority
58	}
59	admin = publisher
60	pendingAdmin = ""
61	treasury = publisher
62}
63
64func init() {
65	seedAuthority(unsafe.OriginCaller())
66	// Seed the launch lanes. "agent" is intentionally unset (TBD) and resolves to
67	// DefaultFeeBPS until the DAO sets it when that lane is built.
68	feeByLane.Set("nft", int64(200))     // 2.0%
69	feeByLane.Set("service", int64(200)) // 2.0% release fee (the 5% cancel fee is escrow-internal → freelancer)
70	feeByLane.Set("token", int64(50))    // 0.5% OTC — competitive vs DEX ~0.3%
71}
72
73func caller() address { return unsafe.PreviousRealm().Address() }
74
75// ── Read getters — PURE, NON-FAILING (never panic, no Pause) ──────────────────
76
77// GetFeeBPS returns the protocol fee in basis points for a lane. An unset or unknown
78// lane returns DefaultFeeBPS. The result is always within [0, MaxFeeBPS] (enforced on
79// write). Never panics — an engine must always be able to settle.
80func GetFeeBPS(lane string) int {
81	v, ok := feeByLane.Get(lane)
82	if !ok {
83		return int(DefaultFeeBPS)
84	}
85	return int(v.(int64))
86}
87
88// GetTreasury returns the address that receives the protocol fee on every lane.
89func GetTreasury() address { return treasury }
90
91// GetLaneConfig returns (feeBPS, treasury) in one read for an engine's settlement path.
92func GetLaneConfig(lane string) (int, address) {
93	return GetFeeBPS(lane), treasury
94}
95
96// GetAdmin returns the current admin (the multisig, or the memba_dao executor after
97// the 2-step handoff).
98func GetAdmin() address { return admin }