UNPKG

@samudai_xyz/web3-sdk

Version:

## All in one web3 integrations for Samudai

129 lines (128 loc) 5.71 kB
import axios from 'axios'; import { formatBytes32String } from '@ethersproject/strings'; import { BigNumber } from '@ethersproject/bignumber'; import { utils } from 'ethers'; import { IdRegistry__factory, NameRegistry__factory, } from '../lib/contracts'; import { GOERLI_ADDRESS } from '../utils/network'; export class Farcaster { constructor() { this.API_URL = 'https://api.farcaster.xyz/v1'; // private nameRegistry: Promise<NameRegistry> // private idRegistry: Promise<IdRegistry> // private username: string // constructor() { // } this.validateUsername = (username) => { const unameBytes = utils.toUtf8Bytes(username); if (unameBytes.length > 16) { throw new Error('username cannot be greater than 16 characters'); } if (unameBytes.length === 0) { throw new Error('username cannot be empty string'); } let nameEnded = false; /** * Iterate over the bytes16 fname one char at a time, ensuring that: * 1. The name begins with [a-z 0-9] or the ascii numbers [48-57, 97-122] inclusive * 2. The name can contain [a-z 0-9 -] or the ascii numbers [45, 48-57, 97-122] inclusive * 3. Once the name is ended with a NULL char (0), the follows character must also be NULLs */ // If the name begins with a hyphen, reject it if (unameBytes[0] === 45) throw new Error('invalid name'); unameBytes.forEach((charInt, index) => { if (nameEnded) { // Only NULL characters are allowed after a name has ended if (charInt !== 0) { throw new Error('invalid name'); } } else { // Only valid ASCII characters [45, 48-57, 97-122] are allowed before the name ends // Check if the character is a-z if (charInt >= 97 && charInt <= 122) { return; } // Check if the character is 0-9 if (charInt >= 48 && charInt <= 57) { return; } // Check if the character is a hyphen if (charInt === 45) { return; } // On seeing the first NULL char in the name, revert if is the first char in the // name, otherwise mark the name as ended if (charInt === 0) { // We check i==1 instead of i==0 because i is incremented before the check if (index === 1) throw new Error('invalid name'); nameEnded = true; return; } throw new Error('invalid name'); } }); }; this.usernameToTokenId = (username) => { this.validateUsername(username); const unameBytes = formatBytes32String(username); return BigNumber.from(unameBytes); }; this.getAddressForUsername = async (web3Provider, username) => { try { const nameRegistry = (async () => { const contractAddress = GOERLI_ADDRESS.nameRegistry; return NameRegistry__factory.connect(contractAddress, web3Provider); })(); const ownrAddress = await (await nameRegistry).ownerOf(this.usernameToTokenId(username)); return ownrAddress; } catch (err) { return undefined; } }; this.getFarcasterID = async (address, web3Provider) => { const idRegistryValue = (async () => { const contractAddress = GOERLI_ADDRESS.idRegistry; return IdRegistry__factory.connect(contractAddress, web3Provider); })(); const idRegistry = await idRegistryValue; return await idRegistry.idOf(address); }; this.lookupByAddress = async (address, web3Provider) => { const response = await axios.get(`${this.API_URL}/profiles/${address}`); const userWithoutFID = response.data.result.user; const farcasterID = await this.getFarcasterID(address, web3Provider); const user = Object.assign(Object.assign({}, userWithoutFID), { farcasterID: farcasterID.toString() }); return user; }; this.getUserLatestActvity = async (userOrAddress) => { try { const address = typeof userOrAddress === 'string' ? userOrAddress : userOrAddress.address; utils.getAddress(address); const response = await axios.get(`${this.API_URL}/profiles/${address}/casts`); return response.data.result; } catch (err) { return []; } }; this.lookupByUsername = async (username, web3Provider) => { try { const ownrAddr = await this.getAddressForUsername(web3Provider, username); if (ownrAddr) { return await this.lookupByAddress(ownrAddr, web3Provider); } else { return undefined; } } catch (err) { return undefined; } }; } }