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.
Pre-requisites
- Install dependencies
graphql
andgraphql-request
to your project :
- npm
- yarn
- pnpm
- bun
npm install graphql graphql-request
yarn add graphql graphql-request
pnpm add graphql graphql-request
bun install graphql graphql graphql-request
- 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
- yarn
- pnpm
- bun
npm install @airstack/node
yarn add @airstack/node
pnpm add @airstack/node
bun install graphql @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:
- TypeScript
- JavaScript
import data from "./moxie_resolve.json";
const resolveFidToAddresses = (fid: number) => {
return data?.filter((d) => d?.fid === fid)?.map((d) => d?.address);
};
export default resolveFidToAddresses;
const data = require("./moxie_resolve.json");
const resolveFidToAddresses = (fid) => {
return data?.filter((d) => d?.fid === fid)?.map((d) => d?.address);
};
module.exports = 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:
- TypeScript
- JavaScript
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;
const { gql, GraphQLClient } = require("graphql-request");
const { config } = require("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) => {
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);
}
};
module.exports = 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
- Variable
- Response
query MyQuery($userAddresses: [ID!]) {
users(where: { id_in: $userAddresses }) {
portfolio {
stakedBalance
unstakedBalance
buyVolume
sellVolume
subjectToken {
name
symbol
}
}
}
}
{
"userAddresses": ["0x00d620def6ccb76c92dbfc87bc2bebab7637ec53"]
}
{
"data": {
"users": [
{
"portfolio": [
{
"stakedBalance": "442691639238050376",
"unstakedBalance": "0",
"buyVolume": "0",
"sellVolume": "0",
"subjectToken": {
"name": "sarvesh371",
"symbol": "fid:11536"
}
}
]
}
]
}
}
With this GraphQL query, you can add it to your source code and call the API with the graphql-request
library:
- TypeScript
- JavaScript
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);
}
const { gql, GraphQLClient } = require("graphql-request");
const resolveFidToAddresses = require("./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:
- TypeScript
- JavaScript
ts-node index.ts
node index.js
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.