NFT Operations (FCL)

The Flow Client Library (FCL)

The FCL JS package enables communication between user wallets and the Flow blockchain, making it unnecessary for dapps to modify their code or integrate custom solutions when utilizing FCL for authentication. Its purpose is to simplify and secure the development of applications that interface with the Flow blockchain by providing a standardized set of communication patterns for wallets, applications, and users. Additionally, FCL JS includes an SDK and utilities to interact with the Flow blockchain, and can be used in both browser and server environments.

Installation

To use the FCL JS in your application, install using yarn or npm

npm i -S @onflow/fcl
yarn add @onflow/fcl

Importing

ES6

import * as fcl from "@onflow/fcl";

Node.js

const fcl = require("@onflow/fcl");

Configuration

import { config } from "@onflow/fcl";

config({
  "accessNode.api": "https://rest-testnet.onflow.org", // Mainnet: "https://rest-mainnet.onflow.org"
  "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn" // Mainnet: "https://fcl-discovery.onflow.org/authn"
})

The accessNode.api key specifies the address of a Flow access node. Flow provides these, but in the future access to Flow may be provided by other 3rd parties, through their own access nodes. discovery.wallet is an address that points to a service that lists FCL compatible wallets. Flow's FCL Discovery service is a service that FCL wallet providers can be added to, and be made 'discoverable' to any application that uses the discovery.wallet endpoint.

Blockchain Interactions

FCL enables interactions with the Flow blockchain by :

  • Query the chain: Send arbitrary Cadence scripts to the chain and receive back decoded values.

import * as fcl from "@onflow/fcl";

const result = await fcl.query({
  cadence: `
    pub fun main(a: Int, b: Int, addr: Address): Int {
      log(addr)
      return a + b
    }
  `,
  args: (arg, t) => [
    arg(7, t.Int), // a: Int
    arg(6, t.Int), // b: Int
    arg("0xba1132bc08f82fe2", t.Address), // addr: Address
  ],
});
console.log(result); // 13
  • Mutate the chain: Send arbitrary transactions with your own signatures or via a user's wallet to perform state changes on chain.

import * as fcl from "@onflow/fcl";
// in the browser, FCL will automatically connect to the user's wallet to request signatures to run the transaction
const txId = await fcl.mutate({
  cadence: `
    import Profile from 0xba1132bc08f82fe2
    
    transaction(name: String) {
      prepare(account: AuthAccount) {
        account.borrow<&{Profile.Owner}>(from: Profile.privatePath)!.setName(name)
      }
    }
  `,
  args: (arg, t) => [arg("myName", t.String)],
});

