hicity-toolkit/packages/pancake-profile-sdk/src/profile-sdk.ts

173 lines
5.7 KiB
TypeScript

import Web3 from "web3";
import { Contract } from "web3-eth-contract";
import { request, gql } from "graphql-request";
import Cookies from "js-cookie";
import web3NoAccount from "./utils/web3";
import { getProfileContract } from "./utils/contractHelpers";
import { profileApi, profileSubgraphApi, MAINNET_CHAIN_ID } from "./constants/common";
import { campaignMap } from "./constants/campaigns";
import teamsList from "./constants/teams";
import { Achievement, Team, GetProfileResponse, Profile, Nft, UserPointIncreaseEvent } from "./types";
import { getAchievementDescription, getAchievementTitle, transformProfileResponse } from "./utils/transformHelpers";
import { getNftByTokenId } from "./utils/collectibles";
type SdkConstructorArguments = {
web3?: Web3;
chainId?: number;
};
class PancakeProfileSdk {
web3 = web3NoAccount;
chainId = MAINNET_CHAIN_ID;
profileContract: Contract;
constructor(args?: SdkConstructorArguments) {
if (args?.web3) this.web3 = args.web3;
if (args?.chainId) this.chainId = args.chainId;
this.profileContract = getProfileContract(this.web3, this.chainId);
}
/**
* Fetches user information via REST API
* Contains user information and leaderboard statistics about latest trading competition.
* API repo - https://github.com/pancakeswap/pancake-profile-api
*/
getUsername = async (address: string): Promise<string> => {
try {
const response = await fetch(`${profileApi}/api/users/${address}`);
if (!response.ok) {
return "";
}
const { username = "" } = await response.json();
return username;
} catch (error) {
return "";
}
};
getAchievements = async (account: string): Promise<Achievement[]> => {
try {
const data = await request(
profileSubgraphApi,
gql`
query getUser($id: String!) {
user(id: $id) {
points {
id
campaignId
points
}
}
}
`,
{ id: account.toLowerCase() }
);
if (data.user === null || data.user.points.length === 0) {
return [];
}
return data.user.points.reduce((accum: Achievement[], userPoint: UserPointIncreaseEvent) => {
const campaignMeta = campaignMap.get(userPoint.campaignId);
return [
...accum,
{
id: userPoint.campaignId,
type: campaignMeta.type,
address: userPoint.id,
title: getAchievementTitle(campaignMeta),
description: getAchievementDescription(campaignMeta),
badge: campaignMeta.badge,
points: Number(userPoint.points),
},
];
}, []);
} catch (error) {
return [];
}
};
/**
* Fetches team information from
* Contains team name, number of users, total number of points for the team and whether the team is joinable.
* This data is combined with static team data (images, description, etc) that is stored in constant in this repo.
* Contract repo - https://github.com/pancakeswap/pancake-contracts/tree/master/projects/profile-nft-gamification
*/
getTeam = async (teamId: number): Promise<Team> => {
try {
const {
0: teamName,
2: numberUsers,
3: numberPoints,
4: isJoinable,
} = await this.profileContract.methods.getTeamProfile(teamId).call();
const staticTeamInfo = teamsList.find((staticTeam) => staticTeam.id === teamId);
return { ...staticTeamInfo, isJoinable, name: teamName, users: numberUsers, points: numberPoints };
} catch (error) {
return null;
}
};
/**
* Fetches profile information for specified address.
* This function combines data from getUsername and getTeam with profile data received getUserProfile method
* from PancakeProfile contract.
* NFT's bunnyId is retrieved from PancakeBunnies contract and mapped to static NFT data stored in constant.
* Contracts repo - https://github.com/pancakeswap/pancake-contracts/tree/master/projects/profile-nft-gamification
*/
getProfile = async (address: string): Promise<GetProfileResponse> => {
try {
const hasRegistered = (await this.profileContract.methods.hasRegistered(address).call()) as boolean;
if (!hasRegistered) {
return { hasRegistered, profile: null };
}
const profileResponse = await this.profileContract.methods.getUserProfile(address).call();
const { userId, points, teamId, tokenId, nftAddress, isActive } = transformProfileResponse(profileResponse);
const team = await this.getTeam(teamId);
const username = await this.getUsername(address);
// If the profile is not active the tokenId returns 0, which is still a valid token id
// so only fetch the nft data if active
let nft: Nft;
if (isActive) {
nft = await getNftByTokenId(nftAddress, tokenId, this.web3, this.chainId);
const avatar = nft ? `https://pancakeswap.finance/images/nfts/${nft.images.sm}` : undefined;
// Save the preview image in a cookie so it can be used on the exchange
// TODO v2: optional (and configurable) Cookies.set
Cookies.set(
`profile_${address}`,
{
username,
avatar,
},
{ domain: "pancakeswap.finance", secure: true, expires: 30 }
);
}
const profile = {
userId,
points,
teamId,
tokenId,
username,
nftAddress,
isActive,
nft,
team,
} as Profile;
return { hasRegistered, profile };
} catch (error) {
console.error("getProfile error: ", error);
return null;
}
};
}
export default PancakeProfileSdk;