Skip to content

Commit

Permalink
fix(tangle-dapp): Fix network switcher bug (#2493)
Browse files Browse the repository at this point in the history
Co-authored-by: Trung-Tin Pham <[email protected]>
  • Loading branch information
yurixander and AtelyPham authored Aug 5, 2024
1 parent 6a2156d commit ccf3bb9
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 166 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,21 @@ const CustomRpcEndpointInput: FC<CustomRpcEndpointInputProps> = ({
}
}, [getCachedCustomRpcEndpoint, value]);

const rightIcon =
value !== '' ? (
<SaveWithBg className="cursor-pointer" onClick={handleSave} />
) : (
<Save className="opacity-60 cursor-not-allowed" />
);

return (
<Input
id={id}
placeholder={placeholder}
value={value}
onChange={setValue}
rightIcon={
value !== '' ? (
<SaveWithBg className="cursor-pointer" onClick={handleSave} />
) : (
<Save className="opacity-60 cursor-not-allowed" />
)
}
isControlled
rightIcon={rightIcon}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ const NetworkSelectionButton: FC = () => {
);

const networkName = useMemo(() => {
if (isConnecting) return 'Connecting...';

if (loading) return 'Loading...';
if (isConnecting) {
return 'Connecting...';
} else if (loading) {
return 'Loading...';
}

return network?.name ?? 'Unknown Network';
}, [isConnecting, loading, network?.name]);
Expand All @@ -57,10 +59,14 @@ const NetworkSelectionButton: FC = () => {
// since it would have no effect there.
const isInLiquidStakingPath = pathname.startsWith(PagePath.LIQUID_STAKING);

const isBridgePage = useMemo(() => pathname === '/bridge', [pathname]);
const isInBridgePath = useMemo(
() => pathname.startsWith(PagePath.BRIDGE),
[pathname],
);

const isWrongEvmNetwork = useMemo(() => {
const isEvmWallet = activeWallet?.platform === 'EVM';

return (
isEvmWallet &&
network.evmChainId !== undefined &&
Expand All @@ -69,18 +75,26 @@ const NetworkSelectionButton: FC = () => {
}, [activeChain?.id, activeWallet?.platform, network.evmChainId]);

const switchToCorrectEvmChain = useCallback(() => {
if (!network.evmChainId || !activeWallet) return;
if (!network.evmChainId || !activeWallet) {
return;
}

const typedChainId = calculateTypedChainId(
ChainType.EVM,
network.evmChainId,
);

const targetChain = chainsPopulated[typedChainId];

switchChain(targetChain, activeWallet);
}, [activeWallet, network.evmChainId, switchChain]);

if (isBridgePage) return null;

if (isInLiquidStakingPath) {
if (isInBridgePath) {
return null;
}
// Network can't be switched from the Tangle Restaking Parachain while
// on liquid staking page.
else if (isInLiquidStakingPath) {
return (
<Tooltip>
<TooltipTrigger asChild>
Expand Down Expand Up @@ -121,6 +135,7 @@ const NetworkSelectionButton: FC = () => {
<TooltipBody>Wrong EVM Chain Connected</TooltipBody>
</Tooltip>
)}

<Dropdown>
<TriggerButton
isLoading={isConnecting || loading}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ import {
Network,
TANGLE_LOCAL_DEV_NETWORK,
TANGLE_MAINNET_NETWORK,
TANGLE_RESTAKING_PARACHAIN_LOCAL_DEV_NETWORK,
TANGLE_TESTNET_NATIVE_NETWORK,
} from '@webb-tools/webb-ui-components/constants/networks';
import { FC, ReactNode, useCallback } from 'react';

import { IS_PRODUCTION_ENV } from '../../constants/env';
import CustomRpcEndpointInput from './CustomRpcEndpointInput';
import { TANGLE_TESTNET_CHAIN_NAME } from './NetworkSelectionButton';

Expand Down Expand Up @@ -63,20 +61,6 @@ export const NetworkSelectorDropdown: FC<NetworkSelectorDropdownProps> = ({
}
/>

{/* Tangle restaking parachain (local dev) network */}
{IS_PRODUCTION_ENV && (
<NetworkOption
isSelected={
selectedNetwork?.id ===
TANGLE_RESTAKING_PARACHAIN_LOCAL_DEV_NETWORK.id
}
name={TANGLE_RESTAKING_PARACHAIN_LOCAL_DEV_NETWORK.name}
onClick={() =>
onNetworkChange(TANGLE_RESTAKING_PARACHAIN_LOCAL_DEV_NETWORK)
}
/>
)}

{/* Custom network */}
<NetworkOption
isSelected={isCustomEndpointSelected}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// TODO: This function checks if the connection can be established, but it doesn't check what kind of network the endpoint is connected to! This means that if a different network than expected (ie. Tangle Restaking Parachain vs. expected Tangle Local Testnet), the app will crash due to attempting to access storage queries or extrinsics that are not available on that network. However, this isn't a huge concern as of now since it only applies to custom RPC endpoints, usually used for testing purposes.
function testRpcEndpointConnection(rpcEndpoint: string): Promise<boolean> {
return new Promise((resolve) => {
try {
Expand Down
2 changes: 1 addition & 1 deletion apps/tangle-dapp/components/UpdateMetadataButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const UpdateMetadataButton: FC = () => {
);

const { setWithPreviousValue: setCache, valueOpt: cachedMetadata } =
useLocalStorage(LocalStorageKey.SUBSTRATE_WALLETS_METADATA, true);
useLocalStorage(LocalStorageKey.SUBSTRATE_WALLETS_METADATA);

const updateCache = useCallback(
(genesisHash: HexString, metadata: SubstrateWalletsMetadataEntry) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@ const BalancesTableContainer: FC = () => {
const {
set: setCachedIsDetailsCollapsed,
valueOpt: cachedIsDetailsCollapsedOpt,
} = useLocalStorage(
LocalStorageKey.IS_BALANCES_TABLE_DETAILS_COLLAPSED,
false,
);
} = useLocalStorage(LocalStorageKey.IS_BALANCES_TABLE_DETAILS_COLLAPSED);

const { result: locks } = useApiRx(
useCallback(
Expand Down
1 change: 0 additions & 1 deletion apps/tangle-dapp/data/NominationsPayouts/usePayouts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export default function usePayouts(): UsePayoutsReturnType {

const { setWithPreviousValue: setCachedPayouts } = useLocalStorage(
LocalStorageKey.PAYOUTS,
true,
);

const { rpcEndpoint, network } = useNetworkStore();
Expand Down
16 changes: 6 additions & 10 deletions apps/tangle-dapp/data/liquidStaking/useLiquidStakingItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,17 @@ import {
} from './helper';

const useLiquidStakingItems = (selectedChain: ParachainChainId) => {
const {
// valueOpt: liquidStakingTableData,
setWithPreviousValue: setLiquidStakingTableData,
} = useLocalStorage(LocalStorageKey.LIQUID_STAKING_TABLE_DATA, true);
const { setWithPreviousValue: setLiquidStakingTableData } = useLocalStorage(
LocalStorageKey.LIQUID_STAKING_TABLE_DATA,
);

const [isLoading, setIsLoading] = useState(false);

const [items, setItems] = useState<
Validator[] | VaultOrStakePool[] | Dapp[] | Collator[]
>([]);
const dataType = useMemo(() => getDataType(selectedChain), [selectedChain]);

// const cachedData = useMemo(
// () => liquidStakingTableData.value[selectedChain] || [],
// [liquidStakingTableData, selectedChain],
// );
// console.debug('cachedData', cachedData);
const dataType = useMemo(() => getDataType(selectedChain), [selectedChain]);

const fetchData = useCallback(
async (chain: ParachainChainId) => {
Expand Down
7 changes: 1 addition & 6 deletions apps/tangle-dapp/data/payouts/usePayoutsAvailability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@ import useLocalStorage, { LocalStorageKey } from '../../hooks/useLocalStorage';
import useSubstrateAddress from '../../hooks/useSubstrateAddress';

const usePayoutsAvailability = () => {
const { valueOpt: cachedPayouts } = useLocalStorage(
LocalStorageKey.PAYOUTS,
true,
);

const { valueOpt: cachedPayouts } = useLocalStorage(LocalStorageKey.PAYOUTS);
const { rpcEndpoint } = useNetworkStore();

const address = useSubstrateAddress();

const payoutsData = useMemo(() => {
Expand Down
132 changes: 132 additions & 0 deletions apps/tangle-dapp/hooks/useInitialNetwork.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import {
Network,
NETWORK_MAP,
NetworkId,
} from '@webb-tools/webb-ui-components/constants/networks';
import { useCallback } from 'react';
import { z } from 'zod';

import testRpcEndpointConnection from '../components/NetworkSelector/testRpcEndpointConnection';
import { DEFAULT_NETWORK } from '../constants/networks';
import createCustomNetwork from '../utils/createCustomNetwork';
import useLocalStorage, { LocalStorageKey } from './useLocalStorage';

const useCachedNetworkId = (): ((
cachedNetworkId: number,
) => Promise<Network>) => {
const { remove: removeCachedNetworkId } = useLocalStorage(
LocalStorageKey.KNOWN_NETWORK_ID,
);

return useCallback(
async (cachedNetworkId: number) => {
// If there is a cached network id, check if it is a known network.
const parsedNetworkId = z
.nativeEnum(NetworkId)
.safeParse(cachedNetworkId);

if (!parsedNetworkId.success) {
console.warn(
`Cached network id appears to be invalid: ${cachedNetworkId}, deleting from local storage`,
);

removeCachedNetworkId();

return DEFAULT_NETWORK;
}

const id = parsedNetworkId.data;
const knownNetwork = NETWORK_MAP[id];

if (knownNetwork === undefined) {
console.warn(
`Could not find an associated network for cached network id: ${id}, deleting from local storage`,
);

removeCachedNetworkId();

return DEFAULT_NETWORK;
}

const connectionEstablished = await testRpcEndpointConnection(
knownNetwork.wsRpcEndpoint,
);

if (!connectionEstablished) {
console.warn(
`Could not connect to cached network: ${knownNetwork.name}, deleting from local storage and connecting to default network instead`,
);

removeCachedNetworkId();

return DEFAULT_NETWORK;
}

return knownNetwork;
},
[removeCachedNetworkId],
);
};

const useCachedCustomRpcEndpoint = (): ((
cachedCustomRpcEndpoint: string,
) => Promise<Network>) => {
const { remove: removeCachedCustomRpcEndpoint } = useLocalStorage(
LocalStorageKey.CUSTOM_RPC_ENDPOINT,
);

return useCallback(
async (cachedCustomRpcEndpoint: string) => {
const connectionEstablished = await testRpcEndpointConnection(
cachedCustomRpcEndpoint,
);

if (!connectionEstablished) {
console.warn(
`Could not connect to cached custom RPC endpoint: ${cachedCustomRpcEndpoint}, deleting from local storage`,
);

removeCachedCustomRpcEndpoint();

return DEFAULT_NETWORK;
}

return createCustomNetwork(cachedCustomRpcEndpoint);
},
[removeCachedCustomRpcEndpoint],
);
};

const useInitialNetwork = () => {
const { refresh: getCachedCustomRpcEndpoint } = useLocalStorage(
LocalStorageKey.CUSTOM_RPC_ENDPOINT,
);

const { refresh: getCachedNetworkId } = useLocalStorage(
LocalStorageKey.KNOWN_NETWORK_ID,
);

const getCustomNetwork = useCachedCustomRpcEndpoint();
const getKnownNetwork = useCachedNetworkId();

return useCallback(async () => {
const cachedCustomRpcEndpointOpt = getCachedCustomRpcEndpoint();
const cachedNetworkIdOpt = getCachedNetworkId();

// If there is a cached custom RPC endpoint, return it as a custom network.
// If there is a cached network id, check if it is a known network.
// Otherwise, return the default network.
return cachedCustomRpcEndpointOpt.value !== null
? getCustomNetwork(cachedCustomRpcEndpointOpt.value)
: cachedNetworkIdOpt.value !== null
? getKnownNetwork(cachedNetworkIdOpt.value)
: DEFAULT_NETWORK;
}, [
getCachedCustomRpcEndpoint,
getCachedNetworkId,
getCustomNetwork,
getKnownNetwork,
]);
};

export default useInitialNetwork;
Loading

0 comments on commit ccf3bb9

Please sign in to comment.