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