Skip to content

Commit

Permalink
fix: improve the process of initializing token information (#638)
Browse files Browse the repository at this point in the history
  • Loading branch information
jinoosss authored Nov 11, 2024
1 parent fe604cf commit bd11462
Show file tree
Hide file tree
Showing 9 changed files with 244 additions and 74 deletions.
12 changes: 9 additions & 3 deletions packages/adena-extension/src/App/use-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,16 @@ const useApp = (): void => {
}, [key]);

useEffect(() => {
if (currentAccount && currentNetwork) {
initTokenMetainfos(true);
if (!currentAccount?.id) {
return;
}
}, [currentAccount, currentNetwork]);

if (!currentNetwork?.networkId) {
return;
}

initTokenMetainfos();
}, [currentAccount?.id, currentNetwork.networkId]);

useEffect(() => {
initAccountNames(wallet?.accounts ?? []);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Wallet } from 'adena-module';
import React, { createContext, useEffect, useState } from 'react';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { Wallet } from 'adena-module';

import { NetworkState, TokenState, WalletState } from '@states';
import { useAdenaContext } from '@hooks/use-context';
import { NetworkState, TokenState, WalletState } from '@states';
import { NetworkMetainfo, StateType, TokenModel } from '@types';
import { GnoProvider } from '../gno/gno-provider';
import { TokenModel, NetworkMetainfo, StateType } from '@types';

export interface WalletContextProps {
wallet: Wallet | null;
Expand All @@ -31,7 +31,7 @@ export const WalletProvider: React.FC<React.PropsWithChildren<unknown>> = ({ chi

const [walletStatus, setWalletStatus] = useRecoilState(WalletState.state);

const [tokenMetainfos] = useRecoilState(TokenState.tokenMetainfos);
const [tokenMetainfos, setTokenMetainfos] = useRecoilState(TokenState.tokenMetainfos);

const [networkMetainfos, setNetworkMetainfos] = useRecoilState(NetworkState.networkMetainfos);

Expand Down Expand Up @@ -95,6 +95,7 @@ export const WalletProvider: React.FC<React.PropsWithChildren<unknown>> = ({ chi
if (currentAccount) {
setCurrentAccount(currentAccount);
await accountService.changeCurrentAccount(currentAccount);
await initTokenMetainfos(currentAccount.id);
}
return true;
}
Expand Down Expand Up @@ -123,6 +124,13 @@ export const WalletProvider: React.FC<React.PropsWithChildren<unknown>> = ({ chi
return true;
}

async function initTokenMetainfos(accountId: string): Promise<void> {
await tokenService.initAccountTokenMetainfos(accountId);
const tokenMetainfos = await tokenService.getTokenMetainfosByAccountId(accountId);
setTokenMetainfos(tokenMetainfos);
balanceService.setTokenMetainfos(tokenMetainfos);
}

async function changeNetwork(networkMetainfo: NetworkMetainfo): Promise<NetworkMetainfo> {
const rpcUrl = networkMetainfo.rpcUrl;
const gnoProvider = new GnoProvider(rpcUrl, networkMetainfo.networkId);
Expand Down
42 changes: 32 additions & 10 deletions packages/adena-extension/src/hooks/use-token-balance.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { useEffect, useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Account } from 'adena-module';
import { useEffect, useMemo } from 'react';

import { isGRC20TokenModel, isNativeTokenModel } from '@common/validation/validation-token';
import { TokenModel, Amount, TokenBalanceType } from '@types';
import { Amount, TokenBalanceType, TokenModel } from '@types';

import { useNetwork } from './use-network';
import { useCurrentAccount } from './use-current-account';
import { useAdenaContext, useWalletContext } from './use-context';
import { useCurrentAccount } from './use-current-account';
import { useGRC20Tokens } from './use-grc20-tokens';
import { useNetwork } from './use-network';
import { useTokenMetainfo } from './use-token-metainfo';
import { useWallet } from './use-wallet';
import { useGRC20Tokens } from './use-grc20-tokens';

export const useTokenBalance = (): {
mainTokenBalance: Amount | null;
Expand All @@ -22,6 +22,7 @@ export const useTokenBalance = (): {
const { isFetched: isFetchedGRC20Tokens } = useGRC20Tokens();
const {
currentTokenMetainfos: tokenMetainfos,
tokenLogoMap,
updateTokenMetainfos,
getTokenAmount,
} = useTokenMetainfo();
Expand All @@ -35,12 +36,26 @@ export const useTokenBalance = (): {
balanceService.setTokenMetainfos(tokenMetainfos);
}, [tokenMetainfos, balanceService]);

const availableBalanceFetching = useMemo(() => {
if (!existWallet || lockedWallet) {
return false;
}

if (!isFetchedGRC20Tokens || tokenMetainfos.length === 0) {
return false;
}

return true;
}, [existWallet, lockedWallet, tokenMetainfos, isFetchedGRC20Tokens]);

const { data: balances = [] } = useQuery<TokenBalanceType[]>(
[
'balances',
currentAddress,
currentNetwork.chainId,
tokenMetainfos.map((token) => token.tokenId),
isFetchedGRC20Tokens,
tokenLogoMap,
],
() => {
if (currentAddress === null || nativeToken == null) {
Expand All @@ -50,21 +65,25 @@ export const useTokenBalance = (): {
tokenMetainfos.map((tokenModel) => fetchBalanceBy(currentAddress, tokenModel)),
);
},
{ refetchInterval: 5000, enabled: existWallet && !lockedWallet },
{
refetchInterval: 5000,
enabled: availableBalanceFetching,
},
);

const { data: accountNativeBalanceMap = {} } = useQuery<Record<string, TokenBalanceType>>(
[
'accountNativeBalanceMap',
wallet?.accounts,
currentNetwork.chainId,
tokenMetainfos,
tokenMetainfos.map((token) => token.tokenId),
isFetchedGRC20Tokens,
],
() => {
if (wallet === null || wallet.accounts === null || nativeToken == null) {
return {};
}

return Promise.all(
wallet.accounts.map(async (account) => {
const address = await account.getAddress(currentNetwork.addressPrefix);
Expand All @@ -79,7 +98,10 @@ export const useTokenBalance = (): {
}, {}),
);
},
{ refetchInterval: 5000, enabled: existWallet && !lockedWallet && isFetchedGRC20Tokens },
{
refetchInterval: 5000,
enabled: availableBalanceFetching,
},
);

const currentBalances = useMemo((): TokenBalanceType[] => {
Expand Down Expand Up @@ -133,14 +155,14 @@ export const useTokenBalance = (): {
const balanceAmount = isNativeTokenModel(token)
? await balanceService.getGnotTokenBalance(address)
: isGRC20TokenModel(token)
? await balanceService.getGRC20TokenBalance(address, token.pkgPath)
? await balanceService.getGRC20TokenBalance(address, token.pkgPath, token.decimals)
: null;

return {
...token,
amount: getTokenAmount({
value: `${balanceAmount || 0}`,
denom: isGRC20TokenModel(token) ? token.pkgPath : token.symbol,
denom: token.symbol,
}),
};
}
Expand Down
69 changes: 40 additions & 29 deletions packages/adena-extension/src/hooks/use-token-metainfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useNetwork } from './use-network';

import { TokenState } from '@states';
import { useQuery } from '@tanstack/react-query';
import { GRC20TokenModel, TokenModel } from '@types';
import { GRC20TokenModel, GRC721CollectionModel, TokenModel } from '@types';
import { Account } from 'adena-module';
import BigNumber from 'bignumber.js';
import { useCallback, useMemo } from 'react';
Expand All @@ -30,7 +30,7 @@ export type UseTokenMetainfoReturn = {
currentTokenMetainfos: TokenModel[];
tokenLogoMap: Record<string, string | null>;
getTokenAmount: (amount: { value: string; denom: string }) => { value: string; denom: string };
initTokenMetainfos: (withTransferEvents?: boolean) => Promise<void>;
initTokenMetainfos: () => Promise<void>;
updateTokenMetainfos: (account: Account, tokenMetainfos: TokenModel[]) => Promise<void>;
addTokenMetainfo: (tokenMetainfo: GRC20TokenModel) => Promise<boolean>;
addGRC20TokenMetainfo: ({
Expand Down Expand Up @@ -137,40 +137,51 @@ export const useTokenMetainfo = (): UseTokenMetainfoReturn => {
}, {});
}, [allTokenMetainfos]);

const initTokenMetainfos = async (withTransferEvents?: boolean): Promise<void> => {
const initTokenMetainfos = async (): Promise<void> => {
if (!currentAccount) {
return;
}

if (withTransferEvents) {
await setTokenMetainfo([]);
const currentAddress = await currentAccount.getAddress(currentNetwork.addressPrefix);
const transferTokens = await fetchTransferTokens(currentAddress).catch(() => null);
if (transferTokens) {
const storedGRC20Tokens = await tokenService.getTokenMetainfosByAccountId(
currentAccount.id,
);
const storedCollections = await tokenService.getAccountGRC721Collections(
currentAccount.id,
currentNetwork.chainId,
);
await setTokenMetainfo([]);
const currentAddress = await currentAccount.getAddress(currentNetwork.addressPrefix);

/**
* For accounts with no transfer events, initialize the state with the list of stored tokens.
*/
const transferTokens = await fetchTransferTokens(currentAddress).catch(() => null);
if (!transferTokens) {
await tokenService.initAccountTokenMetainfos(currentAccount.id);
const tokenMetainfos = await tokenService.getTokenMetainfosByAccountId(currentAccount.id);
setTokenMetainfo([...tokenMetainfos]);
return;
}

const storedGRC20Packages = storedGRC20Tokens.map((grc20Token) => grc20Token.tokenId);
const storedGRC721Packages = storedCollections.map(
(grc721Token) => grc721Token.packagePath,
);
/**
* When there is a transfer event, verify that the token is new and not part of the list of tokens stored in the existing account.
* The new tokens are added to the account's token information.
*/
const storedGRC20Tokens = await tokenService.getTokenMetainfosByAccountId(currentAccount.id);
const storedCollections = await tokenService.getAccountGRC721Collections(
currentAccount.id,
currentNetwork.chainId,
);

const filteredGRC20Packages = (transferTokens.grc20Packages || []).filter(
(grc20Token) => !storedGRC20Packages.includes(grc20Token.tokenId),
);
const filteredGRC721Packages = (transferTokens.grc721Packages || []).filter(
(grc721Token) => !storedGRC721Packages.includes(grc721Token.packagePath),
);
const storedGRC20Packages = storedGRC20Tokens
.filter((token: TokenModel) => token.networkId === currentNetwork.networkId)
.map((grc20Token) => grc20Token.tokenId);
const storedGRC721Packages = storedCollections
.filter((token: GRC721CollectionModel) => token.networkId === currentNetwork.networkId)
.map((grc721Token) => grc721Token.packagePath);

await addTokenMetainfos(filteredGRC20Packages);
await addCollections(filteredGRC721Packages);
}
}
const filteredGRC20Packages = (transferTokens.grc20Packages || []).filter(
(grc20Token) => !storedGRC20Packages.includes(grc20Token.tokenId),
);
const filteredGRC721Packages = (transferTokens.grc721Packages || []).filter(
(grc721Token) => !storedGRC721Packages.includes(grc721Token.packagePath),
);

await addTokenMetainfos(filteredGRC20Packages);
await addCollections(filteredGRC721Packages);

await tokenService.initAccountTokenMetainfos(currentAccount.id);
const tokenMetainfos = await tokenService.getTokenMetainfosByAccountId(currentAccount.id);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React, { useCallback, useEffect, useMemo } from 'react';

import { CommonFullContentLayout } from '@components/atoms';
import ChangeNetwork from '@components/pages/change-network/change-network/change-network';
import useAppNavigate from '@hooks/use-app-navigate';
import { useNetwork } from '@hooks/use-network';
import { useTokenMetainfo } from '@hooks/use-token-metainfo';
import { RoutePath } from '@types';
import { CommonFullContentLayout } from '@components/atoms';
import useAppNavigate from '@hooks/use-app-navigate';

const ChangeNetworkContainer: React.FC = () => {
const { navigate, goBack } = useAppNavigate();
const { modified, currentNetwork, networks, setModified, changeNetwork } = useNetwork();
const { initTokenMetainfos } = useTokenMetainfo();

useEffect(() => {
if (modified) {
Expand Down Expand Up @@ -46,7 +44,6 @@ const ChangeNetworkContainer: React.FC = () => {

if (networkId) {
await changeNetwork(networkId);
await initTokenMetainfos();
navigate(RoutePath.Wallet);
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,11 @@ const ManageTokenAddedContainer: React.FC = () => {
}

const isRegistered = tokenMetainfos.some((tokenMetaInfo) => {
if (tokenMetaInfo.tokenId === manualTokenPath) {
return true;
if (
tokenMetaInfo.tokenId !== manualTokenPath ||
tokenMetaInfo.networkId !== currentNetwork.networkId
) {
return false;
}

if (isGRC20TokenModel(tokenMetaInfo)) {
Expand Down
Loading

0 comments on commit bd11462

Please sign in to comment.