initControllerPath
untyped stringValue
"gno.land/r/sys/users/init"
controllers
addrset.Set// caller whitelist
- OID
- 0ed754…0a6a:4
controllers details
init.2
func()- OID
- 0ed754…0a6a:6
init.2 details
AddControllerAtGenesis
func(addr .uverse.address)AddControllerAtGenesis allows adding a controller during chain genesis (height 0). This is mostly useful for testing.
- OID
- 0ed754…0a6a:8
AddControllerAtGenesis details
ProposeNewController
func(addr .uverse.address) dao.ProposalRequestProposeNewController allows GovDAO to add a whitelisted caller
- OID
- 0ed754…0a6a:9
ProposeNewController details
ProposeControllerRemoval
func(addr .uverse.address) dao.ProposalRequestProposeControllerRemoval allows GovDAO to add a whitelisted caller
- OID
- 0ed754…0a6a:10
ProposeControllerRemoval details
ProposeControllerAdditionAndRemoval
func(toAdd .uverse.address, toRemove .uverse.address) dao.ProposalRequestProposeControllerAdditionAndRemoval allows GovDAO to add a new caller and remove an old caller in the same proposal.
- OID
- 0ed754…0a6a:11
ProposeControllerAdditionAndRemoval details
applyControllerSwap
func(toAdd .uverse.address, toRemove .uverse.address) .uverse.errorapplyControllerSwap is the callback body of ProposeControllerAdditionAndRemoval, extracted so it can be unit-tested without driving the full GovDAO flow. The desired end state is "toAdd is in the whitelist AND toRemove is out". Both operations are made idempotent so the swap doesn't silently no-op when the chain state has drifted between proposal creation and execution: - If toAdd is already whitelisted, treat addToWhitelist's ErrAlreadyWhitelisted as benign and continue to the remove step. - If toRemove is already absent, treat deleteFromWhitelist's ErrNotWhitelisted as benign and return success. Without this idempotency, the original code returned early on an "already whitelisted" toAdd and skipped the remove entirely — a swap proposal could pass governance and silently leave the old controller active. (audit finding #6)
- OID
- 0ed754…0a6a:12
applyControllerSwap details
ProposeRegisterUser
func(name string, addr .uverse.address) dao.ProposalRequestProposeRegisterUser allows GovDAO to register a name without checking controllers. The executor closure runs with ignoreCanonical=true (decision #3): DAO grants always bypass canonical-collision detection. Voters see any collision in the proposal description and can vote NO if unintended.
- OID
- 0ed754…0a6a:13
ProposeRegisterUser details
ProposeUpdateName
func(addr .uverse.address, newName string) dao.ProposalRequestProposeUpdateName allows GovDAO to update a name with an alias without checking controllers. Like ProposeRegisterUser, the executor runs with ignoreCanonical=true (decision #3).
- OID
- 0ed754…0a6a:14
ProposeUpdateName details
ProposeDeleteUser
func(addr .uverse.address) dao.ProposalRequestProposeDeleteUser allows GovDAO to delete a user without checking controllers
- OID
- 0ed754…0a6a:15
ProposeDeleteUser details
IsController
func(addr .uverse.address) boolIsController reports whether the given address is currently in the controller whitelist. Returns the same boolean that gating checks (RegisterUser, UpdateName, Delete) use internally — useful for off-chain monitoring and for governance proposals to inspect state before voting.
- OID
- 0ed754…0a6a:16
IsController details
Controllers
func() [].uverse.address- OID
- 0ed754…0a6a:17
Controllers details
deleteFromWhitelist
func(addr .uverse.address) .uverse.error- OID
- 0ed754…0a6a:18
deleteFromWhitelist details
addToWhitelist
func(newCaller .uverse.address) .uverse.error- OID
- 0ed754…0a6a:19
addToWhitelist details
IsNameTaken
func(name string) boolIsNameTaken reports whether the exact-string name exists in nameStore. Returns true for any name ever registered, including: - active registrations - tombstoned (deleted) users' names — Delete() sets \`deleted=true\` but does not remove the nameStore entry (anti-revival policy) - old aliases from renames — UpdateName inserts the new name alongside the old; the old key stays (anti-rename-squat policy) In short: IsNameTaken(name) answers "would RegisterUser(name, \_) fail with ErrNameTaken?" — same answer for active, deleted, or aliased-away names. Pairs with IsCanonicalTaken (canonical-match) and ResolveName (active-current-user lookup with full UserData). No canonicalization is applied. For controllers that want exact- match uniqueness without pulling in canonical-collision logic.
- OID
- 0ed754…0a6a:20
IsNameTaken details
IsCanonicalTaken
func(name string) (existing string, taken bool)IsCanonicalTaken reports whether the given name's canonical form is already registered. Pass the raw name; canonicalization is applied internally. The first return is the original (non-canonical) name that owns the canonical key, for UX in collision messages. When a bypass write (RegisterUserIgnoreCanonical or the bypass path through ProposeRegisterUser/ProposeUpdateName) overwrites a prior canonical entry, this returns the most-recently-written original.
- OID
- 0ed754…0a6a:22
IsCanonicalTaken details
canonicalStore
*v0.BPTreecanonicalStore maps canonicalized full names to the original name that was registered. Keyed by the result of Canonicalize. Multiple controllers (namereg/v1, future registries, governance, genesis bootstrapping) all share this single store via RegisterUser and the bypass variant RegisterUserIgnoreCanonical. Cross-controller canonical-collision detection is uniform and atomic with the nameStore write.
- OID
- 0ed754…0a6a:24
canonicalStore details
Canonicalize
func(name string) stringCanonicalize returns the canonical form of a name. The substitutions collapse single-character visual confusables that arise across the allowed \[a-z0-9] character set, and strip the three separators that can sneak between identical alphanumeric runs. - {l, i, 1} → i - {0, o} → o - {-, ., \_} → stripped - all other characters unchanged CONTRACT: stable. Future controllers that want to share this canonical namespace MUST use this exact function — do not roll your own. Adding new substitutions later is a breaking change because it would silently re-key existing entries in canonicalStore. Input contract: ASCII-only. r/sys/users.validateName already rejects non-ASCII at the registration boundary, so by the time a name reaches Canonicalize through the standard write path it is guaranteed to be ASCII. Direct callers from other realms must honor this contract; non-ASCII bytes are passed through as-is and will produce undefined collision behavior. Multi-char confusables (m↔rn, nn↔m, cl↔d) are NOT canonicalized. They require fixed-point substring substitution rounds, which is out of scope for the unified store. Pure: no state access. Safe to call from anywhere.
- OID
- 0ed754…0a6a:26
Canonicalize details
prefix
untyped stringValue
"r/sys/users: "
ErrAlreadyWhitelisted
*errors.errorString- OID
- 0ed754…0a6a:29
ErrAlreadyWhitelisted details
ErrWhitelistRemoveFailed
*errors.errorString- OID
- 0ed754…0a6a:32
ErrWhitelistRemoveFailed details
ErrNameTaken
*errors.errorString- OID
- 0ed754…0a6a:35
ErrNameTaken details
ErrCanonicalCollision
*errors.errorString- OID
- 0ed754…0a6a:38
ErrCanonicalCollision details
ErrInvalidAddress
*errors.errorString- OID
- 0ed754…0a6a:41
ErrInvalidAddress details
ErrEmptyUsername
*errors.errorString- OID
- 0ed754…0a6a:44
ErrEmptyUsername details
ErrNameLikeAddress
*errors.errorString- OID
- 0ed754…0a6a:47
ErrNameLikeAddress details
ErrInvalidUsername
*errors.errorString- OID
- 0ed754…0a6a:50
ErrInvalidUsername details
ErrAlreadyHasName
*errors.errorString- OID
- 0ed754…0a6a:53
ErrAlreadyHasName details
ErrDeletedUser
*errors.errorString- OID
- 0ed754…0a6a:56
ErrDeletedUser details
ErrUserNotExistOrDeleted
*errors.errorString- OID
- 0ed754…0a6a:59
ErrUserNotExistOrDeleted details
ErrInvalidRealm
*errors.errorString- OID
- 0ed754…0a6a:62
ErrInvalidRealm details
ErrNotWhitelisted
typeErrNotWhitelisted stores the failing caller's realm identity as a plain string so the error is a pure data record (no live realm values in its fields).
Value
users.ErrNotWhitelisted
NewErrNotWhitelisted
func(int, caller .uverse.realm) users.ErrNotWhitelistedNewErrNotWhitelisted constructs the error with the caller's realm identity captured as a string at construction time. The \_ int discriminator keeps this non-crossing (a non-crossing function can't take a \`realm\`-named-\`cur\` first param, so we use the standard \_ int, rlm realm shape).
- OID
- 0ed754…0a6a:64
NewErrNotWhitelisted details
Render
func(string) string- OID
- 0ed754…0a6a:66
Render details
nameStore
*v0.BPTree// name/aliases > \*UserData
- OID
- 0ed754…0a6a:69
nameStore details
addressStore
*v0.BPTree// address > \*UserData
- OID
- 0ed754…0a6a:72
addressStore details
reAddressLookalike
*regexp.Regexp- OID
- 0ed754…0a6a:75
reAddressLookalike details
reName
*regexp.Regexp- OID
- 0ed754…0a6a:388
reName details
maxNameLen
untyped bigintValue
(64 <untyped> bigint)
RegisterUserEvent
untyped stringValue
"Registered"
UpdateNameEvent
untyped stringValue
"Updated"
DeleteUserEvent
untyped stringValue
"Deleted"
UserData
typeValue
users.UserData
registerUser
func(name string, address_XXX .uverse.address, ignoreCanonical bool) .uverse.errorregisterUser adds a new user to the system without checking controllers. The ignoreCanonical flag suppresses ErrCanonicalCollision; the canonical store is written either way (decision #14: later-wins on bypass).
- OID
- 0ed754…0a6a:458
registerUser details
RegisterUser
func(name string, address_XXX .uverse.address) .uverse.errorRegisterUser adds a new user to the system. Enforces canonical- collision detection: a name whose Canonicalize-form matches a prior registration returns ErrCanonicalCollision.
- OID
- 0ed754…0a6a:460
RegisterUser details
RegisterUserIgnoreCanonical
func(name string, address_XXX .uverse.address) .uverse.errorRegisterUserIgnoreCanonical is the bypass path: same controller- whitelist gate, but ErrCanonicalCollision is suppressed. The canonical store is still written; a prior entry with the same canonical key is silently overwritten (decision #14, later-wins). Use sparingly — names registered here can canonical-collide with existing ones, weakening confusable protection for everyone.
- OID
- 0ed754…0a6a:461
RegisterUserIgnoreCanonical details
validateName
func(username string) .uverse.errorValidate validates username and address passed in Most of the validation is done in the controllers This provides more flexibility down the line
- OID
- 0ed754…0a6a:462
validateName details
ResolveName
func(name string) (data *users.UserData, isCurrent bool)ResolveName returns the latest UserData of a specific user by name or alias
- OID
- 0ed754…0a6a:463
ResolveName details
ResolveAddress
func(addr .uverse.address) *users.UserDataResolveAddress returns the latest UserData of a specific user by address
- OID
- 0ed754…0a6a:465
ResolveAddress details
ResolveAny
func(input string) (*users.UserData, bool)ResolveAny tries to resolve any given string to \*UserData If the input is not found in the registry in any form, nil is returned
- OID
- 0ed754…0a6a:466
ResolveAny details
GetReadonlyAddrStore
func() *rotree.ReadOnlyTreeGetReadonlyAddrStore exposes the address store in readonly mode
- OID
- 0ed754…0a6a:467
GetReadonlyAddrStore details
GetReadOnlyNameStore
func() *rotree.ReadOnlyTreeGetReadOnlyNameStore exposes the name store in readonly mode
- OID
- 0ed754…0a6a:468
GetReadOnlyNameStore details
makeUserDataSafe
func(data interface{...}) interface{...}- OID
- 0ed754…0a6a:469