Smart Contract

PPPV7

A.3ddb31a3880d1d8f.PPPV7

Deployed

1d ago
Feb 26, 2026, 10:41:48 PM UTC

Dependents

0 imports
1/**
2
3# This smart contract is designed for a comprehensive on-chain points system within the Increment.Fi ecosystem.
4# It integrates various DeFi infrastructures including Lending, Swap, Liquid Staking, and Farming.
5
6*/
7
8import FungibleToken from 0xf233dcee88fe0abe
9// Lending
10import LendingInterfaces from 0x2df970b6cdee5735
11import LendingConfig from 0x2df970b6cdee5735
12// Swap
13import SwapConfig from 0xb78ef7afa52ff906
14import SwapInterfaces from 0xb78ef7afa52ff906
15// Liquid Staking
16import LiquidStaking from 0xd6f80565193ad727
17// Farm
18import Staking from 0x1b77ba4b414de352
19import StakingNFT from 0x1b77ba4b414de352
20import FLOAT from 0x2d4c3caffbeab845
21
22// Oracle
23import PublicPriceOracle from 0xec67451f8a58216a
24
25// Referral System
26import RV3 from 0x3ddb31a3880d1d8f
27
28pub contract PPPV7 {
29
30    // Total supply of points in existence
31    access(all) var _totalSupply: UFix64
32
33    // Mapping of user addresses to their base points amount.
34    access(self) let _pointsBase: {Address: UFix64}
35
36    // Snapshot of points for each user at a specific historical moment.
37    access(self) let _pointsHistorySnapshot: {Address: UFix64}
38
39    // Mapping from referrer addresses to the total points they've earned from their referees.
40    // {Referrer: TotalPointsFromReferees}
41    access(self) let _totalPointsAsReferrer: {Address: UFix64}
42
43    // {Referrer: {Referee: PointsFrom}}
44    access(self) let _pointsFromReferees: {Address: {Address: UFix64}}
45
46    // Mapping of user addresses to the points they've boosted as referees.
47    access(self) let _pointsAsReferee: {Address: UFix64}
48
49    // Mapping of user addresses to the points they've boosted as core members of the Increment.
50    access(self) let _pointsAsCoreMember: {Address: UFix64}
51
52    // A blacklist of user addresses that are excluded from earning points.
53    access(self) let _userBlacklist: {Address: Bool}
54
55    // A whitelist of swap pool addresses that are eligible for point earnings.
56    access(self) let _swapPoolWhitelist: {Address: Bool}
57
58    // Configuration for points earning rates based on various criteria such as lending supply, etc.
59    /*
60        {
61            "LendingSupply": {
62                0.0         : 0.001,  //  supply usd amount: 0.0     ~ 1000.0  -> 0.001
63                1000.0      : 0.002,  //  supply usd amount: 1000.0  ~ 10000.0 -> 0.002
64                10000.0     : 0.003   //  supply usd amount: 10000.0 ~ Max     -> 0.003
65            }
66        }
67    */
68    access(self) let _pointsRate: {String: AnyStruct}
69
70    // The duration in seconds for each points rate session, affecting how points accumulate over time.
71    access(self) let _secondsPerPointsRateSession: UFix64
72
73    // Mapping of user states, storing various metrics such as last update timestamp for points calculation.
74    access(self) let _userStates: {Address: {String: UFix64}}
75
76    // Indicates whether a user has claimed their points from the historical snapshot.
77    access(self) let _ifClaimHistorySnapshot: {Address: Bool}
78    access(self) var _claimEndTimestamp: UFix64
79    
80    // A list of user addresses ranked by their total points, representing the top users.
81    access(self) var _topUsers: [Address]
82    
83    //
84    access(self) let _reservedFields: {String: AnyStruct}
85
86    /// Events
87    access(all) event PointsMinted(userAddr: Address, amount: UFix64, source: String, param: {String: String})
88    access(all) event PointsBurned(userAddr: Address, amount: UFix64, source: String, param: {String: String})
89    access(all) event StateUpdated(userAddr: Address, state: {String: UFix64})
90    access(all) event PointsRateChanged(source: String, ori: UFix64, new: UFix64)
91    access(all) event PointsTierRateChanged(source: String, ori: {UFix64: UFix64}, new: {UFix64: UFix64})
92    access(all) event ClaimSnapshotPoints(userAddr: Address, amount: UFix64)
93    access(all) event TopUsersChanged(ori: [Address], new: [Address])
94    access(all) event SetSnapshotPoints(userAddr: Address, pre: UFix64, new: UFix64)
95
96    // Method to calculate a user's total balance of points.
97    access(all) view fun balanceOf(_ userAddr: Address): UFix64 {
98        // Base points plus any unclaimed historical snapshot points, points as referrer, referee, core member,
99        // and newly accrued points since the last update.
100        return self.getBasePoints(userAddr)
101                +
102               (self.ifClaimHistorySnapshot(userAddr)? self.getHistorySnapshotPoints(userAddr): 0.0)
103                +
104               self.getPointsAsReferrer(userAddr)
105                +
106               self.getPointsAsReferee(userAddr)
107                +
108               self.getPointsAsCoreMember(userAddr)
109                +
110               self.calculateNewPointsSinceLastUpdate(userAddr: userAddr) * (1.0 + self.getBasePointsBoostRate(userAddr))  // accured points
111    }
112
113    // Mint Points
114    access(self) fun _mint(targetAddr: Address, amount: UFix64) {
115        if self._userBlacklist.containsKey(targetAddr) {
116            return
117        }
118
119        // mint points
120        if self._pointsBase.containsKey(targetAddr) == false {
121            self._pointsBase[targetAddr] = 0.0
122        }
123        self._pointsBase[targetAddr] = self._pointsBase[targetAddr]! + amount
124        
125        // Attempt to retrieve the referrer address for the target address. If a referrer exists...
126        let referrerAddr: Address? = RV3.getReferrerByReferee(referee: targetAddr)
127        if referrerAddr != nil {
128            // Calculate and mint referee boost points.
129            let boostAmountAsReferee = amount * self.getPointsRate_RefereeUp()
130            if boostAmountAsReferee > 0.0 {
131                if self._pointsAsReferee.containsKey(targetAddr) == false {
132                    self._pointsAsReferee[targetAddr] = boostAmountAsReferee
133                } else {
134                    self._pointsAsReferee[targetAddr] = self._pointsAsReferee[targetAddr]! + boostAmountAsReferee
135                }
136                emit PointsMinted(
137                    userAddr: targetAddr,
138                    amount: boostAmountAsReferee,
139                    source: "AsReferee",
140                    param: {}
141                )
142                self._totalSupply = self._totalSupply + boostAmountAsReferee
143            }
144
145            // Calculate and mint referrer boost points.
146            let boostAmountForReferrer = amount * self.getPointsRate_ReferrerUp()
147            if boostAmountForReferrer > 0.0 && self._userBlacklist.containsKey(referrerAddr!) == false {
148                if self._totalPointsAsReferrer.containsKey(referrerAddr!) == false {
149                    self._totalPointsAsReferrer[referrerAddr!] = boostAmountForReferrer
150                } else {
151                    self._totalPointsAsReferrer[referrerAddr!] = self._totalPointsAsReferrer[referrerAddr!]! + boostAmountForReferrer
152                }
153                if self._pointsFromReferees.containsKey(referrerAddr!) == false {
154                    self._pointsFromReferees[referrerAddr!] = {}
155                }
156                if self._pointsFromReferees[referrerAddr!]!.containsKey(targetAddr) == false {
157                    self._pointsFromReferees[referrerAddr!]!.insert(key: targetAddr, boostAmountForReferrer)
158                } else {
159                    self._pointsFromReferees[referrerAddr!]!.insert(key: targetAddr, self._pointsFromReferees[referrerAddr!]![targetAddr]! + boostAmountForReferrer)
160                }
161                if self._pointsBase.containsKey(referrerAddr!) == false {
162                    self._pointsBase[referrerAddr!] = 0.0
163                }
164                emit PointsMinted(
165                    userAddr: referrerAddr!,
166                    amount: boostAmountForReferrer,
167                    source: "AsReferrer",
168                    param: {}
169                )
170                self._totalSupply = self._totalSupply + boostAmountForReferrer
171            }
172        }
173
174        // Calculate and mint core member boost points if the target address is a core member.
175        if self.isCoreMember(targetAddr) {
176            let boostAmountAsCoreMember = amount * self.getPointsRate_CoreMember()
177            if boostAmountAsCoreMember > 0.0 {
178                if self._pointsAsCoreMember.containsKey(targetAddr) == false {
179                    self._pointsAsCoreMember[targetAddr] = boostAmountAsCoreMember
180                } else {
181                    self._pointsAsCoreMember[targetAddr] = self._pointsAsCoreMember[targetAddr]! + boostAmountAsCoreMember
182                }
183                emit PointsMinted(
184                    userAddr: targetAddr,
185                    amount: boostAmountAsCoreMember,
186                    source: "AsCoreMember",
187                    param: {}
188                )
189                self._totalSupply = self._totalSupply + boostAmountAsCoreMember
190            }
191        }
192
193        // Update the total supply of points by adding the minted amount.
194        self._totalSupply = self._totalSupply + amount;
195    }
196    
197    // Function to calculate new points earned by a user since their last update.
198    access(all) view fun calculateNewPointsSinceLastUpdate(userAddr: Address): UFix64 {
199        let lastUpdateTimestamp = self.getUserState_LastUpdateTimestamp(userAddr: userAddr)
200        if lastUpdateTimestamp == 0.0 { return 0.0 }
201        if self._userBlacklist.containsKey(userAddr) { return 0.0 }
202
203        // Lending Supply
204        let accuredLendingSupplyPoints = self.calculateNewPointsSinceLastUpdate_LendingSupply(userAddr: userAddr)
205        // Lending Borrow
206        let accuredLendingBorrowPoints = self.calculateNewPointsSinceLastUpdate_LendingBorrow(userAddr: userAddr)
207        // stFlow Holdings
208        let accuredStFlowHoldingPoints = self.calculateNewPointsSinceLastUpdate_stFlowHolding(userAddr: userAddr)
209        // Swap LP
210        let accuredSwapLPPoints = self.calculateNewPointsSinceLastUpdate_SwapLP(userAddr: userAddr)
211        
212        // Sums up the accrued points from all activities, adjusting for any base points boost rate applicable to the user.
213        return accuredLendingSupplyPoints + accuredLendingBorrowPoints + accuredStFlowHoldingPoints + accuredSwapLPPoints
214                
215    }
216    
217    // Updates the state of a user, including their related balance based on DeFi activities.
218    access(all) fun updateUserState(userAddr: Address) {
219        if self._userBlacklist.containsKey(userAddr) {
220            return
221        }
222
223        let lastUpdateTimestamp = self.getUserState_LastUpdateTimestamp(userAddr: userAddr)
224        let duration = getCurrentBlock().timestamp - lastUpdateTimestamp
225        let durationStr = duration.toString()
226
227        if duration > 0.0 {
228            // Calculate new points accrued from lending supply activities.
229            let accuredLendingSupplyPoints = self.calculateNewPointsSinceLastUpdate_LendingSupply(userAddr: userAddr)
230            if (accuredLendingSupplyPoints > 0.0) {
231                emit PointsMinted(
232                    userAddr: userAddr,
233                    amount: accuredLendingSupplyPoints,
234                    source: "LendingSupply",
235                    param: {
236                        "SupplyUsdValue": self.getUserState_LendingSupply(userAddr: userAddr).toString(),
237                        "Duration": durationStr
238                    }
239                )
240            }
241
242            // Similar calculations and event emissions for lending borrow, stFlow holding, and Swap LP activities.
243            // Lending Borrow
244            let accuredLendingBorrowPoints = self.calculateNewPointsSinceLastUpdate_LendingBorrow(userAddr: userAddr)
245            if (accuredLendingBorrowPoints > 0.0) {
246                emit PointsMinted(
247                    userAddr: userAddr,
248                    amount: accuredLendingBorrowPoints,
249                    source: "LendingBorrow",
250                    param: {
251                        "BorrowUsdValue": self.getUserState_LendingBorrow(userAddr: userAddr).toString(),
252                        "Duration": durationStr
253                    }
254                )
255            }
256
257            // stFlow Holding
258            let accuredStFlowHoldingPoints = self.calculateNewPointsSinceLastUpdate_stFlowHolding(userAddr: userAddr)
259            if (accuredStFlowHoldingPoints > 0.0) {
260                emit PointsMinted(
261                    userAddr: userAddr,
262                    amount: accuredStFlowHoldingPoints,
263                    source: "stFlowHolding",
264                    param: {
265                        "stFlowHoldingBalance": self.getUserState_stFlowHolding(userAddr: userAddr).toString(),
266                        "Duration": durationStr
267                    }
268                )
269            }
270
271            // Swap LP
272            let accuredSwapLPPoints = self.calculateNewPointsSinceLastUpdate_SwapLP(userAddr: userAddr)
273            if (accuredSwapLPPoints > 0.0) {
274                emit PointsMinted(
275                    userAddr: userAddr,
276                    amount: accuredSwapLPPoints,
277                    source: "SwapLP",
278                    param: {
279                        "SwapLPUsdValue": self.getUserState_SwapLPUsd(userAddr: userAddr).toString(),
280                        "Duration": durationStr
281                    }
282                )
283            }
284
285            // Mint points for the total accrued from all activities.
286            let accuredPointsToMint = 
287                accuredLendingSupplyPoints +
288                accuredLendingBorrowPoints +
289                accuredStFlowHoldingPoints +
290                accuredSwapLPPoints
291            if (accuredPointsToMint > 0.0) {
292                self._mint(targetAddr: userAddr, amount: accuredPointsToMint)
293            }
294        }
295
296        // Fetch updated on-chain user states for various DeFi activities.
297        let states = self.fetchOnchainUserStates(userAddr: userAddr)
298        let totalSupplyAmountInUsd = states[0]
299        let totalBorrowAmountInUsd = states[1]
300        let stFlowTotalBalance = states[2]
301        let totalLpBalanceUsd = states[3]
302        let totalLpAmount = states[4]
303
304         // Update user states with the latest data.
305        if self._userStates.containsKey(userAddr) 
306            || totalSupplyAmountInUsd > 0.0 || totalBorrowAmountInUsd > 0.0
307            || stFlowTotalBalance > 0.0
308            || totalLpBalanceUsd > 0.0
309        {
310            if self._userStates.containsKey(userAddr) == false {
311                self._userStates[userAddr] = {}
312            }
313
314            self.setUserState_LendingSupply(userAddr: userAddr, supplyAmount: totalSupplyAmountInUsd)
315            self.setUserState_LendingBorrow(userAddr: userAddr, borrowAmount: totalBorrowAmountInUsd)
316            self.setUserState_stFlowHolding(userAddr: userAddr, stFlowBalance: stFlowTotalBalance)
317            self.setUserState_SwapLPUsd(userAddr: userAddr, lpUsd: totalLpBalanceUsd)
318            self.setUserState_SwapLPAmount(userAddr: userAddr, lpAmount: totalLpAmount)
319            
320            self.setUserState_LastUpdateTimestamp(userAddr: userAddr, timestamp: getCurrentBlock().timestamp)
321
322            //
323            emit StateUpdated(userAddr: userAddr, state: self._userStates[userAddr]!)
324        }
325    }
326
327    // Function to fetch and calculate a user's state across different DeFi protocols.
328    access(all) view fun fetchOnchainUserStates(userAddr: Address): [UFix64] {
329        // Oracle Price
330        let oraclePrices: {String: UFix64} = { // OracleAddress -> Token Price
331            "Flow": PublicPriceOracle.getLatestPrice(oracleAddr: 0xe385412159992e11),
332            "stFlow": PublicPriceOracle.getLatestPrice(oracleAddr: 0x031dabc5ba1d2932),
333            "USDC": PublicPriceOracle.getLatestPrice(oracleAddr: 0xf5d12412c09d2470)
334        }
335  
336        // Access the lending comptroller to fetch market addresses and calculate the user's supply and borrow in USD.
337        let lendingComptrollerRef = getAccount(0xf80cb737bfe7c792).getCapability<&{LendingInterfaces.ComptrollerPublic}>(LendingConfig.ComptrollerPublicPath).borrow()!
338        let marketAddrs: [Address] = lendingComptrollerRef.getAllMarkets()
339        let lendingOracleRef = getAccount(0x72d3a05910b6ffa3).getCapability<&{LendingInterfaces.OraclePublic}>(LendingConfig.OraclePublicPath).borrow()!
340        var totalSupplyAmountInUsd = 0.0
341        var totalBorrowAmountInUsd = 0.0
342        for poolAddr in marketAddrs {
343            let poolRef = lendingComptrollerRef.getPoolPublicRef(poolAddr: poolAddr)
344            let poolOraclePrice = lendingOracleRef.getUnderlyingPrice(pool: poolAddr)
345            let res: [UInt256; 5] = poolRef.getAccountRealtimeScaled(account: userAddr)
346            let supplyAmount = SwapConfig.ScaledUInt256ToUFix64(res[0] * res[1] / SwapConfig.scaleFactor)
347            let borrowAmount = SwapConfig.ScaledUInt256ToUFix64(res[2])
348            totalSupplyAmountInUsd = totalSupplyAmountInUsd + supplyAmount * poolOraclePrice
349            totalBorrowAmountInUsd = totalBorrowAmountInUsd + borrowAmount * poolOraclePrice
350        }
351
352        // Liquid Staking State
353        // Calculate the user's stFlow token balance by checking their vault capability.
354        var stFlowTotalBalance = 0.0
355        let stFlowVaultCap = getAccount(userAddr).getCapability<&{FungibleToken.Balance}>(/public/stFlowTokenBalance)
356        if stFlowVaultCap.check() {
357            // Prevent fake stFlow token vault
358            if stFlowVaultCap.borrow()!.getType().identifier == "A.d6f80565193ad727.stFlowToken.Vault" {
359                stFlowTotalBalance = stFlowVaultCap.borrow()!.balance
360            }
361        }
362
363        // Calculate the user's total LP balance in USD and total LP amount.
364        let lpPrices: {Address: UFix64} = {}
365        var totalLpBalanceUsd = 0.0
366        var totalLpAmount = 0.0
367        let lpTokenCollectionCap = getAccount(userAddr).getCapability<&{SwapInterfaces.LpTokenCollectionPublic}>(SwapConfig.LpTokenCollectionPublicPath)
368        if lpTokenCollectionCap.check() {
369            // Prevent fake lp token vault
370            if lpTokenCollectionCap.borrow()!.getType().identifier == "A.b063c16cac85dbd1.SwapFactory.LpTokenCollection" {
371                let lpTokenCollectionRef = lpTokenCollectionCap.borrow()!
372                let liquidityPairAddrs = lpTokenCollectionRef.getAllLPTokens()
373                for pairAddr in liquidityPairAddrs {
374                    // 
375                    if self._swapPoolWhitelist.containsKey(pairAddr) == false {
376                        continue
377                    }
378
379                    var lpTokenAmount = lpTokenCollectionRef.getLpTokenBalance(pairAddr: pairAddr)
380                    let pairInfo = getAccount(pairAddr).getCapability<&{SwapInterfaces.PairPublic}>(/public/increment_swap_pair).borrow()!.getPairInfo()
381                    // Cal lp price
382                    var lpPrice = 0.0
383                    if lpPrices.containsKey(pairAddr) {
384                        lpPrice = lpPrices[pairAddr]!
385                    } else {
386                        lpPrice = self.calValidLpPrice(pairInfo: pairInfo, oraclePrices: oraclePrices)
387                        lpPrices[pairAddr] = lpPrice
388                    }
389                    if lpPrice == 0.0 || lpTokenAmount == 0.0 { continue }
390                    totalLpBalanceUsd = totalLpBalanceUsd + lpPrice * lpTokenAmount
391                    totalLpAmount = totalLpAmount + lpTokenAmount
392                }
393            }
394        }
395
396        // Swap LP in Farm & stFlow in Farm
397        // let farmCollectionRef = getAccount(0x1b77ba4b414de352).getCapability<&{Staking.PoolCollectionPublic}>(Staking.CollectionPublicPath).borrow()!
398        // let userFarmIds = Staking.getUserStakingIds(address: userAddr)
399        // for farmPoolId in userFarmIds {
400        //     let farmPool = farmCollectionRef.getPool(pid: farmPoolId)
401        //     let farmPoolInfo = farmPool.getPoolInfo()
402        //     let userInfo = farmPool.getUserInfo(address: userAddr)!
403        //     if farmPoolInfo.status == "0" || farmPoolInfo.status == "1" || farmPoolInfo.status == "2" {
404        //         let acceptTokenKey = farmPoolInfo.acceptTokenKey
405        //         let acceptTokenName = acceptTokenKey.slice(from: 19, upTo: acceptTokenKey.length)
406        //         let userFarmAmount = userInfo.stakingAmount
407        //         // add stFlow holding balance
408        //         if acceptTokenKey == "A.d6f80565193ad727.stFlowToken" {
409        //             stFlowTotalBalance = stFlowTotalBalance + userFarmAmount
410        //             continue
411        //         }
412        //         if userFarmAmount == 0.0 {
413        //             continue
414        //         }
415        //         // add lp holding balance
416        //         let swapPoolAddress = self.type2address(acceptTokenKey)
417        //         if acceptTokenName == "SwapPair" {
418        //             let swapPoolInfo = getAccount(swapPoolAddress).getCapability<&{SwapInterfaces.PairPublic}>(SwapConfig.PairPublicPath).borrow()!.getPairInfo()
419        //             var lpPrice = 0.0
420        //             if lpPrices.containsKey(swapPoolAddress) {
421        //                 lpPrice = lpPrices[swapPoolAddress]!
422        //             } else {
423        //                 lpPrice = self.calValidLpPrice(pairInfo: swapPoolInfo, oraclePrices: oraclePrices)
424        //                 lpPrices[swapPoolAddress] = lpPrice
425        //             }
426        //             totalLpBalanceUsd = totalLpBalanceUsd + userFarmAmount * lpPrice
427        //             totalLpAmount = totalLpAmount + userFarmAmount
428        //         }
429        //     }
430        // }
431
432        return [
433            totalSupplyAmountInUsd,
434            totalBorrowAmountInUsd,
435            stFlowTotalBalance,
436            totalLpBalanceUsd,
437            totalLpAmount
438        ]
439    }
440
441    access(all) fun claimSnapshotPoints(userCertificateCap: Capability<&{LendingInterfaces.IdentityCertificate}>) {
442        pre {
443            self._claimEndTimestamp > getCurrentBlock().timestamp: "The claim period has concluded."
444        }
445        let userAddr: Address = userCertificateCap.borrow()!.owner!.address
446        assert(self.getHistorySnapshotPoints(userAddr) > 0.0, message: "Nothing to claim")
447        self._ifClaimHistorySnapshot[userAddr] = true
448        
449        emit ClaimSnapshotPoints(userAddr: userAddr, amount: self.getHistorySnapshotPoints(userAddr))
450    }
451
452    access(all) view fun getBasePointsLength(): Int {
453        return self._pointsBase.length
454    }
455
456    access(all) view fun getSlicedBasePointsAddrs(from: Int, to: Int): [Address] {
457        let len = self._userStates.length
458        let endIndex = to > len ? len : to
459        var curIndex = from
460        return self._pointsBase.keys.slice(from: from, upTo: to)
461    }
462
463    access(all) view fun getBasePoints(_ userAddr: Address): UFix64 {
464        return self._pointsBase.containsKey(userAddr)? self._pointsBase[userAddr]! : 0.0
465    }
466    
467    access(all) view fun getHistorySnapshotPoints(_ userAddr: Address): UFix64 {
468        return self._pointsHistorySnapshot.containsKey(userAddr)? self._pointsHistorySnapshot[userAddr]! : 0.0
469    }
470
471    access(all) view fun getPointsAsReferrer(_ userAddr: Address): UFix64 {
472        return self._totalPointsAsReferrer.containsKey(userAddr)? self._totalPointsAsReferrer[userAddr]!: 0.0
473    }
474
475    access(all) view fun getPointsAsReferee(_ userAddr: Address): UFix64 {
476        return self._pointsAsReferee.containsKey(userAddr)? self._pointsAsReferee[userAddr]!: 0.0
477    }
478
479    access(all) view fun getLastestPointsAsReferee(_ userAddr: Address): UFix64 {
480        let referrerAddr = RV3.getReferrerByReferee(referee: userAddr)
481        let lastUpdatePointsAsReferee = self.getPointsAsReferee(userAddr);
482        let latestPointsAsReferee = 
483            (referrerAddr != nil? self.getPointsRate_RefereeUp() : 0.0)
484            *
485            self.calculateNewPointsSinceLastUpdate(userAddr: userAddr)
486        return lastUpdatePointsAsReferee + latestPointsAsReferee;
487    }
488
489    access(all) view fun getPointsAsCoreMember(_ userAddr: Address): UFix64 {
490        return self._pointsAsCoreMember.containsKey(userAddr)? self._pointsAsCoreMember[userAddr]!: 0.0
491    }
492
493    access(all) view fun getLastestPointsAsCoreMember(_ userAddr: Address): UFix64 {
494        let lastUpdatePointsAsCoreMember = self.getPointsAsCoreMember(userAddr);
495        let latestPointsAsCoreMember = 
496            (self.isCoreMember(userAddr)? self.getPointsRate_CoreMember() : 0.0)
497            *
498            self.calculateNewPointsSinceLastUpdate(userAddr: userAddr)
499        return lastUpdatePointsAsCoreMember + latestPointsAsCoreMember;
500    }
501
502    access(all) view fun getPointsAndTimestamp(_ userAddr: Address): [UFix64; 3] {
503        return [self.balanceOf(userAddr), self.getPointsAsReferrer(userAddr), self.getUserState_LastUpdateTimestamp(userAddr: userAddr)]
504    }
505
506    access(all) view fun getUserInfo(_ userAddr: Address): [UFix64] {
507        return [
508            self.balanceOf(userAddr),
509            self.getPointsAsReferrer(userAddr),
510            self.getUserState_LastUpdateTimestamp(userAddr: userAddr),
511            self.getUserState_LendingSupply(userAddr: userAddr),
512            self.getUserState_LendingBorrow(userAddr: userAddr),
513            self.getUserState_stFlowHolding(userAddr: userAddr),
514            self.getUserState_SwapLPUsd(userAddr: userAddr),
515            self.getUserState_SwapVolume(userAddr: userAddr)
516        ]
517    }
518
519    access(all) view fun getUserInfosLength(): Int {
520        return self._userStates.length
521    }
522
523    access(all) view fun getSlicedUserInfos(from: Int, to: Int): {Address: [UFix64]} {
524        let len = self._userStates.length
525        let endIndex = to > len ? len : to
526        var curIndex = from
527        let res: {Address: [UFix64]} = {}
528        while curIndex < endIndex {
529            let userAddr: Address = self._userStates.keys[curIndex]
530            res[userAddr] = self.getUserInfo(userAddr)
531            curIndex = curIndex + 1
532        }
533        return res
534    }
535
536    
537
538    access(all) view fun isCoreMember(_ userAddr: Address): Bool {
539        let coreMemberEventID: UInt64 = 326723707
540        let floatCollection = getAccount(userAddr).getCapability(FLOAT.FLOATCollectionPublicPath).borrow<&FLOAT.Collection{FLOAT.CollectionPublic}>()
541        if floatCollection == nil {
542            return false
543        }
544        let nftID: [UInt64] = floatCollection!.ownedIdsFromEvent(eventId: coreMemberEventID)
545        if floatCollection!.getType().identifier == "A.2d4c3caffbeab845.FLOAT.Collection" && nftID.length > 0{
546            return true
547        }
548        let poolCollectionCap = getAccount(StakingNFT.address).getCapability<&{StakingNFT.PoolCollectionPublic}>(StakingNFT.CollectionPublicPath).borrow()!
549        let count = StakingNFT.poolCount
550        var idx: UInt64 = 0
551        while idx < count {
552            let pool = poolCollectionCap.getPool(pid: idx)
553            let poolExtraParams = pool.getExtraParams()
554            if (poolExtraParams.containsKey("eventId") && poolExtraParams["eventId"]! as! UInt64 == coreMemberEventID) {
555                let userInfo = pool.getUserInfo(address: userAddr)
556                if userInfo != nil && userInfo!.stakedNftIds.length > 0 {
557                    return true
558                }
559            }
560            idx = idx + 1
561        }
562        return false
563    }
564
565    access(all) view fun ifClaimHistorySnapshot(_ userAddr: Address): Bool {
566        if self._ifClaimHistorySnapshot.containsKey(userAddr) == true {
567            return self._ifClaimHistorySnapshot[userAddr]!
568        }
569        return false;
570    }
571
572    access(all) view fun getBasePointsBoostRate(_ userAddr: Address): UFix64 {
573        let referrerAddr = RV3.getReferrerByReferee(referee: userAddr)
574        return (self.isCoreMember(userAddr)? self.getPointsRate_CoreMember() : 0.0)
575                +
576               (referrerAddr != nil? self.getPointsRate_RefereeUp() : 0.0)
577    }
578
579    // Accure Lending Supply
580    access(all) view fun calculateNewPointsSinceLastUpdate_LendingSupply(userAddr: Address): UFix64 {
581        let lastUpdateTimestamp = self.getUserState_LastUpdateTimestamp(userAddr: userAddr)
582        var accuredPoints = 0.0
583        if lastUpdateTimestamp == 0.0 { return 0.0 }
584        let currUpdateTimestamp = getCurrentBlock().timestamp
585        let duration = currUpdateTimestamp - lastUpdateTimestamp
586        if duration > 0.0 {
587            let supplyAmountUsd = self.getUserState_LendingSupply(userAddr: userAddr)
588            accuredPoints = supplyAmountUsd * self.getPointsRate_LendingSupply(amount: supplyAmountUsd) / self._secondsPerPointsRateSession * duration
589        }
590        return accuredPoints
591    }
592
593    // Accure Lending Borrow
594    access(all) view fun calculateNewPointsSinceLastUpdate_LendingBorrow(userAddr: Address): UFix64 {
595        let lastUpdateTimestamp = self.getUserState_LastUpdateTimestamp(userAddr: userAddr)
596        var accuredPoints = 0.0
597        if lastUpdateTimestamp == 0.0 { return 0.0 }
598        let currUpdateTimestamp = getCurrentBlock().timestamp
599        let duration = currUpdateTimestamp - lastUpdateTimestamp
600        if duration > 0.0 {
601            let borrowAmountUsd = self.getUserState_LendingBorrow(userAddr: userAddr)
602            accuredPoints = borrowAmountUsd * self.getPointsRate_LendingBorrow(amount: borrowAmountUsd) / self._secondsPerPointsRateSession * duration
603        }
604        return accuredPoints
605    }
606
607    // Accure Liquid Staking - stFlowHolding
608    access(self) view fun calculateNewPointsSinceLastUpdate_stFlowHolding(userAddr: Address): UFix64 {
609        let lastUpdateTimestamp = self.getUserState_LastUpdateTimestamp(userAddr: userAddr)
610        var accuredPoints = 0.0
611        if lastUpdateTimestamp == 0.0 { return 0.0 }
612        let currUpdateTimestamp = getCurrentBlock().timestamp
613        let duration = currUpdateTimestamp - lastUpdateTimestamp
614        if duration > 0.0 {
615            let stFlowHolding = self.getUserState_stFlowHolding(userAddr: userAddr)
616            accuredPoints = stFlowHolding * self.getPointsRate_stFlowHolding(amount: stFlowHolding) / self._secondsPerPointsRateSession * duration
617        }
618        return accuredPoints
619    }
620
621    // Accure Swap LP
622    access(self) view fun calculateNewPointsSinceLastUpdate_SwapLP(userAddr: Address): UFix64 {
623        let lastUpdateTimestamp = self.getUserState_LastUpdateTimestamp(userAddr: userAddr)
624        var accuredPoints = 0.0
625        if lastUpdateTimestamp == 0.0 { return 0.0 }
626        let currUpdateTimestamp = getCurrentBlock().timestamp
627        let duration = currUpdateTimestamp - lastUpdateTimestamp
628        if duration > 0.0 {
629            let swapLP = self.getUserState_SwapLPUsd(userAddr: userAddr)
630            accuredPoints = swapLP * self.getPointsRate_SwapLP(amount: swapLP) / self._secondsPerPointsRateSession * duration
631        }
632        return accuredPoints
633    }
634
635    access(all) view fun getTopUsers(): [Address] { return self._topUsers }
636
637    access(all) view fun getSwapPoolWhiltlist(): {Address: Bool} { return self._swapPoolWhitelist }
638
639    access(all) view fun getUserBlacklist(): {Address: Bool} { return self._userBlacklist }
640
641    // Get Points Rate
642    access(all) view fun getPointsRate(): {String: AnyStruct} { return self._pointsRate }
643    access(all) view fun getPointsRate_LendingSupply(amount: UFix64): UFix64 { return self.calculateTierRateByAmount(amount: amount, tier: self._pointsRate["LendingSupply"]! as! {UFix64: UFix64}) }
644    access(all) view fun getPointsRate_LendingBorrow(amount: UFix64): UFix64 { return self.calculateTierRateByAmount(amount: amount, tier: self._pointsRate["LendingBorrow"]! as! {UFix64: UFix64}) }
645    access(all) view fun getPointsRate_stFlowHolding(amount: UFix64): UFix64 { return self.calculateTierRateByAmount(amount: amount, tier: self._pointsRate["stFlowHolding"]! as! {UFix64: UFix64}) }
646    access(all) view fun getPointsRate_SwapLP(amount: UFix64): UFix64 { return self.calculateTierRateByAmount(amount: amount, tier: self._pointsRate["SwapLP"]! as! {UFix64: UFix64}) }
647    access(all) view fun getPointsRate_SwapVolume(amount: UFix64): UFix64 { return self.calculateTierRateByAmount(amount: amount, tier: self._pointsRate["SwapVolume"]! as! {UFix64: UFix64}) }
648    access(all) view fun getPointsRate_ReferrerUp(): UFix64 { return self._pointsRate["ReferrerUp"]! as! UFix64 }
649    access(all) view fun getPointsRate_RefereeUp(): UFix64 { return self._pointsRate["RefereeUp"]! as! UFix64 }
650    access(all) view fun getPointsRate_CoreMember(): UFix64 { return self._pointsRate["CoreMember"]! as! UFix64 }
651
652    // Get User State
653    access(all) view fun getUserState(userAddr: Address): {String: UFix64} { return self._userStates.containsKey(userAddr)? self._userStates[userAddr]! : {} }
654    access(all) view fun getUserState_LastUpdateTimestamp(userAddr: Address): UFix64 { return self._userStates.containsKey(userAddr)? (self._userStates[userAddr]!.containsKey("LastUpdateTimestamp")? self._userStates[userAddr]!["LastUpdateTimestamp"]! : 0.0): 0.0 }
655    access(all) view fun getUserState_LendingSupply(userAddr: Address): UFix64 { return self._userStates.containsKey(userAddr)? (self._userStates[userAddr]!.containsKey("LendingTotalSupplyUsd")? self._userStates[userAddr]!["LendingTotalSupplyUsd"]! : 0.0): 0.0 }
656    access(all) view fun getUserState_LendingBorrow(userAddr: Address): UFix64 { return self._userStates.containsKey(userAddr)? (self._userStates[userAddr]!.containsKey("LendingTotalBorrowUsd")? self._userStates[userAddr]!["LendingTotalBorrowUsd"]! : 0.0): 0.0 }
657    access(all) view fun getUserState_stFlowHolding(userAddr: Address): UFix64 { return self._userStates.containsKey(userAddr)? (self._userStates[userAddr]!.containsKey("stFlowHolding")? self._userStates[userAddr]!["stFlowHolding"]! : 0.0): 0.0 }
658    access(all) view fun getUserState_SwapLPUsd(userAddr: Address): UFix64 { return self._userStates.containsKey(userAddr)? (self._userStates[userAddr]!.containsKey("SwapLpUsd")? self._userStates[userAddr]!["SwapLpUsd"]! : 0.0): 0.0 }
659    access(all) view fun getUserState_SwapLPAmount(userAddr: Address): UFix64 { return self._userStates.containsKey(userAddr)? (self._userStates[userAddr]!.containsKey("SwapLpAmount")? self._userStates[userAddr]!["SwapLpAmount"]! : 0.0): 0.0 }
660    access(all) view fun getUserState_SwapVolume(userAddr: Address): UFix64 { return self._userStates.containsKey(userAddr)? (self._userStates[userAddr]!.containsKey("SwapVolumeUsd")? self._userStates[userAddr]!["SwapVolumeUsd"]! : 0.0): 0.0 }
661    
662    access(self) fun setUserState_LastUpdateTimestamp(userAddr: Address, timestamp: UFix64) { self._userStates[userAddr]!.insert(key: "LastUpdateTimestamp", timestamp) }
663    access(self) fun setUserState_LendingSupply(userAddr: Address, supplyAmount: UFix64) { self._userStates[userAddr]!.insert(key: "LendingTotalSupplyUsd", supplyAmount) }
664    access(self) fun setUserState_LendingBorrow(userAddr: Address, borrowAmount: UFix64) { self._userStates[userAddr]!.insert(key: "LendingTotalBorrowUsd", borrowAmount) }
665    access(self) fun setUserState_stFlowHolding(userAddr: Address, stFlowBalance: UFix64) { self._userStates[userAddr]!.insert(key: "stFlowHolding", stFlowBalance) }
666    access(self) fun setUserState_SwapLPUsd(userAddr: Address, lpUsd: UFix64) { self._userStates[userAddr]!.insert(key: "SwapLpUsd", lpUsd) }
667    access(self) fun setUserState_SwapLPAmount(userAddr: Address, lpAmount: UFix64) { self._userStates[userAddr]!.insert(key: "SwapLpAmount", lpAmount) }
668    access(self) fun setUserState_SwapVolume(userAddr: Address, volume: UFix64) { self._userStates[userAddr]!.insert(key: "SwapVolumeUsd", volume) }
669
670    access(all) view fun calculateTierRateByAmount(amount: UFix64, tier: {UFix64: UFix64}): UFix64 {
671        var rate = 0.0
672        var maxThreshold = 0.0
673        for threshold in tier.keys {
674            if amount >= threshold && threshold >= maxThreshold {
675                rate = tier[threshold]!
676                maxThreshold = threshold
677            }
678        }
679        return rate
680    }
681
682    // Calculates the price of an LP token based on the reserves of the pair and the current prices of the underlying tokens.
683    access(all) view fun calValidLpPrice(pairInfo: [AnyStruct], oraclePrices: {String: UFix64}): UFix64 {
684        var reserveAmount = 0.0
685        var reservePrice = 0.0
686        var lpPrice = 0.0
687        if pairInfo[0] as! String == "A.b19436aae4d94622.FiatToken" {reserveAmount = pairInfo[2] as! UFix64; reservePrice = oraclePrices["USDC"]!}
688        else if pairInfo[1] as! String == "A.b19436aae4d94622.FiatToken" {reserveAmount = pairInfo[3] as! UFix64; reservePrice = oraclePrices["USDC"]!}
689        else if pairInfo[0] as! String == "A.1654653399040a61.FlowToken" {reserveAmount = pairInfo[2] as! UFix64; reservePrice = oraclePrices["Flow"]!}
690        else if pairInfo[1] as! String == "A.1654653399040a61.FlowToken" {reserveAmount = pairInfo[3] as! UFix64; reservePrice = oraclePrices["Flow"]!}
691        else if pairInfo[0] as! String == "A.d6f80565193ad727.stFlowToken" {reserveAmount = pairInfo[2] as! UFix64; reservePrice = oraclePrices["stFlow"]!}
692        else if pairInfo[1] as! String == "A.d6f80565193ad727.stFlowToken" {reserveAmount = pairInfo[3] as! UFix64; reservePrice = oraclePrices["stFlow"]!}
693        if reservePrice > 0.0 && reserveAmount > 1000.0 {
694            lpPrice = reserveAmount * reservePrice * 2.0 / (pairInfo[5] as! UFix64)
695        }
696        return lpPrice
697    }
698
699    // A.0xabc.Toke -> 0xabc
700    access(all) view fun type2address(_ type: String): Address {
701        let address = type.slice(from: 2, upTo: 18)
702        var r: UInt64 = 0
703        var bytes = address.decodeHex()
704        while bytes.length>0{
705            r = r  + (UInt64(bytes.removeFirst()) << UInt64(bytes.length*8))
706        }
707        return Address(r)
708    }
709
710    access(all) view fun getClaimEndTimestamp(): UFix64 {
711        return self._claimEndTimestamp
712    }
713
714    /// Admin
715    ///
716    access(all) resource Admin {
717        // Set Points Rate
718        access(all) fun setPointsRate_stFlowHoldingTier(tierRate: {UFix64: UFix64}) {
719            emit PointsTierRateChanged(source: "stFlowHolding", ori: PPPV7._pointsRate["stFlowHolding"]! as! {UFix64: UFix64}, new: tierRate)
720            PPPV7._pointsRate["stFlowHolding"] = tierRate
721        }
722        access(all) fun setPointsRate_LendingSupplyTier(tierRate: {UFix64: UFix64}) {
723            emit PointsTierRateChanged(source: "LendingSupply", ori: PPPV7._pointsRate["LendingSupply"]! as! {UFix64: UFix64}, new: tierRate)
724            PPPV7._pointsRate["LendingSupply"] = tierRate
725        }
726        access(all) fun setPointsRate_LendingBorrowTier(tierRate: {UFix64: UFix64}) {
727            emit PointsTierRateChanged(source: "LendingBorrow", ori: PPPV7._pointsRate["LendingBorrow"]! as! {UFix64: UFix64}, new: tierRate)
728            PPPV7._pointsRate["LendingBorrow"] = tierRate
729        }
730        access(all) fun setPointsRate_SwapLPTier(tierRate: {UFix64: UFix64}) {
731            emit PointsTierRateChanged(source: "SwapLP", ori: PPPV7._pointsRate["SwapLP"]! as! {UFix64: UFix64}, new: tierRate)
732            PPPV7._pointsRate["SwapLP"] = tierRate
733        }
734        access(all) fun setPointsRate_SwapVolumeTier(tierRate: {UFix64: UFix64}) {
735            emit PointsTierRateChanged(source: "SwapVolume", ori: PPPV7._pointsRate["SwapVolume"]! as! {UFix64: UFix64}, new: tierRate)
736            PPPV7._pointsRate["SwapVolume"] = tierRate
737        }
738        access(all) fun setPointsRate_ReferrerUp(rate: UFix64) {
739            emit PointsRateChanged(source: "ReferrerUp", ori: PPPV7._pointsRate["ReferrerUp"]! as! UFix64, new: rate)
740            PPPV7._pointsRate["ReferrerUp"] = rate
741        }
742        access(all) fun setPointsRate_RefereeUp(rate: UFix64) {
743            emit PointsRateChanged(source: "RefereeUp", ori: PPPV7._pointsRate["RefereeUp"]! as! UFix64, new: rate)
744            PPPV7._pointsRate["RefereeUp"] = rate
745        }
746        access(all) fun setPointsRate_CoreMember(rate: UFix64) {
747            emit PointsRateChanged(source: "CoreMember", ori: PPPV7._pointsRate["CoreMember"]! as! UFix64, new: rate)
748            PPPV7._pointsRate["CoreMember"] = rate
749        }
750
751        // Add Swap Pool in Whiltelist
752        access(all) fun addSwapPoolInWhiltelist(poolAddr: Address) {
753            PPPV7._swapPoolWhitelist[poolAddr] = true
754        }
755        // Remove Swap Pool in Whitelist
756        access(all) fun removeSwapPoolInWhiltelist(poolAddr: Address) {
757            PPPV7._swapPoolWhitelist.remove(key: poolAddr)
758        }
759
760        // Set history snapshot points
761        access(all) fun setHistorySnapshotPoints(userAddr: Address, newSnapshotBalance: UFix64) {
762            if PPPV7._pointsHistorySnapshot.containsKey(userAddr) == false {
763                PPPV7._pointsHistorySnapshot[userAddr] = 0.0
764            }
765            if PPPV7._pointsBase.containsKey(userAddr) == false {
766                PPPV7._pointsBase[userAddr] = 0.0
767            }
768            let preSnapshotBalance = PPPV7._pointsHistorySnapshot[userAddr]!
769            emit SetSnapshotPoints(userAddr: userAddr, pre: preSnapshotBalance, new: newSnapshotBalance)
770            if preSnapshotBalance == newSnapshotBalance {
771                return
772            }
773            if preSnapshotBalance < newSnapshotBalance {
774                emit PointsMinted(userAddr: userAddr, amount: newSnapshotBalance - preSnapshotBalance, source: "HistorySnapshot", param: {"PreBalance": preSnapshotBalance.toString(), "NewBalance": newSnapshotBalance.toString()})
775            } else {
776                emit PointsBurned(userAddr: userAddr, amount: preSnapshotBalance - newSnapshotBalance, source: "HistorySnapshot", param: {"PreBalance": preSnapshotBalance.toString(), "NewBalance": newSnapshotBalance.toString()})
777            }
778            PPPV7._totalSupply = PPPV7._totalSupply - preSnapshotBalance + newSnapshotBalance
779            PPPV7._pointsHistorySnapshot[userAddr] = newSnapshotBalance
780        }
781        access(all) fun setClaimEndTimestamp(endTime: UFix64) {
782            PPPV7._claimEndTimestamp = endTime
783        }
784
785        // Ban user
786        access(all) fun addUserBlackList(userAddr: Address) {
787            PPPV7._userBlacklist[userAddr] = true
788        }
789        access(all) fun removeUserBlackList(userAddr: Address) {
790            PPPV7._userBlacklist.remove(key: userAddr)
791        }
792
793        access(all) fun addVolumePoints(userAddr: Address, volumePoints: UFix64, volumeUsd: UFix64) {
794            PPPV7._mint(targetAddr: userAddr, amount: volumePoints)
795
796            if PPPV7._userStates.containsKey(userAddr) == false {
797                PPPV7._userStates[userAddr] = {}
798            }
799            PPPV7.setUserState_SwapVolume(userAddr: userAddr, volume: PPPV7.getUserState_SwapVolume(userAddr: userAddr) + volumeUsd)
800            emit PointsMinted(
801                userAddr: userAddr,
802                amount: volumePoints,
803                source: "SwapVolume", 
804                param: {
805                    "VolumeUsd": volumeUsd.toString()
806                }
807            )
808            emit StateUpdated(userAddr: userAddr, state: PPPV7._userStates[userAddr]!)
809        }
810
811        access(all) fun reconcileBasePoints(userAddr: Address, newBasePoints: UFix64) {
812            // TODO process referral points
813            if PPPV7._pointsBase.containsKey(userAddr) == false {
814                PPPV7._pointsBase[userAddr] = 0.0
815            }
816            let preBasePoints = PPPV7._pointsBase[userAddr]!
817            if preBasePoints == newBasePoints {
818                return
819            }
820            if preBasePoints < newBasePoints {
821                emit PointsMinted(userAddr: userAddr, amount: newBasePoints - preBasePoints, source: "Reconcile", param: {"PreBaseBalance": preBasePoints.toString(), "NewBaseBalance": newBasePoints.toString()})
822            } else {
823                emit PointsBurned(userAddr: userAddr, amount: preBasePoints - newBasePoints, source: "Reconcile", param: {"PreBaseBalance": preBasePoints.toString(), "NewBaseBalance": newBasePoints.toString()})
824            }
825            PPPV7._totalSupply = PPPV7._totalSupply - preBasePoints + newBasePoints
826            PPPV7._pointsBase[userAddr] = newBasePoints
827        }
828
829        access(all) fun updateTopUsers(addrs: [Address]) {
830            emit TopUsersChanged(ori: PPPV7._topUsers, new: addrs)
831            PPPV7._topUsers = addrs
832        }
833
834        // TODO
835        access(all) fun testResetIfSnapshot(userAddr: Address) {
836            PPPV7._ifClaimHistorySnapshot[userAddr] = false
837        }
838    }
839
840    init() {
841        self._totalSupply = 0.0
842        self._secondsPerPointsRateSession = 3600.0
843        self._pointsBase = {}
844        self._pointsHistorySnapshot = {}
845        self._totalPointsAsReferrer = {}
846        self._pointsFromReferees = {}
847        self._pointsAsReferee = {}
848        self._pointsAsCoreMember = {}
849        self._topUsers = []
850        self._pointsRate = {
851            "stFlowHolding": {
852                0.0: 0.0,
853                1.0: 0.001
854            },
855            "LendingSupply": {
856                0.0: 0.0,
857                1.0: 0.00007,
858                10.0: 0.000072,
859                100.0: 0.000074,
860                1000.0: 0.000076,
861                10000.0: 0.000074,
862                100000.0: 0.000072,
863                1000000.0: 0.00007
864            },
865            "LendingBorrow": {
866                0.0: 0.0,
867                1.0: 0.00035,
868                10.0: 0.00036,
869                100.0: 0.00037,
870                1000.0: 0.00038,
871                10000.0: 0.00037,
872                100000.0: 0.00036,
873                1000000.0: 0.00035
874            },
875            "SwapLP": {
876                0.0: 0.0,
877                1.0: 0.0001,
878                10.0: 0.0002,
879                100.0: 0.001,
880                1000.0: 0.002,
881                10000.0: 0.001,
882                100000.0: 0.0002,
883                1000000.0: 0.0001
884            },
885            "SwapVolume": {
886                0.0: 0.0,
887                1.0: 0.002
888            },
889            "ReferrerUp": 0.05,
890            "RefereeUp": 0.05,
891            "CoreMember": 0.2
892        }
893        self._swapPoolWhitelist = {
894            0xfa82796435e15832: true, // FLOW-USDC
895            0xc353b9d685ec427d: true, // FLOW-stFLOW stable
896            0xa06c38beec9cf0e8: true, // FLOW-DUST
897            0xbfb26bb8adf90399: true  // FLOW-SLOPPY
898        }
899
900        self._userStates = {}
901        self._userBlacklist = {}
902        self._ifClaimHistorySnapshot = {}
903        self._claimEndTimestamp = getCurrentBlock().timestamp + 86400.0 * 60.0
904
905        self._reservedFields = {}
906
907        destroy <-self.account.load<@AnyResource>(from: /storage/pointsAdmin)
908        self.account.save(<-create Admin(), to: /storage/pointsAdmin)
909    }
910}
911