list_venue.gno
4.87 Kb · 198 lines
1package padv2
2
3import (
4 "chain"
5 "strconv"
6 "strings"
7
8 "gno.land/p/nt/avl/v0"
9)
10
11// ListVenue IDs (compile-time switch in tryListVenue). Adding a new DEX
12// means a new case + adapter file and a new pad version — Gno cannot
13// dynamically import by path string.
14const (
15 VenueGnoswap = "gnoswap"
16 VenueZdex = "zdex"
17)
18
19// listVenueMeta is registry metadata (not a callable adapter).
20type listVenueMeta struct {
21 ID string
22 Label string
23 Enabled bool
24 FeeAssetHint string // e.g. "GNS" for CreatePool fee UX
25}
26
27var (
28 listVenues avl.Tree // id -> *listVenueMeta
29 defaultListVenue string
30)
31
32func ensureListVenuesSeeded() {
33 if listVenues.Size() > 0 {
34 return
35 }
36 // Mainnet-first: zdex default (hub listable when adapter + realm live).
37 // Gnoswap registered but disabled until mainnet router/pool exist — enable via SetListVenue.
38 registerListVenue(VenueZdex, "zdex", true, "ugnot")
39 registerListVenue(VenueGnoswap, "Gnoswap", false, "GNS")
40 if defaultListVenue == "" {
41 defaultListVenue = VenueZdex
42 }
43}
44
45func registerListVenue(id, label string, enabled bool, feeHint string) {
46 id = strings.TrimSpace(strings.ToLower(id))
47 if id == "" {
48 return
49 }
50 label = strings.TrimSpace(label)
51 if label == "" {
52 label = id
53 }
54 listVenues.Set(id, &listVenueMeta{
55 ID: id,
56 Label: label,
57 Enabled: enabled,
58 FeeAssetHint: strings.TrimSpace(feeHint),
59 })
60}
61
62func normalizeVenueID(venueId string) string {
63 ensureListVenuesSeeded()
64 v := strings.TrimSpace(strings.ToLower(venueId))
65 if v == "" {
66 if defaultListVenue != "" {
67 return defaultListVenue
68 }
69 return VenueZdex
70 }
71 return v
72}
73
74func venueEnabled(venueId string) bool {
75 ensureListVenuesSeeded()
76 id := normalizeVenueID(venueId)
77 raw := listVenues.Get(id)
78 if raw == nil {
79 return false
80 }
81 m, ok := raw.(*listVenueMeta)
82 return ok && m != nil && m.Enabled
83}
84
85// DefaultListVenue returns the venue id used when callers pass "".
86func DefaultListVenue() string {
87 ensureListVenuesSeeded()
88 if defaultListVenue == "" {
89 return VenueZdex
90 }
91 return defaultListVenue
92}
93
94// SetDefaultListVenue sets the default list venue (protocol only).
95func SetDefaultListVenue(cur realm, venueId string) {
96 requireProtocol(cur)
97 ensureListVenuesSeeded()
98 id := strings.TrimSpace(strings.ToLower(venueId))
99 if id == "" {
100 panic("pad: empty venue")
101 }
102 if listVenues.Get(id) == nil {
103 panic("pad: unknown venue")
104 }
105 defaultListVenue = id
106 chain.Emit("SetDefaultListVenue", "venue", id)
107}
108
109// SetListVenue registers or updates venue metadata (protocol only).
110// Does not add compile-time dispatch — unknown ids stay non-listable until
111// tryListVenue gains a case in a future pad version.
112func SetListVenue(cur realm, id, label string, enabled bool, feeAssetHint string) {
113 requireProtocol(cur)
114 ensureListVenuesSeeded()
115 id = strings.TrimSpace(strings.ToLower(id))
116 if id == "" || len(id) > 32 {
117 panic("pad: invalid venue id")
118 }
119 for _, c := range id {
120 if !((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '-') {
121 panic("pad: venue id charset")
122 }
123 }
124 registerListVenue(id, label, enabled, feeAssetHint)
125 chain.Emit("SetListVenue",
126 "id", id,
127 "label", strings.TrimSpace(label),
128 "enabled", strconv.FormatBool(enabled),
129 "feeHint", strings.TrimSpace(feeAssetHint),
130 )
131}
132
133// ListVenues returns newline-separated "id|label|enabled|feeHint" (enabled 0|1).
134func ListVenues() string {
135 ensureListVenuesSeeded()
136 out := ""
137 listVenues.Iterate("", "", func(key string, value any) bool {
138 m, ok := value.(*listVenueMeta)
139 if !ok || m == nil {
140 return false
141 }
142 en := "0"
143 if m.Enabled {
144 en = "1"
145 }
146 line := m.ID + "|" + m.Label + "|" + en + "|" + m.FeeAssetHint
147 if out != "" {
148 out += "\n"
149 }
150 out += line
151 return false
152 })
153 return out
154}
155
156// ListVenueOf returns the venue id used for a successful list (or "").
157func ListVenueOf(id string) string {
158 return mustLaunch(id).ListVenue
159}
160
161// resetListVenuesForTest clears venue registry (unit tests).
162func resetListVenuesForTest() {
163 listVenues = avl.Tree{}
164 defaultListVenue = ""
165}
166
167// tryListVenue dispatches to a compile-time adapter. Unknown / disabled
168// venues soft-fail with a note (no panic) so UI can show ListNeed guidance.
169func tryListVenue(cur realm, l *Launch, venueId string, raisedUgnot, liqTokens int64) bool {
170 ensureListVenuesSeeded()
171 id := normalizeVenueID(venueId)
172 if !venueEnabled(id) {
173 if l != nil {
174 l.GnoswapNote = "list skip: venue disabled or unknown: " + id
175 }
176 return false
177 }
178 switch id {
179 case VenueZdex:
180 ok := tryListOnZdex(cur, l, raisedUgnot, liqTokens)
181 if ok && l != nil {
182 l.ListVenue = VenueZdex
183 }
184 return ok
185 case VenueGnoswap:
186 ok := listOnGnoswapWithFunding(cur, l, raisedUgnot, liqTokens)
187 if ok && l != nil {
188 l.ListVenue = VenueGnoswap
189 }
190 return ok
191 default:
192 // Registered in metadata but no adapter case yet.
193 if l != nil {
194 l.GnoswapNote = "list skip: venue adapter not linked in this pad: " + id
195 }
196 return false
197 }
198}