eventix.gno
3.39 Kb ยท 141 lines
1package eventix
2
3import (
4 "std"
5 "strconv"
6 "time"
7
8 "gno.land/p/demo/tokens/grc20"
9 "gno.land/p/demo/tokens/grc721"
10 "gno.land/p/nt/avl"
11 "gno.land/p/nt/avl/pager"
12 "gno.land/p/nt/ufmt"
13)
14
15type Event struct {
16 name string
17 description string
18 date time.Time
19 maxTickets int
20 price uint64
21 paymentToken any
22 ticketsSold int
23}
24
25var (
26 events = avl.NewTree()
27 eventCounter uint64 = 0
28 tickets = grc721.NewBasicNFT("Event Ticket", "EVTIX")
29)
30
31func CreateEvent(_ realm, name, description, dateStr string, paymentToken any, maxTickets int, price uint64) uint64 {
32 // validate inputs
33 if maxTickets <= 0 {
34 panic("Maximum tickets must be greater than 0")
35 }
36
37 date, err := time.Parse("2006-01-02T15:04:05Z", dateStr)
38 if err != nil {
39 panic("Invalid date format. Use: YYYY-MM-DDThh:mm:ssZ")
40 }
41
42 switch pt := paymentToken.(type) {
43 case string:
44 if pt != "ugnot" {
45 panic("Unsupported native token")
46 }
47 case *grc20.Token:
48 if pt == nil {
49 panic("Invalid GRC20 token")
50 }
51 default:
52 panic("Unsupported payment token type")
53 }
54
55 newID := eventCounter + 1
56 event := Event{
57 name: name,
58 description: description,
59 date: date,
60 maxTickets: maxTickets,
61 price: price,
62 ticketsSold: 0,
63 paymentToken: paymentToken,
64 }
65 events.Set(strconv.Itoa(int(newID)), event)
66 eventCounter = newID
67 std.Emit("EventCreated", "id", strconv.FormatUint(newID, 10), "name", name)
68 return newID
69}
70
71func BuyTicket(_ realm, eventId uint64) {
72 event, exists := getEvent(eventId)
73 if !exists {
74 panic("Event does not exist")
75 }
76
77 if event.ticketsSold >= event.maxTickets {
78 panic("Event is sold out")
79 }
80
81 buyer := std.PreviousRealm().Address()
82
83 switch pt := event.paymentToken.(type) {
84 case string:
85 if pt != "ugnot" {
86 panic("Unsupported native token")
87 }
88 if std.OriginSend().AmountOf("ugnot") != int64(event.price) {
89 panic(ufmt.Sprintf("Invalid payment amount: needs to be %dugnot", event.price))
90 }
91 case *grc20.Token:
92 if err := pt.CallerTeller().Transfer(std.CurrentRealm().Address(), int64(event.price)); err != nil {
93 panic("GRC20 transfer error: " + err.Error())
94 }
95 default:
96 panic("Unsupported payment token type")
97 }
98
99 // Mint NFT ticket
100 tokenId := grc721.TokenID(ufmt.Sprintf("event_%d_ticket_%d", eventId, event.ticketsSold+1))
101 tickets.Mint(buyer, tokenId)
102
103 event.ticketsSold++
104 events.Set(strconv.Itoa(int(eventId)), event)
105}
106
107func Render(path string) string {
108 output := "# Event Ticketing System\n\n"
109
110 pg := pager.NewPager(events, 10, true).MustGetPageByPath(path)
111
112 for _, item := range pg.Items {
113 id, _ := strconv.ParseUint(item.Key, 10, 64)
114 event := item.Value.(Event)
115
116 output += ufmt.Sprintf("## Event #%d: %s\n", id, event.name)
117 output += ufmt.Sprintf("Description: %s\n", event.description)
118 output += ufmt.Sprintf("Date: %s\n", event.date.Format(time.RFC3339))
119 output += ufmt.Sprintf("Tickets: %d/%d\n", event.ticketsSold, event.maxTickets)
120 output += ufmt.Sprintf("Price: %d %v\n\n", event.price, event.paymentToken)
121
122 if event.ticketsSold < event.maxTickets {
123 output += ufmt.Sprintf("[Buy Ticket](/r/jjoptimist/eventix/BuyTicket?eventId=%d)\n", id)
124 } else {
125 output += "**SOLD OUT**\n"
126 }
127 output += "---\n\n"
128 }
129
130 output += pg.Picker(path)
131
132 return output
133}
134
135func getEvent(eventId uint64) (Event, bool) {
136 value, exists := events.Get(strconv.Itoa(int(eventId)))
137 if !exists {
138 return Event{}, false
139 }
140 return value.(Event), true
141}