Smart Contract
TokenListHelper
A.15a918087ab12d86.TokenListHelper
1/**
2> Author: Fixes Lab <https://github.com/fixes-world/>
3
4# TokenList Helper
5
6The utility contract to help query the FTs and NFTs from the TokenList and NFTList contracts.
7
8*/
9import MetadataViews from 0x1d7e57aa55817448
10import ViewResolver from 0x1d7e57aa55817448
11import FungibleToken from 0xf233dcee88fe0abe
12import NonFungibleToken from 0x1d7e57aa55817448
13import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
14import EVM from 0xe467b9dd11fa00df
15import FlowEVMBridgeConfig from 0x1e4aa0b87d10b141
16import FlowEVMBridgeUtils from 0x1e4aa0b87d10b141
17import FlowToken from 0x1654653399040a61
18// TokenList Imports
19import TokenList from 0x15a918087ab12d86
20import NFTList from 0x15a918087ab12d86
21import FTViewUtils from 0x15a918087ab12d86
22import NFTViewUtils from 0x15a918087ab12d86
23import EVMTokenList from 0x15a918087ab12d86
24
25access(all) contract TokenListHelper {
26
27 /// Query result
28 ///
29 access(all) struct QueryResult {
30 access(all)
31 let total: Int
32 access(all)
33 let list: [{FTViewUtils.ITokenView}]
34
35 init(total: Int, list: [{FTViewUtils.ITokenView}]) {
36 self.total = total
37 self.list = list
38 }
39 }
40
41 /// Query FTs with pagination and filter
42 ///
43 access(all)
44 fun queryFTs(
45 page: Int,
46 size: Int,
47 reviewer: Address?,
48 filterType: UInt8?,
49 ): QueryResult {
50 // If filterType is not in the range of 0-4, return empty list
51 if filterType != nil && filterType! > 4 {
52 return QueryResult(total: 0, list: [])
53 }
54
55 let registry = TokenList.borrowRegistry()
56
57 var totalAmt = 0
58 var ftTypes: [Type] = []
59 if reviewer != nil && filterType != 0 {
60 if let reviewerRef = TokenList.borrowReviewerPublic(reviewer!) {
61 var all: [Type] = []
62 let start = page * size
63 var end = start + size
64 if filterType == 1 {
65 // Reviewed by Reviewer
66 all = reviewerRef.getReviewedFTTypes()
67 } else if filterType == 2 {
68 // Managed by Reviewer
69 all = reviewerRef.getManagedFTTypes()
70 } else if filterType == 3 {
71 // Verified by Reviewer
72 all = reviewerRef.getVerifiedFTTypes()
73 } else if filterType == 4 {
74 // Featured by Reviewer
75 all = reviewerRef.getFeaturedFTTypes()
76 } else if filterType == 5 {
77 // Blocked by Reviewer
78 all = reviewerRef.getBlockedFTTypes()
79 }
80 totalAmt = all.length
81 if totalAmt == 0 || start >= totalAmt {
82 return QueryResult(total: 0, list: [])
83 }
84 if end > totalAmt {
85 end = totalAmt
86 }
87 ftTypes = all.slice(from: start, upTo: end)
88 }
89 } else {
90 totalAmt = registry.getFTEntriesAmount()
91 ftTypes = registry.getFTEntries(page, size)
92 }
93 log("Page:".concat(page.toString()).concat(" Size:").concat(size.toString()).concat(" Reviewer:").concat(reviewer?.toString() ?? "").concat(" Total:").concat(totalAmt.toString()))
94
95 return QueryResult(
96 total: totalAmt,
97 list: self.buildTheFTList(ftTypes, reviewer)
98 )
99 }
100
101 /// Query FTs by address
102 ///
103 access(all)
104 fun queryFTsByAddress(
105 ftAddress: Address,
106 reviewer: Address?,
107 ): QueryResult {
108 let registry = TokenList.borrowRegistry()
109 let ftTypes: [Type] = registry.getFTEntriesByAddress(ftAddress)
110 return QueryResult(
111 total: ftTypes.length,
112 list: self.buildTheFTList(ftTypes, reviewer)
113 )
114 }
115
116 /// Query NFTs with pagination and filter
117 ///
118 access(self)
119 fun buildTheFTList(_ types: [Type], _ reviewer: Address?): [{FTViewUtils.ITokenView}] {
120 if types.length == 0 {
121 return []
122 }
123
124 let registry = TokenList.borrowRegistry()
125 var list: [{FTViewUtils.ITokenView}] = []
126
127 // load token view
128 for ftType in types {
129 if let ftEntry = registry.borrowFungibleTokenEntry(ftType) {
130 list.append(self.buildFTView(ftEntry, reviewer, false))
131 }
132 }
133 return list
134 }
135
136 access(self)
137 fun buildFTView(
138 _ ftEntry: &{TokenList.FTEntryInterface},
139 _ reviewer: Address?,
140 _ prioritizeEVMData: Bool,
141 ): {FTViewUtils.ITokenView} {
142 let identity = ftEntry.getIdentity()
143 var paths: FTViewUtils.StandardTokenPaths? = nil
144 var source: Address? = nil
145 if let data = ftEntry.getVaultData(reviewer) {
146 source = data.source
147 paths = FTViewUtils.StandardTokenPaths(
148 vaultPath: data.vaultData.storagePath,
149 balancePath: data.vaultData.metadataPath,
150 receiverPath: data.vaultData.receiverPath,
151 )
152 }
153 let tokenType = identity.buildType()
154 if let evmAddr = FlowEVMBridgeConfig.getEVMAddressAssociated(with: tokenType) {
155 var decimals: UInt8 = 8
156 if prioritizeEVMData || FlowEVMBridgeUtils.isCadenceNative(type: tokenType) == false {
157 if prioritizeEVMData && FlowEVMBridgeUtils.isERC20(evmContractAddress: evmAddr) {
158 decimals = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: evmAddr)
159 }
160 }
161 return FTViewUtils.BridgedTokenView(
162 identity: identity,
163 evmAddress: "0x".concat(evmAddr.toString()),
164 decimals: decimals,
165 tags: ftEntry.getTags(reviewer),
166 dataSource: source,
167 paths: paths,
168 display: ftEntry.getDisplay(reviewer),
169 )
170 } else {
171 return FTViewUtils.StandardTokenView(
172 identity: identity,
173 decimals: 8,
174 tags: ftEntry.getTags(reviewer),
175 dataSource: source,
176 paths: paths,
177 display: ftEntry.getDisplay(reviewer),
178 )
179 }
180 }
181
182 /// Query NFTs with pagination and filter
183 ///
184 access(all)
185 fun queryNFTs(
186 page: Int,
187 size: Int,
188 reviewer: Address?,
189 filterType: UInt8?,
190 ): QueryResult {
191 // If filterType is not in the range of 0-4, return empty list
192 if filterType != nil && filterType! > 4 {
193 return QueryResult(total: 0, list: [])
194 }
195
196 let registry = NFTList.borrowRegistry()
197
198 var totalAmt = 0
199 var nftTypes: [Type] = []
200 if reviewer != nil && filterType != 0 {
201 if let reviewerRef = NFTList.borrowReviewerPublic(reviewer!) {
202 var all: [Type] = []
203 let start = page * size
204 var end = start + size
205 if filterType == 1 {
206 // Reviewed by Reviewer
207 all = reviewerRef.getReviewedNFTTypes()
208 } else if filterType == 2 {
209 // Managed by Reviewer
210 all = []
211 } else if filterType == 3 {
212 // Verified by Reviewer
213 all = reviewerRef.getVerifiedNFTTypes()
214 } else if filterType == 4 {
215 // Featured by Reviewer
216 all = reviewerRef.getFeaturedNFTTypes()
217 } else if filterType == 5 {
218 // Blocked by Reviewer
219 all = reviewerRef.getBlockedNFTTypes()
220 }
221 totalAmt = all.length
222 if totalAmt == 0 || start >= totalAmt {
223 return QueryResult(total: 0, list: [])
224 }
225 if end > totalAmt {
226 end = totalAmt
227 }
228 nftTypes = all.slice(from: start, upTo: end)
229 }
230 } else {
231 totalAmt = registry.getNFTEntriesAmount()
232 nftTypes = registry.getNFTEntries(page, size)
233 }
234 log("Page:".concat(page.toString()).concat(" Size:").concat(size.toString()).concat(" Reviewer:").concat(reviewer?.toString() ?? "").concat(" Total:").concat(totalAmt.toString()))
235
236 return QueryResult(
237 total: totalAmt,
238 list: self.buildTheNFTList(nftTypes, reviewer)
239 )
240 }
241
242 /// Query NFTs by address
243 ///
244 access(all)
245 fun queryNFTsByAddress(
246 address: Address,
247 reviewer: Address?,
248 ): QueryResult {
249 let registry = NFTList.borrowRegistry()
250 let types = registry.getNFTEntriesByAddress(address)
251 return QueryResult(
252 total: types.length,
253 list: self.buildTheNFTList(types, reviewer)
254 )
255 }
256
257 /// Build the NFT list
258 ///
259 access(self)
260 fun buildTheNFTList(_ types: [Type], _ reviewer: Address?): [{FTViewUtils.ITokenView}] {
261 if types.length == 0 {
262 return []
263 }
264 let registry = NFTList.borrowRegistry()
265 var list: [{FTViewUtils.ITokenView}] = []
266
267 // load token view
268 for nftType in types {
269 if let entry = registry.borrowNFTEntry(nftType) {
270 list.append(self.buildNFTView(entry: entry, reviewer: reviewer))
271 }
272 }
273 return list
274 }
275
276 access(self)
277 fun buildNFTView(
278 entry: &NFTList.NFTCollectionEntry,
279 reviewer: Address?,
280 ): {FTViewUtils.ITokenView} {
281 let identity = entry.getIdentity()
282 let data = entry.getCollectionData()
283 let paths = NFTViewUtils.StandardNFTPaths(
284 data.storagePath,
285 data.publicPath,
286 )
287 if let evmAddr = FlowEVMBridgeConfig.getEVMAddressAssociated(with: identity.buildNFTType()) {
288 return NFTViewUtils.BridgedTokenView(
289 identity: identity,
290 evmAddress: "0x".concat(evmAddr.toString()),
291 tags: entry.getTags(reviewer),
292 dataSource: nil,
293 paths: paths,
294 display: entry.getDisplay(reviewer),
295 )
296 } else {
297 return NFTViewUtils.StandardTokenView(
298 identity: identity,
299 tags: entry.getTags(reviewer),
300 dataSource: nil,
301 paths: paths,
302 display: entry.getDisplay(reviewer)
303 )
304 }
305 }
306
307 /// Query EVM Bridged FTs with pagination
308 ///
309 access(all)
310 fun queryEVMBridgedFTs(
311 page: Int,
312 size: Int,
313 reviewer: Address?,
314 ): QueryResult {
315 let list: [{FTViewUtils.ITokenView}] = []
316 let registry = EVMTokenList.borrowRegistry()
317
318 let addrs = registry.getERC20AddressesHex(page, size)
319 for addr in addrs {
320 if let entry = registry.borrowFungibleTokenEntry(addr) {
321 list.append(self.buildFTView(entry, reviewer, true))
322 }
323 }
324 return QueryResult(
325 total: registry.getERC20Amount(),
326 list: list
327 )
328 }
329
330 /// Query EVM Bridged NFTs with pagination
331 ///
332 access(all)
333 fun queryEVMBridgedNFTs(
334 page: Int,
335 size: Int,
336 reviewer: Address?,
337 ): QueryResult {
338 let list: [{FTViewUtils.ITokenView}] = []
339 let registry = EVMTokenList.borrowRegistry()
340
341 let addrs = registry.getERC721AddressesHex(page, size)
342 for addr in addrs {
343 if let entry = registry.borrowNonFungibleTokenEntry(addr) {
344 list.append(self.buildNFTView(entry: entry, reviewer: reviewer))
345 }
346 }
347 return QueryResult(
348 total: registry.getERC721Amount(),
349 list: list
350 )
351 }
352}
353