Smart Contract

OragaESports

A.b576a3926d239682.OragaESports

Valid From

118,724,628

Deployed

6d ago
Feb 22, 2026, 03:29:11 PM UTC

Dependents

5 imports
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}