Retrieve All NFTs

  async getAllNFTs(Address: string , chain: string) {
    const ad = Address;

      if (chain === "mainnet") {
          var MetadataViews = process.env.MetadataViews_mainnet;
          var NFTCatalog = process.env.NFTCatalog_mainnet;
          var NFTRetrieval = process.env.NFTRetrieval_mainnet;
          var url = "https://access-mainnet-beta.onflow.org";
      }
      else
      {
          var MetadataViews =process.env.MetadataViews_testnet;
          var NFTCatalog =process.env.NFTCatalog_testnet;
          var NFTRetrieval = process.env.NFTRetrieval_testnet;
          var url = "https://access-testnet.onflow.org";
      }

      fcl.config().put("accessNode.api", url);

      console.log(ad);
    try {

        const response = await fcl.query({
            cadence: `
import MetadataViews from ${MetadataViews}
import NFTCatalog from ${NFTCatalog}
import NFTRetrieval from ${NFTRetrieval}

pub struct NFT {
    pub let id: UInt64
    pub let name: String
    pub let description: String
    pub let thumbnail: String
    pub let externalURL: String
    pub let collectionStoragePath: StoragePath
    pub let collectionPublicPath: PublicPath
    pub let collectionPrivatePath: PrivatePath
    pub let publicLinkedType: Type
    pub let privateLinkedType: Type
    pub let collectionName: String
    pub let collectionDescription: String
    pub let collectionSquareImage: String
    pub let collectionBannerImage: String
    pub let collectionExternalURL: String
    pub let royalties: [MetadataViews.Royalty]

    init(
        id: UInt64,
        name: String,
        description: String,
        thumbnail: String,
        externalURL: String,
        collectionStoragePath: StoragePath,
        collectionPublicPath: PublicPath,
        collectionPrivatePath: PrivatePath,
        publicLinkedType: Type,
        privateLinkedType: Type,
        collectionName: String,
        collectionDescription: String,
        collectionSquareImage: String,
        collectionBannerImage: String,
        collectionExternalURL: String,
        royalties: [MetadataViews.Royalty]
    ) {
        self.id = id
        self.name = name
        self.description = description
        self.thumbnail = thumbnail
        self.externalURL = externalURL
        self.collectionStoragePath = collectionStoragePath
        self.collectionPublicPath = collectionPublicPath
        self.collectionPrivatePath = collectionPrivatePath
        self.publicLinkedType = publicLinkedType
        self.privateLinkedType = privateLinkedType
        self.collectionName = collectionName
        self.collectionDescription = collectionDescription
        self.collectionSquareImage = collectionSquareImage
        self.collectionBannerImage = collectionBannerImage
        self.collectionExternalURL = collectionExternalURL
        self.royalties = royalties
    }
}

pub fun main(ownerAddress: Address): {String: [NFT]} {
    let account = getAuthAccount(ownerAddress)
    let items: [MetadataViews.NFTView] = []
    let data: {String: [NFT]} = {}

    NFTCatalog.forEachCatalogKey(fun (collectionIdentifier: String):Bool {
        let value = NFTCatalog.getCatalogEntry(collectionIdentifier: collectionIdentifier)!
        let keyHash = String.encodeHex(HashAlgorithm.SHA3_256.hash(collectionIdentifier.utf8))
        let tempPathStr = "catalog".concat(keyHash)
        let tempPublicPath = PublicPath(identifier: tempPathStr)!

        account.link<&{MetadataViews.ResolverCollection}>(
            tempPublicPath,
            target: value.collectionData.storagePath
        )

        let collectionCap = account.getCapability<&AnyResource{MetadataViews.ResolverCollection}>(tempPublicPath)

        if !collectionCap.check() {
            return true
        }

        let views = NFTRetrieval.getNFTViewsFromCap(collectionIdentifier: collectionIdentifier, collectionCap: collectionCap)
        let items: [NFT] = []

        for view in views {
            let displayView = view.display
            let externalURLView = view.externalURL
            let collectionDataView = view.collectionData
            let collectionDisplayView = view.collectionDisplay
            let royaltyView = view.royalties

            if (displayView == nil || externalURLView == nil || collectionDataView == nil || collectionDisplayView == nil || royaltyView == nil) {
                // Bad NFT. Skipping....
                return true
            }

            items.append(
                NFT(
                    id: view.id,
                    name: displayView!.name,
                    description: displayView!.description,
                    thumbnail: displayView!.thumbnail.uri(),
                    externalURL: externalURLView!.url,
                    collectionStoragePath: collectionDataView!.storagePath,
                    collectionPublicPath: collectionDataView!.publicPath,
                    collectionPrivatePath: collectionDataView!.providerPath,
                    publicLinkedType: collectionDataView!.publicLinkedType,
                    privateLinkedType: collectionDataView!.providerLinkedType,
                    collectionName: collectionDisplayView!.name,
                    collectionDescription: collectionDisplayView!.description,
                    collectionSquareImage: collectionDisplayView!.squareImage.file.uri(),
                    collectionBannerImage: collectionDisplayView!.bannerImage.file.uri(),
                    collectionExternalURL: collectionDisplayView!.externalURL.url,
                    royalties: royaltyView!.getRoyalties()
                )
            )
        }

        data[collectionIdentifier] = items
        return true
    })

    return data
}
  `,
            //@ts-ignore
            args: (arg, t) => [arg(Address, t.Address)],
        });
        return response;
    }
    catch (error) {
        return error;
    }
  }

