Skip to content

Commit

Permalink
add: balances cache
Browse files Browse the repository at this point in the history
  • Loading branch information
anondev2323 committed Sep 11, 2023
1 parent fac9709 commit f7c272e
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 61 deletions.
44 changes: 24 additions & 20 deletions wormhole-connect/src/components/TokensModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { BigNumber } from 'ethers';
import { RootState } from 'store';
import { CHAINS } from 'config';
import { TokenConfig } from 'config/types';
import { setBalance, formatBalance, clearBalances } from 'store/transferInput';
import { setBalances, formatBalance, ChainBalances } from 'store/transferInput';
import { displayAddress } from 'utils';
import { wh } from 'utils/sdk';
import { CENTER, NO_INPUT } from 'utils/style';
Expand Down Expand Up @@ -266,24 +266,19 @@ function TokensModal(props: Props) {
const [tokens, setTokens] = useState<TokenConfig[]>([]);
const [search, setSearch] = useState('');

const {
sourceBalances,
destBalances,
supportedSourceTokens,
supportedDestTokens,
route,
} = useSelector((state: RootState) => state.transferInput);
const { balances, supportedSourceTokens, supportedDestTokens, route } =
useSelector((state: RootState) => state.transferInput);

const supportedTokens = useMemo(() => {
const supported =
type === 'source' ? supportedSourceTokens : supportedDestTokens;
return supported.filter((t) => !isCosmosNativeToken(t));
}, [type, supportedSourceTokens, supportedDestTokens]);

const tokenBalances = useMemo(
() => (type === 'source' ? sourceBalances : destBalances),
[type, sourceBalances, destBalances],
);
const chainBalancesCache: ChainBalances | undefined = useMemo(() => {
if (!chain || !balances[chain]) return undefined;
return balances[chain];
}, [chain, balances]);

// search tokens
const handleSearch = (
Expand Down Expand Up @@ -329,6 +324,15 @@ function TokensModal(props: Props) {

const getBalances = useCallback(async () => {
if (!walletAddress || !chain) return;
const fiveMinutesAgo = Date.now() - 60 * 1000 * 5;
if (
chainBalancesCache &&
chainBalancesCache.balances &&
chainBalancesCache.lastUpdated! > fiveMinutesAgo
) {
setBalancesLoaded(true);
return;
}
// fetch all N tokens and trigger a single update action
const balancesArr = await Promise.all(
supportedTokens.map(async (t) => {
Expand Down Expand Up @@ -371,12 +375,12 @@ function TokensModal(props: Props) {
}, {});

dispatch(
setBalance({
type,
setBalances({
chain,
balances,
}),
);
}, [walletAddress, chain, dispatch, type, supportedTokens, route]);
}, [walletAddress, chain, dispatch, type, supportedTokens, route, open]);

// fetch token balances and set in store
useEffect(() => {
Expand All @@ -387,7 +391,6 @@ function TokensModal(props: Props) {
}

if (!balancesLoaded) {
dispatch(clearBalances(type));
setLoading(true);
getBalances().finally(() => {
if (active) {
Expand Down Expand Up @@ -417,20 +420,21 @@ function TokensModal(props: Props) {
if (!t.tokenId && t.nativeChain !== chain) return false;
if (t.symbol === 'USDC' && t.nativeChain !== chain) return false;
if (type === 'dest') return true;
const b = tokenBalances[t.key];
if (!chainBalancesCache) return true;
const b = chainBalancesCache.balances[t.key];
const isNullBalance = b !== null && b !== '0';
return isNullBalance;
});
setTokens(filtered);
}, [tokenBalances, chain, supportedTokens, type]);
}, [chainBalancesCache, chain, supportedTokens, type]);

const tabs = [
{
label: 'Available Tokens',
panel: (
<DisplayTokens
tokens={displayedTokens}
balances={tokenBalances}
balances={chainBalancesCache?.balances}
walletAddress={walletAddress}
chain={chain}
selectToken={selectToken}
Expand All @@ -444,7 +448,7 @@ function TokensModal(props: Props) {
panel: (
<DisplayTokens
tokens={supportedTokens}
balances={tokenBalances}
balances={chainBalancesCache?.balances}
walletAddress={walletAddress}
chain={chain}
selectToken={selectToken}
Expand Down
61 changes: 31 additions & 30 deletions wormhole-connect/src/store/transferInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import { TransferWallet, walletAcceptedChains } from 'utils/wallet';
import { clearWallet, setWalletError, WalletData } from './wallet';

export type Balances = { [key: string]: string | null };
export type ChainBalances = {
lastUpdated: number | undefined;
balances: Balances;
};
export type BalancesCache = { [key in ChainName]?: ChainBalances };

export const formatBalance = (
chain: ChainName,
Expand All @@ -22,6 +27,17 @@ export const formatBalance = (
return { [token.key]: formattedBalance };
};

export const accessBalance = (
balances: BalancesCache | undefined,
chain: ChainName | undefined,
token: string,
): string | null => {
if (!chain || !balances) return null;
const chainBalances = balances[chain];
if (!chainBalances) return null;
return chainBalances.balances[token];
};

export type ValidationErr = string;

export type TransferValidations = {
Expand Down Expand Up @@ -49,8 +65,7 @@ export interface TransferInputState {
amount: string;
receiveAmount: string;
route: Route | undefined;
sourceBalances: Balances;
destBalances: Balances;
balances: BalancesCache;
foreignAsset: string;
associatedTokenAddress: string;
gasEst: {
Expand Down Expand Up @@ -86,8 +101,7 @@ const initialState: TransferInputState = {
amount: '',
receiveAmount: '',
route: undefined,
sourceBalances: {},
destBalances: {},
balances: {},
foreignAsset: '',
associatedTokenAddress: '',
gasEst: {
Expand Down Expand Up @@ -141,8 +155,6 @@ export const transferInputSlice = createSlice({
{ payload }: PayloadAction<ChainName>,
) => {
state.fromChain = payload;
// clear balances if the chain changes;
state.sourceBalances = {};

const { fromChain, token } = state;

Expand Down Expand Up @@ -173,37 +185,27 @@ export const transferInputSlice = createSlice({
) => {
state.receiveAmount = payload;
},
setBalance: (
setBalances: (
state: TransferInputState,
{
payload,
}: PayloadAction<{ type: 'source' | 'dest'; balances: Balances }>,
{ payload }: PayloadAction<{ chain: ChainName; balances: Balances }>,
) => {
const { type, balances } = payload;
if (type === 'source') {
state.sourceBalances = { ...state.sourceBalances, ...balances };
} else {
state.destBalances = { ...state.destBalances, ...balances };
}
const { chain, balances } = payload;
state.balances = {
...state.balances,
...{
[chain]: {
lastUpdated: Date.now(),
balances: { ...state.balances[chain], ...balances },
},
},
};
},
setReceiverNativeBalance: (
state: TransferInputState,
{ payload }: PayloadAction<string>,
) => {
state.receiverNativeBalance = payload;
},
clearBalances: (
state: TransferInputState,
{ payload }: PayloadAction<'source' | 'dest' | 'all'>,
) => {
if (payload === 'source' || payload === 'all') {
state.sourceBalances = {};
}

if (payload === 'dest' || payload === 'all') {
state.destBalances = {};
}
},
setForeignAsset: (
state: TransferInputState,
{ payload }: PayloadAction<string>,
Expand Down Expand Up @@ -323,13 +325,12 @@ export const {
setToChain,
setAmount,
setReceiveAmount,
setBalance,
clearBalances,
setForeignAsset,
setAssociatedTokenAddress,
setTransferRoute,
setSendingGasEst,
setClaimGasEst,
setBalances,
clearTransfer,
setIsTransactionInProgress,
setReceiverNativeBalance,
Expand Down
8 changes: 5 additions & 3 deletions wormhole-connect/src/utils/transferValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
touchValidations,
ValidationErr,
TransferValidations,
accessBalance,
} from '../store/transferInput';
import { WalletData, WalletState } from '../store/wallet';
import { walletAcceptedChains } from './wallet';
Expand Down Expand Up @@ -191,7 +192,7 @@ export const validateAll = async (
token,
destToken,
amount,
sourceBalances: balances,
balances,
foreignAsset,
associatedTokenAddress,
route,
Expand All @@ -201,6 +202,7 @@ export const validateAll = async (
const { sending, receiving } = walletData;
const isAutomatic = getIsAutomatic(route);
const minAmt = getMinAmt(route, relayData);
const sendingTokenBalance = accessBalance(balances, fromChain, token);

const baseValidations = {
sendingWallet: await validateWallet(sending, fromChain),
Expand All @@ -209,7 +211,7 @@ export const validateAll = async (
toChain: validateToChain(toChain, fromChain),
token: validateToken(token, fromChain),
destToken: validateDestToken(destToken, toChain),
amount: validateAmount(amount, balances[token], minAmt),
amount: validateAmount(amount, sendingTokenBalance, minAmt),
route: validateRoute(route, availableRoutes),
toNativeToken: '',
foreignAsset: validateForeignAsset(foreignAsset),
Expand All @@ -222,7 +224,7 @@ export const validateAll = async (
if (!isAutomatic) return baseValidations;
return {
...baseValidations,
amount: validateAmount(amount, balances[token], minAmt),
amount: validateAmount(amount, sendingTokenBalance, minAmt),
toNativeToken: validateToNativeAmt(toNativeToken, maxSwapAmt),
};
};
Expand Down
5 changes: 3 additions & 2 deletions wormhole-connect/src/views/Bridge/Inputs/From.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
selectFromChain,
setAmount,
setReceiveAmount,
accessBalance,
} from 'store/transferInput';
import { CHAINS, CHAINS_ARR, TOKENS } from 'config';
import { TransferWallet, walletAcceptedChains } from 'utils/wallet';
Expand All @@ -34,13 +35,13 @@ function FromInputs() {
route,
fromChain,
toChain,
sourceBalances: balances,
balances,
token,
amount,
isTransactionInProgress,
} = useSelector((state: RootState) => state.transferInput);
const tokenConfig = token && TOKENS[token];
const balance = balances[token] || undefined;
const balance = accessBalance(balances, fromChain, token) || undefined;

const isDisabled = (chain: ChainName) => {
// Check if the wallet type (i.e. Metamask, Phantom...) is supported for the given chain
Expand Down
11 changes: 7 additions & 4 deletions wormhole-connect/src/views/Bridge/Inputs/To.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { useDispatch, useSelector } from 'react-redux';
import { ChainName } from '@wormhole-foundation/wormhole-connect-sdk';

import { RootState } from 'store';
import { selectToChain, setDestToken } from 'store/transferInput';
import {
accessBalance,
selectToChain,
setDestToken,
} from 'store/transferInput';
import { TransferWallet, walletAcceptedChains } from 'utils/wallet';
import { getWrappedToken } from 'utils';
import { CHAINS, CHAINS_ARR, TOKENS } from 'config';
Expand All @@ -23,16 +27,15 @@ function ToInputs() {
const {
validate: showErrors,
validations,
// route,
fromChain,
toChain,
destBalances,
balances,
destToken,
receiveAmount,
isTransactionInProgress,
} = useSelector((state: RootState) => state.transferInput);
const { receiving } = useSelector((state: RootState) => state.wallet);
const balance = destBalances[destToken] || undefined;
const balance = accessBalance(balances, toChain, destToken) || undefined;

const tokenConfig = TOKENS[destToken];

Expand Down
3 changes: 1 addition & 2 deletions wormhole-connect/src/views/Bridge/SwapChains.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useDispatch } from 'react-redux';
import { makeStyles } from 'tss-react/mui';

import { swapWallets } from 'store/wallet';
import { swapChains, clearBalances } from 'store/transferInput';
import { swapChains } from 'store/transferInput';

const useStyles = makeStyles()((theme: any) => ({
button: {
Expand All @@ -28,7 +28,6 @@ function SwapChains() {
const swap = () => {
dispatch(swapChains());
dispatch(swapWallets());
dispatch(clearBalances('all'));
};

return (
Expand Down

0 comments on commit f7c272e

Please sign in to comment.