Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: disallowed duplicated chain id or name #1071

Merged
merged 1 commit into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions src/lib/app-provider/hooks/useChainConfigs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { wallets as initiaWallets } from "@cosmos-kit/initia";
import { wallets as keplrWallets } from "@cosmos-kit/keplr";
import { wallets as staionWallets } from "@cosmos-kit/station";
import { assets, chains } from "chain-registry";
import { useMemo } from "react";
import { find } from "lodash";
import { useCallback, useMemo } from "react";

import type { ChainConfig, ChainConfigs } from "config/chain";
import { CHAIN_CONFIGS } from "config/chain";
Expand All @@ -24,7 +25,7 @@ import {
terra2testnet,
terra2testnetAssets,
} from "lib/chain-registry/terra2testnet";
import { useChainConfigStore } from "lib/providers/store";
import { useLocalChainConfigStore } from "lib/providers/store";

const getWallets = (wallets: SharedChainConfig["wallets"]) =>
wallets.reduce(
Expand All @@ -50,8 +51,11 @@ export const useChainConfigs = (): {
registryChains: Chain[];
registryAssets: AssetList[];
supportedChainIds: string[];
isChainIdExist: (chainId: string) => boolean;
isPrettyNameExist: (name: string) => boolean;
} => {
const { chainConfigs: localChainConfigs } = useChainConfigStore();
const { localChainConfigs, isLocalChainIdExist, isLocalPrettyNameExist } =
useLocalChainConfigStore();

const local = useMemo(
() =>
Expand Down Expand Up @@ -123,6 +127,19 @@ export const useChainConfigs = (): {
[JSON.stringify(localChainConfigs)]
);

const isChainIdExist = useCallback(
(chainId: string) =>
!!CHAIN_CONFIGS[chainId] || isLocalChainIdExist(chainId),
[isLocalChainIdExist]
);

const isPrettyNameExist = useCallback(
(name: string) =>
!!find(CHAIN_CONFIGS, { prettyName: name }) ||
isLocalPrettyNameExist(name),
[isLocalPrettyNameExist]
);

return {
chainConfigs: {
...CHAIN_CONFIGS,
Expand All @@ -145,5 +162,7 @@ export const useChainConfigs = (): {
...local.registryAssets,
],
supportedChainIds: [...SUPPORTED_CHAIN_IDS, ...local.supportedChainIds],
isChainIdExist,
isPrettyNameExist,
};
};
4 changes: 2 additions & 2 deletions src/lib/app-provider/hooks/useNetworkChange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useRouter } from "next/router";
import { useEffect, useRef } from "react";

import { FALLBACK_SUPPORTED_CHAIN_ID } from "env";
import { useChainConfigStore } from "lib/providers/store";
import { useLocalChainConfigStore } from "lib/providers/store";
import { getFirstQueryParam } from "lib/utils";

import { useChainConfigs } from "./useChainConfigs";
Expand All @@ -15,7 +15,7 @@ export const useNetworkChange = (
const networkRef = useRef<string>();
const navigate = useInternalNavigate();
const { supportedChainIds } = useChainConfigs();
const { isHydrated: isChainConfigStoreHydrated } = useChainConfigStore();
const { isHydrated: isChainConfigStoreHydrated } = useLocalChainConfigStore();

useEffect(() => {
if (router.isReady && isChainConfigStoreHydrated) {
Expand Down
9 changes: 5 additions & 4 deletions src/lib/components/modal/RemoveChainConfigModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { ReactNode } from "react";

import { useCelatoneApp } from "lib/app-provider";
import { CustomIcon } from "lib/components/icon";
import { useChainConfigStore, useNetworkStore } from "lib/providers/store";
import { useLocalChainConfigStore, useNetworkStore } from "lib/providers/store";

import { ActionModal } from "./ActionModal";

Expand All @@ -17,17 +17,18 @@ export function RemoveChainConfigModal({
chainId,
trigger,
}: RemoveChainConfigModalProps) {
const { removeChainConfig, getChainConfig } = useChainConfigStore();
const { removeLocalChainConfig, getLocalChainConfig } =
useLocalChainConfigStore();
const { removeNetwork } = useNetworkStore();
const router = useRouter();
const { currentChainId } = useCelatoneApp();

const chainConfig = getChainConfig(chainId);
const chainConfig = getLocalChainConfig(chainId);

const toast = useToast();
const handleRemove = () => {
// remove chain id from chain config store
removeChainConfig(chainId);
removeLocalChainConfig(chainId);

// remove chain id from pinned network
removeNetwork(chainId);
Expand Down
6 changes: 3 additions & 3 deletions src/lib/layout/network-menu/network-card/NetworkCardCta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
useMobile,
} from "lib/app-provider";
import { CustomIcon } from "lib/components/icon";
import { useChainConfigStore, useNetworkStore } from "lib/providers/store";
import { useLocalChainConfigStore, useNetworkStore } from "lib/providers/store";

interface NetworkCardCtaProps {
chainId: string;
Expand All @@ -20,9 +20,9 @@ export const NetworkCardCta = observer(
({ chainId, isSelected, isDraggable }: NetworkCardCtaProps) => {
const navigate = useInternalNavigate();
const { chainConfigs } = useChainConfigs();
const { isChainIdExist } = useChainConfigStore();
const { isLocalChainIdExist } = useLocalChainConfigStore();
const isMobile = useMobile();
const isEditable = isChainIdExist(chainId);
const isEditable = isLocalChainIdExist(chainId);
const { isNetworkPinned, pinNetwork, removeNetwork } = useNetworkStore();
const toast = useToast({
status: "success",
Expand Down
6 changes: 3 additions & 3 deletions src/lib/pages/custom-network/edit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { CustomIcon } from "lib/components/icon";
import JsonReadOnly from "lib/components/json/JsonReadOnly";
import { RemoveChainConfigModal } from "lib/components/modal/RemoveChainConfigModal";
import { InvalidState } from "lib/components/state";
import { useChainConfigStore } from "lib/providers/store";
import { useLocalChainConfigStore } from "lib/providers/store";
import { jsonPrettify } from "lib/utils";

// import { ExportNetworkConfig } from "./components/ExportNetworkConfig";
Expand Down Expand Up @@ -51,8 +51,8 @@ interface NetworkConfigBodyProps {
}

const NetworkConfigBody = ({ chainId }: NetworkConfigBodyProps) => {
const { getChainConfig } = useChainConfigStore();
const chainConfig = getChainConfig(chainId);
const { getLocalChainConfig } = useLocalChainConfigStore();
const chainConfig = getLocalChainConfig(chainId);

// const leftButtonProps = {
// label: "Cancel",
Expand Down
10 changes: 5 additions & 5 deletions src/lib/pages/custom-network/manual/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { Flex, useDisclosure } from "@chakra-ui/react";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";

import { useAllowCustomNetworks } from "lib/app-provider";
import { useAllowCustomNetworks, useChainConfigs } from "lib/app-provider";
import ActionPageContainer from "lib/components/ActionPageContainer";
import { CustomIcon } from "lib/components/icon";
import { FooterCta } from "lib/components/layouts";
import { CelatoneSeo } from "lib/components/Seo";
import { useChainConfigStore } from "lib/providers/store";
import { useLocalChainConfigStore } from "lib/providers/store";

import {
AddNetworkForm,
Expand All @@ -27,8 +27,8 @@ import type { AddNetworkManualForm } from "./types";
export const AddNetworkManual = () => {
useAllowCustomNetworks({ shouldRedirect: true });
const { isOpen, onClose, onOpen } = useDisclosure();
const { addChainConfig, isChainIdExist, isPrettyNameExist } =
useChainConfigStore();
const { addLocalChainConfig } = useLocalChainConfigStore();
const { isChainIdExist, isPrettyNameExist } = useChainConfigs();

const {
control,
Expand Down Expand Up @@ -97,7 +97,7 @@ export const AddNetworkManual = () => {
} = watch();

const handleSubmitForm = (data: AddNetworkManualForm) => {
addChainConfig(
addLocalChainConfig(
data.chainId,
zAddNetworkManualChainConfigJson({
isChainIdExist,
Expand Down
6 changes: 3 additions & 3 deletions src/lib/providers/store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export function useNetworkStore() {
return networkStore;
}

export function useChainConfigStore() {
const { chainConfigStore } = useStore();
return chainConfigStore;
export function useLocalChainConfigStore() {
const { localChainConfigStore } = useStore();
return localChainConfigStore;
}
32 changes: 18 additions & 14 deletions src/lib/stores/chain-config.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ChainConfig } from "@alleslabs/shared";

import { ChainConfigStore } from "./chain-config";
import { LocalChainConfigStore } from "./chain-config";

const MOCK_CONFIG: ChainConfig = {
tier: "sequencer",
Expand Down Expand Up @@ -46,37 +46,41 @@ const MOCK_CONFIG: ChainConfig = {
};

describe("chain config management", () => {
let chainConfigStore: ChainConfigStore;
let chainConfigStore: LocalChainConfigStore;
beforeEach(() => {
chainConfigStore = new ChainConfigStore();
chainConfigStore = new LocalChainConfigStore();
});

test("get chain config", () => {
chainConfigStore.addChainConfig("test-1", MOCK_CONFIG);
const chainConfig = chainConfigStore.getChainConfig("test-1");
chainConfigStore.addLocalChainConfig("test-1", MOCK_CONFIG);
const chainConfig = chainConfigStore.getLocalChainConfig("test-1");
expect(chainConfig).toEqual(MOCK_CONFIG);
});

test("save chain config", () => {
chainConfigStore.addChainConfig("test-1", MOCK_CONFIG);
const chainConfig = chainConfigStore.getChainConfig("test-1");
chainConfigStore.addLocalChainConfig("test-1", MOCK_CONFIG);
const chainConfig = chainConfigStore.getLocalChainConfig("test-1");
expect(chainConfig).toEqual(MOCK_CONFIG);
expect(chainConfigStore.isChainIdExist("test-1")).toBeTruthy();
expect(chainConfigStore.isLocalChainIdExist("test-1")).toBeTruthy();
});

test("update chain config", () => {
const newChainConfig = {
...MOCK_CONFIG,
rpc: "https://rpc.test.com",
};
chainConfigStore.updateChainConfig("test-1", newChainConfig);
expect(chainConfigStore.getChainConfig("test-1")).not.toEqual(MOCK_CONFIG);
expect(chainConfigStore.getChainConfig("test-1")).toEqual(newChainConfig);
chainConfigStore.updateLocalChainConfig("test-1", newChainConfig);
expect(chainConfigStore.getLocalChainConfig("test-1")).not.toEqual(
MOCK_CONFIG
);
expect(chainConfigStore.getLocalChainConfig("test-1")).toEqual(
newChainConfig
);
});

test("delete chain config", () => {
chainConfigStore.updateChainConfig("test-1", MOCK_CONFIG);
chainConfigStore.removeChainConfig("test-1");
expect(chainConfigStore.chainConfigs).toEqual({});
chainConfigStore.updateLocalChainConfig("test-1", MOCK_CONFIG);
chainConfigStore.removeLocalChainConfig("test-1");
expect(chainConfigStore.localChainConfigs).toEqual({});
});
});
36 changes: 18 additions & 18 deletions src/lib/stores/chain-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,56 @@ import { isHydrated, makePersistable } from "mobx-persist-store";

import type { Option } from "lib/types";

export class ChainConfigStore {
chainConfigs: Record<
export class LocalChainConfigStore {
localChainConfigs: Record<
string, // chainId
SharedChainConfig
>;

constructor() {
this.chainConfigs = {};
this.localChainConfigs = {};

makeAutoObservable(this, {}, { autoBind: true });

makePersistable(this, {
name: "ChainConfigStore",
properties: ["chainConfigs"],
properties: ["localChainConfigs"],
});
}

get isHydrated(): boolean {
return isHydrated(this);
}

getChainConfig(chainId: string): Option<SharedChainConfig> {
if (!this.isChainIdExist(chainId)) {
getLocalChainConfig(chainId: string): Option<SharedChainConfig> {
if (!this.isLocalChainIdExist(chainId)) {
return undefined;
}

return this.chainConfigs[chainId];
return this.localChainConfigs[chainId];
}

updateChainConfig(chainId: string, chainConfig: SharedChainConfig) {
this.chainConfigs[chainId] = chainConfig;
updateLocalChainConfig(chainId: string, chainConfig: SharedChainConfig) {
this.localChainConfigs[chainId] = chainConfig;
}

addChainConfig(chainId: string, chainConfig: SharedChainConfig) {
if (this.isChainIdExist(chainId)) {
addLocalChainConfig(chainId: string, chainConfig: SharedChainConfig) {
if (this.isLocalChainIdExist(chainId)) {
return;
}

this.updateChainConfig(chainId, chainConfig);
this.updateLocalChainConfig(chainId, chainConfig);
}

removeChainConfig(chainId: string) {
delete this.chainConfigs[chainId];
removeLocalChainConfig(chainId: string) {
delete this.localChainConfigs[chainId];
}

isChainIdExist(chainId: string): boolean {
return !!this.chainConfigs[chainId];
isLocalChainIdExist(chainId: string): boolean {
return !!this.localChainConfigs[chainId];
}

isPrettyNameExist(name: string): boolean {
return !!find(this.chainConfigs, { prettyName: name });
isLocalPrettyNameExist(name: string): boolean {
return !!find(this.localChainConfigs, { prettyName: name });
}
}
6 changes: 3 additions & 3 deletions src/lib/stores/root.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AccountStore } from "./account";
import { ChainConfigStore } from "./chain-config";
import { LocalChainConfigStore } from "./chain-config";
import { CodeStore } from "./code";
import { ContractStore } from "./contract";
import { NetworkStore } from "./networks";
Expand All @@ -19,7 +19,7 @@ export class RootStore {

networkStore: NetworkStore;

chainConfigStore: ChainConfigStore;
localChainConfigStore: LocalChainConfigStore;

constructor() {
this.accountStore = new AccountStore();
Expand All @@ -28,6 +28,6 @@ export class RootStore {
this.publicProjectStore = new PublicProjectStore();
this.schemaStore = new SchemaStore();
this.networkStore = new NetworkStore();
this.chainConfigStore = new ChainConfigStore();
this.localChainConfigStore = new LocalChainConfigStore();
}
}