Fix problems with delivery checking

Hide IGP debug errors for PI chains
Update react-query lib
Remove unused wagmi and rainbowkit libs
pull/73/head
J M Rossy 7 months ago
parent 84a9a3420a
commit b6baaa1e5e
  1. 4
      package.json
  2. 28
      src/features/debugger/debugMessage.ts
  3. 7
      src/features/deliveryStatus/fetchDeliveryStatus.ts
  4. 117
      src/features/deliveryStatus/useMessageDeliveryStatus.tsx
  5. 15
      src/features/messages/MessageDetails.tsx
  6. 18
      src/features/messages/cards/TransactionCard.tsx
  7. 17
      src/features/messages/ica.ts
  8. 38
      src/features/messages/pi-queries/usePiChainMessageQuery.ts
  9. 4
      src/features/messages/queries/useMessageQuery.ts
  10. 40
      src/pages/_app.tsx
  11. 20
      src/store.ts
  12. 2135
      yarn.lock

@ -10,8 +10,7 @@
"@hyperlane-xyz/utils": "3.11.1", "@hyperlane-xyz/utils": "3.11.1",
"@hyperlane-xyz/widgets": "3.8.0", "@hyperlane-xyz/widgets": "3.8.0",
"@metamask/jazzicon": "https://github.com/jmrossy/jazzicon#7a8df28974b4e81129bfbe3cab76308b889032a6", "@metamask/jazzicon": "https://github.com/jmrossy/jazzicon#7a8df28974b4e81129bfbe3cab76308b889032a6",
"@rainbow-me/rainbowkit": "0.12.16", "@tanstack/react-query": "^5.35.5",
"@tanstack/react-query": "^4.24.10",
"bignumber.js": "^9.1.2", "bignumber.js": "^9.1.2",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"ethers": "^5.7.2", "ethers": "^5.7.2",
@ -24,7 +23,6 @@
"react-toastify": "^9.1.1", "react-toastify": "^9.1.1",
"react-tooltip": "^5.26.3", "react-tooltip": "^5.26.3",
"urql": "^3.0.3", "urql": "^3.0.3",
"wagmi": "0.12.18",
"zod": "^3.21.2", "zod": "^3.21.2",
"zustand": "4.3.8" "zustand": "4.3.8"
}, },

