From 4013667d8b43fa7d7fc2aadeaf76c627c97cf100 Mon Sep 17 00:00:00 2001
From: Nur Fikri <codingki@gmail.com>
Date: Tue, 27 Aug 2024 17:52:38 +0700
Subject: [PATCH] refactor(widget-v2): remove chain registry usage for chain
 data

---
 packages/widget-v2/package.json               |  1 +
 .../src/components/AssetChainInput.tsx        | 13 +++-
 .../ManualAddressModal/ManualAddressModal.tsx | 18 ++---
 .../TokenAndChainSelectorModal.tsx            | 48 ++++++------
 .../TokenAndChainSelectorModalRowItem.tsx     | 26 ++++---
 .../TransactionHistoryModalItem.tsx           | 29 ++++---
 .../SwapExecutionPageRouteDetailedRow.tsx     | 23 +++---
 .../SwapExecutionPageRouteSimpleRow.tsx       | 11 +--
 .../widget-v2/src/pages/SwapPage/SwapPage.tsx | 21 +++---
 packages/widget-v2/src/state/chains.ts        | 43 +++++++++++
 packages/widget-v2/src/state/skipClient.ts    | 75 +++++++------------
 .../stories/ManualAddressModals.stories.tsx   |  4 +-
 .../src/stories/SwapExecutionPage.stories.tsx |  4 +-
 packages/widget-v2/src/utils/useUsdValue.ts   | 36 ++++-----
 yarn.lock                                     |  1 +
 15 files changed, 188 insertions(+), 165 deletions(-)
 create mode 100644 packages/widget-v2/src/state/chains.ts

diff --git a/packages/widget-v2/package.json b/packages/widget-v2/package.json
index ec65eb125..adbb4d2af 100644
--- a/packages/widget-v2/package.json
+++ b/packages/widget-v2/package.json
@@ -60,6 +60,7 @@
     "jotai": "^2.9.1",
     "jotai-tanstack-query": "^0.8.6",
     "lodash.debounce": "^4.0.8",
+    "match-sorter": "^6.3.4",
     "pluralize": "^8.0.0",
     "rc-virtual-list": "^3.14.5",
     "react-error-boundary": "^4.0.13",
diff --git a/packages/widget-v2/src/components/AssetChainInput.tsx b/packages/widget-v2/src/components/AssetChainInput.tsx
index 87a2bba0f..1bc2fb36a 100644
--- a/packages/widget-v2/src/components/AssetChainInput.tsx
+++ b/packages/widget-v2/src/components/AssetChainInput.tsx
@@ -6,7 +6,7 @@ import { useTheme } from "styled-components";
 import { CogIcon } from "@/icons/CogIcon";
 import { Button, GhostButton } from "@/components/Button";
 import { useAtom } from "jotai";
-import { skipAssets } from "@/state/skipClient";
+import { skipAssetsAtom, skipChainsAtom } from "@/state/skipClient";
 import { useUsdValue } from "@/utils/useUsdValue";
 import { formatUSD } from "@/utils/intl";
 
