Skip to content

Commit

Permalink
feat(namadillo): querying next rpc if the previous one fails
Browse files Browse the repository at this point in the history
  • Loading branch information
pedrorezende committed Jan 7, 2025
1 parent 7e986f2 commit 5ca8bba
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 48 deletions.
16 changes: 1 addition & 15 deletions apps/namadillo/src/App/Common/QueryProvider.tsx
Original file line number Diff line number Diff line change
@@ -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?: {
Expand All @@ -11,7 +7,6 @@ type ErrorWithResponse = Error & {
};

const MAX_RETRIES = 3;

export const queryClient = new QueryClient({
defaultOptions: {
queries: {
Expand All @@ -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 (
<QueryClientProvider client={queryClient}>
<JotaiProvider store={getDefaultStore()}>
<HydrateAtoms>{children}</HydrateAtoms>
</JotaiProvider>
</QueryClientProvider>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
};
24 changes: 24 additions & 0 deletions apps/namadillo/src/App/Common/StorageProvider.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<JotaiProvider store={defaultStore}>
<HydrateAtoms>{children}</HydrateAtoms>
</JotaiProvider>
);
};
8 changes: 4 additions & 4 deletions apps/namadillo/src/atoms/integrations/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
BuildTxAtomParams,
ChainId,
ChainRegistryEntry,
RpcStorage,
TransferStep,
TransferTransactionData,
} from "types";
Expand Down Expand Up @@ -64,10 +65,9 @@ export const selectedIBCChainAtom = atomWithStorage<string | undefined>(
undefined
);

export const workingRpcsAtom = atomWithStorage<Record<string, string>>(
"namadillo:rpcs",
{}
);
export const rpcByChainAtom = atomWithStorage<
Record<string, RpcStorage> | undefined
>("namadillo:rpc:active", undefined);

export const ibcTransferAtom = atomWithMutation(() => {
return {
Expand Down
11 changes: 8 additions & 3 deletions apps/namadillo/src/atoms/integrations/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
Coin,
GasConfig,
LocalnetToml,
RpcStorage,
} from "types";
import { toDisplayAmount } from "utils";
import { unknownAsset } from "utils/assets";
Expand Down Expand Up @@ -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 => {
Expand Down
32 changes: 16 additions & 16 deletions apps/namadillo/src/atoms/integrations/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -142,28 +142,28 @@ export const submitIbcTransfer = async (

export const queryAndStoreRpc = async <T>(
chain: Chain,
queryFn: QueryFn<T>,
rpcIndex = 0
queryFn: QueryFn<T>
): Promise<T> => {
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;
}
};
Expand Down
21 changes: 12 additions & 9 deletions apps/namadillo/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -23,15 +24,17 @@ if (container) {
root.render(
<React.StrictMode>
<QueryProvider>
<TomlConfigLoader>
<IndexerLoader>
<ExtensionLoader>
<SdkProvider>
<RouterProvider router={router} />
</SdkProvider>
</ExtensionLoader>
</IndexerLoader>
</TomlConfigLoader>
<StorageProvider>
<TomlConfigLoader>
<IndexerLoader>
<ExtensionLoader>
<SdkProvider>
<RouterProvider router={router} />
</SdkProvider>
</ExtensionLoader>
</IndexerLoader>
</TomlConfigLoader>
</StorageProvider>
</QueryProvider>
</React.StrictMode>
);
Expand Down
2 changes: 1 addition & 1 deletion apps/namadillo/src/integrations/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
5 changes: 5 additions & 0 deletions apps/namadillo/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ export type SettingsStorage = {
enableTestnets?: boolean;
};

export type RpcStorage = {
address: string;
index: number;
};

export type Validator = Unique & {
alias?: string;
address: Address;
Expand Down

0 comments on commit 5ca8bba

Please sign in to comment.