Build on FLOW | Learn FCL - 5. Get a List of NFTs Living at Known Address
Tags: javascript, tutorial, flow, fcl
Published: 2022-06-03 21:50:00

## Overview

In this guide, you will expand your knowledge on interacting with smart contracts via Cadence scripts. You will learn how to:

- pull a list of NFTs stored on a specific account address (we’ll use Flovatar in this example!)
- prepare and return them as an array of custom Structs

## Previously on “Learn FCL”

[In the previous post](https://dev.to/onflow/build-on-flow-learn-fcl-4-how-to-resolve-find-identity-name-to-an-address-2po0), we learned how we can interact with deployed contracts and how to return a custom Struct value from the script. We will build on that knowledge to execute a more complex procedure - fetching a list of NFTs stored on an account, mapping it into our preferred format, and then returning it back.

Let’s begin! 💪 

## What is Flovatar?

[Flovatar](https://flovatar.com/) is one of many amazing NFT projects built on Flow. Instead of letting you buy one of thousands unique NFTs, It provides you with tools to create your own identity matching your style and preferences! You would be able to add your personal touch to the final Flovatar persona, that will fit YOUR style 😁 

## Preparation

First things first, we should find the address where the contract is currently deployed. [Flovatar’s GitHub](https://github.com/crash13override/flovatar) has the addresses for deployed contracts on the front page:

- Mainnet - **0x921ea449dffec68a**
- Testnet - **0x0cf264811b95d465**

And in the [get_flovatars.cdc](https://github.com/crash13override/flovatar/blob/main/scripts/get_flovatars.cdc) file, the Flovatar contract has a handy method we can use called `getFlovatars`, that takes an address as an argument:

```jsx
import Flovatar from **0x921ea449dffec68a**
pub fun main(address:Address) : [Flovatar.FlovatarData] {
	return Flovatar.getFlovatars(address: address)
}
```

## Step 1 - Installation

Add `"@onflow/fcl": "1.0.0"` as your dependency

## Step 2 - Setup

Just like the last time, we will import the necessary methods and setup FCL:

```jsx
// Import methods from FCL
import { query, config } from "@onflow/fcl";

// Specify the API endpoint - Mainnet
const api = "https://rest-mainnet.onflow.org";

// Configure FCL to use Mainnet as the access node
config().put("accessNode.api", api);
```

## Step 3 - Implement method `getFlovatars`

```jsx
/// Get a List of Flovatars for Address
const getFlovatars = async (adddress) => {
	// inline code from above
	const cadence = `
		import Flovatar from **0x921ea449dffec68a**
	
		pub fun main(address:Address) : [Flovatar.FlovatarData] {
			return Flovatar.getFlovatars(address: address)
		}
	`

	// We need to pass single argument of type Address
	const args = (arg, t) => [arg(address, t.Address)];

	const flovatars = await query({ cadence, args });
	console.log({ flovatars })
}
```

## Step 4 - Give it a Try

Let’s make a call with our method. Our target will be [Luca (creator of Flovatar)](https://find.xyz/luca) - his address is `0x2a0eccae942667be`

```jsx
(async()=>{
	const user = "0x2a0eccae942667be"
	await getFlovatars(user)
})()
```

If you take a look into console.log you should see an array of objects, representing Flovatars:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fs98x8vojbnaqins59ei.png)

Not so bad, right? Well… let’s try to unwrap that `metadata` field:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jtopvh8lt1qgbemc4qq.png)

Now that’s SVG for you. While you can pull this data every time your user refreshes the page, ideally you would want to cache it somehow and query only the data you need.

Additionally if you query account with hundreds/thousands of NFTs you could hit the limit of the return value, which is around ~10Mbs.

If you go to [Flovatar Showroom](https://flovatar.com/showroom) and use dev tools in your browser you can find out that all images are cached at `https://flovatar.com/api/image/{id}`. Let’s pull only NFT `id` and `creatorAddress` on `metadata` field. This way we can identify if the owner is an original creator of said NFT.

## Step 5 - Rewrite Cadence script

As you remember from last post - we can create custom Struct, which will hold all the data we want to return. We will define `Avatar` struct with two fields: `id` and `isCreator`

```jsx
/// Get a List of Flovatars for Address
const getFlovatarsImproved = async (adddress) => {
	// inline code from above
	const cadence = `
		import Flovatar from **0x921ea449dffec68a
	
		pub struct Avatar{
      pub let id: UInt64
      pub let isCreator: Bool

      // underscore in front of the argument allows us to pass unnamed arguments
			init(_ id: UInt64, _ isCreator: Bool){
        self.id = id
        self.isCreator = isCreator
      }
		}**

		pub fun main(address:Address) : [Avatar] {
			// Just like last time we will call "getFlovatars" method
			let flovatars = Flovatar.getFlovatars(address: address)

      // We will collect processed Flovatar data here
      let data: [Avatar] = []
      
      // Below is a simple loop over Flovatars collected by the contract code
      for flovatar in flovatars {
        let isCreator = flovatar.metadata.creatorAddress == address
        let avatar = Avatar(flovatar.id, isCreator)

				// append newly created instance of Avatar into resulting array
        data.append(avatar)
      }
      return data  
    }
	`

	// We need to pass single argument of type Address
	const args = (arg, t) => [arg(address, t.Address)];

	const flovatars = await query({ cadence, args });
	console.log({ flovatars })
}
```

## Finally

Let’s update our IIFE and try again:

```jsx
(async ()=> {
	const user = "0x2a0eccae942667be"
	await getFlovatarsImproved(user)
})()
```

This invocation shall result in much smaller footprint:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kged4raw87ss3z0q0dpy.png)

Contained information would be enough to construct a link (`https://flovatar.com/flovatars/{id}`) or image (`https://flovatar.com/api/image/{id}`) in your interface.

## ⭐Extra Challenge

Using your knowledge from [.find identity resolver post](https://dev.to/onflow/build-on-flow-learn-fcl-4-how-to-resolve-find-identity-name-to-an-address-2po0) modify your code to allow passing .find identity into `getFlovatars` method.

## Resources

- Example code - [https://codesandbox.io/s/dev-to-fcl-05-list-flovatars-at-address-0bibcd](https://codesandbox.io/s/dev-to-fcl-05-list-flovatars-at-address-0bibcd?file=/src/index.js) - full working solution
- Cadence Structs - [https://docs.onflow.org/cadence/language/composite-types/#composite-type-declaration-and-creation](https://docs.onflow.org/cadence/language/composite-types/#composite-type-declaration-and-creation)
- Flovatar GitHub Repository - [https://github.com/crash13override/flovatar](https://github.com/crash13override/flovatar)
- Flovatar Contract on Flow View Source - [https://flow-view-source.com/mainnet/account/0x921ea449dffec68a/contract/Flovatar](https://flow-view-source.com/mainnet/account/0x921ea449dffec68a/contract/Flovatar)

 

Other resources you might find useful:

- **Flow Docs Site** - [https://docs.onflow.org/](https://docs.onflow.org/) - More detailed information about Flow blockchain and how to interact with it
- **Flow Portal** - [https://flow.com/](https://flow.com/) - your entry point to Flow
- **FCL JS** - [https://github.com/onflow/fcl-js](https://github.com/onflow/fcl-js) - Source code and ability to contribute to the FCL JS library
- **Cadence** - [https://docs.onflow.org/cadence/](https://docs.onflow.org/cadence/) - Introduction to Cadence
- **Codesandbox** - [https://codesandbox.io](https://codesandbox.io/) - An amazing in-browser IDE enabling quick prototyping