@@ -26,12 +26,17 @@ export const AssetChainInput = ({
   handleChangeChain,
 }: AssetChainInputProps) => {
   const theme = useTheme();
-  const [{ data: assets }] = useAtom(skipAssets);
+  const [{ data: assets }] = useAtom(skipAssetsAtom);
+  const [{ data: chains }] = useAtom(skipChainsAtom)
 
   const selectedAsset = assets?.find(
     (asset) => asset.denom === selectedAssetDenom
   );
 
+  const selectedChain = chains?.find(
+    (chain) => chain.chainID === selectedAsset?.chainID
+  );
+
   const usdValue = useUsdValue({ ...selectedAsset, value });
 
   return (
@@ -50,7 +55,7 @@ export const AssetChainInput = ({
           {selectedAsset ? (
             <StyledAssetLabel align="center" justify="center" gap={7}>
               <img src={selectedAsset?.logoURI} width={23} />
-              <Text>{selectedAsset?.name}</Text>
+              <Text>{selectedAsset?.recommendedSymbol}</Text>
             </StyledAssetLabel>
           ) : (
             <StyledSelectTokenLabel>
@@ -73,7 +78,7 @@ export const AssetChainInput = ({
             secondary
             gap={4}
           >
-            <SmallText>on {selectedAsset?.chainName}</SmallText>
+            <SmallText>on {selectedChain?.prettyName}</SmallText>
             <CogIcon color={theme.primary.text.normal} />
           </GhostButton>
         ) : (
diff --git a/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx b/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx
index e9d0da66d..cfcc9a56b 100644
--- a/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx
+++ b/packages/widget-v2/src/modals/ManualAddressModal/ManualAddressModal.tsx
@@ -12,18 +12,18 @@ import { WALLET_LIST } from "@/modals/WalletSelectorModal/WalletSelectorFlow";
 import { Button } from "@/components/Button";
 import { SmallText, Text } from "@/components/Typography";
 import { destinationAssetAtom, destinationWalletAtom } from "@/state/swapPage";
-import { useAtom } from "jotai";
-import { getChain } from "@/state/skipClient";
+import { useAtom, useAtomValue } from "jotai";
+import { skipChainsAtom } from "@/state/skipClient";
 
 export const ManualAddressModal = createModal((modalProps: ModalProps) => {
   const { theme } = modalProps;
   const modal = useModal();
   const [destinationAsset] = useAtom(destinationAssetAtom);
   const [, setDestinationWallet] = useAtom(destinationWalletAtom);
-  const chain = getChain(destinationAsset?.chainID ?? "");
-  const chainName = destinationAsset?.chainName;
-  const chainImage = chain.images?.find((image) => image.svg ?? image.png);
-  const chainLogo = chainImage?.svg ?? chainImage?.png;
+  const { data: chains } = useAtomValue(skipChainsAtom);
+  const chain = chains?.find(c => c.chainID === destinationAsset?.chainID)
+  const chainName = chain?.prettyName
+  const chainLogo = chain?.logoURI
   const [showManualAddressInput, setShowManualAddressInput] = useState(false);
   const [manualWalletAddress, setManualWalletAddress] = useState("");
 
@@ -63,7 +63,7 @@ export const ManualAddressModal = createModal((modalProps: ModalProps) => {
       {showManualAddressInput ? (
         <StyledContainer gap={15}>
           <RenderWalletListHeader
-            title={`Enter a ${chainName} wallet address`}
+            title={`Enter a ${chainName} address`}
             onClickBackButton={() => setShowManualAddressInput(false)}
             rightContent={() => (
               <StyledChainLogoContainerRow align="center" justify="center">
@@ -155,8 +155,8 @@ const StyledAddressValidatorDot = styled.div<{ validAddress?: boolean }>`
     validAddress === true
       ? `background-color: ${theme.success.text}`
       : validAddress === false
-      ? `background-color: ${theme.error.text}`
-      : ""};
+        ? `background-color: ${theme.error.text}`
+        : ""};
 
   top: calc(50% - 11px / 2);
   right: 20px;
diff --git a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx
index c4fcfe987..c77d823bb 100644
--- a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx
+++ b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal.tsx
@@ -1,16 +1,17 @@
 import { createModal, ModalProps, useModal } from "@/components/Modal";
 import { Column } from "@/components/Layout";
 import { styled } from "styled-components";
-import { useAtom } from "jotai";
-import { ChainWithAsset, ClientAsset, skipAssets } from "@/state/skipClient";
+import { useAtomValue } from "jotai";
+import { ChainWithAsset, ClientAsset, skipAssetsAtom, skipChainsAtom } from "@/state/skipClient";
 import { useCallback, useEffect, useMemo, useState } from "react";
 import { VirtualList } from "@/components/VirtualList";
 import {
-  isChainWithAsset,
   TokenAndChainSelectorModalRowItem,
   Skeleton,
+  isClientAsset,
 } from "./TokenAndChainSelectorModalRowItem";
 import { TokenAndChainSelectorModalSearchInput } from "./TokenAndChainSelectorModalSearchInput";
+import { matchSorter } from "match-sorter";
 
 export type TokenAndChainSelectorModalProps = ModalProps & {
   onSelect: (token: ClientAsset | null) => void;
@@ -22,37 +23,36 @@ export const TokenAndChainSelectorModal = createModal(
   (modalProps: TokenAndChainSelectorModalProps) => {
     const modal = useModal();
     const { onSelect, chainsContainingAsset, asset } = modalProps;
-    const [{ data: assets, isPending }] = useAtom(skipAssets);
+    const { data: assets, isLoading: isAssetsLoading } = useAtomValue(skipAssetsAtom);
+    const { isLoading: isChainsLoading } = useAtomValue(skipChainsAtom)
+    const isLoading = isAssetsLoading || isChainsLoading
 
     const [showSkeleton, setShowSkeleton] = useState(true);
     const [searchQuery, setSearchQuery] = useState<string>("");
 
     const filteredAssets = useMemo(() => {
-      if (!assets) return;
-      const filtered = assets.filter((asset) =>
-        asset.symbol?.toLowerCase().includes(searchQuery.toLowerCase())
-      );
-      return filtered;
-    }, [searchQuery, assets]);
+      if (!assets) return
+      return matchSorter(assets, searchQuery, {
+        keys: ["recommendedSymbol", "symbol", "denom"],
+      });
+    }, [assets, searchQuery]);
 
     const filteredChains = useMemo(() => {
-      if (!chainsContainingAsset) return;
-      const filtered = chainsContainingAsset.filter(
-        (chain) =>
-          chain.chain_name?.toLowerCase().includes(searchQuery.toLowerCase()) ||
-          chain.pretty_name?.toLowerCase().includes(searchQuery.toLowerCase())
-      );
-      return filtered;
-    }, [searchQuery, chainsContainingAsset]);
+      if (!chainsContainingAsset) return
+      return matchSorter(chainsContainingAsset, searchQuery, {
+        keys: ["chainID", "chainName", "prettyName"],
+      });
+    }, [chainsContainingAsset, searchQuery]);
+
 
     useEffect(() => {
-      if (!isPending && assets) {
+      if (!isLoading && assets) {
         const timer = setTimeout(() => {
           setShowSkeleton(false);
         }, 100);
         return () => clearTimeout(timer);
       }
-    }, [isPending, assets]);
+    }, [isLoading, assets]);
 
     useEffect(() => {
       setSearchQuery("");
@@ -93,13 +93,13 @@ export const TokenAndChainSelectorModal = createModal(
             listItems={filteredChains ?? filteredAssets ?? []}
             height={530}
             itemHeight={70}
-            renderItem={renderItem}
             itemKey={(item) => {
-              if (isChainWithAsset(item)) {
-                return `${item.chain_id}${item.chain_name}`;
+              if (isClientAsset(item)) {
+                return `${item.denom}-${item.chainID}-${item.recommendedSymbol}`
               }
-              return `${item.chainID}${item.denom}`;
+              return `${item.chainID}-${item.asset?.denom}`
             }}
+            renderItem={renderItem}
           />
         )}
       </StyledContainer>
diff --git a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalRowItem.tsx b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalRowItem.tsx
index d338d441e..3d4bbc0f1 100644
--- a/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalRowItem.tsx
+++ b/packages/widget-v2/src/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModalRowItem.tsx
@@ -1,10 +1,11 @@
 import { Row } from "@/components/Layout";
 import { ModalRowItem } from "@/components/ModalRowItem";
 import { SmallText, Text } from "@/components/Typography";
-import { ChainWithAsset, ClientAsset } from "@/state/skipClient";
+import { ChainWithAsset, ClientAsset, skipChainsAtom } from "@/state/skipClient";
 import { CircleSkeletonElement, SkeletonElement } from "@/components/Skeleton";
 import { styled } from "styled-components";
-import { Chain } from "@chain-registry/types";
+import { useAtomValue } from "jotai";
+import { Chain } from "@skip-go/client";
 
 export const isClientAsset = (
   item: ClientAsset | ChainWithAsset
@@ -15,7 +16,7 @@ export const isClientAsset = (
 export const isChainWithAsset = (
   item: ClientAsset | ChainWithAsset
 ): item is ChainWithAsset => {
-  return (item as Chain).chain_id !== undefined;
+  return (item as Chain).chainID !== undefined;
 };
 
 export type TokenAndChainSelectorModalRowItemProps = {
@@ -31,9 +32,12 @@ export const TokenAndChainSelectorModalRowItem = ({
   skeleton,
   onSelect,
 }: TokenAndChainSelectorModalRowItemProps) => {
-  if (!item) return skeleton;
+  const { isLoading: isChainsLoading, data: chains } = useAtomValue(skipChainsAtom)
+
+  if (!item || isChainsLoading) return skeleton;
 
   if (isClientAsset(item)) {
+    const chain = chains?.find((chain) => chain.chainID === item.chainID)
     return (
       <ModalRowItem
         key={`${index}${item.denom}`}
@@ -49,7 +53,7 @@ export const TokenAndChainSelectorModalRowItem = ({
             />
             <Text>{item.symbol}</Text>
             <SmallText>
-              {item.chainName ?? item.originChainID ?? item.chainID}
+              {chain?.prettyName}
             </SmallText>
           </Row>
         }
@@ -58,9 +62,11 @@ export const TokenAndChainSelectorModalRowItem = ({
   }
 
   if (isChainWithAsset(item)) {
+
+    const chain = chains?.find((chain) => chain.chainID === item.chainID)
     return (
       <ModalRowItem
-        key={item.chain_id}
+        key={item.chainID}
         onClick={() => onSelect(item?.asset || null)}
         style={{ margin: "5px 0" }}
         leftContent={
@@ -68,11 +74,11 @@ export const TokenAndChainSelectorModalRowItem = ({
             <StyledAssetImage
               height={35}
               width={35}
-              src={item?.images?.[0].svg ?? item?.images?.[0].png}
-              alt={`${item.chain_id} logo`}
+              src={item?.logoURI}
+              alt={`${item.chainID} logo`}
             />
-            <Text>{item.pretty_name}</Text>
-            <SmallText>{item.chain_name}</SmallText>
+            <Text>{chain?.prettyName}</Text>
+            <SmallText>{item.chainID}</SmallText>
           </Row>
         }
       />
diff --git a/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModalItem.tsx b/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModalItem.tsx
index f23b14426..d1df7a2b6 100644
--- a/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModalItem.tsx
+++ b/packages/widget-v2/src/modals/TransactionHistoryModal/TransactionHistoryModalItem.tsx
@@ -1,7 +1,7 @@
 import { RouteResponse } from "@skip-go/client";
 import { SmallText } from "@/components/Typography";
 import { useAtom } from "jotai";
-import { skipAssets, getChain, ClientAsset } from "@/state/skipClient";
+import { skipAssetsAtom, ClientAsset, skipChainsAtom } from "@/state/skipClient";
 import { Column, Row } from "@/components/Layout";
 import styled, { useTheme } from "styled-components";
 import { getFormattedAssetAmount } from "@/utils/crypto";
@@ -56,25 +56,22 @@ export const TransactionHistoryModalItem = ({
     timestamp,
     status,
   } = txHistoryItem;
-  const [{ data: assets }] = useAtom(skipAssets);
-  const sourceChain = getChain(sourceAssetChainID ?? "");
-  const sourceChainImage = sourceChain.images?.find(
-    (image) => image.svg ?? image.png
-  );
+  const [{ data: assets }] = useAtom(skipAssetsAtom);
+  const [{ data: chains }] = useAtom(skipChainsAtom)
+  const sourceChain = chains?.find(c => c.chainID === sourceAssetChainID)
+  const sourceChainImage = sourceChain?.logoURI
   const source = {
     amount: amountIn,
     asset: assets?.find((asset) => asset.denom === sourceAssetDenom),
-    chainImage: sourceChainImage?.svg ?? sourceChainImage?.png ?? "",
+    chainImage: sourceChainImage ?? "",
   };
 
-  const destinationChain = getChain(destAssetChainID ?? "");
-  const destinationChainImage = destinationChain.images?.find(
-    (image) => image.svg ?? image.png
-  );
+  const destinationChain = chains?.find(c => c.chainID === destAssetChainID)
+  const destinationChainImage = destinationChain?.logoURI
   const destination = {
     amount: amountOut,
     asset: assets?.find((asset) => asset.denom === destAssetDenom),
-    chainImage: destinationChainImage?.svg ?? destinationChainImage?.png ?? "",
+    chainImage: destinationChainImage ?? "",
   };
 
   const renderStatus = useMemo(() => {
@@ -119,7 +116,7 @@ export const TransactionHistoryModalItem = ({
           <HistoryArrowIcon color={theme.primary.text.lowContrast} />
           <RenderAssetAmount {...destination} />
           <SmallText normalTextColor>
-            on {destinationChain?.pretty_name ?? destinationChain?.chain_name}
+            on {destinationChain?.prettyName ?? destinationChain?.chainName}
           </SmallText>
         </Row>
         <Row align="center" gap={10}>
@@ -130,9 +127,9 @@ export const TransactionHistoryModalItem = ({
       {showDetails && (
         <TransactionHistoryModalItemDetails
           status={status}
-          sourceChainName={sourceChain?.pretty_name ?? sourceChain?.chain_name}
+          sourceChainName={sourceChain?.prettyName ?? sourceChain?.chainName ?? "--"}
           destinationChainName={
-            destinationChain?.pretty_name ?? destinationChain?.chain_name
+            destinationChain?.prettyName ?? destinationChain?.chainName ?? "--"
           }
           absoluteTimeString={absoluteTimeString}
           relativeTimeString={relativeTime}
@@ -144,7 +141,7 @@ export const TransactionHistoryModalItem = ({
   );
 };
 
-const StyledHistoryContainer = styled(Column)<{ showDetails?: boolean }>`
+const StyledHistoryContainer = styled(Column) <{ showDetails?: boolean }>`
   background-color: ${({ theme, showDetails }) =>
     showDetails && theme.secondary.background.normal};
   &:hover {
diff --git a/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPageRouteDetailedRow.tsx b/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPageRouteDetailedRow.tsx
index 4a0998d75..36caff9a5 100644
--- a/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPageRouteDetailedRow.tsx
+++ b/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPageRouteDetailedRow.tsx
@@ -1,7 +1,7 @@
 import { useAtom } from "jotai";
 import { Row } from "@/components/Layout";
 import { SmallText } from "@/components/Typography";
-import { getChain, skipAssets } from "@/state/skipClient";
+import { skipAssetsAtom, skipChainsAtom } from "@/state/skipClient";
 import { getFormattedAssetAmount } from "@/utils/crypto";
 import { css, styled, useTheme } from "styled-components";
 import React from "react";
@@ -56,12 +56,13 @@ export const SwapExecutionPageRouteDetailedRow = ({
   ...props
 }: SwapExecutionPageRouteDetailedRowProps) => {
   const theme = useTheme();
-  const [{ data: assets }] = useAtom(skipAssets);
+  const [{ data: assets }] = useAtom(skipAssetsAtom);
+  const [{ data: chains }] = useAtom(skipChainsAtom);
 
   const asset = assets?.find((asset) => asset.denom === denom);
 
-  const chain = getChain(chainID ?? "");
-  const chainImage = chain.images?.find((image) => image.svg ?? image.png);
+  const chain = chains?.find(c => c.chainID === chainID)
+  const chainImage = chain?.logoURI
 
   return (
     <Row gap={15} align="center" {...props}>
@@ -75,7 +76,7 @@ export const SwapExecutionPageRouteDetailedRow = ({
           <StyledChainImage
             height={30}
             width={30}
-            src={chainImage.svg ?? chainImage.png}
+            src={chainImage}
             state={txState}
           />
         </StyledAnimatedBorder>
@@ -151,7 +152,7 @@ export const StyledAnimatedBorder = ({
   </StyledLoadingContainer>
 );
 
-const StyledLoadingContainer = styled(Row)<{
+const StyledLoadingContainer = styled(Row) <{
   height: number;
   width: number;
   borderSize: number;
@@ -178,11 +179,11 @@ const StyledLoadingContainer = styled(Row)<{
   &:before {
     content: '';
     position: absolute;
-    height: ${({ height }) => `${height + 20}px;`}
-    width: ${({ width }) => `${width + 20}px;`}
+    height: ${({ height }) => `${height + 20}px;`};
+    width: ${({ width }) => `${width + 20}px;`};
     ${({ txState, backgroundColor, theme }) =>
-      txState === "broadcasted" &&
-      css`
+    txState === "broadcasted" &&
+    css`
         background-image: conic-gradient(
           transparent,
           transparent,
@@ -202,7 +203,7 @@ const StyledLoadingContainer = styled(Row)<{
   }
 `;
 
-const StyledLoadingOverlay = styled(Row)<{
+const StyledLoadingOverlay = styled(Row) <{
   backgroundColor?: string;
   width: number;
   height: number;
diff --git a/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPageRouteSimpleRow.tsx b/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPageRouteSimpleRow.tsx
index 4dd21e297..bc82eca7d 100644
--- a/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPageRouteSimpleRow.tsx
+++ b/packages/widget-v2/src/pages/SwapExecutionPage/SwapExecutionPageRouteSimpleRow.tsx
@@ -2,7 +2,7 @@ import { useTheme } from "styled-components";
 import { Button } from "@/components/Button";
 import { Column, Row } from "@/components/Layout";
 import { SmallText, Text } from "@/components/Typography";
-import { getChain, skipAssets } from "@/state/skipClient";
+import { skipAssetsAtom, skipChainsAtom } from "@/state/skipClient";
 import { getFormattedAssetAmount } from "@/utils/crypto";
 import { Wallet } from "@/components/RenderWalletList";
 import { iconMap, ICONS } from "@/icons";
@@ -45,11 +45,12 @@ export const SwapExecutionPageRouteSimpleRow = ({
     "mount";
   }, []);
   const theme = useTheme();
-  const [{ data: assets }] = useAtom(skipAssets);
+  const [{ data: assets }] = useAtom(skipAssetsAtom);
+  const [{ data: chains }] = useAtom(skipChainsAtom);
   const asset = assets?.find((asset) => asset.denom === denom);
 
-  const chain = getChain(chainID ?? "");
-  const chainImage = chain.images?.find((image) => image.svg ?? image.png);
+  const chain = chains?.find((chain) => chain.chainID === chainID);
+  const chainImage = chain?.logoURI
 
   if (!asset) {
     throw new Error(`Asset not found for denom: ${denom}`);
@@ -80,7 +81,7 @@ export const SwapExecutionPageRouteSimpleRow = ({
           backgroundColor={theme.success.text}
           txState={txStateOfAnimatedBorder}
         >
-          <img height={50} width={50} src={chainImage.svg ?? chainImage.png} />
+          <img height={50} width={50} src={chainImage} />
         </StyledAnimatedBorder>
       )}
       <Column gap={5}>
diff --git a/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx b/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx
index cc50824d7..ba3df03dc 100644
--- a/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx
+++ b/packages/widget-v2/src/pages/SwapPage/SwapPage.tsx
@@ -5,7 +5,7 @@ import { Column } from "@/components/Layout";
 import { MainButton } from "@/components/MainButton";
 import { SmallText } from "@/components/Typography";
 import { ICONS } from "@/icons";
-import { skipAssets, getChainsContainingAsset } from "@/state/skipClient";
+import { skipAssetsAtom, getChainsContainingAsset, skipChainsAtom } from "@/state/skipClient";
 import { sourceAssetAtom, destinationAssetAtom } from "@/state/swapPage";
 import { TokenAndChainSelectorModal } from "@/modals/TokenAndChainSelectorModal/TokenAndChainSelectorModal";
 import { SwapPageSettings } from "./SwapPageSettings";
@@ -20,23 +20,24 @@ export const SwapPage = () => {
   const [container, setContainer] = useState<HTMLDivElement>();
   const [drawerOpen, setDrawerOpen] = useState(false);
   const [sourceAsset, setSourceAsset] = useAtom(sourceAssetAtom);
-  const [{ data: assets }] = useAtom(skipAssets);
+  const [{ data: assets }] = useAtom(skipAssetsAtom);
+  const [{ data: chains }] = useAtom(skipChainsAtom);
   const [destinationAsset, setDestinationAsset] = useAtom(destinationAssetAtom);
 
   const swapFlowSettings = useModal(SwapPageSettings);
   const tokenAndChainSelectorFlow = useModal(TokenAndChainSelectorModal);
 
   const chainsContainingSourceAsset = useMemo(() => {
-    if (!assets || !sourceAsset?.symbol) return;
-    const chains = getChainsContainingAsset(sourceAsset?.symbol, assets);
-    return chains;
-  }, [assets, sourceAsset?.symbol]);
+    if (!chains || !assets || !sourceAsset?.symbol) return;
+    const result = getChainsContainingAsset(sourceAsset?.symbol, assets, chains);
+    return result;
+  }, [assets, sourceAsset?.symbol, chains]);
 
   const chainsContainingDestinationAsset = useMemo(() => {
-    if (!assets || !destinationAsset?.symbol) return;
-    const chains = getChainsContainingAsset(destinationAsset?.symbol, assets);
-    return chains;
-  }, [assets, destinationAsset?.symbol]);
+    if (!chains || !assets || !destinationAsset?.symbol) return;
+    const result = getChainsContainingAsset(destinationAsset?.symbol, assets, chains);
+    return result;
+  }, [assets, destinationAsset?.symbol, chains]);
 
   const handleChangeSourceAsset = useCallback(() => {
     tokenAndChainSelectorFlow.show({
diff --git a/packages/widget-v2/src/state/chains.ts b/packages/widget-v2/src/state/chains.ts
new file mode 100644
index 000000000..563d16eee
--- /dev/null
+++ b/packages/widget-v2/src/state/chains.ts
@@ -0,0 +1,43 @@
+
+import { Chain, AssetList } from "@chain-registry/types";
+import {
+  chains as chainsChainRegistry,
+  assets as assetsChainRegistry,
+} from "chain-registry";
+import {
+  chains as chainsInitiaRegistry,
+  assets as assetsInitiaRegistry,
+} from "@initia/initia-registry";
+
+export const chains = [
+  ...chainsChainRegistry,
+  ...chainsInitiaRegistry,
+] as Chain[];
+export const assets = [
+  ...assetsChainRegistry,
+  ...assetsInitiaRegistry,
+] as AssetList[];
+
+export function getChain(chainId: string): Chain {
+  const chain = chains.find((c) => c.chain_id === chainId);
+  if (!chain) {
+    throw new Error(`chain '${chainId}' does not exist in chainRecord`);
+  }
+  return chain;
+}
+
+export function chainIdToName(chainId: string): string {
+  return getChain(chainId).chain_name;
+}
+
+export function getAssets(chainId: string) {
+  const chainName = chainIdToName(chainId);
+  const assetsFoundForChain = assets.find(
+    (a) => a.chain_name === chainName
+  )?.assets;
+
+  if (!assetsFoundForChain) {
+    throw new Error(`chain '${chainId}' does not exist in assetsRecord`);
+  }
+  return assetsFoundForChain;
+}
diff --git a/packages/widget-v2/src/state/skipClient.ts b/packages/widget-v2/src/state/skipClient.ts
index 40e33d6c9..6f4d36b45 100644
--- a/packages/widget-v2/src/state/skipClient.ts
+++ b/packages/widget-v2/src/state/skipClient.ts
@@ -1,24 +1,7 @@
 import { atom } from "jotai";
-import { Asset, SkipClient } from "@skip-go/client";
-import { Chain, AssetList } from "@chain-registry/types";
-import {
-  chains as chainsChainRegistry,
-  assets as assetsChainRegistry,
-} from "chain-registry";
-import {
-  chains as chainsInitiaRegistry,
-  assets as assetsInitiaRegistry,
-} from "@initia/initia-registry";
+import { Asset, SkipClient, Chain } from "@skip-go/client";
 import { atomWithQuery } from "jotai-tanstack-query";
 
-export const chains = [
-  ...chainsChainRegistry,
-  ...chainsInitiaRegistry,
-] as Chain[];
-export const assets = [
-  ...assetsChainRegistry,
-  ...assetsInitiaRegistry,
-] as AssetList[];
 
 export const skipClient = atom(new SkipClient());
 
@@ -27,16 +10,16 @@ export type ClientAsset = Asset & {
   chainName: string;
 };
 
-const flattenData = (data: Record<string, Asset[]>) => {
+const flattenData = (data: Record<string, Asset[] >, chains?: Chain[]) => {
   const flattenedData: ClientAsset[] = [];
 
   for (const chainKey in data) {
     data[chainKey].forEach((asset: Asset) => {
-      const chain = chains.find((c) => c.chain_id === asset.chainID);
+      const chain = chains?.find((c) => c.chainID === asset.chainID);
       flattenedData.push({
         ...asset,
         chain_key: chainKey,
-        chainName: chain?.pretty_name ?? chain?.chain_name ?? "",
+        chainName: chain?.prettyName ?? chain?.chainName ?? asset.chainID ??  "--",
       });
     });
   }
@@ -44,8 +27,10 @@ const flattenData = (data: Record<string, Asset[]>) => {
   return flattenedData;
 };
 
-export const skipAssets = atomWithQuery((get) => {
+export const skipAssetsAtom = atomWithQuery((get) => {
   const skip = get(skipClient);
+  const chains = get(skipChainsAtom);
+
   return {
     queryKey: ["skipAssets"],
     queryFn: async () => {
@@ -55,57 +40,47 @@ export const skipAssets = atomWithQuery((get) => {
           includeCW20Assets: true,
           includeSvmAssets: true,
         })
-        .then(flattenData);
+        .then((v) => flattenData(v, chains.data));
     },
   };
 });
 
+export const skipChainsAtom = atomWithQuery((get) => {
+  const skip = get(skipClient);
+  return {
+    queryKey: ["skipChains"],
+    queryFn: async () => {
+      return skip.chains({
+        includeEVM: true,
+        includeSVM: true,
+      })
+    }
+  }
+})
+
 export type ChainWithAsset = Chain & {
   asset?: ClientAsset;
 };
 
 export const getChainsContainingAsset = (
   assetSymbol: string,
-  assets: ClientAsset[]
+  assets: ClientAsset[],
+  chains: Chain[]
 ): ChainWithAsset[] => {
   if (!assets) return [];
   const chainIDs = assets
     .filter((asset) => asset.symbol === assetSymbol)
     .map((asset) => asset.chainID);
   const chainsContainingAsset = chains
-    .filter((chain) => chainIDs?.includes(chain.chain_id))
+    .filter((chain) => chainIDs?.includes(chain.chainID))
     .map((chain) => {
       return {
         ...chain,
         asset: assets.find(
           (asset) =>
-            asset.chainID === chain.chain_id && asset.symbol === assetSymbol
+            asset.chainID === chain.chainID && asset.symbol === assetSymbol
         ),
       };
     });
   return chainsContainingAsset;
 };
-
-export function getChain(chainId: string): Chain {
-  const chain = chains.find((c) => c.chain_id === chainId);
-  if (!chain) {
-    throw new Error(`chain '${chainId}' does not exist in chainRecord`);
-  }
-  return chain;
-}
-
-export function chainIdToName(chainId: string): string {
-  return getChain(chainId).chain_name;
-}
-
-export function getAssets(chainId: string) {
-  const chainName = chainIdToName(chainId);
-  const assetsFoundForChain = assets.find(
-    (a) => a.chain_name === chainName
-  )?.assets;
-
-  if (!assetsFoundForChain) {
-    throw new Error(`chain '${chainId}' does not exist in assetsRecord`);
-  }
-  return assetsFoundForChain;
-}
diff --git a/packages/widget-v2/src/stories/ManualAddressModals.stories.tsx b/packages/widget-v2/src/stories/ManualAddressModals.stories.tsx
index 799370abc..9af0e3e87 100644
--- a/packages/widget-v2/src/stories/ManualAddressModals.stories.tsx
+++ b/packages/widget-v2/src/stories/ManualAddressModals.stories.tsx
@@ -4,7 +4,7 @@ import { Row } from "@/components/Layout";
 import { defaultTheme, lightTheme } from "@/widget/theme";
 import { ManualAddressModal } from "@/modals/ManualAddressModal/ManualAddressModal";
 import { useEffect, useState } from "react";
-import { skipAssets } from "@/state/skipClient";
+import { skipAssetsAtom } from "@/state/skipClient";
 import { destinationAssetAtom } from "@/state/swapPage";
 import { useAtom } from "jotai";
 
@@ -24,7 +24,7 @@ export const ManualAddressModalsExample = () => {
   const [destinationAsset, setDestinationAsset] = useAtom(destinationAssetAtom);
   const [shouldRender, setShouldRender] = useState(false);
 
-  const [{ data: assets }] = useAtom(skipAssets);
+  const [{ data: assets }] = useAtom(skipAssetsAtom);
 
   const asset = assets?.find((asset) => asset.denom === "uatom");
 
diff --git a/packages/widget-v2/src/stories/SwapExecutionPage.stories.tsx b/packages/widget-v2/src/stories/SwapExecutionPage.stories.tsx
index 6f5e4ce51..112d76097 100644
--- a/packages/widget-v2/src/stories/SwapExecutionPage.stories.tsx
+++ b/packages/widget-v2/src/stories/SwapExecutionPage.stories.tsx
@@ -5,7 +5,7 @@ import NiceModal from "@ebay/nice-modal-react";
 import { destinationAssetAtom } from "@/state/swapPage";
 import { useAtom } from "jotai";
 import operations from "@/pages/SwapExecutionPage/operations.json";
-import { skipAssets } from "@/state/skipClient";
+import { skipAssetsAtom } from "@/state/skipClient";
 import { useEffect, useState } from "react";
 
 const meta = {
@@ -17,7 +17,7 @@ const meta = {
     const firstOperation = operations[0];
     const lastOperation = operations[operations.length - 1];
 
-    const [{ data: assets }] = useAtom(skipAssets);
+    const [{ data: assets }] = useAtom(skipAssetsAtom);
 
     const sourceAsset = assets?.find(
       (asset) => asset.denom === firstOperation.denomIn
diff --git a/packages/widget-v2/src/utils/useUsdValue.ts b/packages/widget-v2/src/utils/useUsdValue.ts
index aa4c680cf..ab8991996 100644
--- a/packages/widget-v2/src/utils/useUsdValue.ts
+++ b/packages/widget-v2/src/utils/useUsdValue.ts
@@ -1,7 +1,8 @@
-import { useQuery } from "@tanstack/react-query";
+import { skipAssetsAtom } from "@/state/skipClient";
+import { useQuery, UseQueryResult } from "@tanstack/react-query";
+import { useAtomValue } from "jotai";
 import { useMemo } from "react";
 import { z } from "zod";
-import { getAssets } from "@/state/skipClient";
 
 type Args = {
   coingeckoID: string;
@@ -37,33 +38,23 @@ const priceResponseSchema = z.object({
 });
 
 export type Asset = {
-  chainID: string;
   denom: string;
-  coingeckoID?: string;
   value: string;
 };
 
-const getCoinGeckoId = (asset: Asset) => {
-  if (asset.coingeckoID) {
-    return asset.coingeckoID;
-  } else {
-    const assets = getAssets(asset.chainID);
-    const assetFound = assets.find((a) => a.base === asset.denom);
-    if (!assetFound?.coingecko_id) {
-      throw new Error(
-        `getUsdValue error: ${asset.denom} does not have a 'coingecko_id' in ${asset.chainID}`
-      );
-    }
-    return assetFound.coingecko_id;
-  }
-};
 
-async function getUsdValue(asset: Asset) {
-  const usd = await getUsdPrice({ coingeckoID: getCoinGeckoId(asset) });
+
+async function getUsdValue(asset: Asset, coingeckoID?: string) {
+  if (!coingeckoID) {
+    throw new Error(`getUsdValue error: ${asset.denom} does not have a 'coingeckoID'`);
+  }
+  const usd = await getUsdPrice({ coingeckoID });
   return parseFloat(asset.value) * usd;
 }
 
-export function useUsdValue(asset?: Partial<Asset>) {
+
+export function useUsdValue(asset?: Partial<Asset>): UseQueryResult<number | undefined, Error> {
+  const {data: assets} = useAtomValue(skipAssetsAtom)
   const queryKey = useMemo(() => ["USE_USD_VALUE", asset] as const, [asset]);
 
   const enabled = useMemo(() => {
@@ -78,7 +69,8 @@ export function useUsdValue(asset?: Partial<Asset>) {
       asset ? [key, ...Object.values(asset)].join("-") : key,
     queryFn: async ({ queryKey: [, asset] }) => {
       if (asset?.value) {
-        return getUsdValue(asset as Asset);
+        const coingeckoID = assets?.find((a) => a.denom === asset.denom)?.coingeckoID
+        return getUsdValue(asset as Asset, coingeckoID);
       }
     },
     staleTime: 1000 * 60, // 1 minute
diff --git a/yarn.lock b/yarn.lock
index 789793a01..a3a99feaa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -28835,6 +28835,7 @@ __metadata:
     jotai: ^2.9.1
     jotai-tanstack-query: ^0.8.6
     lodash.debounce: ^4.0.8
+    match-sorter: ^6.3.4
     pluralize: ^8.0.0
     rc-virtual-list: ^3.14.5
     react-error-boundary: ^4.0.13