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.
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");
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.
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)],
});
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;
}
}
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;
}
}
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;
}
}