Skip to content

Commit e72d0f1

Browse files
MASP indexer integration (#1120)
* feat: code compiles * feat: poc shielded sync * feat: masp indexer url UI and rpc backup * fix: shielded context for nodejs feature * chore: cleanup test code * fix: use namada_sdk version with masp indexer fix * fix: make sync job blocking
1 parent cbdc8f7 commit e72d0f1

File tree

25 files changed

+1045
-560
lines changed

25 files changed

+1045
-560
lines changed

apps/extension/src/background/sdk/service.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const {
88
defaultTokenAddress = "tnam1qxgfw7myv4dh0qna4hq0xdg6lx77fzl7dcem8h7e",
99
} = process.env;
1010

11+
// Extension does not care about the MASP indexer - this will map to None in Rust
12+
const MASP_INDEXER_URL = "";
13+
1114
export class SdkService {
1215
private constructor(
1316
private rpc: string,
@@ -27,6 +30,12 @@ export class SdkService {
2730
}
2831

2932
getSdk(): Sdk {
30-
return getSdk(this.cryptoMemory, this.rpc, "NOT USED DB NAME", this.token);
33+
return getSdk(
34+
this.cryptoMemory,
35+
this.rpc,
36+
MASP_INDEXER_URL,
37+
"NOT USED DB NAME",
38+
this.token
39+
);
3140
}
3241
}

apps/namadillo/src/App/Settings/Advanced.tsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import { ActionButton, Input, Stack } from "@namada/components";
22
import { chainParametersAtom } from "atoms/chain";
33
import {
44
indexerUrlAtom,
5+
maspIndexerUrlAtom,
56
rpcUrlAtom,
67
updateIndexerUrlAtom,
8+
updateMaspIndexerUrlAtom,
79
updateRpcUrlAtom,
810
} from "atoms/settings";
911
import { useAtom, useAtomValue } from "jotai";
@@ -16,25 +18,32 @@ export const Advanced = (): JSX.Element => {
1618
const [currentRpc] = useAtom(rpcUrlAtom);
1719
const [rpcMutation] = useAtom(updateRpcUrlAtom);
1820
const [currentIndexer] = useAtom(indexerUrlAtom);
21+
const [currentMaspIndexer] = useAtom(maspIndexerUrlAtom);
1922
const [indexerMutation] = useAtom(updateIndexerUrlAtom);
23+
const [maspIndexerMutation] = useAtom(updateMaspIndexerUrlAtom);
2024
const { data: chainParameters } = useAtomValue(chainParametersAtom);
2125

2226
const [rpc, setRpc] = useState(currentRpc);
2327
const [indexer, setIndexer] = useState(currentIndexer);
28+
const [maspIndexer, setMaspIndexer] = useState(currentMaspIndexer);
2429

2530
const onSubmit = async (e: React.FormEvent): Promise<void> => {
2631
e.preventDefault();
2732
try {
2833
await Promise.all([
2934
rpcMutation.mutateAsync(rpc),
3035
indexerMutation.mutateAsync(indexer),
36+
maspIndexerMutation.mutateAsync(maspIndexer),
3137
]);
3238
document.location.href =
3339
location.state.backgroundLocation.pathname ?? location.pathname;
3440
} catch {}
3541
};
3642

37-
const isPending = rpcMutation.isPending || indexerMutation.isPending;
43+
const isPending =
44+
rpcMutation.isPending ||
45+
indexerMutation.isPending ||
46+
maspIndexerMutation.isPending;
3847

3948
return (
4049
<form
@@ -71,6 +80,21 @@ export const Advanced = (): JSX.Element => {
7180
}}
7281
required
7382
/>
83+
<Input
84+
type="text"
85+
placeholder="Optional"
86+
value={maspIndexer}
87+
error={
88+
maspIndexerMutation.error instanceof Error &&
89+
maspIndexerMutation.error.message
90+
}
91+
label="MASP Indexer URL"
92+
className="[&_input]:border-neutral-300"
93+
onChange={(e) => {
94+
setMaspIndexer(e.currentTarget.value);
95+
maspIndexerMutation.reset();
96+
}}
97+
/>
7498
<Input
7599
type="text"
76100
variant="ReadOnlyCopy"

apps/namadillo/src/atoms/settings/atoms.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import { Getter, Setter, atom, getDefaultStore } from "jotai";
44
import { atomWithMutation, atomWithQuery } from "jotai-tanstack-query";
55
import { atomWithStorage } from "jotai/utils";
66
import { SettingsStorage } from "types";
7-
import { fetchDefaultTomlConfig, isIndexerAlive, isRpcAlive } from "./services";
7+
import {
8+
fetchDefaultTomlConfig,
9+
isIndexerAlive,
10+
isMaspIndexerAlive,
11+
isRpcAlive,
12+
} from "./services";
813

914
export type ConnectStatus = "idle" | "connecting" | "connected" | "error";
1015

@@ -65,18 +70,21 @@ const changeSettings =
6570
const changeSettingsUrl =
6671
(
6772
key: keyof SettingsStorage,
68-
healthCheck: (url: string) => Promise<boolean>
73+
healthCheck: (url: string) => Promise<boolean>,
74+
allowEmpty = false
6975
) =>
70-
async (url: string) => {
71-
const sanitizedUrl = sanitizeUrl(url);
72-
if (!isUrlValid(sanitizedUrl)) {
76+
async (inputUrl: string) => {
77+
const allowedEmpty = allowEmpty && inputUrl.length === 0;
78+
const url = allowedEmpty ? "" : sanitizeUrl(inputUrl);
79+
80+
if (!allowedEmpty && !isUrlValid(url)) {
7381
throw new Error(
7482
"Invalid URL. The URL should be valid starting with 'http', 'https', 'ws', or 'wss'."
7583
);
7684
}
77-
if (await healthCheck(sanitizedUrl)) {
85+
if (allowedEmpty || (await healthCheck(url))) {
7886
const { get, set } = getDefaultStore();
79-
changeSettings(key)(get, set, sanitizedUrl);
87+
changeSettings(key)(get, set, url);
8088
} else {
8189
throw new Error(
8290
"Couldn't reach the URL. Please provide a valid Namada URL service."
@@ -138,13 +146,30 @@ export const indexerUrlAtom = atom((get) => {
138146
return "";
139147
});
140148

149+
export const maspIndexerUrlAtom = atom((get) => {
150+
const customIndexerUrl = get(settingsAtom).maspIndexerUrl;
151+
if (customIndexerUrl) return customIndexerUrl;
152+
153+
const tomlIndexerUrl = get(defaultServerConfigAtom).data?.masp_indexer_url;
154+
if (tomlIndexerUrl) return tomlIndexerUrl;
155+
156+
return "";
157+
});
158+
141159
export const updateIndexerUrlAtom = atomWithMutation(() => {
142160
return {
143161
mutationKey: ["update-indexer-url"],
144162
mutationFn: changeSettingsUrl("indexerUrl", isIndexerAlive),
145163
};
146164
});
147165

166+
export const updateMaspIndexerUrlAtom = atomWithMutation(() => {
167+
return {
168+
mutationKey: ["update-masp-indexer-url"],
169+
mutationFn: changeSettingsUrl("maspIndexerUrl", isMaspIndexerAlive, true),
170+
};
171+
});
172+
148173
export const signArbitraryEnabledAtom = atom(
149174
(get) => get(settingsAtom).signArbitraryEnabled,
150175
changeSettings<boolean>("signArbitraryEnabled")

apps/namadillo/src/atoms/settings/services.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ export const isIndexerAlive = async (url: string): Promise<boolean> => {
1717
}
1818
};
1919

20+
export const isMaspIndexerAlive = async (url: string): Promise<boolean> => {
21+
if (!isUrlValid(url)) {
22+
return false;
23+
}
24+
try {
25+
const response = await fetch(`${url}/health`);
26+
return response.ok && response.status === 200;
27+
} catch {
28+
return false;
29+
}
30+
};
31+
2032
export const isRpcAlive = async (url: string): Promise<boolean> => {
2133
if (!isUrlValid(url)) {
2234
return false;

apps/namadillo/src/hooks/useSdk.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import initSdk from "@heliax/namada-sdk/inline-init";
22
import { getSdk, Sdk } from "@heliax/namada-sdk/web";
33
import { QueryStatus, useQuery } from "@tanstack/react-query";
44
import { nativeTokenAddressAtom } from "atoms/chain";
5-
import { rpcUrlAtom } from "atoms/settings";
5+
import { maspIndexerUrlAtom, rpcUrlAtom } from "atoms/settings";
66
import { getDefaultStore, useAtomValue } from "jotai";
77
import {
88
createContext,
@@ -33,13 +33,20 @@ const initializeSdk = async (): Promise<Sdk> => {
3333
const { cryptoMemory } = await initSdk();
3434
const store = getDefaultStore();
3535
const rpcUrl = store.get(rpcUrlAtom);
36+
const maspIndexerUrl = store.get(maspIndexerUrlAtom);
3637
const nativeToken = store.get(nativeTokenAddressAtom);
3738

3839
if (!nativeToken.isSuccess) {
3940
throw "Native token not loaded";
4041
}
4142

42-
const sdk = getSdk(cryptoMemory, rpcUrl, "", nativeToken.data);
43+
const sdk = getSdk(
44+
cryptoMemory,
45+
rpcUrl,
46+
maspIndexerUrl,
47+
"",
48+
nativeToken.data
49+
);
4350
return sdk;
4451
};
4552

apps/namadillo/src/types.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export type ChainSettings = {
4545

4646
export type SettingsTomlOptions = {
4747
indexer_url?: string;
48+
masp_indexer_url?: string;
4849
rpc_url?: string;
4950
};
5051

@@ -61,6 +62,7 @@ export type SettingsStorage = {
6162
fiat: CurrencyType;
6263
rpcUrl?: string;
6364
indexerUrl: string;
65+
maspIndexerUrl?: string;
6466
signArbitraryEnabled: boolean;
6567
};
6668

0 commit comments

Comments
 (0)