Smart Contract

TokenListHelper

A.15a918087ab12d86.TokenListHelper

Valid From

126,444,410

Deployed

1w ago
Feb 19, 2026, 11:06:59 PM UTC

Dependents

0 imports
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