diff --git a/apps/namadillo/.gitignore b/apps/namadillo/.gitignore index 320fb3dfb..812f78443 100644 --- a/apps/namadillo/.gitignore +++ b/apps/namadillo/.gitignore @@ -8,3 +8,4 @@ /test-results/ /playwright-report/ /playwright/.cache/ +/public/localnet-config.toml diff --git a/apps/namadillo/src/App/AccountOverview/TransparentOverviewPanel.tsx b/apps/namadillo/src/App/AccountOverview/TransparentOverviewPanel.tsx index 7ee9c8e0c..20c8e0728 100644 --- a/apps/namadillo/src/App/AccountOverview/TransparentOverviewPanel.tsx +++ b/apps/namadillo/src/App/AccountOverview/TransparentOverviewPanel.tsx @@ -72,7 +72,7 @@ const TransparentTokensTable = ({ > Shield - {originalAddress === namadaAsset.address && ( + {originalAddress === namadaAsset().address && ( { - const namBalance = data.find((i) => i.asset.base === namadaAsset.base); + const namBalance = data.find((i) => i.asset.base === namadaAsset().base); return (
diff --git a/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx b/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx index fd63b2d60..8fe7b2772 100644 --- a/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx +++ b/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx @@ -55,8 +55,8 @@ export const IbcWithdraw: React.FC = () => { const transactionFee = mapUndefined( ({ gasLimit, gasPrice }) => ({ - originalAddress: namadaAsset.address, - asset: namadaAsset, + originalAddress: namadaAsset().address, + asset: namadaAsset(), amount: gasPrice.multipliedBy(gasLimit), }), gasConfig diff --git a/apps/namadillo/src/App/Setup/ChainLoader.tsx b/apps/namadillo/src/App/Setup/ChainLoader.tsx index 43a087424..f4ac85a7d 100644 --- a/apps/namadillo/src/App/Setup/ChainLoader.tsx +++ b/apps/namadillo/src/App/Setup/ChainLoader.tsx @@ -2,6 +2,7 @@ import { AtomErrorBoundary } from "App/Common/AtomErrorBoundary"; import { ErrorBox } from "App/Common/ErrorBox"; import { routes } from "App/routes"; import { chainAtom } from "atoms/chain"; +import { localnetConfigAtom } from "atoms/integrations"; import { useAtomValue } from "jotai"; import { ReactNode } from "react"; import { useLocation, useNavigate } from "react-router-dom"; @@ -31,6 +32,8 @@ export const ChainLoader = ({ children: ReactNode; }): JSX.Element => { const chain = useAtomValue(chainAtom); + useAtomValue(localnetConfigAtom); + const errorContainerProps = { className: "bg-black max-w-full rounded-sm w-full text-white min-h-full", }; diff --git a/apps/namadillo/src/App/Transfer/AssetImage.tsx b/apps/namadillo/src/App/Transfer/AssetImage.tsx index cef009103..cf91c75bf 100644 --- a/apps/namadillo/src/App/Transfer/AssetImage.tsx +++ b/apps/namadillo/src/App/Transfer/AssetImage.tsx @@ -21,7 +21,7 @@ export const AssetImage = ({ {altText} {isShielded !== undefined && ( - + )} diff --git a/apps/namadillo/src/App/Transfer/__tests__/TransferDestination.test.tsx b/apps/namadillo/src/App/Transfer/__tests__/TransferDestination.test.tsx index 081004a17..8489b8a7c 100644 --- a/apps/namadillo/src/App/Transfer/__tests__/TransferDestination.test.tsx +++ b/apps/namadillo/src/App/Transfer/__tests__/TransferDestination.test.tsx @@ -102,8 +102,8 @@ describe("Component: TransferDestination", () => { ); diff --git a/apps/namadillo/src/atoms/balance/functions.ts b/apps/namadillo/src/atoms/balance/functions.ts index 61d646b68..4d3d09596 100644 --- a/apps/namadillo/src/atoms/balance/functions.ts +++ b/apps/namadillo/src/atoms/balance/functions.ts @@ -53,7 +53,7 @@ export const getTotalDollar = (list?: TokenBalance[]): BigNumber | undefined => sumDollars(list ?? []); export const getTotalNam = (list?: TokenBalance[]): BigNumber => - list?.find((i) => i.asset.base === namadaAsset.base)?.amount ?? + list?.find((i) => i.asset.base === namadaAsset().base)?.amount ?? new BigNumber(0); const tnamAddressToDenomTrace = ( diff --git a/apps/namadillo/src/atoms/integrations/atoms.ts b/apps/namadillo/src/atoms/integrations/atoms.ts index 0d78ad61d..ff5851930 100644 --- a/apps/namadillo/src/atoms/integrations/atoms.ts +++ b/apps/namadillo/src/atoms/integrations/atoms.ts @@ -20,6 +20,7 @@ import { TransferTransactionData, } from "types"; import { + addLocalnetToRegistry, createIbcTx, getIbcChannels, getKnownChains, @@ -28,6 +29,7 @@ import { mapCoinsToAssets, } from "./functions"; import { + fetchLocalnetTomlConfig, IbcTransferParams, queryAndStoreRpc, queryAssetBalances, @@ -198,3 +200,27 @@ export const createIbcTxAtom = atomWithMutation((get) => { }, }; }); + +export const localnetConfigAtom = atomWithQuery((_get) => { + return { + queryKey: ["localnet-config"], + staleTime: Infinity, + retry: false, + + queryFn: async () => { + try { + const { enabled, chain_id, token_address } = + await fetchLocalnetTomlConfig(); + + if (enabled && chain_id && token_address) { + addLocalnetToRegistry(chain_id, token_address); + } + + return { chainId: chain_id, tokenAddress: token_address }; + } catch (_) { + // If file not found just ignore + return null; + } + }, + }; +}); diff --git a/apps/namadillo/src/atoms/integrations/functions.ts b/apps/namadillo/src/atoms/integrations/functions.ts index 602335924..2f88ca91c 100644 --- a/apps/namadillo/src/atoms/integrations/functions.ts +++ b/apps/namadillo/src/atoms/integrations/functions.ts @@ -1,4 +1,4 @@ -import { Asset, Chain } from "@chain-registry/types"; +import { Asset, AssetList, Chain } from "@chain-registry/types"; import { Coin } from "@cosmjs/launchpad"; import { QueryClient, setupIbcExtension } from "@cosmjs/stargate"; import { Tendermint34Client } from "@cosmjs/tendermint-rpc"; @@ -43,13 +43,6 @@ import internalDevnetCosmosTestnetIbc from "namada-chain-registry/_IBC/namadaint // TODO: this causes a big increase on bundle size. See #1224. import cosmosRegistry from "chain-registry"; -import { namadaLocal, namadaLocalAsset } from "registry/namada-local"; - -const { - VITE_LOCALNET: localnet = false, - VITE_LOCALNET_CHAIN_ID: localChainId, - VITE_LOCALNET_NAM_TOKEN: localToken, -} = import.meta.env; cosmosRegistry.chains.push(internalDevnetChain, housefireChain, dryrunChain); @@ -82,18 +75,6 @@ const testnetChains: ChainRegistryEntry[] = [ const mainnetAndTestnetChains = [...mainnetChains, ...testnetChains]; -if (localnet && localChainId && localToken) { - const localChain: ChainRegistryEntry = { - chain: namadaLocal(localChainId), - assets: namadaLocalAsset(localToken), - }; - - cosmosRegistry.chains.push(localChain.chain); - cosmosRegistry.assets.push(localChain.assets); - - mainnetChains.push(localChain); -} - export const getKnownChains = ( includeTestnets?: boolean ): ChainRegistryEntry[] => { @@ -389,3 +370,37 @@ export const createIbcTx = async ( ); return transactionPair; }; + +export const namadaLocal = (chainId: string): Chain => ({ + ...internalDevnetChain, + chain_name: "localnet", + chain_id: chainId, +}); + +export const namadaLocalAsset = (tokenAddress: string): AssetList => ({ + ...internalDevnetAssets, + chain_name: "localnet", + assets: internalDevnetAssets.assets.map((asset) => + asset.name === "NAM" ? + { + ...asset, + address: tokenAddress, + } + : asset + ), +}); + +export const addLocalnetToRegistry = ( + chainId: string, + tokenAddress: string +): void => { + const localChain: ChainRegistryEntry = { + chain: namadaLocal(chainId), + assets: namadaLocalAsset(tokenAddress), + }; + + cosmosRegistry.chains.push(localChain.chain); + cosmosRegistry.assets.push(localChain.assets); + + mainnetChains.push(localChain); +}; diff --git a/apps/namadillo/src/atoms/integrations/services.ts b/apps/namadillo/src/atoms/integrations/services.ts index a5b56b8d7..c168201ab 100644 --- a/apps/namadillo/src/atoms/integrations/services.ts +++ b/apps/namadillo/src/atoms/integrations/services.ts @@ -11,9 +11,11 @@ import { queryForAck, queryForIbcTimeout } from "atoms/transactions"; import BigNumber from "bignumber.js"; import { getDefaultStore } from "jotai"; import { createIbcTransferMessage } from "lib/transactions"; +import toml from "toml"; import { AddressWithAsset, IbcTransferTransactionData, + LocalnetToml, TransferStep, } from "types"; import { toBaseAmount } from "utils"; @@ -189,3 +191,8 @@ export const updateIbcTransactionStatus = async ( }); } }; + +export const fetchLocalnetTomlConfig = async (): Promise => { + const response = await fetch("/localnet-config.toml"); + return toml.parse(await response.text()) as LocalnetToml; +}; diff --git a/apps/namadillo/src/registry/namada-local.ts b/apps/namadillo/src/registry/namada-local.ts deleted file mode 100644 index 8af08de54..000000000 --- a/apps/namadillo/src/registry/namada-local.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { AssetList, Chain } from "@chain-registry/types"; -import internalDevnetAssets from "namada-chain-registry/namadainternaldevnet/assetlist.json"; -import internalDevnetChain from "namada-chain-registry/namadainternaldevnet/chain.json"; - -export const namadaLocal = (chainId: string): Chain => ({ - ...internalDevnetChain, - chain_name: "localnet", - chain_id: chainId, -}); - -export const namadaLocalAsset = (tokenAddress: string): AssetList => ({ - ...internalDevnetAssets, - chain_name: "localnet", - assets: internalDevnetAssets.assets.map((asset) => - asset.name === "NAM" ? - { - ...asset, - address: tokenAddress, - } - : asset - ), -}); diff --git a/apps/namadillo/src/registry/namadaAsset.ts b/apps/namadillo/src/registry/namadaAsset.ts index d88c59dc6..86043e7b2 100644 --- a/apps/namadillo/src/registry/namadaAsset.ts +++ b/apps/namadillo/src/registry/namadaAsset.ts @@ -1,27 +1,31 @@ import { Asset } from "@chain-registry/types"; +import { localnetConfigAtom } from "atoms/integrations"; +import { getDefaultStore } from "jotai"; import namadaShieldedSvg from "./assets/namada-shielded.svg"; -const { VITE_LOCALNET: localnet = false, VITE_LOCALNET_NAM_TOKEN: localToken } = - import.meta.env; +// We can't return "satisfies Asset" from fn +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export const namadaAsset = () => { + const store = getDefaultStore(); + const config = store.get(localnetConfigAtom); + const localNamAddress = config.data?.tokenAddress; -export const namadaAsset = { - name: "Namada", - base: "unam", - address: - localnet && localToken ? localToken : ( - "tnam1qxp7u2vmlgcrpn9j0ml7hrtr79g2w2fdesteh7tu" - ), - display: "nam", - symbol: "NAM", - denom_units: [ - { - denom: "unam", - exponent: 0, - }, - { - denom: "nam", - exponent: 6, - }, - ], - logo_URIs: { svg: namadaShieldedSvg }, -} satisfies Asset; + return { + name: "Namada", + base: "unam", + address: localNamAddress || "tnam1qxp7u2vmlgcrpn9j0ml7hrtr79g2w2fdesteh7tu", + display: "nam", + symbol: "NAM", + denom_units: [ + { + denom: "unam", + exponent: 0, + }, + { + denom: "nam", + exponent: 6, + }, + ], + logo_URIs: { svg: namadaShieldedSvg }, + } satisfies Asset; +}; diff --git a/apps/namadillo/src/types.ts b/apps/namadillo/src/types.ts index c53ff65c8..6433c6002 100644 --- a/apps/namadillo/src/types.ts +++ b/apps/namadillo/src/types.ts @@ -333,3 +333,9 @@ export type TransferTransactionData = export type PartialTransferTransactionData = Partial & Pick; + +export type LocalnetToml = { + enabled: boolean; + chain_id: string; + token_address: string; +}; diff --git a/apps/namadillo/src/utils/index.ts b/apps/namadillo/src/utils/index.ts index bfe79e5e0..ce1f52619 100644 --- a/apps/namadillo/src/utils/index.ts +++ b/apps/namadillo/src/utils/index.ts @@ -122,7 +122,7 @@ const findDisplayUnit = (asset: Asset): AssetDenomUnit | undefined => { }; const isNamAsset = (asset: Asset): boolean => - asset.symbol === namadaAsset.symbol; + asset.symbol === namadaAsset().symbol; export const toDisplayAmount = ( asset: Asset,