render.gno
5.38 Kb · 171 lines
1package pad
2
3import (
4 "strconv"
5 "strings"
6
7 "gno.land/p/g1mv0052e7r6s09f5t9xsqf00nj3tqsgt9dg52jr/gnomemepad/ammmath"
8 "gno.land/p/nt/ufmt/v0"
9)
10
11// Render provides on-chain discovery (gnoweb). Read-only by convention.
12//
13// Paths:
14//
15// "" — home / list
16// token/{id} — launch detail
17// help — API help
18func Render(path string) string {
19 path = strings.Trim(path, "/")
20 if path == "" {
21 return renderHome()
22 }
23 if path == "help" {
24 return renderHelp()
25 }
26 if strings.HasPrefix(path, "token/") {
27 id := strings.TrimPrefix(path, "token/")
28 return renderToken(id)
29 }
30 return "> [!WARNING]\n> Path not found: " + sanitize(path) + "\n"
31}
32
33func sanitize(s string) string {
34 s = strings.ReplaceAll(s, "`", "'")
35 s = strings.ReplaceAll(s, "<", "")
36 s = strings.ReplaceAll(s, ">", "")
37 return s
38}
39
40func renderHome() string {
41 out := "# gnomemepad\n\n"
42 out += "Self-contained meme launchpad on gno.land — bonding curve to locked CPMM (no external AMM).\n\n"
43 if !inited {
44 out += "> [!CAUTION]\n> Protocol not initialized. Call Init first.\n\n"
45 return out
46 }
47 out += ufmt.Sprintf("- Launches: **%d**\n", launches.Size())
48 out += ufmt.Sprintf("- Protocol fees accrued: **%d** ugnot\n\n", protocolFees)
49 out += "## Markets\n\n"
50 if launches.Size() == 0 {
51 out += "_No launches yet. Call Create with name, symbol, uri and bond._\n"
52 return out
53 }
54 launches.Iterate("", "", func(key string, value any) bool {
55 l := value.(*Launch)
56 st := "curve"
57 if l.Status == StatusGraduated {
58 st = "graduated"
59 }
60 out += ufmt.Sprintf("- [%s ($%s)](token/%s) — %s — raised %d ugnot — buyers %d\n",
61 sanitize(l.Name), sanitize(l.Symbol), l.ID, st, l.RaisedUgnot, l.BuyerCount)
62 return false
63 })
64 out += "\n[Help](help)\n"
65 return out
66}
67
68func renderToken(id string) string {
69 id = sanitize(id)
70 l, ok := launches.Get(id).(*Launch)
71 if !ok {
72 return "> [!WARNING]\n> Unknown launch " + id + "\n\n[Home](./)\n"
73 }
74 st := "bonding curve"
75 if l.Status == StatusGraduated {
76 st = "graduated pool (LP locked)"
77 }
78 out := ufmt.Sprintf("# %s ($%s)\n\n", sanitize(l.Name), sanitize(l.Symbol))
79 out += ufmt.Sprintf("- **ID:** %s\n", l.ID)
80 out += ufmt.Sprintf("- **Status:** %s\n", st)
81 out += ufmt.Sprintf("- **Creator:** %s\n", l.Creator.String())
82 if l.URI != "" {
83 out += ufmt.Sprintf("- **URI:** %s\n", sanitize(l.URI))
84 }
85 out += ufmt.Sprintf("- **Unique buyers:** %d\n", l.BuyerCount)
86 out += ufmt.Sprintf("- **Creator fees (claimable):** %d ugnot\n\n", l.CreatorFees)
87
88 if l.Status == StatusCurve {
89 remaining := CurveSupply - l.RealSold
90 pct := int64(0)
91 if GraduationThreshold > 0 {
92 pct = l.RaisedUgnot * 100 / GraduationThreshold
93 if pct > 100 {
94 pct = 100
95 }
96 }
97 spot := ammmath.SpotPriceUgnotPerToken(l.VirtualUgnot, l.VirtualToken)
98 out += "## Bonding curve\n\n"
99 out += ufmt.Sprintf("- Raised: **%d** / %d ugnot (%d%%)\n", l.RaisedUgnot, GraduationThreshold, pct)
100 out += ufmt.Sprintf("- Tokens sold: **%d** / %d\n", l.RealSold, CurveSupply)
101 out += ufmt.Sprintf("- Remaining on curve: **%d**\n", remaining)
102 out += ufmt.Sprintf("- Spot (ugnot/token x1e6): **%d**\n", spot)
103 out += "\nProgress toward graduation:\n\n"
104 out += progressBar(pct) + "\n"
105 } else {
106 spot := ammmath.SpotPriceUgnotPerToken(l.PoolUgnot, l.PoolToken)
107 out += "## Locked pool\n\n"
108 out += ufmt.Sprintf("- Pool ugnot: **%d**\n", l.PoolUgnot)
109 out += ufmt.Sprintf("- Pool tokens: **%d**\n", l.PoolToken)
110 out += ufmt.Sprintf("- Spot (ugnot/token x1e6): **%d**\n", spot)
111 out += "\n> [!NOTE]\n> Liquidity is permanently locked — there is no remove-liquidity path.\n"
112 }
113
114 out += "\n## Trade\n\n"
115 out += "Use wallet MsgCall (payable txs):\n\n"
116 if l.Status == StatusCurve {
117 out += ufmt.Sprintf("- Buy(id) with -send ugnot — id=%s\n", l.ID)
118 out += "- Sell(id, tokensIn)\n"
119 out += "- Graduate(id) when threshold met\n"
120 } else {
121 out += "- SwapBuy(id) with -send ugnot\n"
122 out += "- SwapSell(id, tokensIn)\n"
123 }
124 out += "\n[Home](./) · [Help](help)\n"
125 return out
126}
127
128func progressBar(pct int64) string {
129 if pct < 0 {
130 pct = 0
131 }
132 if pct > 100 {
133 pct = 100
134 }
135 filled := int(pct / 5)
136 bar := "["
137 for i := 0; i < 20; i++ {
138 if i < filled {
139 bar += "#"
140 } else {
141 bar += "."
142 }
143 }
144 bar += "] " + strconv.FormatInt(pct, 10) + "%"
145 return bar
146}
147
148func renderHelp() string {
149 out := "# gnomemepad API\n\n"
150 out += "## Lifecycle\n\n"
151 out += "1. Init() — once; caller becomes protocol treasury\n"
152 out += "2. Create(name, symbol, uri) + CreateBondUgnot — fair launch\n"
153 out += "3. Buy(id) / Sell(id, amount) — bonding curve\n"
154 out += "4. Auto or Graduate(id) at threshold\n"
155 out += "5. SwapBuy(id) / SwapSell(id, amount) — locked CPMM\n"
156 out += "6. ClaimCreatorFees(id) / ClaimProtocolFees()\n\n"
157 out += "## Params (MVP)\n\n"
158 out += ufmt.Sprintf("- Total supply: %d\n", TotalSupply)
159 out += ufmt.Sprintf("- Curve sale: %d\n", CurveSupply)
160 out += ufmt.Sprintf("- Pool seed: %d\n", PoolSeed)
161 out += ufmt.Sprintf("- Graduation: %d ugnot\n", GraduationThreshold)
162 out += ufmt.Sprintf("- Fee: %d BPS\n", FeeBPS)
163 out += ufmt.Sprintf("- Create bond: %d ugnot\n\n", CreateBondUgnot)
164 out += "## Design\n\n"
165 out += "- No external AMM — this realm is the market\n"
166 out += "- Permanent LP lock after graduation\n"
167 out += "- EOA + OriginSend payment guards\n"
168 out += "- Factory-managed token balances (GRC20 wrap optional later)\n\n"
169 out += "[Home](./)\n"
170 return out
171}