Smart Contract

MoxyData

A.123cb47fe122f6e3.MoxyData

Deployed

1d ago
Feb 26, 2026, 09:44:38 PM UTC

Dependents

0 imports
1 
2
3pub contract MoxyData {
4    
5    pub struct DictionaryMapped {
6        pub var dictionary: {UFix64:AnyStruct}
7        pub var arrayMap: [UFix64]
8
9        pub fun setValue(_ value: AnyStruct) {
10            let timestamp = getCurrentBlock().timestamp
11            self.dictionary[timestamp] = value
12            self.arrayMap.append(timestamp)
13        }
14
15        pub fun valueNow():AnyStruct {
16            return self.valueFor(timestamp: getCurrentBlock().timestamp)
17
18        }
19        
20        pub fun valueFor(timestamp: UFix64):AnyStruct {
21            if (self.arrayMap.length == 0 || timestamp < self.arrayMap[0]) {
22                // No values for that timestamp
23                return nil
24            }
25
26            if (timestamp >= self.arrayMap[self.arrayMap.length-1]) {
27                return self.dictionary[self.arrayMap[self.arrayMap.length-1]]!
28            }
29
30            //search
31            var i = 0
32            while (self.arrayMap.length < i && self.arrayMap[i] < timestamp) {
33                i = i + 1
34            }
35
36            if (i > self.arrayMap.length-1) {
37                i = self.arrayMap.length-1
38            }
39
40            return self.dictionary[self.arrayMap[i]]
41        }
42
43        init() {
44            self.dictionary = {}
45            self.arrayMap = []
46        }
47    }
48
49    /** Resource to store key: Timestamp, value: amount
50     *  The amounts in dictionary accumulates from last amounts added
51     *  so the changes must to be calculated.
52     */
53
54    pub resource OrderedDictionary {
55        pub var dictionary: {UFix64:UFix64}
56        pub var arrayMap: [UFix64]
57        pub var ages: {UFix64:UFix64}
58        pub var agesMap: [UFix64]
59
60        pub fun getDictionary(): {UFix64: UFix64} {
61            return self.dictionary
62        }
63
64        /**
65            Returns the value for the given timestamp. If the timestamp
66            is not found, it returns the most recent timestamp that is
67            less than the parameter received.
68         */
69        pub fun getValueOrMostRecentFor(timestamp: UFix64): UFix64 {
70            let time0000 = MoxyData.getTimestampTo0000(timestamp: timestamp)
71            if (self.dictionary[time0000] != nil) {
72                return self.dictionary[time0000]!
73            }
74
75            // For this day there are no registered balances, look for the
76            // last recorded balance or zero if there are no previous records
77            // per requested day
78            var index = -1
79            var hasActivity = false
80            for time in self.arrayMap {
81                if (time >= time0000  ) {
82                    hasActivity = true
83                    break
84                }
85                index = index + 1
86            }
87            if (index < 0) {
88                // No previous activity
89                return 0.0
90            }
91            return self.dictionary[self.arrayMap[index]]!
92        }
93
94        pub fun getValueFor(timestamp: UFix64): UFix64 {
95            let time0000 = MoxyData.getTimestampTo0000(timestamp: timestamp)
96            if (self.dictionary[time0000] == nil) {
97                return 0.0
98            }
99            return self.dictionary[time0000]!
100        }
101
102        pub fun getValueForToday(): UFix64 {
103            let balance = self.getValueOrMostRecentFor(timestamp: getCurrentBlock().timestamp)
104            if (balance == nil) {
105                return 0.0
106            }
107            return balance
108        }
109
110        pub fun getValueChangeForToday(): Fix64 {
111            return self.getValueChange(timestamp: getCurrentBlock().timestamp)
112        }
113
114        // Get the difference between the day (represented by timestamp) with the
115        // previous date (previous date could be several days ago, depending on activity)
116        pub fun getValueChange(timestamp: UFix64): Fix64 {
117            let time0000 = MoxyData.getTimestampTo0000(timestamp: timestamp)
118
119            if (self.dictionary.length < 1) {
120                // No records > no change
121                return 0.0
122            }
123            if (self.arrayMap[0] > time0000 ) {
124                // Date is previous to the first registered
125                return 0.0
126            }
127            var lastTimestamp = self.getLastKeyAdded()
128            if (time0000 > lastTimestamp!) {
129                // Date is over last timestamp
130                return 0.0
131            }
132
133            // Balance en la fecha consultada
134            var timestamp = self.dictionary[time0000]
135            
136            if (timestamp == nil) {
137                // No records > no changes
138                return 0.0
139            }
140
141            // Look for last balance
142            if (self.arrayMap[0] == time0000 ) {
143                // No previous > change is balance total
144                return Fix64(timestamp!)
145            }
146
147            // There is a balance, we have to look for the previous balance to see
148            // what was the change
149            // search
150            var index = 0
151            for time in self.arrayMap {
152                if (time == time0000) {
153                    break
154                }
155                index = index + 1
156            }
157            let indexBefore = index - 1
158            var timestampBefore = self.dictionary[self.arrayMap[indexBefore]]
159
160            return Fix64(timestamp!) - Fix64(timestampBefore!)
161        }
162
163        pub fun getValueChanges(): {UFix64:UFix64} {
164            return self.getValueChangesUpTo(timestamp: getCurrentBlock().timestamp)
165        }
166
167        pub fun getValueChangesUpTo(timestamp: UFix64): {UFix64:UFix64} {
168            let resu: {UFix64:UFix64} = {}
169            var amountBefore = 0.0
170            var timeBefore = 0.0
171            var remaining = 0.0
172
173            for time in self.arrayMap {
174                if (time > timestamp) {
175                    // If timestamp
176                    continue
177                }
178                if (self.dictionary[time]! > amountBefore ) {
179                    let amount = self.dictionary[time]! - amountBefore
180
181                    // Add to dictionary
182                    resu[time] = amount
183                } else {
184                    // Changes are negative
185                    remaining = remaining + amountBefore - self.dictionary[time]!
186                }
187                if (remaining > 0.0 && resu[timeBefore] != nil) {
188                    if (resu[timeBefore]! > remaining) {
189                        resu[timeBefore] = resu[timeBefore]! - remaining
190                        remaining = 0.0
191                    } else {
192                        let amnt = resu[timeBefore]!
193                        resu.remove(key: timeBefore) ?? nil
194                        remaining = remaining - amnt
195                    }
196                }
197                amountBefore = self.dictionary[time]!
198                timeBefore = time
199            }
200            for time in resu.keys {
201                if (remaining == 0.0) {
202                    break
203                }
204                if (resu[time]! > remaining) {
205                    resu[time] = resu[time]! - remaining
206                    remaining = 0.0
207                } else {
208                    let amnt = resu[time]!
209                    resu.remove(key: time) ?? nil
210                    remaining = remaining - amnt
211                }
212            }
213
214            return resu
215        }
216
217        pub fun getLastKeyAdded(): UFix64? {
218            let pos = self.dictionary.length - 1
219            if (pos < 0) {
220                return nil
221            }
222            return self.arrayMap[pos]
223        }
224
225        pub fun getFirstKeyAdded(): UFix64? {
226            if (self.arrayMap.length == 0) {
227                return nil
228            }
229            return self.arrayMap[0]
230        }
231
232        pub fun getLastValue(): UFix64 {
233            let pos = self.dictionary.length - 1
234            if (pos < 0) {
235                return 0.0
236            }
237            return self.dictionary[self.arrayMap[pos]!]!
238        }
239
240        pub fun setAmountFor(timestamp: UFix64, amount: UFix64) {
241            let time0000 = MoxyData.getTimestampTo0000(timestamp: timestamp)
242            let lastTimestamp = self.getLastKeyAdded()
243
244            // Check if timestamp to add exists and that is greater than
245            // the last timestamp added, to keep order on arrayMap
246            if (lastTimestamp == nil || time0000 > lastTimestamp! || self.dictionary[time0000] == nil) {
247                // Assign last value as initial amount for required timestamp
248                self.dictionary[time0000] = self.getLastValue()
249                self.arrayMap.append(time0000)
250            }
251            self.addAge(timestamp: time0000, amount: amount)
252            self.dictionary[time0000] = self.dictionary[time0000]! + amount
253        }
254        
255        pub fun addAge(timestamp: UFix64, amount: UFix64) {
256            if (self.ages[timestamp] == nil) {
257                self.ages[timestamp] = 0.0
258                self.agesMap.append(timestamp)
259            }
260            self.ages[timestamp] = self.ages[timestamp]! + amount
261        }
262
263        pub fun subtractOldestAge(amount: UFix64): {UFix64: UFix64} {
264            var amountRemaining = amount
265            let dict: {UFix64:UFix64} = {}
266
267            while(amountRemaining > 0.0 && self.agesMap.length > 0) {
268                // Always ask for index zero as is the oldest deposit
269                let timestamp = self.agesMap[0]
270                let balance = self.ages[timestamp]!
271                if (amountRemaining > balance ) {
272                    //balance of the day is not enough for total withdraw
273                    amountRemaining = amountRemaining - balance
274                    //remove daily balance
275                    self.ages.remove(key: timestamp)
276                    self.agesMap.remove(at: 0)
277                    dict[timestamp] = balance
278                } else {
279                    //balance is enough to complete total withdraw
280                    self.ages[timestamp] = self.ages[timestamp]! - amountRemaining
281                    dict[timestamp] = amountRemaining
282                    amountRemaining = 0.0
283                }
284            }
285            if (amountRemaining > 0.0) {
286                panic("Not enough amount to withdraw from dictionary.")
287            }
288            return dict
289        }
290
291
292        pub fun canUpdateTo(timestamp: UFix64): Bool {
293
294            let time0000 = MoxyData.getTimestampTo0000(timestamp: timestamp)
295            let lastTimestamp = self.getLastKeyAdded()
296
297            // Returns true if there are no registered timestamp yet or
298            // if the time to add is equal or greater than the las timestamp added.
299            return lastTimestamp == nil || time0000 >= lastTimestamp!
300        }
301
302        pub fun withdrawValueFromOldest(amount: UFix64): {UFix64: UFix64} {
303            let time0000 = MoxyData.getTimestampTo0000(timestamp: getCurrentBlock().timestamp)
304            let lastTimestamp = self.getLastKeyAdded()
305            let value = self.getLastValue()
306
307            if (value < amount) {
308                panic("Not enough amount to withdraw from dictionary.")
309            }
310
311            let dict = self.subtractOldestAge(amount: amount)
312            for time in dict.keys {
313                self.dictionary[time] = self.dictionary[time]! - dict[time]!
314            }
315
316            return dict
317        }
318
319        pub fun destroyWith(orderedDictionary: @OrderedDictionary) {
320            let dict = orderedDictionary.getDictionary()
321            for timestamp in dict.keys {
322                if (self.dictionary[timestamp] != nil) {
323                    self.dictionary[timestamp] = self.dictionary[timestamp]! - dict[timestamp]!
324                }
325            }
326
327            destroy orderedDictionary
328        }
329
330
331        init() {
332            self.dictionary = {}
333            self.arrayMap = []
334            self.ages = {}
335            self.agesMap = []
336        }
337
338    }
339
340    pub resource interface OrderedDictionaryInfo {
341        pub fun getDictionary(): {UFix64: UFix64}
342    }
343
344    pub fun getTimestampTo0000(timestamp: UFix64): UFix64 {
345        let dayInSec = 86400.0
346        let days = timestamp / dayInSec
347        return UFix64(UInt64(days)) * dayInSec
348    }
349
350    pub fun createNewOrderedDictionary(): @OrderedDictionary {
351        return <-create OrderedDictionary()
352    }
353
354    
355    init() {
356    }
357}
358 
359