Smart Contract

FlunksGumDrop

A.807c3d470888cc48.FlunksGumDrop

Valid From

130,382,637

Deployed

1w ago
Feb 19, 2026, 10:24:09 AM UTC

Dependents

2 imports
1// FlunksGumDrop.cdc
2// Production-ready GumDrop contract for special events
3// This contract allows Flunk NFT holders to claim special GUM rewards during limited-time events
4
5access(all) contract FlunksGumDrop {
6    
7    // Event emitted when a user claims their GumDrop
8    access(all) event GumDropClaimed(user: Address, amount: UInt64, timestamp: UFix64)
9    
10    // Event emitted when the drop window changes
11    access(all) event DropWindowUpdated(startTime: UFix64, endTime: UFix64, isActive: Bool)
12    
13    // Storage paths
14    access(all) let AdminStoragePath: StoragePath
15    
16    // Contract state
17    access(all) var dropStartTime: UFix64
18    access(all) var dropEndTime: UFix64
19    access(all) var gumAmountPerFlunk: UInt64
20    access(all) var dropActive: Bool
21    
22    // Track who has claimed (address -> claimed timestamp)
23    access(self) let claimRecord: {Address: UFix64}
24    
25    // Admin resource for managing drops
26    access(all) resource Admin {
27        // Start a new GumDrop event
28        access(all) fun startDrop(startTime: UFix64, endTime: UFix64, gumPerFlunk: UInt64) {
29            pre {
30                endTime > startTime: "End time must be after start time"
31                gumPerFlunk > 0: "GUM amount must be positive"
32            }
33            
34            FlunksGumDrop.dropStartTime = startTime
35            FlunksGumDrop.dropEndTime = endTime
36            FlunksGumDrop.gumAmountPerFlunk = gumPerFlunk
37            FlunksGumDrop.dropActive = true
38            
39            emit DropWindowUpdated(startTime: startTime, endTime: endTime, isActive: true)
40        }
41        
42        // End the current drop
43        access(all) fun endDrop() {
44            FlunksGumDrop.dropActive = false
45            emit DropWindowUpdated(startTime: 0.0, endTime: 0.0, isActive: false)
46        }
47        
48        // Reset a user's claim (emergency only)
49        access(all) fun resetUserClaim(user: Address) {
50            let removed = FlunksGumDrop.claimRecord.remove(key: user)
51        }
52    }
53    
54    // Check if drop is currently active
55    access(all) view fun checkDropActive(): Bool {
56        let now = getCurrentBlock().timestamp
57        return self.dropActive && 
58               now >= self.dropStartTime && 
59               now <= self.dropEndTime
60    }
61    
62    // Get remaining time in seconds
63    access(all) view fun getTimeRemaining(): UFix64 {
64        if !self.checkDropActive() {
65            return 0.0
66        }
67        let now = getCurrentBlock().timestamp
68        if now >= self.dropEndTime {
69            return 0.0
70        }
71        return self.dropEndTime - now
72    }
73    
74    // Check if user is eligible to claim
75    access(all) view fun isEligibleForGumDrop(user: Address): Bool {
76        // User is eligible if:
77        // 1. Drop is active
78        // 2. They haven't claimed yet
79        // 3. They own at least one Flunk NFT (checked in frontend/API)
80        return self.checkDropActive() && 
81               self.claimRecord[user] == nil
82    }
83    
84    // Get drop info
85    access(all) view fun getGumDropInfo(): {String: AnyStruct} {
86        let now = getCurrentBlock().timestamp
87        let active = self.checkDropActive()
88        
89        return {
90            "isActive": active,
91            "startTime": self.dropStartTime,
92            "endTime": self.dropEndTime,
93            "timeRemaining": active ? self.getTimeRemaining() : 0.0,
94            "gumPerFlunk": self.gumAmountPerFlunk,
95            "currentTime": now
96        }
97    }
98    
99    // Claim GumDrop - records on-chain that user claimed
100    access(all) fun claimGumDrop(user: Address) {
101        pre {
102            self.checkDropActive(): "No active GumDrop event"
103            self.claimRecord[user] == nil: "Already claimed this drop"
104        }
105        
106        // Record the claim
107        let now = getCurrentBlock().timestamp
108        self.claimRecord[user] = now
109        
110        // Emit event (actual GUM crediting happens via Supabase API)
111        emit GumDropClaimed(user: user, amount: self.gumAmountPerFlunk, timestamp: now)
112    }
113    
114    // Get user's claim status
115    access(all) view fun getUserClaimTime(user: Address): UFix64? {
116        return self.claimRecord[user]
117    }
118    
119    init() {
120        // Set storage paths
121        self.AdminStoragePath = /storage/FlunksGumDropAdmin
122        
123        // Initialize with no active drop
124        self.dropStartTime = 0.0
125        self.dropEndTime = 0.0
126        self.gumAmountPerFlunk = 100
127        self.dropActive = false
128        self.claimRecord = {}
129        
130        // Create and store admin resource
131        let admin <- create Admin()
132        self.account.storage.save(<-admin, to: self.AdminStoragePath)
133    }
134}
135