Smart Contract
OragaESports
A.b576a3926d239682.OragaESports
1import FlowToken from 0x1654653399040a61
2import FungibleToken from 0xf233dcee88fe0abe
3
4access(all) contract OragaESports {
5
6 access(self) var totalCount: UInt
7 access(self) let GamerFlowTokenVault: {UInt: Capability<&{FungibleToken.Receiver}>}
8 access(self) let FlowTokenVault: Capability<&{FungibleToken.Receiver}>
9 access(self) let gamersInfo: GamersInfo
10
11 access(all) event GamerCreatted(gamerId: UInt)
12 access(all) event WonThePrize(gamerId: UInt, amount: UFix64)
13
14 // [Struct] GamersInfo
15 access(all) struct GamersInfo {
16 access(contract) var currentPrize: UInt
17 access(contract) var tryingPrize: {UInt: UInt}
18 access(contract) var lastTimePlayed: {UInt: UFix64?}
19 access(contract) var prizeWinners: {UInt: GamerPrizeInfo}
20 access(contract) var freePlayCount: {UInt: UInt8}
21 access(contract) var tipJarBalance: UFix64
22
23 access(contract) fun setCurrentPrize(added: UInt, gamerId: UInt, paid: Bool): UInt {
24 if (paid == false) {
25 self.currentPrize = self.currentPrize + added
26 self.unsetTryingPrize(gamerId: gamerId)
27 return 0
28 } else {
29 if let paidPrize = self.tryingPrize[gamerId] {
30 if (self.currentPrize - paidPrize >= 0) {
31 self.currentPrize = self.currentPrize - paidPrize
32 self.unsetTryingPrize(gamerId: gamerId)
33 if let prizeHistory = self.prizeWinners[gamerId] {
34 self.setPrizeWinners(gamerId: gamerId, prize: paidPrize + prizeHistory.prize, nickname: nil)
35 } else {
36 self.setPrizeWinners(gamerId: gamerId, prize: paidPrize, nickname: nil)
37 }
38 return paidPrize + added
39 } else {
40 // In this case, any other person snatched the prize while playing a game. That's why the prize is only the fee this player paid.
41 self.currentPrize = self.currentPrize - added
42 self.unsetTryingPrize(gamerId: gamerId)
43 if let prizeHistory = self.prizeWinners[gamerId] {
44 self.setPrizeWinners(gamerId: gamerId, prize: added + prizeHistory.prize, nickname: nil)
45 } else {
46 self.setPrizeWinners(gamerId: gamerId, prize: added, nickname: nil)
47 }
48 return added
49 }
50 }
51 panic("Error. Oops, something is not good.")
52 }
53 }
54
55 access(contract) fun unsetTryingPrize(gamerId: UInt) {
56 self.tryingPrize[gamerId] = 0
57 self.lastTimePlayed[gamerId] = nil
58 }
59
60 access(contract) fun setTryingPrize(gamerId: UInt) {
61 self.tryingPrize[gamerId] = self.currentPrize
62 self.lastTimePlayed[gamerId] = getCurrentBlock().timestamp
63 }
64
65 access(contract) fun setPrizeWinners(gamerId: UInt, prize: UInt, nickname: String?) {
66 if let prizeWinnerInfo = self.prizeWinners[gamerId] {
67 prizeWinnerInfo.setPrize(prize: prize)
68 if (prize > 0) {
69 prizeWinnerInfo.setTotalCountUp()
70 }
71 self.prizeWinners[gamerId] = prizeWinnerInfo
72 } else {
73 if (nickname != nil) {
74 self.prizeWinners[gamerId] = GamerPrizeInfo(prize: prize, gamerId: gamerId, nickname: nickname!, totalCount: prize > 0 ? 1 : 0)
75 }
76 }
77 }
78
79 access(contract) fun setFreePlayCount(gamerId: UInt) {
80 self.freePlayCount[gamerId] = self.freePlayCount[gamerId] == nil ? 1 : (self.freePlayCount[gamerId]! + 1)
81 }
82
83 access(contract) fun setTipJarBalance(amount: UFix64) {
84 self.tipJarBalance = self.tipJarBalance + amount
85 }
86
87 access(contract) fun useTipJarBalance() {
88 if (self.tipJarBalance > 0.0) {
89 self.tipJarBalance = self.tipJarBalance - 1.0
90 } else {
91 panic("Sorry, tip jar is empty..")
92 }
93 }
94
95 init() {
96 self.currentPrize = 0
97 self.tryingPrize = {}
98 self.lastTimePlayed = {}
99 self.prizeWinners = {}
100 self.freePlayCount = {}
101 self.tipJarBalance = 0.0
102 }
103 }
104
105 // [Struct] GamerPrizeInfo
106 access(all) struct GamerPrizeInfo {
107 access(contract) var prize: UInt
108 access(contract) let gamerId: UInt
109 access(contract) let gamerName: String
110 access(contract) var totalCount: UInt
111
112 access(contract) fun setPrize(prize: UInt) {
113 self.prize = self.prize + prize
114 }
115 access(contract) fun setTotalCountUp() {
116 self.totalCount = self.totalCount + 1
117 }
118
119 init(prize: UInt, gamerId: UInt, nickname: String, totalCount: UInt) {
120 self.prize = prize
121 self.gamerId = gamerId
122 self.gamerName = nickname
123 self.totalCount = totalCount
124 }
125 }
126
127 access(all) fun getGamersInfo(): GamersInfo {
128 return self.gamersInfo
129 }
130
131 access(all) resource Gamer {
132 access(all) let gamerId: UInt
133 access(all) let nickname: String
134
135 access(all) fun insert_coin(payment: @FlowToken.Vault) {
136 pre {
137 payment.balance == 1.1: "payment is not 1.1FLOW coin."
138 }
139 // There is a possibility that double withdrawal may occur by the following logic, comment out this logic.(July/6/2025)
140 // if let isStillPlayed = OragaESports.gamersInfo.lastTimePlayed[self.gamerId] {
141 // if (isStillPlayed != nil && isStillPlayed! + 80.0 < getCurrentBlock().timestamp) { // 60 + 10 * 2 (game time + transaction)
142 // // NOTE. If a player cut the network after the game won, we don't care about it.
143 // let prizePaid = OragaESports.gamersInfo.setCurrentPrize(added: 1, gamerId: self.gamerId, paid: false) // set lose
144 // }
145 // }
146 // if let challenged = OragaESports.gamersInfo.tryingPrize[self.gamerId] {
147 // if (challenged > 0) {
148 // panic("You are now on playing the game. Payment is not accepted.")
149 // }
150 // }
151 OragaESports.gamersInfo.setTryingPrize(gamerId: self.gamerId)
152 OragaESports.FlowTokenVault.borrow()!.deposit(from: <- payment)
153 }
154
155 access(all) fun tipping(tip: @FlowToken.Vault) {
156 pre {
157 tip.balance == 1.0 || tip.balance == 5.0: "tip is not 1.0FLOW or 5.0FLOW coin."
158 }
159 OragaESports.gamersInfo.setTipJarBalance(amount: tip.balance)
160 OragaESports.FlowTokenVault.borrow()!.deposit(from: <- tip)
161 }
162
163 init(nickname: String) {
164 OragaESports.totalCount = OragaESports.totalCount + 1
165 self.gamerId = OragaESports.totalCount
166 self.nickname = nickname
167 OragaESports.gamersInfo.setPrizeWinners(gamerId: self.gamerId, prize: 0, nickname: nickname)
168 emit GamerCreatted(gamerId: self.gamerId)
169 }
170 }
171
172 access(all) fun createGamer(nickname: String, flow_vault_receiver: Capability<&{FungibleToken.Receiver}>): @OragaESports.Gamer {
173 let gamer <- create Gamer(nickname: nickname)
174
175 if (OragaESports.GamerFlowTokenVault[gamer.gamerId] == nil) {
176 OragaESports.GamerFlowTokenVault[gamer.gamerId] = flow_vault_receiver
177 }
178 return <- gamer
179 }
180
181 /*
182 ** [Resource] Admin (Game Server Processing)
183 */
184 access(all) resource Admin {
185 /*
186 ** Save the Gamer's shooting game outcome
187 */
188 access(all) fun shootingGameOutcome(gamerId: UInt, outcome: Bool) {
189 let prizePaid = OragaESports.gamersInfo.setCurrentPrize(added: 1, gamerId: gamerId, paid: outcome)
190 if (prizePaid > 0) {
191 // Pay the prize.
192 let reward <- OragaESports.account.storage.borrow<auth(FungibleToken.Withdraw) &{FungibleToken.Provider}>(from: /storage/flowTokenVault)!.withdraw(amount: UFix64.fromString(prizePaid.toString().concat(".0"))!) as! @FlowToken.Vault
193 OragaESports.GamerFlowTokenVault[gamerId]!.borrow()!.deposit(from: <- reward)
194 emit WonThePrize(gamerId: gamerId, amount: UFix64.fromString(prizePaid.toString().concat(".0"))!)
195 }
196 }
197
198 /*
199 ** Start the free play using tip jar coin.
200 */
201 access(all) fun useTipJarForFreePlay(gamerId: UInt) {
202 if let freePlayed = OragaESports.gamersInfo.freePlayCount[gamerId] {
203 if (freePlayed >= 2) {
204 panic("It's not acceptable.")
205 }
206 // To avoid double withdrawal using multi monitor gaming, comment out this logic.(July/6/2025)
207 // if let isStillPlayed = OragaESports.gamersInfo.lastTimePlayed[gamerId] {
208 // if (isStillPlayed != nil && isStillPlayed! + 80.0 < getCurrentBlock().timestamp) { // 60 + 10 * 2 (game time + transaction)
209 // // NOTE. If a player cut the network after the game won, we don't care about it.
210 // let prizePaid = OragaESports.gamersInfo.setCurrentPrize(added: 1, gamerId: gamerId, paid: false) // set lose
211 // }
212 // }
213 // if let challenged = OragaESports.gamersInfo.tryingPrize[gamerId] {
214 // if (challenged > 0) {
215 // panic("You are now on playing the game. Payment is not accepted.")
216 // }
217 // }
218 OragaESports.gamersInfo.freePlayCount[gamerId] = freePlayed + 1
219 OragaESports.gamersInfo.setTryingPrize(gamerId: gamerId)
220 OragaESports.gamersInfo.useTipJarBalance()
221 } else {
222 OragaESports.gamersInfo.freePlayCount[gamerId] = 1
223 OragaESports.gamersInfo.setTryingPrize(gamerId: gamerId)
224 OragaESports.gamersInfo.useTipJarBalance()
225 }
226 }
227 }
228
229 init() {
230 self.account.storage.save( <- create Admin(), to: /storage/OragaESportsAdmin) // grant admin resource
231 self.totalCount = 0
232 self.GamerFlowTokenVault = {}
233 self.FlowTokenVault = self.account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
234 self.gamersInfo = GamersInfo()
235 }
236}