Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Naming service #571

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/adena-extension/.storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const extensionViewport = {
name: 'Adena Extension',
styles: {
width: '360px',
height: '540px',
height: '566px',
},
};

Expand Down
2 changes: 1 addition & 1 deletion packages/adena-extension/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ body {
width: 100%;
height: 100%;
min-width: 360px;
min-height: 540px;
min-height: 566px;
padding: 0;
margin: 0;
font-family: 'Poppins', sans-serif;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe('AccountDetails Component', () => {
originName: '',
name: '',
address: '',
dns: '',
moveGnoscan: () => {
return;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const Default: StoryObj<AccountDetailsProps> = {
originName: '',
name: '',
address: '',
dns: '',
moveGnoscan: () => action('moveGnoscan'),
moveExportPrivateKey: () => action('moveExportPrivateKey'),
setName: () => action('setName'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const AccountDetailsWrapper = styled.div`
border-radius: 8px;
}

.qrcode-address-wrapper {
.qrcode-address-wrapper , .qrcode-gno-name-wrapper {
${mixins.flex({ direction: 'row', justify: 'space-between' })};
width: 100%;
height: 42px;
Expand All @@ -34,7 +34,7 @@ export const AccountDetailsWrapper = styled.div`
padding: 12px 18px 12px 16px;
border-radius: 18px;

.address {
.address, .gno-name {
display: block;
width: 100%;
margin-right: 8px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface AccountDetailsProps {
originName: string;
name: string;
address: string;
dns: string | undefined;
moveGnoscan: () => void;
moveExportPrivateKey: () => void;
setName: (name: string) => void;
Expand All @@ -20,6 +21,7 @@ const AccountDetails: React.FC<AccountDetailsProps> = ({
originName,
name,
address,
dns,
setName,
reset,
moveGnoscan,
Expand Down Expand Up @@ -50,6 +52,10 @@ const AccountDetails: React.FC<AccountDetailsProps> = ({
<span className='address'>{address}</span>
<CopyIconButton copyText={address} />
</div>
<div className='qrcode-gno-name-wrapper'>
<span className='gno-name'>{dns}</span>
<CopyIconButton copyText={dns || ''} />
</div>
</div>

<div className='button-group-wrapper'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const AddressInput: React.FC<AddressInputProps> = ({
className='address-input'
value={address}
onChange={(event): void => onChangeAddress(event.target.value)}
placeholder='Recipient’s Gnoland Address'
placeholder='Recipient’s Name Or Address'
autoComplete='off'
maxLength={40}
rows={1}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('TransferInput Component', () => {
return;
},
},
isNext: true,
isNext: Promise.resolve(true),
hasBackButton: true,
onClickBack: () => {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const Default: StoryObj<TransferInputProps> = {
onChangeAddress: action('change address'),
onClickAddressBook: action('click address book'),
},
isNext: true,
isNext: Promise.resolve(true),
hasBackButton: true,
onClickBack: action('click back'),
onClickCancel: action('click cancel'),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState } from 'react';

import { SubHeader } from '@components/atoms';
import { TransferInputWrapper } from './transfer-input.styles';
Expand Down Expand Up @@ -36,7 +36,7 @@ export interface TransferInputProps {
onChangeAmount: (value: string) => void;
onClickMax: () => void;
};
isNext: boolean;
isNext: Promise<boolean>;
hasBackButton: boolean;
onClickBack: () => void;
onClickCancel: () => void;
Expand All @@ -53,6 +53,17 @@ const TransferInput: React.FC<TransferInputProps> = ({
onClickCancel,
onClickNext,
}) => {

const [canNext, setCanNext] = useState(false);

useEffect(() => {
const checkNext = async () => {
const result = await isNext;
setCanNext(result);
};
checkNext();
}, [isNext]);

return (
<TransferInputWrapper>
{hasBackButton ? (
Expand All @@ -77,7 +88,7 @@ const TransferInput: React.FC<TransferInputProps> = ({
</div>
<div className='button-group'>
<button onClick={onClickCancel}>Cancel</button>
<button className={isNext ? 'next' : 'next disabled'} onClick={onClickNext}>
<button className={canNext ? 'next' : 'next disabled'} onClick={onClickNext}>
Next
</button>
</div>
Expand Down
37 changes: 28 additions & 9 deletions packages/adena-extension/src/hooks/use-address-book-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { formatAddress, formatNickname } from '@common/utils/client-utils';
import { useNetwork } from './use-network';
import { addressValidationCheck } from '@common/utils/client-utils';
import { useAccountName } from './use-account-name';
import useDNSResolver from './use-dns';

export type UseAddressBookInputHookReturn = {
opened: boolean;
Expand All @@ -21,15 +22,15 @@ export type UseAddressBookInputHookReturn = {
name: string;
description: string;
}[];
resultAddress: string;
resultAddress: Promise<string>;
setSelected: (selected: boolean) => void;
setSelectedAddressBook: (selectedAddressBook: AddressBookItem | null) => void;
setAddress: (address: string) => void;
updateAddressBook: () => Promise<void>;
onClickInputIcon: (selected: boolean) => void;
onChangeAddress: (address: string) => void;
onClickAddressBook: (addressBookId: string) => void;
validateAddressBookInput: () => boolean;
validateAddressBookInput: () => Promise<boolean>;
validateEqualAddress: () => Promise<boolean>;
};

Expand All @@ -53,6 +54,7 @@ export const useAddressBookInput = (): UseAddressBookInputHookReturn => {
description: string;
}[]
>([]);
const { resolveDomainToAddress, result } = useDNSResolver();

const updateAddressBook = async (): Promise<void> => {
const addressBooks = await addressBookService.getAddressBook();
Expand Down Expand Up @@ -104,12 +106,29 @@ export const useAddressBookInput = (): UseAddressBookInputHookReturn => {
};
}, [selectedAddressBook]);

const getResultAddress = useCallback(() => {
const getResultAddress = useCallback(async () => {
if (address.endsWith('.gno')) {
const resolvedAddress = await resolveDomainToAddress(address);
if (resolvedAddress)
return resolvedAddress;
}
if (selected) {
return selectedAddressBook?.address ?? '';
}
return address;
}, [selected, selectedAddressBook, address]);
}, [resolveDomainToAddress, selected, selectedAddressBook, address]);

// useEffect(() => {
// const resolveAddress = async () => {
// if (address.endsWith('.gno')) {
// console.log(address)
// await resolveDomainToAddress(address);
// console.log(result?.address)
// setAddress(result?.address || address)
// }
// };
// resolveAddress();
// }, [resolveDomainToAddress, getResultAddress, address, result]);

const onClickInputIcon = useCallback(
(selected: boolean) => {
Expand All @@ -127,7 +146,7 @@ export const useAddressBookInput = (): UseAddressBookInputHookReturn => {

const onChangeAddress = useCallback(
(address: string) => {
const regex = /^[a-zA-Z0-9]*$/;
const regex = /^[a-zA-Z0-9.]*$/;
if (!regex.test(address)) {
return;
}
Expand Down Expand Up @@ -169,19 +188,19 @@ export const useAddressBookInput = (): UseAddressBookInputHookReturn => {
[addressBooks, wallet?.accounts],
);

const validateAddressBookInput = useCallback(() => {
const address = getResultAddress();
const validateAddressBookInput = useCallback(async () => {
const address = await getResultAddress();
if (!addressValidationCheck(address)) {
setHasError(true);
setErrorMessage('Invalid Address');
return false;
}
clearError();
return true;
}, [selected, selectedAddressBook, address]);
}, [resolveDomainToAddress, result, selected, selectedAddressBook, address]);

const validateEqualAddress = useCallback(async () => {
const address = getResultAddress();
const address = await getResultAddress();
const currentAddress = await getCurrentAddress(currentNetwork?.addressPrefix);
if (address === currentAddress) {
setHasError(true);
Expand Down
60 changes: 60 additions & 0 deletions packages/adena-extension/src/hooks/use-dns.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useState, useCallback } from 'react';
import { useWalletContext } from './use-context';

type DNSResult = {
address: string;
domain: string;
};

type DNSResolverHook = {
resolveDomainToAddress: (domain: string) => Promise<string | null>;
resolveAddressToDomain: (address: string) => Promise<void>;
result: DNSResult | null;
error: string | null;
};

function useDNSResolver(): DNSResolverHook {
const { gnoProvider } = useWalletContext();
const [error, setError] = useState<string | null>(null);
const [result, setResult] = useState<DNSResult | null>(null);

const resolveDomainToAddress = useCallback(async (domain: string) => {
try {
if (!gnoProvider) throw new Error('gnoProvider is not available');

const response = await gnoProvider.evaluateExpression("gno.land/r/varmeta/demo/v1/domain/resolver", `Resolve("${domain}")`);
const address = response?.split('"')[1] || '';

if (!address) throw new Error('Failed to resolve address');

setResult({ domain, address });
return address; // Return the resolved address
} catch (err) {
setError((err as Error).message);
setResult(null);
return null; // Return null on failure
}
}, [gnoProvider]);


const resolveAddressToDomain = useCallback(async (address: string) => {
setError(null); // Clear previous errors
try {
if (!gnoProvider) throw new Error('gnoProvider is not available');

const response = await gnoProvider.evaluateExpression("gno.land/r/varmeta/demo/v1/domain/resolver", `GetDomainName("${address}")`);
const domain = response?.split('"')[1] || '';

if (!domain) throw new Error('Failed to resolve domain');

setResult({ domain, address });
} catch (err) {
setError((err as Error).message);
setResult(null); // Clear the result on error
}
}, [gnoProvider]);

return { resolveDomainToAddress, resolveAddressToDomain, result, error };
}

export default useDNSResolver;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '@common/constants/storage.constant';
import { SCANNER_URL } from '@common/constants/resource.constant';
import { makeQueryString } from '@common/utils/string-utils';
import useDNSResolver from '@hooks/use-dns';

const ACCOUNT_NAME_LENGTH_LIMIT = 23;

Expand All @@ -27,6 +28,13 @@ const AccountDetailsContainer: React.FC = () => {
const [originName, setOriginName] = useState('');
const [name, setName] = useState('');
const [address, setAddress] = useState<string>('');
const { resolveAddressToDomain, result } = useDNSResolver();

useEffect(() => {
if (address) {
resolveAddressToDomain(address);
}
}, [address, resolveAddressToDomain]);

const account = useMemo(() => {
return accounts.find((current) => current.id === accountId);
Expand Down Expand Up @@ -94,6 +102,7 @@ const AccountDetailsContainer: React.FC = () => {
<AccountDetails
originName={originName}
name={name}
dns={result?.domain}
address={address}
hasPrivateKey={hasPrivateKey}
moveGnoscan={moveGnoscan}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ const TransferInputContainer: React.FC = () => {
});
};

const isNext = useCallback(() => {
const isNext = useCallback(async () => {
if (balanceInput.amount === '' || BigNumber(balanceInput.amount).isLessThanOrEqualTo(0)) {
return false;
}
if (addressBookInput.resultAddress === '') {
if (await addressBookInput.resultAddress === '') {
return false;
}
return true;
Expand All @@ -129,7 +129,7 @@ const TransferInputContainer: React.FC = () => {
return;
}
const validAddress =
addressBookInput.validateAddressBookInput() &&
await addressBookInput.validateAddressBookInput() &&
(isNativeTokenModel(tokenMetainfo) || (await addressBookInput.validateEqualAddress()));
const validBalance = balanceInput.validateBalanceInput();
if (validAddress && validBalance) {
Expand All @@ -138,7 +138,7 @@ const TransferInputContainer: React.FC = () => {
state: {
isTokenSearch,
tokenMetainfo,
toAddress: addressBookInput.resultAddress,
toAddress: await addressBookInput.resultAddress,
transferAmount: {
value: balanceInput.amount,
denom: balanceInput.denom,
Expand Down
Loading
Loading