Smart Contract
ShowUpStaking
A.a19273383554e1e1.ShowUpStaking
1import FungibleToken from 0xf233dcee88fe0abe
2import FlowToken from 0x1654653399040a61
3import ShowUpEvents from 0xa19273383554e1e1
4
5access(all) contract ShowUpStaking {
6
7 // Events
8 access(all) event StakeDeposited(eventId: String, user: Address, amount: UFix64)
9 access(all) event StakeWithdrawn(eventId: String, user: Address, amount: UFix64)
10 access(all) event StakeForfeited(eventId: String, user: Address, amount: UFix64)
11
12 // Paths
13 access(all) let StakeVaultStoragePath: StoragePath
14 access(all) let StakeVaultPublicPath: PublicPath
15
16 // Stake Vault Resource Interface
17 access(all) resource interface StakeVaultPublic {
18 access(all) fun getStakedAmount(eventId: String): UFix64
19 access(all) fun getStakedEvents(): [String]
20 }
21
22 // Individual Stake Resource
23 access(all) resource Stake {
24 access(all) let eventId: String
25 access(all) var amount: UFix64
26 access(all) let timestamp: UFix64
27 access(all) var isReturned: Bool
28
29 init(eventId: String, amount: UFix64) {
30 self.eventId = eventId
31 self.amount = amount
32 self.timestamp = getCurrentBlock().timestamp
33 self.isReturned = false
34 }
35
36 access(all) fun getAmount(): UFix64 {
37 return self.amount
38 }
39
40 access(contract) fun markReturned() {
41 self.isReturned = true
42 }
43 }
44
45 // Stake Vault Resource - holds all stakes for a user
46 access(all) resource StakeVault: StakeVaultPublic {
47 access(all) var stakes: @{String: Stake}
48 access(all) let vault: @FlowToken.Vault
49
50 init() {
51 self.stakes <- {}
52 self.vault <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()) as! @FlowToken.Vault
53 }
54
55 // Deposit stake for an event
56 access(all) fun depositStake(eventId: String, stake: @FlowToken.Vault) {
57 pre {
58 !self.stakes.containsKey(eventId): "Already staked for this event"
59 stake.balance > 0.0: "Stake amount must be greater than 0"
60 }
61
62 let amount = stake.balance
63 self.vault.deposit(from: <-stake)
64 let stakeResource <- create Stake(eventId: eventId, amount: amount)
65 let oldStake <- self.stakes[eventId] <- stakeResource
66 destroy oldStake
67
68 emit StakeDeposited(eventId: eventId, user: self.owner?.address!, amount: amount)
69 }
70
71 // Withdraw stake after checking in
72 access(all) fun withdrawStake(eventId: String): @FlowToken.Vault {
73 pre {
74 self.stakes.containsKey(eventId): "No stake found for this event"
75 }
76
77 let stake <- self.stakes.remove(key: eventId)!
78 let amount = stake.getAmount()
79 stake.markReturned()
80 destroy stake
81
82 // Withdraw from main vault
83 let withdrawnVault <- self.vault.withdraw(amount: amount)
84
85 emit StakeWithdrawn(eventId: eventId, user: self.owner?.address!, amount: amount)
86 return <-(withdrawnVault as! @FlowToken.Vault)
87 }
88
89 // Forfeit stake (called by contract owner for no-shows)
90 access(contract) fun forfeitStake(eventId: String): @FlowToken.Vault {
91 pre {
92 self.stakes.containsKey(eventId): "No stake found for this event"
93 }
94
95 let stake <- self.stakes.remove(key: eventId)!
96 let amount = stake.getAmount()
97 destroy stake
98
99 // Withdraw from main vault
100 let withdrawnVault <- self.vault.withdraw(amount: amount)
101
102 emit StakeForfeited(eventId: eventId, user: self.owner?.address!, amount: amount)
103 return <-(withdrawnVault as! @FlowToken.Vault)
104 }
105
106 access(all) fun getStakedAmount(eventId: String): UFix64 {
107 if let stake = &self.stakes[eventId] as &Stake? {
108 return stake.getAmount()
109 }
110 return 0.0
111 }
112
113 access(all) fun getStakedEvents(): [String] {
114 return self.stakes.keys
115 }
116
117 access(all) fun getTotalStaked(): UFix64 {
118 var total: UFix64 = 0.0
119 for eventId in self.stakes.keys {
120 total = total + self.getStakedAmount(eventId: eventId)
121 }
122 return total
123 }
124 }
125
126 // Create Stake Vault
127 access(all) fun createStakeVault(): @StakeVault {
128 return <-create StakeVault()
129 }
130
131 // Public function to stake for an event
132 access(all) fun stakeForEvent(
133 userVault: &StakeVault,
134 paymentVault: @FlowToken.Vault,
135 eventId: String,
136 eventsCollection: &ShowUpEvents.EventsCollection
137 ) {
138 pre {
139 paymentVault.balance > 0.0: "Payment amount must be greater than 0"
140 }
141
142 let amount = paymentVault.balance
143
144 // Deposit stake in user's vault
145 userVault.depositStake(eventId: eventId, stake: <-paymentVault)
146
147 // Record stake in events collection
148 eventsCollection.stakeForEvent(
149 eventId: eventId,
150 staker: userVault.owner?.address!,
151 amount: amount
152 )
153 }
154
155 // Public function to check in and return stake
156 access(all) fun checkInAndReturnStake(
157 userVault: &StakeVault,
158 eventId: String,
159 eventsCollection: &ShowUpEvents.EventsCollection
160 ): @FlowToken.Vault {
161 // Check in user
162 eventsCollection.checkInUser(eventId: eventId, user: userVault.owner?.address!)
163
164 // Return stake
165 return <-userVault.withdrawStake(eventId: eventId)
166 }
167
168 init() {
169 self.StakeVaultStoragePath = /storage/ShowUpStakeVault
170 self.StakeVaultPublicPath = /public/ShowUpStakeVault
171 }
172}
173