eventix.gno

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