Skip to main content

Get All Fan Tokens Owned By Certain User

In this tutorial, you will learn how to get all the fan tokens owned by a certain user, whether it is hold in their wallet/vesting contract or locked in the staking contract, by calling the Moxie Protocol Subgraph API.

You can either use the subgraph APIs or Airstack API to fetch this data.

Method #1: Airstack API

Using the Airstack MoxieUserPortolio API, you can simply provide the user FID to get all the fan tokens owned by the user, both staked and non-staked in the Moxie Power Staking contract.

To learn more, click here.

Method #2: Subgraphs

Pre-requisites

  1. Install dependencies graphqlandgraphql-request to your project:
npm install graphql graphql-request
  1. For profile resolution from FID to addresses, you will either download moxie_resolve.json file or use a third-service API provider, such as Airstack. If you are using Airstack, you can get the Airstack API key and install the Airstack Node SDK:
npm install @airstack/node

For access to the Airstack API key, you'll need to hold at least 1 /airstack Channel Fan Token in either your Farcaster custodial wallet or one of your Farcaster verified wallets AND make sure that you have connected one of those wallet or your Farcaster account to your Airstack account.

If you don't have it yet, you can buy it here.

Step 1: Resolve User's FID to Addresses

A user can hold their Fan tokens in either their Farcaster verified wallet or their vesting contract address (a.k.a. airdrop wallet).

Thus, the first step is to resolve the user's FID to their Farcaster verified wallet and vesting contract wallet. To do so, you have 2 options:

Using moxie_resolve.json

To use moxie_resolve.json, simply download the file and add the following utility function to your code:

utils/resolve.ts
import data from "./moxie_resolve.json";

const resolveFidToAddresses = (fid: number) => {
return data?.filter((d) => d?.fid === fid)?.map((d) => d?.address);
};

export default resolveFidToAddresses;

To resolve, simply call the function and provide the user's FID as input. In return, you will get an array of the user's Farcaster verified wallets and vesting contract wallet addresses that can be used in Step 2.

Using subgraph and third-party APIs

Alternatively, you can use the call a third-party API provider, such as Airstack, to get all user's Farcaster verified wallets and the Moxie Vesting Subgraph API to get all user's vesting contract wallet addresses with the following utility function:

utils/resolve.ts
import { gql, GraphQLClient } from "graphql-request";
import { config } from "dotenv";

config();

const airstackGraphQLClient = new GraphQLClient("https://api.airstack.xyz/gql");

const vestingSubgraphQLClient = new GraphQLClient(
"https://api.studio.thegraph.com/query/23537/moxie_vesting_mainnet/version/latest"
);

const airstackQuery = gql`
query MyQuery($fid: String) {
Socials(
input: { filter: { userId: { _eq: $fid } }, blockchain: ethereum }
) {
Social {
connectedAddresses {
address
blockchain
}
}
}
}
`;

const vestingSubgraphQuery = gql`
query MyQuery($beneficiaries: [Bytes!]) {
tokenLockWallets(where: { beneficiary_in: $beneficiaries }) {
address: id
}
}
`;

const resolveFidToAddresses = async (fid: number) => {
try {
const farcasterWalletData = await airstackGraphQLClient.request(
airstackQuery,
{
fid: fid?.toString(),
},
{
// Provide Airstack API key here
Authorization: process.env.AIRSTACK_API_KEY,
}
);
const userAddresses =
// Get all Farcaster verified wallet addresses
farcasterWalletData?.Socials?.Social?.[0]?.connectedAddresses
// Filter out non-Ethereum addresses
?.filter(({ blockchain }) => blockchain === "ethereum")
?.map(({ address }) => address) ?? [];
const vestingAddressesData = await vestingSubgraphQLClient.request(
vestingSubgraphQuery,
{
beneficiaries: userAddresses,
}
);
return [
...userAddresses,
...vestingAddressesData.tokenLockWallets.map((t) => t?.address),
];
} catch (e) {
throw new Error(e);
}
};

export default resolveFidToAddresses;

To resolve, simply call the function and provide the user's FID as input. In return, you will get an array of the user's Farcaster verified wallets and vesting contract wallet addresses that can be used in Step 2.

Step 2: Add The API Query To Your Code

To get all the fan tokens owned by a certain user, you can use the following query on the Moxie Protocol Subgraph API and provide the array of addresses resolved in Step 1 as input to the $userAddresses variable:

query MyQuery($userAddresses: [ID!]) {
users(where: { id_in: $userAddresses }) {
portfolio {
stakedBalance
unstakedBalance
buyVolume
sellVolume
subjectToken {
name
symbol
}
}
}
}

With this GraphQL query, you can add it to your source code and call the API with the graphql-request library:

index.ts
import { gql, GraphQLClient } from "graphql-request";
import resolveFidToAddresses from "./utils/resolve";

// Add you FID here
const fid = 3;

const graphQLClient = new GraphQLClient(
"https://api.studio.thegraph.com/query/23537/moxie_protocol_stats_mainnet/version/latest"
);

const query = gql`
query MyQuery($userAddresses: [ID!]) {
users(where: { id_in: $userAddresses }) {
portfolio {
stakedBalance
unstakedBalance
buyVolume
sellVolume
subjectToken {
name
symbol
}
}
}
}
`;

const variable = {
// You can remove await if you are using `moxie_resolve.json`
userAddresses: await resolveFidToAddresses(fid),
};

try {
const data = await graphQLClient.request(query, variable);
console.log(data);
} catch (e) {
throw new Error(e);
}

Step 3: Execute Your Code

Once you have your code ready, you can execute it by running the following command:

ts-node index.ts

If it runs successfully, you should see the data returned in the terminal:

{
"data": {
"users": [
{
"portfolio": [
{
"stakedBalance": "442691639238050376",
"unstakedBalance": "0",
"buyVolume": "0",
"sellVolume": "0",
"subjectToken": {
"name": "sarvesh371",
"symbol": "fid:11536"
}
}
]
}
]
}
}

Congrats! 🥳🎉 You've just fetched all fan tokens owned by a certain user!

Developer Support

If you have any questions or need help with other use cases, feel free to join the /airstack Warpcast channel and ask your questions there.

Our team is always ready to help you with any questions you may have.