(null);
+ const [loading, setLoading] = useState(false);
+ const { enqueueSnackbar } = useSnackbar();
+
+ const onChange = (e) => {
+ setNewOwner(e.target.value.trim());
+ };
+ const canSumbit = newOwner && checked;
+ const onClick = async () => {
+ if (!newOwner) {
+ return enqueueSnackbar('Invalid input', { variant: 'error' });
+ }
+ let newOwnerPubkey: PublicKey;
+ try {
+ newOwnerPubkey = new PublicKey(newOwner);
+ } catch {
+ return enqueueSnackbar('Invalid input', { variant: 'error' });
+ }
+ try {
+ setLoading(true);
+ const instructions = await transferNameOwnership(
+ connection,
+ domainName,
+ newOwnerPubkey,
+ undefined,
+ SOL_TLD_AUTHORITY,
+ );
+ await signAndSendTransaction(
+ connection,
+ new Transaction().add(instructions),
+ wallet,
+ [],
+ );
+ enqueueSnackbar('Domain name transfered', { variant: 'success' });
+ setOpen(false);
+ } catch (err) {
+ console.warn(`Error transferring domain name ${err}`);
+ return enqueueSnackbar('Error transferring domain name', {
+ variant: 'error',
+ });
+ } finally {
+ refreshCache(tuple('useUserDomain', wallet?.publicKey?.toBase58()));
+ setLoading(false);
+ }
+ };
+ return (
+ setOpen(false)}
+ >
+
+
+
+
+ Ownership transfer
+
+
+
+
+
+
+ New Owner
+
+
+
+
setChecked(e.target.checked)}
+ />
+ }
+ label={
+
+ I understand that transferring ownership is irreversible
+
+ }
+ />
+
+
+
+
+ );
+};
+
+const DomainListItemDetails = ({ domainName }: { domainName: string }) => {
+ const classes = useStyles();
+ const [transferVisible, setTransferVisible] = useState(false);
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+};
+
+const DomainListItem = ({
+ domainName,
+ domainKey,
+}: {
+ domainName: string;
+ domainKey: PublicKey;
+}) => {
+ const classes = useStyles();
+ const [open, setOpen] = useState(false);
+ return (
+ <>
+ setOpen((prev) => !prev)}>
+
+
+
+
+ {open ? : }
+
+
+
+
+ >
+ );
+};
+
+const DomainsList = () => {
+ const [userDomains, userDomainsLoaded] = useUserDomains();
+ if (!userDomainsLoaded) {
+ return ;
+ }
+ if (userDomainsLoaded && userDomains?.length === 0) {
+ return (
+
+ You don't own any domain
+
+ );
+ }
+ return (
+ <>
+
+ {userDomains?.map((d) => {
+ return (
+
+ );
+ })}
+
+ >
+ );
+};
+
+const DomainDialog = ({
+ open,
+ setOpen,
+}: {
+ open: boolean;
+ setOpen: (arg: boolean) => void;
+}) => {
+ const classes = useStyles();
+ return (
+ setOpen(false)} className={classes.modal}>
+
+
+
+
+ Your domains
+
+
+
+
+
+
+ );
+};
+
+export default DomainDialog;
diff --git a/src/utils/name-service/index.ts b/src/utils/name-service/index.ts
index 03657e7..92b48d4 100644
--- a/src/utils/name-service/index.ts
+++ b/src/utils/name-service/index.ts
@@ -4,13 +4,24 @@ import {
getHashedName,
getNameAccountKey,
NameRegistryState,
+ getFilteredProgramAccounts,
+ NAME_PROGRAM_ID,
} from '@bonfida/spl-name-service';
+import { useConnection } from '../connection';
+import { useWallet } from '../wallet';
+import BN from 'bn.js';
+import { useAsyncData } from '../fetch-loop';
+import tuple from 'immutable-tuple';
// Address of the SOL TLD
export const SOL_TLD_AUTHORITY = new PublicKey(
'58PwtjSDuFHuUkYjH9BYnnQKHfwo9reZhC2zMJv9JPkx',
);
+export const PROGRAM_ID = new PublicKey(
+ 'jCebN34bUfdeUYJT13J1yG16XWQpt5PDx6Mse9GUqhR',
+);
+
export const resolveTwitterHandle = async (
connection: Connection,
twitterHandle: string,
@@ -45,3 +56,74 @@ export const resolveDomainName = async (
return undefined;
}
};
+
+export async function findOwnedNameAccountsForUser(
+ connection: Connection,
+ userAccount: PublicKey,
+): Promise {
+ const filters = [
+ {
+ memcmp: {
+ offset: 32,
+ bytes: userAccount.toBase58(),
+ },
+ },
+ ];
+ const accounts = await getFilteredProgramAccounts(
+ connection,
+ NAME_PROGRAM_ID,
+ filters,
+ );
+ return accounts.map((a) => a.publicKey);
+}
+
+export async function performReverseLookup(
+ connection: Connection,
+ nameAccount: PublicKey,
+): Promise {
+ let [centralState] = await PublicKey.findProgramAddress(
+ [PROGRAM_ID.toBuffer()],
+ PROGRAM_ID,
+ );
+ let hashedReverseLookup = await getHashedName(nameAccount.toBase58());
+ let reverseLookupAccount = await getNameAccountKey(
+ hashedReverseLookup,
+ centralState,
+ );
+
+ let name = await NameRegistryState.retrieve(connection, reverseLookupAccount);
+ if (!name.data) {
+ throw new Error('Could not retrieve name data');
+ }
+ let nameLength = new BN(name.data.slice(0, 4), 'le').toNumber();
+ return name.data.slice(4, 4 + nameLength).toString();
+}
+
+export const useUserDomains = () => {
+ const wallet = useWallet();
+ const connection = useConnection();
+ const fn = async () => {
+ const domains = await findOwnedNameAccountsForUser(
+ connection,
+ wallet.publicKey,
+ );
+ let names: { name: string; nameKey: PublicKey }[] = [];
+ const fn = async (d) => {
+ try {
+ const name = await performReverseLookup(connection, d);
+ names.push({ name: name, nameKey: d });
+ } catch (err) {
+ console.log(`Passing account ${d.toBase58()} - err ${err}`);
+ }
+ };
+ const promises = domains.map((d) => fn(d));
+ await Promise.allSettled(promises);
+ return names.sort((a, b) => {
+ return a.name.localeCompare(b.name);
+ });
+ };
+ return useAsyncData(
+ fn,
+ tuple('useUserDomain', wallet?.publicKey?.toBase58()),
+ );
+};