Search Apps Documentation Source Content File Folder Download Copy Actions Download

users.gno

3.04 Kb · 86 lines
 1package namereg
 2
 3import (
 4	"chain"
 5	"chain/banker"
 6	"chain/runtime"
 7
 8	"gno.land/p/moul/fifo"
 9	susers "gno.land/r/sys/users"
10)
11
12// MinRegisterPrice is the lowest price (in ugnot) that
13// ProposeNewRegisterPrice will accept. Set to 0 — registration is free
14// by default; governance can raise the price via ProposeNewRegisterPrice
15// without a floor.
16const MinRegisterPrice = int64(0)
17
18var (
19	registerPrice = int64(0)      // free by default; governance can raise via ProposeNewRegisterPrice
20	latestUsers   = fifo.New(100) // Save the latest 100 users for rendering purposes
21)
22
23// Register registers a new username for the caller.
24//
25// Valid usernames match `nym-[a-z]{5,13}\d{3}`:
26//   - literal `nym-` prefix (4 chars)
27//   - 5-13 lowercase letters (the alpha stem)
28//   - exactly 3 trailing decimal digits
29//
30// Total length 12-20 chars. The alpha stem additionally must NOT start
31// with `gno`/`gi`/`gl` and must not match a reserved role name (with
32// implicit `s`-suffix expansion). See ValidateNymFormat for the
33// format/blacklist check.
34//
35// Canonical-collision detection is enforced atomically by
36// susers.RegisterUser via the unified canonical store in r/sys/users
37// (decision: per Option B, every controller participates in the same
38// canonical-form lookup keyed by full canonical name).
39//
40// Only direct EOA (maketx call) invocations are supported.
41func Register(_ realm, username string) {
42	// Anti-squatting payment check, two paired guards:
43	//
44	//   (a) PreviousRealm must be a pure EOA (IsUserCall: pkgPath == "").
45	//       This excludes intermediate code realms AND user-run ephemeral
46	//       realms ("maketx run" scripts). Both can attach -send to the
47	//       tx but spend the coins on something other than forwarding to
48	//       this realm, leaving OriginSend() describing a phantom payment.
49	//       IsUserCall is the only PreviousRealm shape where the tx-send
50	//       envelope is guaranteed to have landed at this realm's address.
51	//
52	//   (b) OriginSend amount must exactly equal registerPrice. Verifies
53	//       the tx actually attached the expected amount.
54	//
55	// Both checks MUST run together. Removing (a) alone makes (b) meaningless
56	// because OriginSend() describes tx intent, not realm receipt.
57	if !runtime.PreviousRealm().IsUserCall() {
58		panic(ErrNonUserCall)
59	}
60
61	if paused {
62		panic(ErrPaused)
63	}
64
65	if banker.OriginSend().AmountOf("ugnot") != registerPrice {
66		panic(errInvalidPayment())
67	}
68
69	// Format + prefix + reserved-name check. ValidateNymFormat returns
70	// one of ErrInvalidFormat, ErrReservedPrefix, ErrBlacklisted.
71	if err := ValidateNymFormat(username); err != nil {
72		panic(err)
73	}
74
75	// Delegate the canonical-collision check + nameStore write atomically
76	// to r/sys/users. Returns susers.ErrCanonicalCollision if the
77	// canonical form clashes with an existing registration in any
78	// controller.
79	registrant := runtime.PreviousRealm().Address()
80	if err := susers.RegisterUser(cross, username, registrant); err != nil {
81		panic(err)
82	}
83
84	latestUsers.Append(username)
85	chain.Emit("Registration", "address", registrant.String(), "name", username)
86}