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.

profile.gno

3.04 Kb · 162 lines
  1// Package profile is the Shoal sailor card. One address has one username.
  2// This realm holds no ugnot. It does not mint FISH and it does not mint a fish NFT.
  3package profile
  4
  5import (
  6	"chain"
  7	"chain/runtime/unsafe"
  8)
  9
 10type card struct {
 11	username string
 12	country  string
 13	crest    string
 14}
 15
 16var (
 17	byAddr map[address]*card
 18	byName map[string]address
 19)
 20
 21func SetProfile(cur realm, username, country, crest string) {
 22	caller := requireUser(cur)
 23	takeExact(0)
 24	name := cleanUser(username)
 25	if name == "" {
 26		panic("profile: name")
 27	}
 28	if !knownCountry(country) {
 29		panic("profile: country")
 30	}
 31	if !knownCrest(crest) {
 32		panic("profile: crest")
 33	}
 34	ensure()
 35	if owner, ok := byName[name]; ok && owner != caller {
 36		panic("profile: taken")
 37	}
 38	prev := byAddr[caller]
 39	if prev != nil && prev.username == name && prev.country == country && prev.crest == crest {
 40		return
 41	}
 42	if prev != nil && prev.username != name {
 43		delete(byName, prev.username)
 44	}
 45	byAddr[caller] = &card{username: name, country: country, crest: crest}
 46	byName[name] = caller
 47	chain.Emit("SetProfile", "who", caller.String(), "username", name, "country", country, "crest", crest)
 48}
 49
 50func Has(cur realm, who address) bool {
 51	takeExact(0)
 52	return cardOf(who) != nil
 53}
 54
 55func UsernameOf(cur realm, who address) string {
 56	takeExact(0)
 57	body := cardOf(who)
 58	if body == nil {
 59		return ""
 60	}
 61	return body.username
 62}
 63
 64func CountryOf(cur realm, who address) string {
 65	takeExact(0)
 66	body := cardOf(who)
 67	if body == nil {
 68		return ""
 69	}
 70	return body.country
 71}
 72
 73func CrestOf(cur realm, who address) string {
 74	takeExact(0)
 75	body := cardOf(who)
 76	if body == nil {
 77		return ""
 78	}
 79	return body.crest
 80}
 81
 82func AddressOf(cur realm, username string) address {
 83	takeExact(0)
 84	name := cleanUser(username)
 85	if name == "" || byName == nil {
 86		return address("")
 87	}
 88	return byName[name]
 89}
 90
 91func requireUser(cur realm) address {
 92	if !cur.Previous().IsUserCall() {
 93		panic("profile: eoa")
 94	}
 95	return cur.Previous().Address()
 96}
 97
 98func takeExact(n int64) {
 99	sent := unsafe.OriginSend()
100	if n == 0 {
101		if len(sent) != 0 {
102			panic("profile: payment")
103		}
104		return
105	}
106	panic("profile: payment")
107}
108
109func ensure() {
110	if byAddr == nil {
111		byAddr = make(map[address]*card)
112	}
113	if byName == nil {
114		byName = make(map[string]address)
115	}
116}
117
118func cardOf(who address) *card {
119	if byAddr == nil || !who.IsValid() {
120		return nil
121	}
122	return byAddr[who]
123}
124
125func cleanUser(name string) string {
126	for len(name) > 0 && name[0] == ' ' {
127		name = name[1:]
128	}
129	for len(name) > 0 && name[len(name)-1] == ' ' {
130		name = name[:len(name)-1]
131	}
132	if len(name) < 3 || len(name) > 16 {
133		return ""
134	}
135	out := ""
136	for _, c := range name {
137		if c >= 'A' && c <= 'Z' {
138			c = c - 'A' + 'a'
139		}
140		if (c < 'a' || c > 'z') && (c < '0' || c > '9') {
141			return ""
142		}
143		out += string(c)
144	}
145	return out
146}
147
148func knownCountry(s string) bool {
149	switch s {
150	case "Sea", "Vietnam", "Korea", "Japan", "Brazil", "France", "Nigeria", "Canada", "Australia":
151		return true
152	}
153	return false
154}
155
156func knownCrest(s string) bool {
157	switch s {
158	case "wave", "reef", "moon", "sun", "fang", "shell":
159		return true
160	}
161	return false
162}