Skip to content

Instantly share code, notes, and snippets.

@hughescoin
Created August 20, 2024 18:29
Show Gist options
  • Save hughescoin/95b680619d602782396fa954e981adae to your computer and use it in GitHub Desktop.
Save hughescoin/95b680619d602782396fa954e981adae to your computer and use it in GitHub Desktop.
import {
Address,
ContractFunctionParameters,
createPublicClient,
encodePacked,
http,
keccak256,
namehash,
} from "viem";
import { base, mainnet } from "viem/chains";
import L2ResolverAbi from "@/abis/L2ResolverAbi";
export type Basename = `${string}.base.eth`;
export const BASENAME_L2_RESOLVER_ADDRESS =
"0xC6d566A56A1aFf6508b41f6c90ff131615583BCD";
export enum BasenameTextRecordKeys {
Description = "description",
Keywords = "keywords",
Url = "url",
Email = "email",
Phone = "phone",
Github = "com.github",
Twitter = "com.twitter",
Farcaster = "xyz.farcaster",
Lens = "xyz.lens",
Telegram = "org.telegram",
Discord = "com.discord",
Avatar = "avatar",
}
export const textRecordsKeysEnabled = [
BasenameTextRecordKeys.Description,
BasenameTextRecordKeys.Keywords,
BasenameTextRecordKeys.Url,
BasenameTextRecordKeys.Github,
BasenameTextRecordKeys.Email,
BasenameTextRecordKeys.Phone,
BasenameTextRecordKeys.Twitter,
BasenameTextRecordKeys.Farcaster,
BasenameTextRecordKeys.Lens,
BasenameTextRecordKeys.Telegram,
BasenameTextRecordKeys.Discord,
BasenameTextRecordKeys.Avatar,
];
const baseClient = createPublicClient({
chain: base,
transport: http("https://mainnet.base.org"),
});
export async function getBasenameAvatar(basename: Basename) {
const avatar = await baseClient.getEnsAvatar({
name: basename,
universalResolverAddress: BASENAME_L2_RESOLVER_ADDRESS,
});
return avatar;
}
export function buildBasenameTextRecordContract(
basename: Basename,
key: BasenameTextRecordKeys
): ContractFunctionParameters {
return {
abi: L2ResolverAbi,
address: BASENAME_L2_RESOLVER_ADDRESS,
args: [namehash(basename), key],
functionName: "text",
};
}
// Get a single TextRecord
export async function getBasenameTextRecord(
basename: Basename,
key: BasenameTextRecordKeys
) {
try {
const contractParameters = buildBasenameTextRecordContract(basename, key);
const textRecord = await baseClient.readContract(contractParameters);
return textRecord as string;
} catch (error) {}
}
// Get a all TextRecords
export async function getBasenameTextRecords(basename: Basename) {
try {
const readContracts: ContractFunctionParameters[] =
textRecordsKeysEnabled.map((key) =>
buildBasenameTextRecordContract(basename, key)
);
const textRecords = await baseClient.multicall({
contracts: readContracts,
});
return textRecords;
} catch (error) {}
}
/**
* Convert an chainId to a coinType hex for reverse chain resolution
*/
export const convertChainIdToCoinType = (chainId: number): string => {
// L1 resolvers to addr
if (chainId === mainnet.id) {
return "addr";
}
const cointype = (0x80000000 | chainId) >>> 0;
return cointype.toString(16).toLocaleUpperCase();
};
/**
* Convert an address to a reverse node for ENS resolution
*/
export const convertReverseNodeToBytes = (
address: Address,
chainId: number
) => {
const addressFormatted = address.toLocaleLowerCase() as Address;
const addressNode = keccak256(addressFormatted.substring(2) as Address);
const chainCoinType = convertChainIdToCoinType(chainId);
const baseReverseNode = namehash(
`${chainCoinType.toLocaleUpperCase()}.reverse`
);
const addressReverseNode = keccak256(
encodePacked(["bytes32", "bytes32"], [baseReverseNode, addressNode])
);
return addressReverseNode;
};
export async function getBasename(address: Address) {
try {
const addressReverseNode = convertReverseNodeToBytes(address, base.id);
const basename = await baseClient.readContract({
abi: L2ResolverAbi,
address: BASENAME_L2_RESOLVER_ADDRESS,
functionName: "name",
args: [addressReverseNode],
});
if (basename) {
return basename as Basename;
}
} catch (error) {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment