gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/arena/v0⧉ Realm Open in gnoweb ↗
Kind Realm (renderable)
Name v0
Namespace g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd / gnofly / arena
Exported functions 21
Module gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/arena/v0
gno 0.9 spec.gno gno
⧉
1 package arena 2 3 import ( 4 "crypto/sha256" 5 "encoding/hex" 6 "strings" 7 8 ArenaJSON (id string) string
ArenasJSON () string
CancelRound (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}, id string)
Claim (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}) int64
Claimable (addr string) int64
ClaimsJSON (addr string) string
EarningsJSON () 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}, spec string, ticket string) string
Escrowed () int64
ExpireLobby (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}, id string)
Leave (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}, id string)
PlayerJSON (addr string) string
RefundDelay () int64
RefundRound (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}, id string)
Render (path string) string
ResultJSON (id string) string
ResultsJSON () string
SetRefundDelay (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}, seconds int64)
SettleRound (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}, id string, deaths string)
StartRound (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}, id string) int64
Version () int64
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
"gno.land/p/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/arena/payout/v0"
9 )
10
11 // An arena is created off chain, by the game server, at a player's request.
12 // It is described by a spec, a string of fields separated by "|":
13 //
14 // v1|mode|stake|minSeats|maxSeats|lives|seconds|killTarget|creator|created|nonce
15 //
16 // v1|deathmatch|10000000|2|8|3|900|5|g1abc...|1760000000|k3x9
17 //
18 // and known by its id, the first 24 hex characters of the SHA-256 of the
19 // spec. The first player to pay for an arena hands the realm its spec; the
20 // realm checks it and stores the arena under the id it computes. Nobody can
21 // change the stake or the rules of an id: a different spec is a different
22 // id.
23 //
24 // created is the server's clock when the arena was proposed. An arena takes
25 // entries for an hour from then, and its lobby can be closed by anyone after
26 // that, see ExpireLobby.
27
28 // Bounds of a spec, the same as the game server's.
29 const (
30 specVersion = "v1"
31 idLen = 24
32
33 minStake = 1000000 // ugnot, 1 GNOT
34 maxStake = 1000000000 // ugnot, 1000 GNOT
35 minSeconds = 300 // 5 minutes
36 maxSeconds = 1800 // 30 minutes
37 entryWindow = 3600 // seconds an arena takes entries after it was created
38 clockSkew = 300 // seconds a server clock may run ahead of the chain
39 maxNonceLen = 16
40 maxSpecLength = 160
41
42 // feeBps is the house's share of every settled game, for the treasury.
43 feeBps = 500
44 )
45
46 // spec is a parsed arena spec.
47 type spec struct {
48 mode string
49 stake int64
50 minSeats int64
51 maxSeats int64
52 lives int64
53 seconds int64
54 killTarget int64
55 creator address
56 created int64
57 nonce string
58 }
59
60 // idOf returns the id of a spec string.
61 func idOf(s string ) string {
62 sum := sha256.Sum256([] byte (s))
63 return hex.EncodeToString(sum[:])[:idLen]
64 }
65
66 // parseSpec reads and checks a spec string. It panics on anything the realm
67 // would not play.
68 func parseSpec(s string ) spec {
69 if len(s) > maxSpecLength {
70 panic(errInvalidSpec)
71 }
72 f := strings.Split(s, "|" )
73 if len(f) != 11 || f[ 0 ] != specVersion {
74 panic(errInvalidSpec)
75 }
76 num := func (i int ) int64 {
77 n, ok := digits(f[i])
78 if !ok {
79 panic(errInvalidSpec)
80 }
81 return n
82 }
83 sp := spec{
84 mode: f[ 1 ],
85 stake: num( 2 ),
86 minSeats: num( 3 ),
87 maxSeats: num( 4 ),
88 lives: num( 5 ),
89 seconds: num( 6 ),
90 killTarget: num( 7 ),
91 creator: address(f[ 8 ]),
92 created: num( 9 ),
93 nonce: f[ 10 ],
94 }
95 if payout.Lookup(sp.mode) == nil {
96 panic(errInvalidMode)
97 }
98 if sp.stake < minStake || sp.stake > maxStake {
99 panic(errInvalidStake)
100 }
101 if sp.minSeats < payout.MinPlayers || sp.minSeats > sp.maxSeats || sp.maxSeats > payout.MaxPlayers {
102 panic(errInvalidSeats)
103 }
104 if sp.lives < payout.MinLives || sp.lives > payout.MaxLives {
105 panic(errInvalidLives)
106 }
107 if sp.seconds < minSeconds || sp.seconds > maxSeconds {
108 panic(errInvalidSeconds)
109 }
110 if sp.killTarget > payout.MaxKillTarget {
111 panic(errInvalidKillTarget)
112 }
113 // A battle royale is won by staying in the air: a kill target would end
114 // it before that.
115 if sp.mode == payout.ModeBattleRoyale && sp.killTarget != 0 {
116 panic(errRoyaleTarget)
117 }
118 if !validAddress(sp.creator) {
119 panic(errInvalidAddress)
120 }
121 if !validNonce(sp.nonce) {
122 panic(errInvalidSpec)
123 }
124 return sp
125 }
126
127 // validNonce reports whether s is 1 to 16 characters of [a-z0-9].
128 func validNonce(s string ) bool {
129 if len(s) == 0 || len(s) > maxNonceLen {
130 return false
131 }
132 for i := 0 ; i < len(s); i++ {
133 c := s[i]
134 if !(c >= 'a' && c <= 'z' ) && !(c >= '0' && c <= '9' ) {
135 return false
136 }
137 }
138 return true
139 }
140
141 // validID reports whether s can be an arena id: 24 lowercase hex characters.
142 func validID(s string ) bool {
143 if len(s) != idLen {
144 return false
145 }
146 for i := 0 ; i < len(s); i++ {
147 c := s[i]
148 if !(c >= '0' && c <= '9' ) && !(c >= 'a' && c <= 'f' ) {
149 return false
150 }
151 }
152 return true
153 }
154
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.