From 5ca8bba5a6bae990ad7ca45a55ae905cc8132d09 Mon Sep 17 00:00:00 2001 From: Pedro Rezende Date: Tue, 7 Jan 2025 12:45:03 -0300 Subject: [PATCH] feat(namadillo): querying next rpc if the previous one fails --- .../src/App/Common/QueryProvider.tsx | 16 +--------- .../src/App/Common/StorageProvider.tsx | 24 ++++++++++++++ .../namadillo/src/atoms/integrations/atoms.ts | 8 ++--- .../src/atoms/integrations/functions.ts | 11 +++++-- .../src/atoms/integrations/services.ts | 32 +++++++++---------- apps/namadillo/src/index.tsx | 21 ++++++------ apps/namadillo/src/integrations/utils.ts | 2 +- apps/namadillo/src/types.ts | 5 +++ 8 files changed, 71 insertions(+), 48 deletions(-) create mode 100644 apps/namadillo/src/App/Common/StorageProvider.tsx diff --git a/apps/namadillo/src/App/Common/QueryProvider.tsx b/apps/namadillo/src/App/Common/QueryProvider.tsx index b3e0200077..afa5428447 100644 --- a/apps/namadillo/src/App/Common/QueryProvider.tsx +++ b/apps/namadillo/src/App/Common/QueryProvider.tsx @@ -1,8 +1,4 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { getDefaultStore } from "jotai"; -import { queryClientAtom } from "jotai-tanstack-query"; -import { Provider as JotaiProvider } from "jotai/react"; -import { useHydrateAtoms } from "jotai/utils"; type ErrorWithResponse = Error & { response?: { @@ -11,7 +7,6 @@ type ErrorWithResponse = Error & { }; const MAX_RETRIES = 3; - export const queryClient = new QueryClient({ defaultOptions: { queries: { @@ -31,21 +26,12 @@ export const queryClient = new QueryClient({ }, }); -const HydrateAtoms = (props: { children: JSX.Element }): JSX.Element => { - useHydrateAtoms([[queryClientAtom, queryClient]]); - return props.children; -}; - export const QueryProvider = ({ children, }: { children: JSX.Element; }): JSX.Element => { return ( - - - {children} - - + {children} ); }; diff --git a/apps/namadillo/src/App/Common/StorageProvider.tsx b/apps/namadillo/src/App/Common/StorageProvider.tsx new file mode 100644 index 0000000000..5a9e941090 --- /dev/null +++ b/apps/namadillo/src/App/Common/StorageProvider.tsx @@ -0,0 +1,24 @@ +import { queryClient } from "App/Common/QueryProvider"; +import { getDefaultStore } from "jotai"; +import { queryClientAtom } from "jotai-tanstack-query"; +import { Provider as JotaiProvider } from "jotai/react"; +import { useHydrateAtoms } from "jotai/utils"; + +type StorageProviderProps = { children: JSX.Element }; + +const HydrateAtoms = (props: { children: JSX.Element }): JSX.Element => { + useHydrateAtoms([[queryClientAtom, queryClient]]); + return props.children; +}; + +export const defaultStore = getDefaultStore(); + +export const StorageProvider = ({ + children, +}: StorageProviderProps): JSX.Element => { + return ( + + {children} + + ); +}; diff --git a/apps/namadillo/src/atoms/integrations/atoms.ts b/apps/namadillo/src/atoms/integrations/atoms.ts index d4326cc0df..3d414e062a 100644 --- a/apps/namadillo/src/atoms/integrations/atoms.ts +++ b/apps/namadillo/src/atoms/integrations/atoms.ts @@ -18,6 +18,7 @@ import { BuildTxAtomParams, ChainId, ChainRegistryEntry, + RpcStorage, TransferStep, TransferTransactionData, } from "types"; @@ -64,10 +65,9 @@ export const selectedIBCChainAtom = atomWithStorage( undefined ); -export const workingRpcsAtom = atomWithStorage>( - "namadillo:rpcs", - {} -); +export const rpcByChainAtom = atomWithStorage< + Record | undefined +>("namadillo:rpc:active", undefined); export const ibcTransferAtom = atomWithMutation(() => { return { diff --git a/apps/namadillo/src/atoms/integrations/functions.ts b/apps/namadillo/src/atoms/integrations/functions.ts index 43ee5a455e..b5e3408f2b 100644 --- a/apps/namadillo/src/atoms/integrations/functions.ts +++ b/apps/namadillo/src/atoms/integrations/functions.ts @@ -26,6 +26,7 @@ import { Coin, GasConfig, LocalnetToml, + RpcStorage, } from "types"; import { toDisplayAmount } from "utils"; import { unknownAsset } from "utils/assets"; @@ -299,13 +300,17 @@ export const mapCoinsToAssets = async ( ); }; -export const getRpcByIndex = (chain: Chain, index = 0): string => { +export const getRpcByIndex = (chain: Chain, index = 0): RpcStorage => { const availableRpcs = chain.apis?.rpc; if (!availableRpcs) { throw new Error("There are no available RPCs for " + chain.chain_name); } - const randomRpc = availableRpcs[Math.min(index, availableRpcs.length - 1)]; - return randomRpc.address; + + const rpc = availableRpcs[Math.min(index, availableRpcs.length - 1)]; + return { + address: rpc.address, + index, + }; }; export const getRestApiAddressByIndex = (chain: Chain, index = 0): string => { diff --git a/apps/namadillo/src/atoms/integrations/services.ts b/apps/namadillo/src/atoms/integrations/services.ts index 39a26673f6..31676f2e51 100644 --- a/apps/namadillo/src/atoms/integrations/services.ts +++ b/apps/namadillo/src/atoms/integrations/services.ts @@ -24,7 +24,7 @@ import { } from "types"; import { toBaseAmount } from "utils"; import { getSdkInstance } from "utils/sdk"; -import { workingRpcsAtom } from "./atoms"; +import { rpcByChainAtom } from "./atoms"; import { getRpcByIndex } from "./functions"; type CommonParams = { @@ -142,28 +142,28 @@ export const submitIbcTransfer = async ( export const queryAndStoreRpc = async ( chain: Chain, - queryFn: QueryFn, - rpcIndex = 0 + queryFn: QueryFn ): Promise => { const { get, set } = getDefaultStore(); - const workingRpcs = get(workingRpcsAtom); - const rpcAddress = - chain.chain_id in workingRpcs ? - workingRpcs[chain.chain_id] - : getRpcByIndex(chain, rpcIndex); + const lastRpc = get(rpcByChainAtom) || {}; + const rpc = + chain.chain_id in lastRpc ? + lastRpc[chain.chain_id] + : getRpcByIndex(chain, 0); try { - const output = await queryFn(rpcAddress); - set(workingRpcsAtom, { - ...workingRpcs, - [chain.chain_id]: rpcAddress, + const output = await queryFn(rpc.address); + set(rpcByChainAtom, { + ...lastRpc, + [chain.chain_id]: { ...rpc }, }); return output; } catch (err) { - if (chain.chain_id in workingRpcs) { - delete workingRpcs[chain.chain_id]; - set(workingRpcsAtom, { ...workingRpcs }); - } + // On error, saves the next available rpc + set(rpcByChainAtom, { + ...lastRpc, + [chain.chain_id]: getRpcByIndex(chain, rpc.index + 1), + }); throw err; } }; diff --git a/apps/namadillo/src/index.tsx b/apps/namadillo/src/index.tsx index 73ebfd6dd0..4e1553e745 100644 --- a/apps/namadillo/src/index.tsx +++ b/apps/namadillo/src/index.tsx @@ -8,6 +8,7 @@ import { getRouter } from "./App/AppRoutes"; import "@namada/components/src/base.css"; import "@namada/utils/bigint-to-json-polyfill"; +import { StorageProvider } from "App/Common/StorageProvider"; import { ExtensionLoader } from "App/Setup/ExtensionLoader"; import { IndexerLoader } from "App/Setup/IndexerLoader"; import { TomlConfigLoader } from "App/Setup/TomlConfigLoader"; @@ -23,15 +24,17 @@ if (container) { root.render( - - - - - - - - - + + + + + + + + + + + ); diff --git a/apps/namadillo/src/integrations/utils.ts b/apps/namadillo/src/integrations/utils.ts index b616f858d7..63eeb26899 100644 --- a/apps/namadillo/src/integrations/utils.ts +++ b/apps/namadillo/src/integrations/utils.ts @@ -154,7 +154,7 @@ export const basicConvertToKeplrChain = ( return { chainId: chain.chain_id, chainName: chain.chain_name, - rpc, + rpc: rpc.address, rest, bip44: { coinType: chain.slip44 }, bech32Config: generateBech32Config(chain.bech32_prefix), diff --git a/apps/namadillo/src/types.ts b/apps/namadillo/src/types.ts index 6387b47b5d..49deac9efb 100644 --- a/apps/namadillo/src/types.ts +++ b/apps/namadillo/src/types.ts @@ -81,6 +81,11 @@ export type SettingsStorage = { enableTestnets?: boolean; }; +export type RpcStorage = { + address: string; + index: number; +}; + export type Validator = Unique & { alias?: string; address: Address;