{"id":19610724,"url":"https://github.com/onflow/nft-catalog","last_synced_at":"2026-02-08T14:34:10.268Z","repository":{"id":41304421,"uuid":"488980107","full_name":"onflow/nft-catalog","owner":"onflow","description":null,"archived":false,"fork":false,"pushed_at":"2024-11-05T20:01:12.000Z","size":7064,"stargazers_count":35,"open_issues_count":17,"forks_count":12,"subscribers_count":21,"default_branch":"main","last_synced_at":"2025-07-23T01:40:59.047Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.flow-nft-catalog.com/","language":"Cadence","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/onflow.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-05T13:18:42.000Z","updated_at":"2025-07-07T20:22:38.000Z","dependencies_parsed_at":"2025-01-09T10:14:40.621Z","dependency_job_id":null,"html_url":"https://github.com/onflow/nft-catalog","commit_stats":null,"previous_names":["onflow/nft-catalog","dapperlabs/nft-catalog"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/onflow/nft-catalog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onflow%2Fnft-catalog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onflow%2Fnft-catalog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onflow%2Fnft-catalog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onflow%2Fnft-catalog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/onflow","download_url":"https://codeload.github.com/onflow/nft-catalog/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onflow%2Fnft-catalog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29233266,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T14:18:14.570Z","status":"ssl_error","status_checked_at":"2026-02-08T14:18:14.071Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T10:32:47.719Z","updated_at":"2026-02-08T14:34:10.250Z","avatar_url":"https://github.com/onflow.png","language":"Cadence","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DEPRECATED\n\nThis project is deprecated in favour of https://github.com/fixes-world/token-list\n\nfor more information check the [forum post](https://forum.flow.com/t/replacing-nft-catalog-with-a-decentralized-alternative-proposal/6723)\n\n# NFT Catalog\n\nThe NFT Catalog is an on chain registry listing NFT collections that exists on Flow which adhere to the NFT metadata standard. This empowers dApp developers to easily build on top of and discover interoperable NFT collections on Flow.\n\n## Live Site\n\nCheckout the catalog [site](https://www.flow-nft-catalog.com/) to submit your NFT collection both on testnet and mainnet.\n\n## NPM Module\n\nWe exposed an interface to the catalog via a consumable NPM module. This library will expose a number of methods that can be called to interact with the catalog. The module can be found here with installation instructions below: https://www.npmjs.com/package/flow-catalog\n\n### Methods\n\nMethod signatures and their associating parameters/responses can be found in the `cadence/` folder of this repo.\n\n#### Scripts\n\n```\ncheckForRecommendedV1Views\ngetAllNftsAndViewsInAccount\ngetAllNftsInAccount\ngetExamplenftCollectionLength\ngetExamplenftType\ngetNftAndViewsInAccount\ngetNftCatalog\ngetNftCatalogCount\ngetNftCatalogIdentifiers\ngetNftCatalogProposals\ngetNftCatalogProposalsCount\ngetNftCollectionsForNftType\ngetNftIdsInAccount\ngetNftInAccount\ngetNftInAccountFromPath\ngetNftMetadataForCollectionIdentifier\ngetNftProposalForId\ngetNftsCountInAccount\ngetNftsInAccount\ngetNftsInAccountFromIds\ngetNftsInAccountFromPath\nhasAdminProxy\nisCatalogAdmin\n```\n\n#### Transactions\n\n```\naddToNftCatalog\naddToNftCatalogAdmin\napproveNftCatalogProposal\nmintExampleNft\nproposeNftToCatalog\nrejectNftCatalogProposal\nremoveFromNftCatalog\nremoveNftCatalogProposal\nsendAdminCapabilityToProxy\nsetupExamplenftCollection\nsetupNftCatalogAdminProxy\ntransferExamplenft\nupdateNftCatalogEntry\nwithdrawNftProposalFromCatalog\n```\n\n### Installation\n\n```\nnpm install flow-catalog\n```\n\nor\n\n```\nyarn add flow-catalog\n```\n\n### Usage\n\nMethods can be imported as follows, all nested methods live under the `scripts` or `transactions` variable.\n\nNOTE: In order to properly bootstrap the method, you will need to run and `await` on the `getAddressMaps()` method, passing it into all of the methods as shown below.\n\n```\nimport { getAddressMaps, scripts } from \"flow-catalog\";\n\nconst main = async () =\u003e {\n    const addressMap = await getAddressMaps();\n    console.log(await scripts.getNftCatalog(addressMap));\n};\n\nmain();\n```\n\nThe response of any method is a tuple-array, with the first element being the result, and the second being the error (if applicable).\n\nFor example, the result of the method above would look like -\n\n```\n[\n  {\n    BILPlayerCollection: {\n      contractName: 'Player',\n      contractAddress: '0x9e6cdb88e34fa1f3',\n      nftType: [Object],\n      collectionData: [Object],\n      collectionDisplay: [Object]\n    },\n    ...\n    SoulMadeComponent: {\n      contractName: 'SoulMadeComponent',\n      contractAddress: '0x421c19b7dc122357',\n      nftType: [Object],\n      collectionData: [Object],\n      collectionDisplay: [Object]\n    }\n  },\n  null\n]\n```\n\n## Contract Addresses\n\n`NFTCatalog.cdc`: This contract contains the NFT Catalog\n\n| Network | Address            |\n| ------- | ------------------ |\n| Mainnet | 0x49a7cda3a1eecc29 |\n| Testnet | 0x324c34e1c517e4db |\n\n`NFTRetrieval.cdc`: This contract contains helper functions to make it easier to discover NFTs within accounts and from the catalog\n\n| Network | Address            |\n| ------- | ------------------ |\n| Mainnet | 0x49a7cda3a1eecc29 |\n| Testnet | 0x324c34e1c517e4db |\n\n## Submitting a Collection to the NFT Catalog\n\n1. Visit [here](https://www.flow-nft-catalog.com/v)\n2. Enter the address containing the NFT contract which contains the collection and select the contract\n\n \u003cimg width=\"1509\" alt=\"Screen Shot 2023-02-08 at 9 40 01 AM\" src=\"https://user-images.githubusercontent.com/5430668/217561873-54beb50e-0ea2-46fb-b9f8-8dbe758ee12f.png\"\u003e\n\n3. Enter the storage path where the NFTs are stored and enter an address that holds a sample NFT or log in if you have access to an account that owns the NFT\n   \u003cimg width=\"1508\" alt=\"Screen Shot 2023-02-08 at 9 42 54 AM\" src=\"https://user-images.githubusercontent.com/5430668/217562366-e6cbf3cb-38b8-45cb-943e-e20185565743.png\"\u003e\n\n4. The application will verify that your NFT collection implements the required Metadata views.\n\n    1. The required metadata views include…\n        1. NFT Display\n            1. How to display an individual NFT part of the collection\n        2. External URL\n            1. A website for the NFT collection\n        3. Collection Data\n            1. Information needed to store and retrieve an NFT\n        4. Collection Display\n            1. How to display information about the NFT collection the NFT belongs to\n        5. Royalties\n            1. Any royalties that should be accounted for during marketplace transactions\n    2. You can find sample implementations of all these views in this example NFT [contract](https://github.com/onflow/flow-nft/blob/master/contracts/ExampleNFT.cdc).\n    3. If you are not implementing a view, the app will communicate this and you can update your NFT contract and try resubmitting.\n\n     \u003cimg width=\"738\" alt=\"Screen Shot 2023-02-08 at 9 46 56 AM\" src=\"https://user-images.githubusercontent.com/5430668/217563435-86863297-183b-4345-9615-61f9d4212fe9.png\"\u003e\n\n5. Submit proposal transaction to the NFT catalog by entering a unique url safe identifier for the collection and a message including any additional context (like contact information).\n\n \u003cimg width=\"1503\" alt=\"Screen Shot 2023-02-08 at 9 48 45 AM\" src=\"https://user-images.githubusercontent.com/5430668/217563785-65065f51-37bc-49c7-8b3e-ba5d1dda3b24.png\"\u003e\n\n6. Once submitted you can view all proposals [here](https://www.flow-nft-catalog.com/proposals/mainnet) to track the review of your NFT.\n\nIf you would like to make a proposal manually, you may submit the following transaction with all parameters filled in: [https://github.com/dapperlabs/nft-catalog/blob/main/cadence/transactions/propose_nft_to_catalog.cdc](https://github.com/dapperlabs/nft-catalog/blob/main/cadence/transactions/propose_nft_to_catalog.cdc)\n\nProposals should be reviewed and approved within a few days. Reasons for a proposal being rejected may include:\n\n-   Providing duplicate path or name information of an existing collection on the catalog\n-   Providing a not url safe or inaccurate name as the identifier\n\n## Using the Catalog (For marketplaces and other NFT applications)\n\nAll of the below examples use the catalog in mainnet, you may replace the imports to the testnet address when using the testnet network.\n\n**Example 1 - Retrieve all NFT collections on the catalog**\n\n```cadence\nimport NFTCatalog from 0x49a7cda3a1eecc29\n\n/*\n    The catalog is returned as a `String: NFTCatalogMetadata`\n    The key string is intended to be a unique identifier for a specific collection.\n    The NFTCatalogMetadata contains collection-level views corresponding to each\n    collection identifier.\n    Due to the large size of the response, only the first 10 entries are returned.\n*/\naccess(all) fun main(): {String: NFTCatalog.NFTCatalogMetadata} {\n    let catalogKeys = NFTCatalog.getCatalogKeys()\n    let keys = catalogKeys.slice(from: 0, upTo: 10)\n    let collections: {String: NFTCatalog.NFTCatalogMetadata} = {}\n\n    for key in keys {\n        collections[key] = catalog[key]\n    }\n\n    return collections\n}\n```\n\n**Example 2 - Retrieve all collection names in the catalog**\n\n```cadence\nimport NFTCatalog from 0x49a7cda3a1eecc29\n\naccess(all) fun main(): [String] {\n    let catalogKeys: {String: NFTCatalog.NFTCatalogMetadata} = NFTCatalog.getCatalogKeys()\n    let catalogNames: [String] = []\n\n    for collectionIdentifier in catalogKeys {\n        catalogNames.append(catalog[collectionIdentifier]!.collectionDisplay.name)\n    }\n\n    return catalogNames\n}\n```\n\n**Example 3 - Retrieve NFT collections and counts owned by an account**\n\n```cadence\nimport MetadataViews from 0x1d7e57aa55817448\nimport NFTCatalog from 0x49a7cda3a1eecc29\nimport NFTRetrieval from 0x49a7cda3a1eecc29\n\naccess(all) fun main(ownerAddress: Address): {String: Number} {\n    let account = getAuthAccount(ownerAddress)\n    let items: {String: Number} = {}\n\n    NFTCatalog.forEachCatalogKey(fun (collectionIdentifier: String):Bool {\n        let value = NFTCatalog.getCatalogEntry(collectionIdentifier: collectionIdentifier)!\n        let keyHash = String.encodeHex(HashAlgorithm.SHA3_256.hash(collectionIdentifier.utf8))\n        let tempPathStr = \"catalog\".concat(keyHash)\n        let tempPublicPath = PublicPath(identifier: tempPathStr)!\n\n        account.link\u003c\u0026{MetadataViews.ResolverCollection}\u003e(\n            tempPublicPath,\n            target: value.collectionData.storagePath\n        )\n\n        let collectionCap = account.getCapability\u003c\u0026AnyResource{MetadataViews.ResolverCollection}\u003e(tempPublicPath)\n\n        if !collectionCap.check() {\n            return true\n        }\n\n        let count = NFTRetrieval.getNFTCountFromCap(collectionIdentifier: collectionIdentifier, collectionCap: collectionCap)\n\n        if count != 0 {\n            items[collectionIdentifier] = count\n        }\n        return true\n    })\n\n    return items\n}\n```\n\n`Sample Response...`\n\n```text\n{\n    \"schmoes_prelaunch_token\": 1\n}\n```\n\n**Example 4 - Retrieve all NFTs including metadata owned by an account**\n\n```cadence\nimport MetadataViews from 0x1d7e57aa55817448\nimport NFTCatalog from 0x49a7cda3a1eecc29\nimport NFTRetrieval from 0x49a7cda3a1eecc29\n\naccess(all) struct NFT {\n    access(all) let id: UInt64\n    access(all) let name: String\n    access(all) let description: String\n    access(all) let thumbnail: String\n    access(all) let externalURL: String\n    access(all) let storagePath: StoragePath\n    access(all) let publicPath: PublicPath\n    access(all) let privatePath: PrivatePath\n    access(all) let publicLinkedType: Type\n    access(all) let privateLinkedType: Type\n    access(all) let collectionName: String\n    access(all) let collectionDescription: String\n    access(all) let collectionSquareImage: String\n    access(all) let collectionBannerImage: String\n    access(all) let collectionExternalURL: String\n    access(all) let royalties: [MetadataViews.Royalty]\n\n    init(\n        id: UInt64,\n        name: String,\n        description: String,\n        thumbnail: String,\n        externalURL: String,\n        storagePath: StoragePath,\n        publicPath: PublicPath,\n        privatePath: PrivatePath,\n        publicLinkedType: Type,\n        privateLinkedType: Type,\n        collectionName: String,\n        collectionDescription: String,\n        collectionSquareImage: String,\n        collectionBannerImage: String,\n        collectionExternalURL: String,\n        royalties: [MetadataViews.Royalty]\n    ) {\n        self.id = id\n        self.name = name\n        self.description = description\n        self.thumbnail = thumbnail\n        self.externalURL = externalURL\n        self.storagePath = storagePath\n        self.publicPath = publicPath\n        self.privatePath = privatePath\n        self.publicLinkedType = publicLinkedType\n        self.privateLinkedType = privateLinkedType\n        self.collectionName = collectionName\n        self.collectionDescription = collectionDescription\n        self.collectionSquareImage = collectionSquareImage\n        self.collectionBannerImage = collectionBannerImage\n        self.collectionExternalURL = collectionExternalURL\n        self.royalties = royalties\n    }\n}\n\naccess(all) fun main(ownerAddress: Address): {String: [NFT]} {\n    let account = getAuthAccount(ownerAddress)\n    let items: [MetadataViews.NFTView] = []\n    let data: {String: [NFT]} = {}\n\n    NFTCatalog.forEachCatalogKey(fun (collectionIdentifier: String):Bool {\n        let value = NFTCatalog.getCatalogEntry(collectionIdentifier: collectionIdentifier)!\n        let keyHash = String.encodeHex(HashAlgorithm.SHA3_256.hash(collectionIdentifier.utf8))\n        let tempPathStr = \"catalog\".concat(keyHash)\n        let tempPublicPath = PublicPath(identifier: tempPathStr)!\n\n        account.link\u003c\u0026{MetadataViews.ResolverCollection}\u003e(\n            tempPublicPath,\n            target: value.collectionData.storagePath\n        )\n\n        let collectionCap = account.getCapability\u003c\u0026AnyResource{MetadataViews.ResolverCollection}\u003e(tempPublicPath)\n\n        if !collectionCap.check() {\n            return true\n        }\n\n        let views = NFTRetrieval.getNFTViewsFromCap(collectionIdentifier: collectionIdentifier, collectionCap: collectionCap)\n        let items: [NFT] = []\n\n        for view in views {\n            let displayView = view.display\n            let externalURLView = view.externalURL\n            let collectionDataView = view.collectionData\n            let collectionDisplayView = view.collectionDisplay\n            let royaltyView = view.royalties\n\n            if (displayView == nil || externalURLView == nil || collectionDataView == nil || collectionDisplayView == nil || royaltyView == nil) {\n                // Bad NFT. Skipping....\n                return true\n            }\n\n            items.append(\n                NFT(\n                    id: view.id,\n                    name: displayView!.name,\n                    description: displayView!.description,\n                    thumbnail: displayView!.thumbnail.uri(),\n                    externalURL: externalURLView!.url,\n                    storagePath: collectionDataView!.storagePath,\n                    publicPath: collectionDataView!.publicPath,\n                    publicLinkedType: collectionDataView!.publicLinkedType,\n                    collectionName: collectionDisplayView!.name,\n                    collectionDescription: collectionDisplayView!.description,\n                    collectionSquareImage: collectionDisplayView!.squareImage.file.uri(),\n                    collectionBannerImage: collectionDisplayView!.bannerImage.file.uri(),\n                    collectionExternalURL: collectionDisplayView!.externalURL.url,\n                    royalties: royaltyView!.getRoyalties()\n                )\n            )\n        }\n\n        data[collectionIdentifier] = items\n        return true\n    })\n\n    return data\n}\n```\n\n`Sample Response...`\n\n```text\n{\n    \"FlovatarComponent\": [],\n    \"schmoes_prelaunch_token\": [\n        s.aa16be98aac20e8073f923261531cbbdfae1464f570f5be796b57cdc97656248.NFT(\n            id: 1006,\n            name: \"Schmoes Pre Launch Token #1006\",\n            description: \"\",\n            thumbnail: \"https://gateway.pinata.cloud/ipfs/QmXQ1iBke5wjcjYG22ACVXsCvtMJKEkwFiMf96UChP8uJq\",\n            externalURL: \"https://schmoes.io\",\n            storagePath: /storage/SchmoesPreLaunchTokenCollection,\n            publicPath: /public/SchmoesPreLaunchTokenCollection,\n            privatePath: /private/SchmoesPreLaunchTokenCollection,\n            publicLinkedType: Type\u003c\u0026A.6c4fe48768523577.SchmoesPreLaunchToken.Collection{A.1d7e57aa55817448.NonFungibleToken.CollectionPublic,A.  1d7e57aa55817448.NonFungibleToken.Receiver,A.1d7e57aa55817448.MetadataViews.ResolverCollection}\u003e(),\n            privateLinkedType: Type\u003c\u0026A.6c4fe48768523577.SchmoesPreLaunchToken.Collection{A.1d7e57aa55817448.NonFungibleToken.CollectionPublic,A.1d7e57aa55817448.NonFungibleToken.Provider,A.1d7e57aa55817448.MetadataViews.ResolverCollection}\u003e(),\n            collectionName: \"Schmoes Pre Launch Token\",\n            collectionDescription: \"\",\n            collectionSquareImage: \"https://gateway.pinata.cloud/ipfs/QmXQ1iBke5wjcjYG22ACVXsCvtMJKEkwFiMf96UChP8uJq\",\n            collectionBannerImage: \"https://gateway.pinata.cloud/ipfs/QmXQ1iBke5wjcjYG22ACVXsCvtMJKEkwFiMf96UChP8uJq\",\n            royalties: []\n        )\n    ],\n    \"Flovatar\": []\n}\n```\n\n**Example 5 - Retrieve all NFTs including metadata owned by an account for large wallets**\n\nFor Wallets that have a lot of NFTs you may run into memory issues. The common pattern to get around this for now is to retrieve just the ID's in a wallet by calling the following script\n\n```cadence\nimport MetadataViews from 0x1d7e57aa55817448\nimport NFTCatalog from 0x49a7cda3a1eecc29\nimport NFTRetrieval from 0x49a7cda3a1eecc29\n\naccess(all) fun main(ownerAddress: Address): {String: [UInt64]} {\n    let account = getAuthAccount(ownerAddress)\n    let items: {String: [UInt64]} = {}\n\n    NFTCatalog.forEachCatalogKey(fun (key: String):Bool {\n        let value = NFTCatalog.getCatalogEntry(collectionIdentifier: key)!\n        let keyHash = String.encodeHex(HashAlgorithm.SHA3_256.hash(key.utf8))\n        let tempPathStr = \"catalogIDs\".concat(keyHash)\n        let tempPublicPath = PublicPath(identifier: tempPathStr)!\n\n        account.link\u003c\u0026{MetadataViews.ResolverCollection}\u003e(\n            tempPublicPath,\n            target: value.collectionData.storagePath\n        )\n\n        let collectionCap = account.getCapability\u003c\u0026AnyResource{MetadataViews.ResolverCollection}\u003e(tempPublicPath)\n\n        if !collectionCap.check() {\n            return true\n        }\n\n        let ids = NFTRetrieval.getNFTIDsFromCap(collectionIdentifier: key, collectionCap: collectionCap)\n\n        if ids.length \u003e 0 {\n            items[key] = ids\n        }\n        return true\n    })\n\n    return items\n}\n```\n\nand then use the ids to retrieve the full metadata for only those ids by calling the following script and passing in a map of collectlionIdentifer -\u003e [ids]\n\n```cadence\nimport MetadataViews from 0x1d7e57aa55817448\nimport NFTCatalog from 0x49a7cda3a1eecc29\nimport NFTRetrieval from 0x49a7cda3a1eecc29\n\naccess(all) struct NFT {\n    access(all) let id: UInt64\n    access(all) let name: String\n    access(all) let description: String\n    access(all) let thumbnail: String\n    access(all) let externalURL: String\n    access(all) let storagePath: StoragePath\n    access(all) let publicPath: PublicPath\n    access(all) let privatePath: PrivatePath\n    access(all) let publicLinkedType: Type\n    access(all) let privateLinkedType: Type\n    access(all) let collectionName: String\n    access(all) let collectionDescription: String\n    access(all) let collectionSquareImage: String\n    access(all) let collectionBannerImage: String\n    access(all) let collectionExternalURL: String\n    access(all) let royalties: [MetadataViews.Royalty]\n\n    init(\n        id: UInt64,\n        name: String,\n        description: String,\n        thumbnail: String,\n        externalURL: String,\n        storagePath: StoragePath,\n        publicPath: PublicPath,\n        privatePath: PrivatePath,\n        publicLinkedType: Type,\n        privateLinkedType: Type,\n        collectionName: String,\n        collectionDescription: String,\n        collectionSquareImage: String,\n        collectionBannerImage: String,\n        collectionExternalURL: String,\n        royalties: [MetadataViews.Royalty]\n    ) {\n        self.id = id\n        self.name = name\n        self.description = description\n        self.thumbnail = thumbnail\n        self.externalURL = externalURL\n        self.storagePath = storagePath\n        self.publicPath = publicPath\n        self.privatePath = privatePath\n        self.publicLinkedType = publicLinkedType\n        self.privateLinkedType = privateLinkedType\n        self.collectionName = collectionName\n        self.collectionDescription = collectionDescription\n        self.collectionSquareImage = collectionSquareImage\n        self.collectionBannerImage = collectionBannerImage\n        self.collectionExternalURL = collectionExternalURL\n        self.royalties = royalties\n    }\n}\n\naccess(all) fun main(ownerAddress: Address, collections: {String: [UInt64]}): {String: [NFT]} {\n    let data: {String: [NFT]} = {}\n    let account = getAuthAccount(ownerAddress)\n\n    for collectionIdentifier in collections.keys {\n        if NFTCatalog.getCatalogEntry(collectionIdentifier: collectionIdentifier) != nil {\n            let value = NFTCatalog.getCatalogEntry(collectionIdentifier: collectionIdentifier)!\n            let identifierHash = String.encodeHex(HashAlgorithm.SHA3_256.hash(collectionIdentifier.utf8))\n            let tempPathStr = \"catalog\".concat(identifierHash)\n            let tempPublicPath = PublicPath(identifier: tempPathStr)!\n\n            account.link\u003c\u0026{MetadataViews.ResolverCollection}\u003e(\n                tempPublicPath,\n                target: value.collectionData.storagePath\n            )\n\n            let collectionCap = account.getCapability\u003c\u0026AnyResource{MetadataViews.ResolverCollection}\u003e(tempPublicPath)\n\n            if !collectionCap.check() {\n                return data\n            }\n\n            let views = NFTRetrieval.getNFTViewsFromIDs(collectionIdentifier: collectionIdentifier, ids: collections[collectionIdentifier]!, collectionCap: collectionCap)\n\n            let items: [NFT] = []\n\n            for view in views {\n                let displayView = view.display\n                let externalURLView = view.externalURL\n                let collectionDataView = view.collectionData\n                let collectionDisplayView = view.collectionDisplay\n                let royaltyView = view.royalties\n\n                if (displayView == nil || externalURLView == nil || collectionDataView == nil || collectionDisplayView == nil || royaltyView == nil) {\n                    // Bad NFT. Skipping....\n                    continue\n                }\n\n                items.append(\n                    NFT(\n                        id: view.id,\n                        name: displayView!.name,\n                        description: displayView!.description,\n                        thumbnail: displayView!.thumbnail.uri(),\n                        externalURL: externalURLView!.url,\n                        storagePath: collectionDataView!.storagePath,\n                        publicPath: collectionDataView!.publicPath,\n                        publicLinkedType: collectionDataView!.publicLinkedType,\n                        collectionName: collectionDisplayView!.name,\n                        collectionDescription: collectionDisplayView!.description,\n                        collectionSquareImage: collectionDisplayView!.squareImage.file.uri(),\n                        collectionBannerImage: collectionDisplayView!.bannerImage.file.uri(),\n                        collectionExternalURL: collectionDisplayView!.externalURL.url,\n                        royalties: royaltyView!.getRoyalties()\n                    )\n                )\n            }\n\n            data[collectionIdentifier] = items\n        }\n    }\n\n    return data\n}\n```\n\n**Example 6 - Retrieve all MetadataViews for NFTs in a wallet**\n\nIf you're looking for some MetadataViews that aren't in the [core view list](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc#L36) you can leverage this script to grab all the views each NFT supports. Note: You lose some typing here but get more data.\n\n```cadence\nimport MetadataViews from 0x1d7e57aa55817448\nimport NFTCatalog from 0x49a7cda3a1eecc29\nimport NFTRetrieval from 0x49a7cda3a1eecc29\n\naccess(all) struct NFTCollectionData {\n    access(all) let storagePath: StoragePath\n    access(all) let publicPath: PublicPath\n    access(all) let privatePath: PrivatePath\n    access(all) let publicLinkedType: Type\n    access(all) let privateLinkedType: Type\n\n    init(\n        storagePath: StoragePath,\n        publicPath: PublicPath,\n        privatePath: PrivatePath,\n        publicLinkedType: Type,\n        privateLinkedType: Type,\n    ) {\n        self.storagePath = storagePath\n        self.publicPath = publicPath\n        self.privatePath = privatePath\n        self.publicLinkedType = publicLinkedType\n        self.privateLinkedType = privateLinkedType\n    }\n}\n\naccess(all) fun main(ownerAddress: Address): {String: {String: AnyStruct}} {\n    let account = getAuthAccount(ownerAddress)\n    let items: [MetadataViews.NFTView] = []\n    let data: {String: {String: AnyStruct}} = {}\n\n    NFTCatalog.forEachCatalogKey(fun (collectionIdentifier: String):Bool {\n        let value = NFTCatalog.getCatalogEntry(collectionIdentifier: collectionIdentifier)!\n        let keyHash = String.encodeHex(HashAlgorithm.SHA3_256.hash(collectionIdentifier.utf8))\n        let tempPathStr = \"catalog\".concat(keyHash)\n        let tempPublicPath = PublicPath(identifier: tempPathStr)!\n\n        account.link\u003c\u0026{MetadataViews.ResolverCollection}\u003e(\n            tempPublicPath,\n            target: value.collectionData.storagePath\n        )\n\n        let collectionCap = account.getCapability\u003c\u0026AnyResource{MetadataViews.ResolverCollection}\u003e(tempPublicPath)\n\n        if !collectionCap.check() {\n            return true\n        }\n\n        var views = NFTRetrieval.getAllMetadataViewsFromCap(collectionIdentifier: collectionIdentifier, collectionCap: collectionCap)\n\n        if views.keys.length == 0 {\n            return true\n        }\n\n        // Cadence doesn't support function return types, lets manually get rid of it\n        let nftCollectionDisplayView = views[Type\u003cMetadataViews.NFTCollectionData\u003e().identifier] as! MetadataViews.NFTCollectionData?\n        let collectionDataView = NFTCollectionData(\n            storagePath: nftCollectionDisplayView!.storagePath,\n            publicPath: nftCollectionDisplayView!.publicPath,\n            publicLinkedType: nftCollectionDisplayView!.publicLinkedType,\n        )\n        views.insert(key: Type\u003cMetadataViews.NFTCollectionData\u003e().identifier, collectionDataView)\n\n        data[collectionIdentifier] = views\n\n        return true\n    })\n\n    return data\n}\n```\n\n**Example 7 - Setup a user’s account to receive a specific collection**\n\n1. Run the following script to retrieve some collection-level information for an NFT collection identifier from the catalog\n\n```cadence\n// Assuming file name is `get_nft_collection_data.cdc`\nimport MetadataViews from 0x1d7e57aa55817448\nimport NFTCatalog from 0x49a7cda3a1eecc29\nimport NFTRetrieval from 0x49a7cda3a1eecc29\n\naccess(all) struct NFTCollection {\n    access(all) let contractName: String\n    access(all) let contractAddress: String\n    access(all) let storagePath: StoragePath\n    access(all) let publicPath: PublicPath\n    access(all) let privatePath: PrivatePath\n    access(all) let publicLinkedType: Type\n    access(all) let privateLinkedType: Type\n    access(all) let collectionName: String\n    access(all) let collectionDescription: String\n    access(all) let collectionSquareImage: String\n    access(all) let collectionBannerImage: String\n\n    init(\n        contractName: String,\n        contractAddress: String,\n        storagePath: StoragePath,\n        publicPath: PublicPath,\n        privatePath: PrivatePath,\n        publicLinkedType: Type,\n        privateLinkedType: Type,\n        collectionName: String,\n        collectionDescription: String,\n        collectionSquareImage: String,\n        collectionBannerImage: String\n    ) {\n        self.contractName = contractName\n        self.contractAddress = contractAddress\n        self.storagePath = storagePath\n        self.publicPath = publicPath\n        self.privatePath = privatePath\n        self.publicLinkedType = publicLinkedType\n        self.privateLinkedType = privateLinkedType\n        self.collectionName = collectionName\n        self.collectionDescription = collectionDescription\n        self.collectionSquareImage = collectionSquareImage\n        self.collectionBannerImage = collectionBannerImage\n    }\n}\n\naccess(all) fun main(collectionIdentifier : String) : NFTCollection? {\n    pre {\n        NFTCatalog.getCatalogEntry(collectionIdentifier: collectionIdentifier) != nil : \"Invalid collection identifier\"\n    }\n\n    let contractView = NFTCatalog.getCatalogEntry(collectionIdentifier: collectionIdentifier)!\n    let collectionDataView = NFTCatalog.getCatalogEntry(collectionIdentifier: collectionIdentifier)!.collectionData\n    let collectionDisplayView = NFTCatalog.getCatalogEntry(collectionIdentifier: collectionIdentifier)!.collectionDisplay\n\n    return NFTCollection(\n        contractName: contractView.contractName,\n        contractAddress: contractView.contractAddress.toString(),\n        storagePath: collectionDataView!.storagePath,\n        publicPath: collectionDataView!.publicPath,\n        privatePath: collectionDataView!.privatePath,\n        publicLinkedType: collectionDataView!.publicLinkedType,\n        privateLinkedType: collectionDataView!.privateLinkedType,\n        collectionName: collectionDisplayView!.name,\n        collectionDescription: collectionDisplayView!.description,\n        collectionSquareImage: collectionDisplayView!.squareImage.file.uri(),\n        collectionBannerImage: collectionDisplayView!.bannerImage.file.uri()\n    )\n}\n```\n\n2. This script result can then be used to form a transaction by inserting the relevant variables from above into a transaction template like the following:\n\n```cadence\n// Assuming file name is `setup_collection_template.cdc`\nimport NonFungibleToken from 0x1d7e57aa55817448\nimport MetadataViews from 0x1d7e57aa55817448\nimport {CONTRACT_NAME} from {CONTRACT_ADDRESS}\n\ntransaction {\n\n    prepare(signer: AuthAccount) {\n        // Create a new empty collection\n        let collection \u003c- {CONTRACT_NAME}.createEmptyCollection()\n\n        // save it to the account\n        signer.save(\u003c-collection, to: {STORAGE_PATH})\n\n        // create a public capability for the collection\n        signer.link\u003c\u0026{PUBLIC_LINKED_TYPE}\u003e(\n            {PUBLIC_PATH},\n            target: {STORAGE_PATH}\n        )\n\n        // create a private capability for the collection\n        signer.link\u003c\u0026{PRIVATE_LINKED_TYPE}\u003e(\n            {PRIVATE_PATH},\n            target: {STORAGE_PATH}\n        )\n    }\n}\n```\n\nWe can achieve this with JavaScript, for example:\n\n```javascript\nimport { readFileSync, writeFileSync } from \"fs\";\nimport * as fcl from \"@onflow/fcl\";\n\nfcl.config()\n    .put(\"accessNode.api\", \"https://rest-mainnet.onflow.org\")\n    .put(\"flow.network\", \"mainnet\");\n\nconst args = process.argv.slice(2);\n\nconst collectionIdentifier = args[0];\nif (collectionIdentifier === undefined) {\n    console.error(\"You need to pass the Collection identifier as an argument.\");\n    process.exit(1);\n}\n\ntry {\n    const scriptPath = new URL(\"get_nft_collection_data.cdc\", import.meta.url);\n    const scriptCode = readFileSync(scriptPath, { encoding: \"utf8\" });\n\n    const nftCollection = await fcl.query({\n        cadence: scriptCode,\n        args: (arg, t) =\u003e [arg(collectionIdentifier, t.String)],\n    });\n\n    console.log(nftCollection);\n\n    const filePath = new URL(\"setup_collection_template.cdc\", import.meta.url);\n    const transactionTemplate = readFileSync(filePath, { encoding: \"utf8\" });\n\n    const transaction = transactionTemplate\n        .replaceAll(\"{CONTRACT_NAME}\", nftCollection.contractName)\n        .replaceAll(\"{CONTRACT_ADDRESS}\", nftCollection.contractAddress)\n        .replaceAll(\n            \"{STORAGE_PATH}\",\n            `/${nftCollection.storagePath.domain}/${nftCollection.storagePath.identifier}`\n        )\n        .replaceAll(\n            \"{PUBLIC_PATH}\",\n            `/${nftCollection.publicPath.domain}/${nftCollection.publicPath.identifier}`\n        )\n        .replaceAll(\n            \"{PRIVATE_PATH}\",\n            `/${nftCollection.privatePath.domain}/${nftCollection.privatePath.identifier}`\n        )\n        .replaceAll(\n            \"{PUBLIC_LINKED_TYPE}\",\n            nftCollection.publicLinkedType.typeID.replace(/A\\.\\w{16}\\./g, \"\")\n        )\n        .replaceAll(\n            \"{PRIVATE_LINKED_TYPE}\",\n            nftCollection.privateLinkedType.typeID.replace(/A\\.\\w{16}\\./g, \"\")\n        );\n\n    const transactionPath = `setup_${nftCollection.contractName}_collection.cdc`;\n    writeFileSync(transactionPath, transaction);\n\n    console.log(transaction);\n} catch (err) {\n    console.error(err.message);\n}\n```\n\nRunning the above with:\n\n```bash\nnode setupCollection.mjs \"ChainmonstersRewards\"\n```\n\nwill generate a file called `setup_ChainmonstersRewards_collection.cdc`, containing:\n\n```cadence\nimport NonFungibleToken from 0x1d7e57aa55817448\nimport MetadataViews from 0x1d7e57aa55817448\nimport ChainmonstersRewards from 0x93615d25d14fa337\n\ntransaction {\n\n    prepare(signer: AuthAccount) {\n        // Create a new empty collection\n        let collection \u003c- ChainmonstersRewards.createEmptyCollection()\n\n        // save it to the account\n        signer.save(\u003c-collection, to: /storage/ChainmonstersRewardCollection)\n\n        // create a public capability for the collection\n        signer.link\u003c\u0026ChainmonstersRewards.Collection{ChainmonstersRewards.ChainmonstersRewardCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}\u003e(\n            /public/ChainmonstersRewardCollection,\n            target: /storage/ChainmonstersRewardCollection\n        )\n\n        // create a private capability for the collection\n        signer.link\u003c\u0026ChainmonstersRewards.Collection{ChainmonstersRewards.ChainmonstersRewardCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}\u003e(\n            /private/ChainmonstersRewardsCollectionProvider,\n            target: /storage/ChainmonstersRewardCollection\n        )\n    }\n}\n```\n\n## Developer Usage\n\n### 1. [Install the Flow CLI](https://github.com/onflow/flow-cli)\n\n### 2. [Install Node](https://nodejs.org/en/)\n\n### 3. Clone the project\n\n```sh\ngit clone --depth=1 https://github.com/onflow/nft-catalog.git\n```\n\n### 4. Install packages\n\n-   Run `npm install` in the root of the project\n\n### 5. Run Test Suite\n\n-   Run `npm test` in the root of the project\n\n## License\n\nThe works in these files:\n\n-   [FungibleToken.cdc](cadence/contracts/FungibleToken.cdc)\n-   [NonFungibleToken.cdc](cadence/contracts/NonFungibleToken.cdc)\n-   [ExampleNFT.cdc](cadence/contracts/ExampleNFT.cdc)\n-   [MetadataViews.cdc](cadence/contracts/MetadataViews.cdc)\n-   [NFTCatalog.cdc](cadence/contracts/NFTCatalog.cdc)\n-   [NFTCatalogAdmin.cdc](cadence/contracts/NFTCatalogAdmin.cdc)\n-   [NFTRetrieval.cdc](cadence/contracts/NFTRetrieval.cdc)\n\nare under the [Unlicense](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonflow%2Fnft-catalog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonflow%2Fnft-catalog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonflow%2Fnft-catalog/lists"}