Get NFT by Token id

  async getNftById(account_id : String  , contractAddress: string,  collectionPublicPath : string,id: number, chain: string) {
      if (chain === "mainnet") {
          var MetadataViews = process.env.MetadataViews_mainnet;
          var url = "https://access-mainnet-beta.onflow.org";
      }
      else
      {
          var MetadataViews =process.env.MetadataViews_testnet;
          var url = "https://access-testnet.onflow.org";
      }

      fcl.config().put("accessNode.api", url);

    const ad = id;

    try {
        const response = await fcl.query({
            cadence: `
        
import MetadataViews from ${MetadataViews}

pub struct NFTView {
          pub let id: UInt64
          pub let name: String
          pub let description: String
          pub let externalURL: String
          pub let thumbnail : String
        
          init(
              id: UInt64,
              name: String,
              description: String,
              externalURL: String,
              thumbnail : String
              
          ) {
              self.id = id
              self.name = name
              self.description = description
              self.externalURL = externalURL
              self.thumbnail = thumbnail
          }
        }
/// This script gets all the view-based metadata associated with the specified NFT
/// and returns it as a single struct

pub fun main(address: Address, id: UInt64) : NFTView {
    let account = getAccount(address)

    
    
 let collection = account
              .getCapability(${collectionPublicPath})
              .borrow<&{MetadataViews.ResolverCollection}>()
              ?? panic("Could not borrow a reference to the collection")
        
          let viewResolver = collection.borrowViewResolver(id: id)!
        
          let nftView = MetadataViews.getNFTView(id: id, viewResolver : viewResolver)
        
          let collectionSocials: {String: String} = {}
          for key in nftView.collectionDisplay!.socials.keys {
              collectionSocials[key] = nftView.collectionDisplay!.socials[key]!.url
          }

            

 return NFTView(
              id: nftView.id,
              name: nftView.display!.name,
              description: nftView.display!.description,
              externalURL: nftView.externalURL!.url,
              thumbnail :  nftView.display!.thumbnail.uri()
          )
   
}
 
     `,
            //@ts-ignore
            args: (arg, t) => [
                arg(account_id, t.Address),
                arg(ad, t.UInt64)
            ],

        });
        return response;
    }catch (error) {
        return error;
    }

  }

Get NFTs in Collection

  async getNftsByAddressInCollection(Address: string ,collectionPath : string ,chain: string) {

      if (chain === "mainnet") {
          var MetadataViews = process.env.MetadataViews_mainnet;
          var url = "https://access-mainnet-beta.onflow.org";
      }
      else
      {
          var MetadataViews =process.env.MetadataViews_testnet;
          var url = "https://access-testnet.onflow.org";
      }

      fcl.config().put("accessNode.api", url);



    try {
        const response = await fcl.query({
            cadence: `

import MetadataViews from ${MetadataViews}

/// This script gets all the view-based metadata associated with the specified NFT
/// and returns it as a single struct

pub fun main(address: Address): [{String: AnyStruct}] {
    let account = getAccount(address)

    let collection = account
        .getCapability(${collectionPath})
        .borrow<&{MetadataViews.ResolverCollection}>()
        ?? panic("Could not borrow a reference to the collection")

    let nft = collection.getIDs()
       var nfts: [{String: AnyStruct}] = []
    for id in nft {
       
       let nft = collection.borrowViewResolver(id: id)

    // Get the basic display information for this NFT
         let display = MetadataViews.getDisplay(nft)!

        let identifier = nft.getType().identifier
        let traits = MetadataViews.getTraits(nft)!
        
        let externalURL = MetadataViews.getExternalURL(nft)!.url

        
        

        
      let nftData = {
        "id": UInt64(id), 
        
         "name": display.name,
         "description": display.description, 
         "thumbnail": display.thumbnail.uri(),
         "identifier": identifier,
         "traits": traits,
         "externalURL": externalURL
            
       
          
      }
        nfts.append(nftData)
    }
  
    

    return nfts
}
 
  `,
            //@ts-ignore
            args: (arg, t) => [arg(Address, t.Address)],
        });
        return response;
    }catch (error) {
        return error;
    }
  }

Last updated