UNPKG

@citizenwallet/sdk

Version:

An sdk to easily work with citizen wallet.

133 lines (109 loc) 3.36 kB
import { hexlify, toUtf8Bytes, JsonRpcProvider, Contract } from "ethers"; import { type CommunityConfig } from "../config"; import { downloadJsonFromIpfs } from "../ipfs"; import profileContractAbi from "../abi/Profile.abi.json"; import dotenv from "dotenv"; import { addressToId, idToAddress } from "./utils"; dotenv.config(); export interface Profile { account: string; description: string; image: string; image_medium: string; image_small: string; name: string; username: string; } export interface ProfileWithTokenId extends Profile { token_id: string; } export const formatProfileImageLinks = ( ipfsUrl: string, profile: Profile ): Profile => { if (profile.image_small.startsWith("ipfs://")) { profile.image_small = `${ipfsUrl}/${profile.image_small.replace( "ipfs://", "" )}`; } if (profile.image_medium.startsWith("ipfs://")) { profile.image_medium = `${ipfsUrl}/${profile.image_medium.replace( "ipfs://", "" )}`; } if (profile.image.startsWith("ipfs://")) { profile.image = `${ipfsUrl}/${profile.image.replace("ipfs://", "")}`; } return profile; }; const padBytesWithSpace = (bytes: Uint8Array, length: number): Uint8Array => { const spaceByte = new TextEncoder().encode(" "); while (bytes.length < length) { bytes = new Uint8Array([...spaceByte, ...bytes]); } return bytes; }; export const formatUsernameToBytes32 = (username: string): string => { return hexlify(padBytesWithSpace(toUtf8Bytes(username.replace("@", "")), 32)); }; export const getProfileFromId = async ( ipfsDomain: string, config: CommunityConfig, id: string ): Promise<ProfileWithTokenId | null> => { const rpc = new JsonRpcProvider(config.primaryRPCUrl); const contract = new Contract( config.community.profile.address, profileContractAbi, rpc ); try { const address = idToAddress(BigInt(id)); const uri: string = await contract.getFunction("tokenURI")(address); const profile = await downloadJsonFromIpfs<Profile>(ipfsDomain, uri); return { ...formatProfileImageLinks(`https://${ipfsDomain}`, profile), token_id: id, }; } catch (error) { console.error("Error fetching profile:", error); return null; } }; export const getProfileFromAddress = async ( ipfsDomain: string, config: CommunityConfig, address: string ): Promise<ProfileWithTokenId | null> => { const id = addressToId(address); return getProfileFromId(ipfsDomain, config, id.toString()); }; export const getProfileFromUsername = async ( ipfsDomain: string, config: CommunityConfig, username: string ): Promise<ProfileWithTokenId | null> => { const rpc = new JsonRpcProvider(config.primaryRPCUrl); const contract = new Contract( config.community.profile.address, profileContractAbi, rpc ); try { const formattedUsername = formatUsernameToBytes32(username); const uri: string = await contract.getFunction("getFromUsername")( formattedUsername ); const profile = await downloadJsonFromIpfs<Profile>(ipfsDomain, uri); const id = addressToId(profile.account); return { ...formatProfileImageLinks(`https://${ipfsDomain}`, profile), token_id: id.toString(), }; } catch (error) { console.error("Error fetching profile:", error); return null; } };