@ -31,6 +31,7 @@ import { GasPayment, IsmModuleTypes, MessageDebugResult, MessageDebugStatus } fr
type Provider = providers.Provider; type Provider = providers.Provider;
const HANDLE_FUNCTION_SIG = 'handle(uint32,bytes32,bytes)'; const HANDLE_FUNCTION_SIG = 'handle(uint32,bytes32,bytes)';
const IGP_PAYMENT_CHECK_DELAY = 30_000; // 30 seconds
export async function debugMessage( export async function debugMessage(
multiProvider: MultiProvider, multiProvider: MultiProvider,
@ -41,10 +42,12 @@ export async function debugMessage(
nonce, nonce,
sender, sender,
recipient, recipient,
origin,
originDomainId: originDomain, originDomainId: originDomain,
destinationDomainId: destDomain, destinationDomainId: destDomain,
body, body,
totalGasAmount, totalGasAmount,
isPiMsg,
}: Message, }: Message,
): Promise<MessageDebugResult> { ): Promise<MessageDebugResult> {
logger.debug(`Debugging message id: ${msgId}`); logger.debug(`Debugging message id: ${msgId}`);
@ -95,15 +98,21 @@ export async function debugMessage(
if (ismCheckResult.status && ismCheckResult.description) return { ...ismCheckResult, ...details }; if (ismCheckResult.status && ismCheckResult.description) return { ...ismCheckResult, ...details };
else details.ismDetails = ismCheckResult.ismDetails; else details.ismDetails = ismCheckResult.ismDetails;
const gasCheckResult = await tryCheckIgpGasFunded( // TODO support for non-default IGP gas checks here
msgId, // Disabling for now for https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/3668
originProvider, // Also skipping if the message is still very new otherwise this raises premature
deliveryResult.gasEstimate, // underfunded errors when in fact payment was made
totalGasAmount, if (!isPiMsg && Date.now() - origin.timestamp > IGP_PAYMENT_CHECK_DELAY) {
); const gasCheckResult = await tryCheckIgpGasFunded(
if (gasCheckResult?.status && gasCheckResult?.description) msgId,
return { ...gasCheckResult, ...details }; originProvider,
else details.gasDetails = gasCheckResult?.gasDetails; deliveryResult.gasEstimate,
totalGasAmount,
);
if (gasCheckResult?.status && gasCheckResult?.description)
return { ...gasCheckResult, ...details };
else details.gasDetails = gasCheckResult?.gasDetails;
}
logger.debug(`No errors found debugging message id: ${msgId}`); logger.debug(`No errors found debugging message id: ${msgId}`);
return { return {
@ -243,6 +252,7 @@ async function tryCheckIgpGasFunded(
logger.warn('No gas estimate provided, skipping IGP check'); logger.warn('No gas estimate provided, skipping IGP check');
return null; return null;
} }
try { try {
let gasAlreadyFunded = BigNumber.from(0); let gasAlreadyFunded = BigNumber.from(0);
let gasDetails: MessageDebugResult['gasDetails'] = { let gasDetails: MessageDebugResult['gasDetails'] = {

@ -19,6 +19,8 @@ import {
MessageDeliverySuccessResult, MessageDeliverySuccessResult,
} from './types'; } from './types';
const DELIVERY_LOG_CHECK_BLOCK_RANGE = 1000;
export async function fetchDeliveryStatus( export async function fetchDeliveryStatus(
multiProvider: MultiProvider, multiProvider: MultiProvider,
registry: IRegistry, registry: IRegistry,
@ -92,7 +94,8 @@ async function checkIsMessageDelivered(
// Try finding logs first as they have more info // Try finding logs first as they have more info
try { try {
logger.debug(`Searching for process logs for msgId ${msgId}`); logger.debug(`Searching for process logs for msgId ${msgId}`);
const logs = await mailbox.queryFilter(mailbox.filters.ProcessId(msgId)); const fromBlock = (await provider.getBlockNumber()) - DELIVERY_LOG_CHECK_BLOCK_RANGE;
const logs = await mailbox.queryFilter(mailbox.filters.ProcessId(msgId), fromBlock, 'latest');
if (logs?.length) { if (logs?.length) {
logger.debug(`Found process log for ${msgId}}`); logger.debug(`Found process log for ${msgId}}`);
const log = logs[0]; // Should only be 1 log per message delivery const log = logs[0]; // Should only be 1 log per message delivery
@ -109,7 +112,7 @@ async function checkIsMessageDelivered(
// Logs are unreliable so check the mailbox itself as a fallback // Logs are unreliable so check the mailbox itself as a fallback
logger.debug(`Querying mailbox about msgId ${msgId}`); logger.debug(`Querying mailbox about msgId ${msgId}`);
const isDelivered = await mailbox.delivered(msgId); const isDelivered = await mailbox.delivered(msgId);
logger.debug(`Mailbox delivery status for ${msgId}: ${isDelivered}}`); logger.debug(`Mailbox delivery status for ${msgId}: ${isDelivered}`);
return { isDelivered }; return { isDelivered };
} }

@ -1,10 +1,11 @@
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useEffect, useMemo } from 'react'; import { useEffect } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { MultiProvider } from '@hyperlane-xyz/sdk';
import { errorToString } from '@hyperlane-xyz/utils'; import { errorToString } from '@hyperlane-xyz/utils';
import { useMultiProvider, useRegistry } from '../../store'; import { useReadyMultiProvider, useRegistry } from '../../store';
import { Message, MessageStatus } from '../../types'; import { Message, MessageStatus } from '../../types';
import { logger } from '../../utils/logger'; import { logger } from '../../utils/logger';
import { MissingChainConfigToast } from '../chains/MissingChainConfigToast'; import { MissingChainConfigToast } from '../chains/MissingChainConfigToast';
@ -12,46 +13,70 @@ import { useChainConfigs } from '../chains/useChainConfigs';
import { fetchDeliveryStatus } from './fetchDeliveryStatus'; import { fetchDeliveryStatus } from './fetchDeliveryStatus';
export function useMessageDeliveryStatus({ message, pause }: { message: Message; pause: boolean }) { export function useMessageDeliveryStatus({
message,
enabled = true,
}: {
message: Message;
enabled: boolean;
}) {
const chainConfigs = useChainConfigs(); const chainConfigs = useChainConfigs();
const multiProvider = useMultiProvider(); const multiProvider = useReadyMultiProvider();
const registry = useRegistry(); const registry = useRegistry();
const serializedMessage = JSON.stringify(message); const { data, error, isFetching } = useQuery({
const { data, error, isFetching } = useQuery( queryKey: ['messageDeliveryStatus', message, !!multiProvider],
['messageDeliveryStatus', serializedMessage, pause], queryFn: async () => {
async () => { if (!multiProvider || message.status == MessageStatus.Delivered) {
if (pause || !message || message.status === MessageStatus.Delivered) return null; return { message };
}
const { id, originChainId, originDomainId, destinationChainId, destinationDomainId } =
message;
if (!multiProvider.tryGetChainMetadata(message.originChainId)) { if (
toast.error( !checkHasChain(multiProvider, originChainId, originDomainId) ||
<MissingChainConfigToast !checkHasChain(multiProvider, destinationChainId, destinationDomainId)
chainId={message.originChainId} ) {
domainId={message.originDomainId} return { message };
/>,
);
return null;
} else if (!multiProvider.tryGetChainMetadata(message.destinationChainId)) {
toast.error(
<MissingChainConfigToast
chainId={message.destinationChainId}
domainId={message.destinationDomainId}
/>,
);
return null;
} }
logger.debug('Fetching message delivery status for:', message.id); logger.debug('Fetching message delivery status for:', id);
const deliverStatus = await fetchDeliveryStatus( const deliverStatus = await fetchDeliveryStatus(
multiProvider, multiProvider,
registry, registry,
chainConfigs, chainConfigs,
message, message,
); );
return deliverStatus;
if (deliverStatus.status === MessageStatus.Delivered) {
return {
message: {
...message,
status: MessageStatus.Delivered,
destination: deliverStatus.deliveryTransaction,
},
};
} else if (
deliverStatus.status === MessageStatus.Failing ||
deliverStatus.status === MessageStatus.Pending
) {
return {
message: {
...message,
status: deliverStatus.status,
},
debugResult: deliverStatus.debugResult,
};
} else {
return { message };
}
}, },
{ retry: false }, retry: false,
); refetchInterval: (query) =>
query.state.data?.message.status === MessageStatus.Delivered ? false : 10_000,
enabled,
});
// Show toast on error // Show toast on error
useEffect(() => { useEffect(() => {
@ -61,27 +86,17 @@ export function useMessageDeliveryStatus({ message, pause }: { message: Message;
} }
}, [error]); }, [error]);
const [messageWithDeliveryStatus, debugResult] = useMemo(() => { return {
if (data?.status === MessageStatus.Delivered) { messageWithDeliveryStatus: data?.message || message,
return [ debugResult: data?.debugResult,
{ isDeliveryStatusFetching: isFetching,
...message, };
status: MessageStatus.Delivered, }
destination: data.deliveryTransaction,
},
];
} else if (data?.status === MessageStatus.Failing || data?.status === MessageStatus.Pending) {
return [
{
...message,
status: data.status,
},
data.debugResult,
];
} else {
return [message];
}
}, [message, data]);
return { messageWithDeliveryStatus, debugResult, isDeliveryStatusFetching: isFetching }; function checkHasChain(multiProvider: MultiProvider, chainId: ChainId, domainId: number) {
if (!multiProvider.hasChain(chainId)) {
toast.error(<MissingChainConfigToast chainId={chainId} domainId={domainId} />);
return false;
}
return true;
} }

@ -1,5 +1,5 @@
import Image from 'next/image'; import Image from 'next/image';
import { useEffect, useState } from 'react'; import { useEffect } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { toTitleCase, trimToLength } from '@hyperlane-xyz/utils'; import { toTitleCase, trimToLength } from '@hyperlane-xyz/utils';
@ -32,10 +32,6 @@ interface Props {
export function MessageDetails({ messageId, message: messageFromUrlParams }: Props) { export function MessageDetails({ messageId, message: messageFromUrlParams }: Props) {
const multiProvider = useMultiProvider(); const multiProvider = useMultiProvider();
// Needed to force pause of message query if the useMessageDeliveryStatus
// Hook finds a delivery record on it's own
const [deliveryFound, setDeliveryFound] = useState(false);
// GraphQL query and results // GraphQL query and results
const { const {
isFetching: isGraphQlFetching, isFetching: isGraphQlFetching,
@ -43,7 +39,7 @@ export function MessageDetails({ messageId, message: messageFromUrlParams }: Pro
hasRun: hasGraphQlRun, hasRun: hasGraphQlRun,
isMessageFound: isGraphQlMessageFound, isMessageFound: isGraphQlMessageFound,
message: messageFromGraphQl, message: messageFromGraphQl,
} = useMessageQuery({ messageId, pause: !!messageFromUrlParams || deliveryFound }); } = useMessageQuery({ messageId, pause: !!messageFromUrlParams });
// Run permissionless interop chains query if needed // Run permissionless interop chains query if needed
const { const {
@ -73,7 +69,7 @@ export function MessageDetails({ messageId, message: messageFromUrlParams }: Pro
isDeliveryStatusFetching, isDeliveryStatusFetching,
} = useMessageDeliveryStatus({ } = useMessageDeliveryStatus({
message: _message, message: _message,
pause: !isMessageFound, enabled: isMessageFound,
}); });
const { const {
@ -87,11 +83,6 @@ export function MessageDetails({ messageId, message: messageFromUrlParams }: Pro
destination, destination,
} = message; } = message;
// Mark delivery found to prevent pause queries
useEffect(() => {
if (status === MessageStatus.Delivered) setDeliveryFound(true);
}, [status]);
// Banner color setter // Banner color setter
useDynamicBannerColor(isFetching, status, isMessageFound, isError || isPiError); useDynamicBannerColor(isFetching, status, isMessageFound, isError || isPiError);

@ -212,14 +212,16 @@ function TransactionDetails({
showCopy={true} showCopy={true}
blurValue={blur} blurValue={blur}
/> />
<KeyValueRow {!!timestamp && (
label="Time:" <KeyValueRow
labelWidth="w-16" label="Time:"
display={getHumanReadableTimeString(timestamp)} labelWidth="w-16"
subDisplay={`(${getDateTimeString(timestamp)})`} display={getHumanReadableTimeString(timestamp)}
displayWidth="w-60 sm:w-64" subDisplay={`(${getDateTimeString(timestamp)})`}
blurValue={blur} displayWidth="w-60 sm:w-64"
/> blurValue={blur}
/>
)}
<KeyValueRow <KeyValueRow
label="Block:" label="Block:"
labelWidth="w-16" labelWidth="w-16"

@ -5,7 +5,7 @@ import { useMemo } from 'react';
import { InterchainAccountRouter__factory } from '@hyperlane-xyz/core'; import { InterchainAccountRouter__factory } from '@hyperlane-xyz/core';
import { eqAddress, isValidAddress } from '@hyperlane-xyz/utils'; import { eqAddress, isValidAddress } from '@hyperlane-xyz/utils';
import { useMultiProvider } from '../../store'; import { useReadyMultiProvider } from '../../store';
import { logger } from '../../utils/logger'; import { logger } from '../../utils/logger';
// This assumes all chains have the same ICA address // This assumes all chains have the same ICA address
@ -98,15 +98,16 @@ export async function tryFetchIcaAddress(
} }
export function useIcaAddress(originDomainId: DomainId, sender?: Address | null) { export function useIcaAddress(originDomainId: DomainId, sender?: Address | null) {
const multiProvider = useMultiProvider(); const multiProvider = useReadyMultiProvider();
return useQuery( return useQuery({
['useIcaAddress', originDomainId, sender], queryKey: ['useIcaAddress', originDomainId, sender, !!multiProvider],
() => { queryFn: () => {
if (!originDomainId || !sender || BigNumber.from(sender).isZero()) return null; if (!originDomainId || !multiProvider || !sender || BigNumber.from(sender).isZero())
return null;
const provider = multiProvider.tryGetProvider(originDomainId); const provider = multiProvider.tryGetProvider(originDomainId);
if (!provider) return null; if (!provider) return null;
return tryFetchIcaAddress(originDomainId, sender, provider); return tryFetchIcaAddress(originDomainId, sender, provider);
}, },
{ retry: false }, retry: false,
); });
} }

@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import { MultiProvider } from '@hyperlane-xyz/sdk'; import { MultiProvider } from '@hyperlane-xyz/sdk';
import { ensure0x } from '@hyperlane-xyz/utils'; import { ensure0x } from '@hyperlane-xyz/utils';
import { useMultiProvider } from '../../../store'; import { useReadyMultiProvider } from '../../../store';
import { Message } from '../../../types'; import { Message } from '../../../types';
import { logger } from '../../../utils/logger'; import { logger } from '../../../utils/logger';
import { ChainConfig } from '../../chains/chainConfig'; import { ChainConfig } from '../../chains/chainConfig';
@ -26,20 +26,28 @@ export function usePiChainMessageSearchQuery({
pause: boolean; pause: boolean;
}) { }) {
const chainConfigs = useChainConfigs(); const chainConfigs = useChainConfigs();
const multiProvider = useMultiProvider(); const multiProvider = useReadyMultiProvider();
const { isLoading, isError, data } = useQuery( const { isLoading, isError, data } = useQuery({
[ queryKey: [
'usePiChainMessageSearchQuery', 'usePiChainMessageSearchQuery',
chainConfigs, chainConfigs,
sanitizedInput, sanitizedInput,
startTimeFilter, startTimeFilter,
endTimeFilter, endTimeFilter,
!!multiProvider,
pause, pause,
], ],
async () => { queryFn: async () => {
const hasInput = !!sanitizedInput; const hasInput = !!sanitizedInput;
const isValidInput = isValidSearchQuery(sanitizedInput, true); const isValidInput = isValidSearchQuery(sanitizedInput, true);
if (pause || !hasInput || !isValidInput || !Object.keys(chainConfigs).length) return []; if (
pause ||
!multiProvider ||
!hasInput ||
!isValidInput ||
!Object.keys(chainConfigs).length
)
return [];
logger.debug('Starting PI Chain message search for:', sanitizedInput); logger.debug('Starting PI Chain message search for:', sanitizedInput);
// TODO convert timestamps to from/to blocks here // TODO convert timestamps to from/to blocks here
const query = { input: ensure0x(sanitizedInput) }; const query = { input: ensure0x(sanitizedInput) };
@ -53,8 +61,8 @@ export function usePiChainMessageSearchQuery({
return []; return [];
} }
}, },
{ retry: false }, retry: false,
); });
return { return {
isFetching: isLoading, isFetching: isLoading,
@ -73,11 +81,11 @@ export function usePiChainMessageQuery({
pause: boolean; pause: boolean;
}) { }) {
const chainConfigs = useChainConfigs(); const chainConfigs = useChainConfigs();
const multiProvider = useMultiProvider(); const multiProvider = useReadyMultiProvider();
const { isLoading, isError, data } = useQuery( const { isLoading, isError, data } = useQuery({
['usePiChainMessageQuery', chainConfigs, messageId, pause], queryKey: ['usePiChainMessageQuery', chainConfigs, messageId, !!multiProvider, pause],
async () => { queryFn: async () => {
if (pause || !messageId || !Object.keys(chainConfigs).length) return []; if (pause || !multiProvider || !messageId || !Object.keys(chainConfigs).length) return [];
logger.debug('Starting PI Chain message query for:', messageId); logger.debug('Starting PI Chain message query for:', messageId);
const query = { input: ensure0x(messageId) }; const query = { input: ensure0x(messageId) };
try { try {
@ -92,8 +100,8 @@ export function usePiChainMessageQuery({
return []; return [];
} }
}, },
{ retry: false }, retry: false,
); });
const message = data?.length ? data[0] : null; const message = data?.length ? data[0] : null;
const isMessageFound = !!message; const isMessageFound = !!message;

@ -14,8 +14,8 @@ import {
import { MessagesQueryResult, MessagesStubQueryResult } from '../queries/fragments'; import { MessagesQueryResult, MessagesStubQueryResult } from '../queries/fragments';
import { parseMessageQueryResult, parseMessageStubResult } from '../queries/parse'; import { parseMessageQueryResult, parseMessageStubResult } from '../queries/parse';
const SEARCH_AUTO_REFRESH_DELAY = 15000; const SEARCH_AUTO_REFRESH_DELAY = 15_000; // 15s
const MSG_AUTO_REFRESH_DELAY = 10000; const MSG_AUTO_REFRESH_DELAY = 10_000; // 10s
const LATEST_QUERY_LIMIT = 20; const LATEST_QUERY_LIMIT = 20;
const SEARCH_QUERY_LIMIT = 50; const SEARCH_QUERY_LIMIT = 50;

@ -1,10 +1,3 @@
// import {
// RainbowKitProvider,
// connectorsForWallets,
// lightTheme,
// wallet,
// } from '@rainbow-me/rainbowkit';
// import '@rainbow-me/rainbowkit/styles.css';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { AppProps } from 'next/app'; import type { AppProps } from 'next/app';
import { ToastContainer, Zoom, toast } from 'react-toastify'; import { ToastContainer, Zoom, toast } from 'react-toastify';
@ -14,8 +7,6 @@ import { Provider as UrqlProvider, createClient as createUrqlClient } from 'urql
import '@hyperlane-xyz/widgets/styles.css'; import '@hyperlane-xyz/widgets/styles.css';
// import { WagmiConfig, configureChains, createClient as createWagmiClient } from 'wagmi';
// import { publicProvider } from 'wagmi/providers/public';
import { ErrorBoundary } from '../components/errors/ErrorBoundary'; import { ErrorBoundary } from '../components/errors/ErrorBoundary';
import { AppLayout } from '../components/layout/AppLayout'; import { AppLayout } from '../components/layout/AppLayout';
import { config } from '../consts/config'; import { config } from '../consts/config';
@ -24,26 +15,6 @@ import '../styles/fonts.css';
import '../styles/global.css'; import '../styles/global.css';
import { useIsSsr } from '../utils/ssr'; import { useIsSsr } from '../utils/ssr';
// const { chains, provider } = configureChains(prodAndTestChains, [publicProvider()]);
// const connectors = connectorsForWallets([
// {
// groupName: 'Recommended',
// wallets: [
// wallet.metaMask({ chains }),
// wallet.walletConnect({ chains }),
// wallet.rainbow({ chains }),
// wallet.steak({ chains }),
// ],
// },
// ]);
// const wagmiClient = createWagmiClient({
// autoConnect: false, // TODO
// provider,
// connectors,
// });
const urqlClient = createUrqlClient({ const urqlClient = createUrqlClient({
url: config.apiUrl, url: config.apiUrl,
}); });
@ -66,15 +37,6 @@ export default function App({ Component, router, pageProps }: AppProps) {
return ( return (
<ErrorBoundary> <ErrorBoundary>
{/* <WagmiConfig client={wagmiClient}> */}
{/* <RainbowKitProvider
chains={chains}
theme={lightTheme({
accentColor: Color.primaryRed,
borderRadius: 'small',
fontStack: 'system',
})}
> */}
<QueryClientProvider client={reactQueryClient}> <QueryClientProvider client={reactQueryClient}>
<UrqlProvider value={urqlClient}> <UrqlProvider value={urqlClient}>
<ChainConfigSyncer> <ChainConfigSyncer>
@ -86,8 +48,6 @@ export default function App({ Component, router, pageProps }: AppProps) {
</QueryClientProvider> </QueryClientProvider>
<ToastContainer transition={Zoom} position={toast.POSITION.BOTTOM_RIGHT} limit={2} /> <ToastContainer transition={Zoom} position={toast.POSITION.BOTTOM_RIGHT} limit={2} />
<Tooltip id="root-tooltip" className="z-50" /> <Tooltip id="root-tooltip" className="z-50" />
{/* </RainbowKitProvider> */}
{/* </WagmiConfig> */}
</ErrorBoundary> </ErrorBoundary>
); );
} }

@ -29,14 +29,17 @@ export const useStore = create<AppState>()(
chainConfigs: {}, chainConfigs: {},
setChainConfigs: async (configs: ChainMap<ChainConfig>) => { setChainConfigs: async (configs: ChainMap<ChainConfig>) => {
const multiProvider = await buildMultiProvider(get().registry, configs); const multiProvider = await buildMultiProvider(get().registry, configs);
console.log('setChainConfigs');
set({ chainConfigs: configs, multiProvider }); set({ chainConfigs: configs, multiProvider });
}, },
multiProvider: new MultiProvider({}), multiProvider: new MultiProvider({}),
setMultiProvider: (multiProvider: MultiProvider) => { setMultiProvider: (multiProvider: MultiProvider) => {
console.log('setMultiProvider');
set({ multiProvider }); set({ multiProvider });
}, },
registry: new GithubRegistry(), registry: new GithubRegistry(),
setRegistry: (registry: IRegistry) => { setRegistry: (registry: IRegistry) => {
console.log('setRegistry');
set({ registry }); set({ registry });
}, },
bannerClassName: '', bannerClassName: '',
@ -54,7 +57,10 @@ export const useStore = create<AppState>()(
return; return;
} }
buildMultiProvider(state.registry, state.chainConfigs) buildMultiProvider(state.registry, state.chainConfigs)
.then((mp) => state.setMultiProvider(mp)) .then((mp) => {
state.setMultiProvider(mp);
logger.debug('Rehydration complete');
})
.catch((e) => logger.error('Error building MultiProvider', e)); .catch((e) => logger.error('Error building MultiProvider', e));
}; };
}, },
@ -62,12 +68,20 @@ export const useStore = create<AppState>()(
), ),
); );
export function useRegistry() {
return useStore((s) => s.registry);
}
export function useMultiProvider() { export function useMultiProvider() {
return useStore((s) => s.multiProvider); return useStore((s) => s.multiProvider);
} }
export function useRegistry() { // Ensures that the multiProvider has been populated during the onRehydrateStorage hook above,
return useStore((s) => s.registry); // otherwise returns undefined
export function useReadyMultiProvider() {
const multiProvider = useMultiProvider();
if (multiProvider.getKnownChainNames().length === 0) return undefined;
return multiProvider;
} }
async function buildMultiProvider(registry: IRegistry, customChainConfigs: ChainMap<ChainConfig>) { async function buildMultiProvider(registry: IRegistry, customChainConfigs: ChainMap<ChainConfig>) {

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save