PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/moul/x/daily/lottery/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
moul / x / daily / lottery
Files
3 (README)(gnomod.toml)
Exported functions
6
Module
gno.land/r/moul/x/daily/lottery/v0
gno
0.9

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • lottery.gnogno
lottery.gnogno
1// Package lottery is an idiomatic gno.land port of the classic Solidity2// Lottery contract. Players Enter the current round (one entry per address per3// round). Once a round has at least two entrants, anyone may DrawWinner: a4// winner is picked deterministically from the block height (ChainHeight() %5// len(entrants), over the deterministically-sorted entrant set), recorded in6// the winners history, and a fresh round is opened.7//8// There is no real randomness on-chain, so "random" selection is derived from9// the block height — the same source Solidity ports use via block.number.10package lottery1112import (13	"strconv"14	"strings"1516	"chain"17	"chain/runtime"18	"chain/runtime/unsafe"1920	"gno.land/p/nt/avl/v0"21)2223// round is the current (open) round number, 1-based.24var round int = 12526// entrants holds the current round's players: key = address string, value =27// the address. Iteration is deterministic (sorted by key), which makes winner28// selection reproducible.29var entrants avl.Tree3031// winners records past rounds: key = zero-padded round number (for ordered32// iteration), value = *winnerRecord.33var winners avl.Tree3435type winnerRecord struct {36	Round       int37	Winner      address38	NumEntrants int39	Height      int6440}4142// winnerKey zero-pads the round number so avl iteration yields chronological43// order for up to 10^9 rounds.44func winnerKey(r int) string {45	s := strconv.Itoa(r)46	for len(s) < 9 {47		s = "0" + s48	}49	return s50}5152// pickIndex derives the winning entrant index from the block height. Panics if53// there are no entrants. Pure helper (deterministic, no state) — safe to test.54func pickIndex(height int64, n int) int {55	if n <= 0 {56		panic("lottery: no entrants to draw from")57	}58	i := height % int64(n)59	if i < 0 {60		i += int64(n)61	}62	return int(i)63}6465// Enter adds the caller to the current round's entrants. Each address may only66// enter a given round once; a duplicate entry panics.67func Enter(cur realm) {68	player := unsafe.PreviousRealm().Address()69	key := player.String()70	if entrants.Has(key) {71		panic("lottery: already entered this round")72	}73	entrants.Set(key, player)7475	chain.Emit("Enter",76		"round", strconv.Itoa(round),77		"player", key,78		"entrants", strconv.Itoa(entrants.Size()),79	)80}8182// DrawWinner closes the current round, provided it has at least two entrants,83// picks the winner deterministically from the block height, records it, and84// opens a new empty round.85func DrawWinner(cur realm) address {86	n := entrants.Size()87	if n < 2 {88		panic("lottery: need at least 2 entrants to draw")89	}9091	height := runtime.ChainHeight()92	idx := pickIndex(height, n)9394	var winner address95	i := 096	entrants.Iterate("", "", func(_ string, value interface{}) bool {97		if i == idx {98			winner = value.(address)99			return true // stop100		}101		i++102		return false103	})104105	rec := &winnerRecord{106		Round:       round,107		Winner:      winner,108		NumEntrants: n,109		Height:      height,110	}111	winners.Set(winnerKey(round), rec)112113	chain.Emit("DrawWinner",114		"round", strconv.Itoa(round),115		"winner", winner.String(),116		"entrants", strconv.Itoa(n),117		"height", strconv.FormatInt(height, 10),118	)119120	// Open a fresh round.121	round++122	entrants = avl.Tree{}123124	return winner125}126127// CurrentRound returns the currently open round number.128func CurrentRound() int {129	return round130}131132// NumEntrants returns how many players have entered the current round.133func NumEntrants() int {134	return entrants.Size()135}136137// HasEntered reports whether addr is in the current round.138func HasEntered(addr address) bool {139	return entrants.Has(addr.String())140}141142// Render shows the current round, its entrants, and the winners history.143func Render(path string) string {144	var b strings.Builder145	b.WriteString("# Lottery\n\n")146	b.WriteString("Enter the open round, then anyone can draw once it has ")147	b.WriteString("at least two players. The winner is picked from the block ")148	b.WriteString("height and a new round opens automatically.\n\n")149150	b.WriteString("## Round " + strconv.Itoa(round) + " (open)\n\n")151	if entrants.Size() == 0 {152		b.WriteString("_No entrants yet. Call `Enter` to join._\n\n")153	} else {154		b.WriteString(strconv.Itoa(entrants.Size()) + " entrant(s):\n\n")155		entrants.Iterate("", "", func(key string, _ interface{}) bool {156			b.WriteString("- `" + key + "`\n")157			return false158		})159		b.WriteString("\n")160		if entrants.Size() < 2 {161			b.WriteString("_Need at least 2 entrants before a draw._\n\n")162		} else {163			b.WriteString("_Ready to draw: call `DrawWinner`._\n\n")164		}165	}166167	b.WriteString("## Past winners\n\n")168	if winners.Size() == 0 {169		b.WriteString("_No rounds drawn yet._\n")170	} else {171		b.WriteString("| Round | Winner | Entrants | Block Height |\n")172		b.WriteString("|---|---|---|---|\n")173		winners.Iterate("", "", func(_ string, value interface{}) bool {174			r := value.(*winnerRecord)175			b.WriteString("| " + strconv.Itoa(r.Round) +176				" | `" + r.Winner.String() + "`" +177				" | " + strconv.Itoa(r.NumEntrants) +178				" | " + strconv.FormatInt(r.Height, 10) + " |\n")179			return false180		})181	}182183	return b.String()184}185

Functions

  • CurrentRound() int

  • DrawWinner(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}) string

  • Enter(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string})

  • HasEntered(addr string) bool

  • NumEntrants() int

  • Render(path string) string

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

Rendered

RenderedRawgnoweb ↗

vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.