Skip to content

Commit

Permalink
Use new registry [part 1] (#946)
Browse files Browse the repository at this point in the history
* Use new registry

* convert webpack config to .ts

* grpc form refactors

* Make todo clearer
  • Loading branch information
grod220 committed Apr 17, 2024
1 parent 90498a7 commit 61eb7d5
Show file tree
Hide file tree
Showing 17 changed files with 338 additions and 237 deletions.
6 changes: 0 additions & 6 deletions apps/extension/.env

This file was deleted.

4 changes: 4 additions & 0 deletions apps/extension/.env.testnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CHAIN_ID=penumbra-testnet-deimos-6
IDB_VERSION=34
MINIFRONT_URL=https://app.testnet.penumbra.zone
PRAX=lkpmkhpnhknhmibgnmmhdhgdilepfghe
1 change: 1 addition & 0 deletions apps/extension/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
bin
auto-login.ts
9 changes: 7 additions & 2 deletions apps/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
"description": "chrome-extension",
"type": "module",
"scripts": {
"dev": "webpack --watch --mode=development -d inline-source-map",
"dev": "NODE_ENV=testnet pnpm bundle --watch --mode=development -d inline-source-map",
"build": "NODE_ENV=mainnet pnpm bundle",
"clean": "rm -rfv dist bin",
"build": "webpack",
"bundle": "NODE_OPTIONS=\"--import=./src/utils/webpack-register.js\" webpack",
"lint": "eslint \"**/*.ts*\"",
"test": "vitest run"
},
"dependencies": {
"@penumbra-labs/registry": "^2.0.0",
"@penumbra-zone/bech32": "workspace:*",
"@penumbra-zone/client": "workspace:*",
"@penumbra-zone/constants": "workspace:*",
Expand All @@ -36,6 +38,7 @@
"node-fetch": "^3.3.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-loader-spinner": "^6.1.6",
"react-router-dom": "^6.22.3",
"react-use-measure": "^2.1.1",
"usehooks-ts": "^3.0.2",
Expand All @@ -49,6 +52,7 @@
"@types/lodash": "^4.17.0",
"@types/react": "^18.2.72",
"@types/react-dom": "^18.2.22",
"@types/webpack": "^5.28.5",
"autoprefixer": "^10.4.19",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^6.10.0",
Expand All @@ -60,6 +64,7 @@
"style-loader": "^3.3.4",
"tailwindcss": "^3.4.1",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"vite-plugin-top-level-await": "^1.4.1",
"vite-plugin-wasm": "^3.3.0",
"webpack": "^5.91.0",
Expand Down
5 changes: 1 addition & 4 deletions apps/extension/prax.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

declare const PRAX: string;
declare const PRAX_ORIGIN: string;

declare const IDB_VERSION: number;
declare const USDC_ASSET_ID: string;

declare const MINIFRONT_URL: string;
declare const DEFAULT_GRPC_URL: string;
declare const CHAIN_ID: string;
9 changes: 7 additions & 2 deletions apps/extension/src/entry/page-root.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { createRoot } from 'react-dom/client';
import { RouterProvider } from 'react-router-dom';
import { pageRouter } from '../routes/page/router';
import { StrictMode } from 'react';
import { StrictMode, useState } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

import '@penumbra-zone/ui/styles/globals.css';

const MainPage = () => {
const [queryClient] = useState(() => new QueryClient());

return (
<StrictMode>
<RouterProvider router={pageRouter} />
<QueryClientProvider client={queryClient}>
<RouterProvider router={pageRouter} />
</QueryClientProvider>
</StrictMode>
);
};
Expand Down
21 changes: 18 additions & 3 deletions apps/extension/src/hooks/chain-id.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
import { useQuery } from '@tanstack/react-query';
import { viewClient } from '../clients';
import { localExtStorage } from '@penumbra-zone/storage/chrome/local';
import { AppQuerier } from '@penumbra-zone/query/src/queriers/app';

export const getChainId = async (): Promise<string> => {
export const getChainIdWithFallback = async (): Promise<string> => {
// Check storage first to see if available
const grpcEndpoint = await localExtStorage.get('grpcEndpoint');
if (grpcEndpoint) {
const queryClient = new AppQuerier({ grpcEndpoint });
const { chainId } = await queryClient.appParams();
return chainId;
}

// If not, fallback onto the env variable passed in at build time
return CHAIN_ID;
};

const getChainIdViaViewService = async (): Promise<string> => {
const { parameters } = await viewClient.appParameters({});
if (!parameters?.chainId) throw new Error('No chainId in response');

Expand All @@ -11,8 +26,8 @@ export const getChainId = async (): Promise<string> => {
export const useChainIdQuery = () => {
const { data, refetch } = useQuery({
queryKey: ['chain-id'],
queryFn: getChainId,
refetchInterval: false,
queryFn: getChainIdViaViewService,
staleTime: Infinity,
});

return { chainId: data, refetchChainId: refetch };
Expand Down
33 changes: 33 additions & 0 deletions apps/extension/src/hooks/registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useQuery } from '@tanstack/react-query';
import { ChainRegistryClient, Registry, Rpc } from '@penumbra-labs/registry';
import { getChainIdWithFallback } from './chain-id';

const getRegistry = async (): Promise<Registry> => {
const chainId = await getChainIdWithFallback();
const registryClient = new ChainRegistryClient();
return registryClient.get(chainId);
};

export const useRegistry = () => {
return useQuery({
queryKey: ['registry'],
queryFn: async (): Promise<Registry> => {
const chainId = await getChainIdWithFallback();
const registryClient = new ChainRegistryClient();
return registryClient.get(chainId);
},
staleTime: Infinity,
});
};

export const useRpcEndpoints = () => {
return useQuery({
queryKey: ['rpcEndpoints'],
queryFn: async (): Promise<Rpc[]> => {
const { rpcs } = await getRegistry();
return rpcs;
},
staleTime: Infinity,
retry: 1,
});
};
57 changes: 41 additions & 16 deletions apps/extension/src/shared/components/grpc-endpoint-form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Network } from 'lucide-react';
import { useGrpcEndpointForm } from './use-grpc-endpoint-form';
import { ConfirmChangedChainIdDialog } from './confirm-changed-chain-id-dialog';
import { ChainIdOrError } from './chain-id-or-error';
import { LineWave } from 'react-loader-spinner';

/**
* Renders all the parts of the gRPC endpoint form that are shared between the
Expand All @@ -29,6 +30,7 @@ export const GrpcEndpointForm = ({
rpcError,
isSubmitButtonEnabled,
isCustomGrpcEndpoint,
rpcsQuery,
} = useGrpcEndpointForm();
const customGrpcEndpointInput = useRef<HTMLInputElement | null>(null);

Expand All @@ -41,22 +43,36 @@ export const GrpcEndpointForm = ({
<>
<div className='flex flex-col gap-2'>
<form className='flex flex-col gap-4' onSubmit={handleSubmit}>
{rpcsQuery.isLoading && <LoadingIndicator />}
{rpcsQuery.error && (
<div className='text-red-700'>
Error loading chain registry: {String(rpcsQuery.error)}
</div>
)}
<SelectList>
{grpcEndpoints.map(option => (
<SelectList.Option
key={option.url}
label={option.name}
secondary={option.url}
onSelect={setGrpcEndpointInput}
value={option.url}
isSelected={option.url === grpcEndpointInput}
image={
!!option.imageUrl && (
<img src={option.imageUrl} className='size-full object-contain' />
)
}
/>
))}
{rpcsQuery.data &&
grpcEndpoints.map(option => {
const imageUrl = option.images[0]?.png ?? option.images[0]?.svg;
return (
<SelectList.Option
key={option.url}
label={option.name}
secondary={option.url}
onSelect={setGrpcEndpointInput}
value={option.url}
isSelected={option.url === grpcEndpointInput}
image={
!!imageUrl && (
<img
src={imageUrl}
className='size-full object-contain'
alt='rpc endpoint brand image'
/>
)
}
/>
);
})}

<SelectList.Option
label='Custom RPC'
Expand All @@ -79,7 +95,7 @@ export const GrpcEndpointForm = ({
</SelectList>

<a
href='https://github.com/penumbra-zone/web/blob/main/packages/constants/src/grpc-endpoints.ts'
href='https://github.com/prax-wallet/registry'
target='_blank'
rel='noreferrer'
className='block text-right text-xs text-muted-foreground'
Expand All @@ -103,3 +119,12 @@ export const GrpcEndpointForm = ({
</>
);
};

const LoadingIndicator = () => {
return (
<div className='flex gap-2'>
<span>Loading rpcs from registry</span>
<LineWave visible={true} height='70' width='70' color='white' wrapperClass='-mt-9' />
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import { AllSlices } from '../../../state';
import { useStoreShallow } from '../../../utils/use-store-shallow';
import { ServicesMessage } from '@penumbra-zone/types/src/services';
import { GRPC_ENDPOINTS } from '@penumbra-zone/constants/src/grpc-endpoints';
import debounce from 'lodash/debounce';
import { PromiseWithResolvers } from '@penumbra-zone/polyfills/src/Promise.withResolvers';
import { useRpcEndpoints } from '../../../hooks/registry';

const randomSort = () => (Math.random() >= 0.5 ? 1 : -1);

Expand All @@ -26,20 +26,24 @@ const isValidUrl = (url: string) => {
};

export const useGrpcEndpointForm = () => {
// Fetch latest rpc list from registry
const rpcsQuery = useRpcEndpoints();
const grpcEndpoints = useMemo(() => (rpcsQuery.data ?? []).toSorted(randomSort), [rpcsQuery]);

// Get the rpc set in storage (if present)
const { grpcEndpoint, setGrpcEndpoint } = useStoreShallow(useSaveGrpcEndpointSelector);

const [originalChainId, setOriginalChainId] = useState<string | undefined>();
const [chainId, setChainId] = useState<string>();
const grpcEndpoints = useMemo(() => [...GRPC_ENDPOINTS].sort(randomSort), []);
const { grpcEndpoint, setGrpcEndpoint } = useStoreShallow(useSaveGrpcEndpointSelector);
const [grpcEndpointInput, setGrpcEndpointInput] = useState<string>(
grpcEndpoint ?? grpcEndpoints[0]?.url ?? '',
);
const [grpcEndpointInput, setGrpcEndpointInput] = useState<string>('');
const [rpcError, setRpcError] = useState<string>();
const [isSubmitButtonEnabled, setIsSubmitButtonEnabled] = useState(false);
const [confirmChangedChainIdPromise, setConfirmChangedChainIdPromise] = useState<
PromiseWithResolvers<void> | undefined
>();

const isCustomGrpcEndpoint = !GRPC_ENDPOINTS.some(({ url }) => url === grpcEndpointInput);
const isCustomGrpcEndpoint =
grpcEndpointInput !== '' && !grpcEndpoints.some(({ url }) => url === grpcEndpointInput);

const setGrpcEndpointInputOnLoadFromState = useCallback(() => {
if (grpcEndpoint) setGrpcEndpointInput(grpcEndpoint);
Expand Down Expand Up @@ -149,5 +153,6 @@ export const useGrpcEndpointForm = () => {
onSubmit,
isSubmitButtonEnabled,
isCustomGrpcEndpoint,
rpcsQuery,
};
};
1 change: 0 additions & 1 deletion apps/extension/src/utils/.gitignore

This file was deleted.

4 changes: 4 additions & 0 deletions apps/extension/src/utils/webpack-register.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { register } from 'node:module';
import { pathToFileURL } from 'node:url';

register('ts-node/esm', pathToFileURL('./'));
Loading

0 comments on commit 61eb7d5

Please sign in to comment.