Smart Contract
BloctoStorageRent
A.1dfd1e5b87b847dc.BloctoStorageRent
Address
Dependents
0 imports1/*
2This tool adds a new entitlemtent called all to some functions that it cannot be sure if it is safe to make access(all)
3those functions you should check and update their entitlemtents ( or change to all access )
4
5Please see:
6https://cadence-lang.org/docs/cadence-migration-guide/nft-guide#update-all-pub-access-modfiers
7
8IMPORTANT SECURITY NOTICE
9Please familiarize yourself with the new entitlements feature because it is extremely important for you to understand in order to build safe smart contracts.
10If you change pub to access(all) without paying attention to potential downcasting from public interfaces, you might expose private functions like withdraw
11that will cause security problems for your contract.
12
13*/
14
15import FungibleToken from 0xf233dcee88fe0abe
16import FlowStorageFees from 0xe467b9dd11fa00df
17import FlowToken from 0x1654653399040a61
18
19access(all)
20contract BloctoStorageRent{
21 access(all)
22 let BloctoStorageRentAdminStoragePath: StoragePath
23
24 access(contract)
25 var StorageRentRefillThreshold: UInt64
26
27 access(contract)
28 var RefilledAccounts: [Address]
29
30 access(contract)
31 var RefilledAccountInfos:{ Address: RefilledAccountInfo}
32
33 access(contract)
34 var RefillRequiredBlocks: UInt64
35
36 access(all)
37 view fun getStorageRentRefillThreshold(): UInt64{
38 return self.StorageRentRefillThreshold
39 }
40
41 access(all)
42 view fun getRefilledAccounts(): [Address]{
43 return self.RefilledAccounts
44 }
45
46 access(all)
47 view fun getRefilledAccountInfos():{ Address: RefilledAccountInfo}{
48 return self.RefilledAccountInfos
49 }
50
51 access(all)
52 view fun getRefillRequiredBlocks(): UInt64{
53 return self.RefillRequiredBlocks
54 }
55
56 access(all)
57 fun tryRefill(_ address: Address){
58 self.cleanExpiredRefilledAccounts(10)
59 let recipient = getAccount(address)
60 let receiverRef =
61 recipient.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver).borrow()
62 if receiverRef == nil || (receiverRef!).owner == nil{
63 return
64 }
65
66 if self.RefilledAccountInfos[address] != nil
67 && getCurrentBlock().height - (self.RefilledAccountInfos[address]!).atBlock
68 < self.RefillRequiredBlocks{
69 return
70 }
71 var low: UInt64 = recipient.storage.used
72 var high: UInt64 = recipient.storage.capacity
73 if high < low{
74 high <-> low
75 }
76 if high - low < self.StorageRentRefillThreshold {
77 let vaultRef = self.account.storage.borrow<auth(FungibleToken.Withdraw) &FlowToken.Vault>(from: /storage/flowTokenVault)
78 ?? panic("Could not borrow reference to the owner's Vault!")
79
80 let requiredAmount = FlowStorageFees.storageCapacityToFlow(FlowStorageFees.convertUInt64StorageBytesToUFix64Megabytes(self.StorageRentRefillThreshold * 2))
81 self.addRefilledAccount(address)
82 (receiverRef!).deposit(from: <-(vaultRef!).withdraw(amount: requiredAmount))
83 }
84 }
85
86 access(all)
87 view fun checkEligibility(_ address: Address): Bool{
88 if self.RefilledAccountInfos[address] != nil
89 && getCurrentBlock().height - (self.RefilledAccountInfos[address]!).atBlock
90 < self.RefillRequiredBlocks{
91 return false
92 }
93 let acct = getAccount(address)
94 var high: UInt64 = acct.storage.capacity
95 var low: UInt64 = acct.storage.used
96 if high < low{
97 high <-> low
98 }
99 if high - low >= self.StorageRentRefillThreshold{
100 return false
101 }
102 return true
103 }
104
105 access(contract)
106 fun addRefilledAccount(_ address: Address){
107 if self.RefilledAccountInfos[address] != nil{
108 self.RefilledAccounts.remove(at: (self.RefilledAccountInfos[address]!).index)
109 }
110 self.RefilledAccounts.append(address)
111 self.RefilledAccountInfos[address] = RefilledAccountInfo(
112 self.RefilledAccounts.length - 1,
113 getCurrentBlock().height
114 )
115 }
116
117 access(all)
118 fun cleanExpiredRefilledAccounts(_ batchSize: Int){
119 var index = 0
120 while index < batchSize && self.RefilledAccounts.length > index{
121 if self.RefilledAccountInfos[self.RefilledAccounts[index]] != nil && getCurrentBlock().height - (self.RefilledAccountInfos[self.RefilledAccounts[index]]!).atBlock < self.RefillRequiredBlocks{
122 break
123 }
124 self.RefilledAccountInfos.remove(key: self.RefilledAccounts[index])
125 self.RefilledAccounts.remove(at: index)
126 index = index + 1
127 }
128 }
129
130 access(all)
131 struct RefilledAccountInfo{
132 access(all)
133 let atBlock: UInt64
134
135 access(all)
136 let index: Int
137
138 init(_ index: Int, _ atBlock: UInt64){
139 self.index = index
140 self.atBlock = atBlock
141 }
142 }
143
144 access(all)
145 resource Admin{
146 access(all)
147 fun setStorageRentRefillThreshold(_ threshold: UInt64){
148 BloctoStorageRent.StorageRentRefillThreshold = threshold
149 }
150
151 access(all)
152 fun setRefillRequiredBlocks(_ blocks: UInt64){
153 BloctoStorageRent.RefillRequiredBlocks = blocks
154 }
155 }
156
157 init(){
158 self.BloctoStorageRentAdminStoragePath = /storage/BloctoStorageRentAdmin
159 self.StorageRentRefillThreshold = 5000
160 self.RefilledAccounts = []
161 self.RefilledAccountInfos ={}
162 self.RefillRequiredBlocks = 86400
163 let admin <- create Admin()
164 self.account.storage.save(<-admin, to: /storage/BloctoStorageRentAdmin)
165 }
166}