ECO-258: Log error to DD (#769)

* Log error to DD in prod

* log error

* add context
This commit is contained in:
Léo Galley
2024-07-31 20:32:04 -04:00
committed by GitHub
parent bd819d7a9f
commit ceb87dc60f
21 changed files with 214 additions and 92 deletions

View File

@@ -1,3 +1,4 @@
import ErrorsProvider from 'apps/web/contexts/Errors';
import UsernameNav from 'apps/web/src/components/Layout/UsernameNav';
import type { Metadata } from 'next';
@@ -25,9 +26,11 @@ export default async function BasenameLayout({
children: React.ReactNode;
}) {
return (
<div className="max-w-screen flex min-h-screen flex-col">
<UsernameNav />
{children}
</div>
<ErrorsProvider context="basenames">
<div className="max-w-screen flex min-h-screen flex-col">
<UsernameNav />
{children}
</div>
</ErrorsProvider>
);
}

View File

@@ -9,6 +9,7 @@ import { redirect } from 'next/navigation';
import classNames from 'classnames';
import { BaseName } from '@coinbase/onchainkit/identity';
import UsernameProfile from 'apps/web/src/components/Basenames/UsernameProfile';
import ErrorsProvider from 'apps/web/contexts/Errors';
type UsernameProfileProps = {
params: { username: BaseName };
@@ -49,10 +50,12 @@ export default async function Username({ params }: UsernameProfileProps) {
);
return (
<ProfileProviders username={username} address={ensAddress}>
<main className={usernameProfilePageClasses}>
<UsernameProfile />
</main>
</ProfileProviders>
<ErrorsProvider context="profile">
<ProfileProviders username={username} address={ensAddress}>
<main className={usernameProfilePageClasses}>
<UsernameProfile />
</main>
</ProfileProviders>
</ErrorsProvider>
);
}

View File

@@ -1,4 +1,5 @@
import RegistrationProviders from 'apps/web/app/(basenames)/names/RegistrationProviders';
import ErrorsProvider from 'apps/web/contexts/Errors';
import RegistrationFlow from 'apps/web/src/components/Basenames/RegistrationFlow';
import type { Metadata } from 'next';
import { Suspense } from 'react';
@@ -16,10 +17,12 @@ export const metadata: Metadata = {
export default async function Page() {
return (
<RegistrationProviders>
<Suspense>
<RegistrationFlow />
</Suspense>
</RegistrationProviders>
<ErrorsProvider context="registration">
<RegistrationProviders>
<Suspense>
<RegistrationFlow />
</Suspense>
</RegistrationProviders>
</ErrorsProvider>
);
}

View File

@@ -27,6 +27,8 @@ import { base, baseSepolia } from 'wagmi/chains';
import { cookieManagerConfig } from '../src/utils/cookieManagerConfig';
import ClientAnalyticsScript from 'apps/web/src/components/ClientAnalyticsScript/ClientAnalyticsScript';
import dynamic from 'next/dynamic';
import ErrorsProvider from 'apps/web/contexts/Errors';
import { isDevelopment } from 'apps/web/src/constants';
const DynamicCookieBannerWrapper = dynamic(
async () => import('apps/web/src/components/CookieBannerWrapper'),
@@ -102,42 +104,42 @@ export default function AppProviders({ children }: AppProvidersProps) {
const handleLogError = useCallback((err: Error) => console.error(err), []);
const isDevelopment = process.env.NODE_ENV === 'development';
useSprig(sprigEnvironmentId);
return (
<CookieManagerProvider
projectName="base_web"
locale="en"
region={Region.DEFAULT}
log={console.log}
onError={handleLogError}
onPreferenceChange={setTrackingPreference}
config={cookieManagerConfig}
>
<MotionConfig reducedMotion="user">
<ClientAnalyticsScript />
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<OnchainKitProvider
chain={isDevelopment ? baseSepolia : base}
apiKey={process.env.NEXT_PUBLIC_ONCHAINKIT_API_KEY}
>
<RainbowKitProvider modalSize="compact">
<TooltipProvider>
<ExperimentsProvider>
<>
{children}
<DynamicCookieBannerWrapper />
</>
</ExperimentsProvider>
</TooltipProvider>
</RainbowKitProvider>
</OnchainKitProvider>
</QueryClientProvider>
</WagmiProvider>
</MotionConfig>
</CookieManagerProvider>
<ErrorsProvider context="web">
<CookieManagerProvider
projectName="base_web"
locale="en"
region={Region.DEFAULT}
log={console.log}
onError={handleLogError}
onPreferenceChange={setTrackingPreference}
config={cookieManagerConfig}
>
<MotionConfig reducedMotion="user">
<ClientAnalyticsScript />
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<OnchainKitProvider
chain={isDevelopment ? baseSepolia : base}
apiKey={process.env.NEXT_PUBLIC_ONCHAINKIT_API_KEY}
>
<RainbowKitProvider modalSize="compact">
<TooltipProvider>
<ExperimentsProvider>
<>
{children}
<DynamicCookieBannerWrapper />
</>
</ExperimentsProvider>
</TooltipProvider>
</RainbowKitProvider>
</OnchainKitProvider>
</QueryClientProvider>
</WagmiProvider>
</MotionConfig>
</CookieManagerProvider>
</ErrorsProvider>
);
}

View File

@@ -2,11 +2,11 @@
'use client';
import { datadogRum } from '@datadog/browser-rum';
import { isDevelopment } from 'apps/web/src/constants';
import { useEffect } from 'react';
const nextPublicDatadogAppId = process.env.NEXT_PUBLIC_DATADOG_APP_ID ?? '';
const nextPublicDatadogClientToken = process.env.NEXT_PUBLIC_DATADOG_CLIENT_TOKEN ?? '';
const isDevelopment = process.env.NODE_ENV === 'development';
export default function DatadogInit() {
useEffect(() => {

View File

@@ -0,0 +1,57 @@
'use client';
import { datadogRum } from '@datadog/browser-rum';
import { isDevelopment } from 'apps/web/src/constants';
import { ReactNode, createContext, useCallback, useContext, useMemo } from 'react';
export type ErrorsContextProps = {
logError: (error: unknown, message: string) => void;
fullContext: string;
};
export const ErrorsContext = createContext<ErrorsContextProps>({
logError: function () {
return undefined;
},
fullContext: '',
});
export function useErrors() {
const context = useContext(ErrorsContext);
if (context === undefined) {
throw new Error('useErrors must be used within a ErrorsProvider');
}
return context;
}
type ErrorsProviderProps = {
children?: ReactNode;
context: string;
};
export default function ErrorsProvider({ children, context }: ErrorsProviderProps) {
const { fullContext: previousContext } = useErrors();
const fullContext = [previousContext, context].filter((c) => !!c).join('_');
const logError = useCallback(
(error: unknown, message: string) => {
if (isDevelopment) {
console.log('\n--------------------------------------');
console.info(`Error caught with message: "${message}"`);
console.error(error);
console.info(`Context: "${fullContext}"`);
console.log('--------------------------------------\n');
return;
}
datadogRum.addError(error, { context: fullContext, message: message });
},
[fullContext],
);
const values = useMemo(() => {
return { logError, context, fullContext };
}, [context, fullContext, logError]);
return <ErrorsContext.Provider value={values}>{children}</ErrorsContext.Provider>;
}

View File

@@ -7,6 +7,7 @@ import { namehash } from 'viem';
import { getBasenamePublicClient } from 'apps/web/src/hooks/useBasenameChain';
import L2ResolverAbi from 'apps/web/src/abis/L2Resolver';
import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames';
import { isDevelopment } from 'apps/web/src/constants';
const emojiCache: Record<string, Promise<string>> = {};
@@ -33,7 +34,7 @@ export default async function handler(request: NextRequest) {
).then(async (res) => res.arrayBuffer());
const url = new URL(request.url);
const isDevelopment = process.env.NODE_ENV === 'development';
const username = url.searchParams.get('name') ?? 'yourname';
const domainName = isDevelopment ? `${url.protocol}//${url.host}` : 'https://www.base.org';
const profilePicture = getUserNamePicture(username);

View File

@@ -8,6 +8,7 @@ import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames
import L2ResolverAbi from 'apps/web/src/abis/L2Resolver';
import { base } from 'viem/chains';
import { getBasenamePublicClient } from 'apps/web/src/hooks/useBasenameChain';
import { isDevelopment } from 'apps/web/src/constants';
export const config = {
runtime: 'edge',
@@ -19,7 +20,6 @@ export default async function handler(request: NextRequest) {
).then(async (res) => res.arrayBuffer());
const url = new URL(request.url);
const isDevelopment = process.env.NODE_ENV === 'development';
const username = url.searchParams.get('name') ?? 'yourname';
const domainName = isDevelopment ? `${url.protocol}//${url.host}` : 'https://www.base.org';
const profilePicture = getUserNamePicture(username);

View File

@@ -1,3 +1,4 @@
import { isDevelopment } from 'apps/web/src/constants';
import { NextResponse } from 'next/server';
import { base } from 'viem/chains';
@@ -7,7 +8,6 @@ export const config = {
export default async function GET(request: Request) {
const url = new URL(request.url);
const isDevelopment = process.env.NODE_ENV === 'development';
const domainName = isDevelopment ? `${url.protocol}//${url.host}` : 'https://www.base.org';
const chainId = url.searchParams.get('chainId') ?? base.id;

View File

@@ -1,3 +1,4 @@
import { isDevelopment } from 'apps/web/src/constants';
import { NextResponse } from 'next/server';
import { base } from 'viem/chains';
@@ -7,7 +8,7 @@ export const config = {
export default async function GET(request: Request) {
const url = new URL(request.url);
const isDevelopment = process.env.NODE_ENV === 'development';
const domainName = isDevelopment ? `${url.protocol}//${url.host}` : 'https://www.base.org';
const chainId = url.searchParams.get('chainId') ?? base.id;
if (!chainId) return NextResponse.json({ error: '406: chainId is missing' }, { status: 406 });

View File

@@ -1,6 +1,7 @@
import { premintMapping } from 'apps/web/pages/api/basenames/metadata/premintsMapping';
import L2Resolver from 'apps/web/src/abis/L2Resolver';
import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames';
import { isDevelopment } from 'apps/web/src/constants';
import { getBasenamePublicClient } from 'apps/web/src/hooks/useBasenameChain';
import { USERNAME_DOMAINS } from 'apps/web/src/utils/usernames';
import { NextResponse } from 'next/server';
@@ -13,7 +14,7 @@ export const config = {
export default async function GET(request: Request) {
const url = new URL(request.url);
const isDevelopment = process.env.NODE_ENV === 'development';
const domainName = isDevelopment ? `${url.protocol}//${url.host}` : 'https://www.base.org';
let tokenId = url.searchParams.get('tokenId');
if (tokenId?.endsWith('.json')) tokenId = tokenId.slice(0, -5);

View File

@@ -1,5 +1,6 @@
'use client';
import { useAnalytics } from 'apps/web/contexts/Analytics';
import { useErrors } from 'apps/web/contexts/Errors';
import {
DiscountData,
findFirstValidDiscount,
@@ -113,6 +114,7 @@ export default function RegistrationProvider({ children }: RegistrationProviderP
// Analytics
const { logEventWithContext } = useAnalytics();
const { logError } = useErrors();
// Web3 data
const { address } = useAccount();
@@ -152,6 +154,7 @@ export default function RegistrationProvider({ children }: RegistrationProviderP
enabled: !!registerNameTransactionHash,
},
});
const [registerNameCallsBatchId, setRegisterNameCallsBatchId] = useState<string>('');
// The "correct" way to transition the UI would be to watch for call success, but this experimental
@@ -174,7 +177,9 @@ export default function RegistrationProvider({ children }: RegistrationProviderP
setRegistrationStep(RegistrationSteps.Success);
}
})
.catch(() => {});
.catch((error) => {
logError(error, 'Failed to refetch basename');
});
}, 1500);
const redirectToProfile = useCallback(() => {
@@ -232,6 +237,13 @@ export default function RegistrationProvider({ children }: RegistrationProviderP
logEventWithContext('selected_name', ActionType.change);
}, [logEventWithContext, selectedName]);
// Log error
useEffect(() => {
if (transactionError) {
logError(transactionError, 'Failed to fetch the transaction receipt');
}
}, [logError, transactionError]);
const values = useMemo(() => {
return {
searchInputFocused,

View File

@@ -6,6 +6,7 @@ import {
} from '@heroicons/react/16/solid';
import { ConnectButton, useConnectModal } from '@rainbow-me/rainbowkit';
import { useAnalytics } from 'apps/web/contexts/Analytics';
import { useErrors } from 'apps/web/contexts/Errors';
import { useRegistration } from 'apps/web/src/components/Basenames/RegistrationContext';
import RegistrationLearnMoreModal from 'apps/web/src/components/Basenames/RegistrationLearnMoreModal';
import { Button, ButtonSizes, ButtonVariants } from 'apps/web/src/components/Button/Button';
@@ -50,6 +51,7 @@ export default function RegistrationForm() {
const chains = useChains();
const { openConnectModal } = useConnectModal();
const { logEventWithContext } = useAnalytics();
const { logError } = useErrors();
const { basenameChain } = useBasenameChain();
const { switchChain } = useSwitchChain();
const switchToIntendedNetwork = useCallback(
@@ -132,8 +134,10 @@ export default function RegistrationForm() {
const registerNameCallback = useCallback(() => {
registerName()
.then(() => {})
.catch(() => {});
}, [registerName]);
.catch((error) => {
logError(error, 'Failed to register name');
});
}, [logError, registerName]);
const { data: balance } = useBalance({ address, chainId: connectedChain?.id });
const insufficientBalanceToRegister =

View File

@@ -1,4 +1,5 @@
import { useAnalytics } from 'apps/web/contexts/Analytics';
import { useErrors } from 'apps/web/contexts/Errors';
import {
registrationTransitionDuration,
useRegistration,
@@ -35,6 +36,7 @@ export enum FormSteps {
export default function RegistrationProfileForm() {
const [currentFormStep, setCurrentFormStep] = useState<FormSteps>(FormSteps.Description);
const [transitionStep, setTransitionStep] = useState<boolean>(false);
const { logError } = useErrors();
const { selectedName, redirectToProfile } = useRegistration();
const { address } = useAccount();
const { logEventWithContext } = useAnalytics();
@@ -90,7 +92,9 @@ export default function RegistrationProfileForm() {
.then(() => {
redirectToProfile();
})
.catch(() => {});
.catch((error) => {
logError(error, 'Failed to refetch text records');
});
}
if (transactionData.status === 'reverted') {
@@ -106,6 +110,7 @@ export default function RegistrationProfileForm() {
selectedName,
basenameChain.id,
redirectToProfile,
logError,
]);
useEffect(() => {
@@ -165,13 +170,16 @@ export default function RegistrationProfileForm() {
redirectToProfile();
}
})
.catch(console.error);
.catch((error) => {
logError(error, 'Failed to write text records');
});
}
event.preventDefault();
},
[
currentFormStep,
logError,
logEventWithContext,
redirectToProfile,
textRecords,

View File

@@ -1,5 +1,6 @@
import { upload } from '@vercel/blob/client';
import { useAnalytics } from 'apps/web/contexts/Analytics';
import { useErrors } from 'apps/web/contexts/Errors';
import UsernameAvatarField from 'apps/web/src/components/Basenames/UsernameAvatarField';
import UsernameDescriptionField from 'apps/web/src/components/Basenames/UsernameDescriptionField';
import UsernameKeywordsField from 'apps/web/src/components/Basenames/UsernameKeywordsField';
@@ -35,6 +36,7 @@ export default function UsernameProfileEditModal({
const { profileUsername, profileAddress, currentWalletIsOwner } = useUsernameProfile();
const [avatarFile, setAvatarFile] = useState<File | undefined>();
const { logEventWithContext } = useAnalytics();
const { logError } = useErrors();
const { basenameChain } = useBasenameChain(profileUsername);
const {
@@ -88,7 +90,9 @@ export default function UsernameProfileEditModal({
.then(() => {
toggleModal();
})
.catch(() => {});
.catch((error) => {
logError(error, 'Failed to refetch existing text records');
});
}
if (transactionData.status === 'reverted') {
@@ -103,6 +107,7 @@ export default function UsernameProfileEditModal({
logEventWithContext,
transactionIsFetching,
toggleModal,
logError,
]);
useEffect(() => {
@@ -174,25 +179,26 @@ export default function UsernameProfileEditModal({
})
.catch((error) => {
console.error(error);
logError(error, 'Update text records transaction canceled');
logEventWithContext('update_text_records_transaction_canceled', ActionType.click);
});
})
.catch((e) => {
console.error(e);
.catch((error) => {
logError(error, 'Failed to upload avatar');
logEventWithContext('avatar_upload_failed', ActionType.error);
});
logEventWithContext('update_text_records_transaction_initiated', ActionType.change);
},
[
avatarFile,
currentWalletIsOwner,
logEventWithContext,
uploadAvatar,
textRecords,
toggleModal,
uploadAvatar,
avatarFile,
logEventWithContext,
writeTextRecords,
toggleModal,
logError,
],
);

View File

@@ -4,6 +4,7 @@ import { useEffect, useMemo, useState } from 'react';
import { Divider } from 'apps/web/src/components/Divider/Divider';
import { Job } from 'apps/web/src/components/Jobs/Job';
import { greenhouseApiUrl } from 'apps/web/src/constants';
import { useErrors } from 'apps/web/contexts/Errors';
async function getJobs() {
const res = await fetch(`${greenhouseApiUrl}/boards/basejobs/jobs?content=true`);
@@ -30,11 +31,14 @@ export type JobType = {
export default function JobsList() {
const [jobs, setJobs] = useState<JobType[]>([]);
const { logError } = useErrors();
useEffect(() => {
getJobs()
.then((js) => setJobs(js))
.catch(console.error);
}, []);
.catch((error) => {
logError(error, 'Failed to get jobs');
});
}, [logError]);
const departments = useMemo(() => {
const departmentsById = jobs.reduce<DepartmentByIdReduceType>((acc, job) => {

View File

@@ -13,10 +13,10 @@ import useBasenameChain from 'apps/web/src/hooks/useBasenameChain';
import { base, baseSepolia } from 'viem/chains';
import { Icon } from 'apps/web/src/components/Icon/Icon';
import { useCallback } from 'react';
import { isDevelopment } from 'apps/web/src/constants';
export default function UsernameNav() {
const { isConnected } = useAccount();
const isDevelopment = process.env.NODE_ENV === 'development';
const { basenameChain } = useBasenameChain();
const { switchChain } = useSwitchChain();

View File

@@ -1,3 +1,4 @@
import { useErrors } from 'apps/web/contexts/Errors';
import { NameSuggestionResponseData } from 'apps/web/pages/api/name/[alreadyClaimedName]';
import { useAreNamesAvailable } from 'apps/web/src/hooks/useIsNameAvailable';
import { normalizeEnsDomainName, validateEnsDomainName } from 'apps/web/src/utils/usernames';
@@ -7,7 +8,7 @@ export function useAlternativeNameSuggestions(nameNeedingAlternatives: string, d
const [suggestions, setSuggestions] = useState<string[]>();
const [error, setError] = useState<string>();
const [isLoading, setIsLoading] = useState(false);
const { logError } = useErrors();
useEffect(() => {
async function checkAlternatives() {
if (!doLookup || !nameNeedingAlternatives || nameNeedingAlternatives.length < 3) {
@@ -21,14 +22,14 @@ export function useAlternativeNameSuggestions(nameNeedingAlternatives: string, d
setSuggestions(suggestionData.suggestion);
}
} catch (e) {
console.error('error checking for alternative names: ', e);
logError(e, 'Failed to fetch alternative names');
setError('error fetching name suggestions');
} finally {
setIsLoading(false);
}
}
void checkAlternatives();
}, [doLookup, nameNeedingAlternatives]);
}, [doLookup, logError, nameNeedingAlternatives]);
const normalizedNames = useMemo(
() =>

View File

@@ -9,6 +9,7 @@ import { useEffect, useMemo, useState } from 'react';
import { Address, ReadContractErrorType, encodeAbiParameters } from 'viem';
import { useAccount, useReadContract } from 'wagmi';
import useBasenameChain from 'apps/web/src/hooks/useBasenameChain';
import { useErrors } from 'apps/web/contexts/Errors';
export type AttestationData = {
discountValidatorAddress: Address;
@@ -21,6 +22,7 @@ type AttestationHookReturns = {
error: ReadContractErrorType | null;
};
export function useCheckCBIDAttestations(): AttestationHookReturns {
const { logError } = useErrors();
const { address } = useAccount();
const [cBIDProofResponse, setCBIDProofResponse] = useState<CBIDProofResponse | null>(null);
const { basenameChain } = useBasenameChain();
@@ -35,15 +37,17 @@ export function useCheckCBIDAttestations(): AttestationHookReturns {
const result = (await response.json()) as CBIDProofResponse;
setCBIDProofResponse(result);
}
} catch (e) {
console.error('Error checking CB.ID attestation:', e);
} catch (error) {
logError(error, 'Error checking CB.ID attestation');
}
}
if (address && !IS_EARLY_ACCESS) {
checkCBIDAttestations(address).catch(console.error);
checkCBIDAttestations(address).catch((error) => {
logError(error, 'Error checking CB.ID attestation');
});
}
}, [address, basenameChain.id]);
}, [address, basenameChain.id, logError]);
const encodedProof = useMemo(
() =>
@@ -87,6 +91,7 @@ export function useCheckCBIDAttestations(): AttestationHookReturns {
// returns info about Coinbase verified account attestations
export function useCheckCoinbaseAttestations() {
const { logError } = useErrors();
const { address } = useAccount();
const [loading, setLoading] = useState(false);
const [coinbaseProofResponse, setCoinbaseProofResponse] = useState<CoinbaseProofResponse | null>(
@@ -106,17 +111,19 @@ export function useCheckCoinbaseAttestations() {
if (response.ok) {
setCoinbaseProofResponse(result);
}
} catch (e) {
console.error('Error checking Coinbase account attestations:', e);
} catch (error) {
logError(error, 'Error checking Coinbase account attestations');
} finally {
setLoading(false);
}
}
if (address && !IS_EARLY_ACCESS) {
checkCoinbaseAttestations(address).catch(console.error);
checkCoinbaseAttestations(address).catch((error) => {
logError(error, 'Error checking Coinbase account attestations');
});
}
}, [address, basenameChain.id]);
}, [address, basenameChain.id, logError]);
const signature = coinbaseProofResponse?.signedMessage as undefined | `0x${string}`;
@@ -149,6 +156,7 @@ export function useCheckCoinbaseAttestations() {
}
export function useCheckCB1Attestations() {
const { logError } = useErrors();
const { address } = useAccount();
const [loading, setLoading] = useState(false);
const [cb1ProofResponse, setCB1ProofResponse] = useState<CoinbaseProofResponse | null>(null);
@@ -165,17 +173,19 @@ export function useCheckCB1Attestations() {
const result = (await response.json()) as CoinbaseProofResponse;
setCB1ProofResponse(result);
}
} catch (e) {
console.error('Error checking CB1 attestation:', e);
} catch (error) {
logError(error, 'Error checking CB1 attestation');
} finally {
setLoading(false);
}
}
if (address && !IS_EARLY_ACCESS) {
checkCB1Attestations(address).catch(console.error);
checkCB1Attestations(address).catch((error) => {
logError(error, 'Error checking CB1 attestation');
});
}
}, [address, basenameChain.id]);
}, [address, basenameChain.id, logError]);
const signature = cb1ProofResponse?.signedMessage as undefined | `0x${string}`;
@@ -208,6 +218,7 @@ export function useCheckCB1Attestations() {
}
export function useCheckEAAttestations(): AttestationHookReturns {
const { logError } = useErrors();
const { address } = useAccount();
const [EAProofResponse, setEAProofResponse] = useState<EarlyAccessProofResponse | null>(null);
const { basenameChain } = useBasenameChain();
@@ -223,15 +234,17 @@ export function useCheckEAAttestations(): AttestationHookReturns {
const result = (await response.json()) as EarlyAccessProofResponse;
setEAProofResponse(result);
}
} catch (e) {
console.error('Error checking early access:', e);
} catch (error) {
logError(error, 'Error checking early access');
}
}
if (address) {
checkEarlyAccess(address).catch(console.error);
checkEarlyAccess(address).catch((error) => {
logError(error, 'Error checking early access');
});
}
}, [address, basenameChain.id]);
}, [address, basenameChain.id, logError]);
const encodedProof = useMemo(
() =>

View File

@@ -5,6 +5,7 @@ import { createPublicClient, http } from 'viem';
import { cdpBaseRpcEndpoint, cdpBaseSepoliaRpcEndpoint } from 'apps/web/src/cdp/constants';
import { BaseName } from '@coinbase/onchainkit/identity';
import { getChainForBasename } from 'apps/web/src/utils/usernames';
import { isDevelopment } from 'apps/web/src/constants';
export function getBasenamePublicClient(chainId: number) {
const rpcEndpoint = chainId === baseSepolia.id ? cdpBaseSepoliaRpcEndpoint : cdpBaseRpcEndpoint;
@@ -22,7 +23,6 @@ export function isBasenameSupportedChain(chainId: number) {
}
export default function useBasenameChain(username?: BaseName) {
const isDevelopment = process.env.NODE_ENV === 'development';
const { chain: connectedChain } = useAccount();
const chains = useChains();
@@ -37,7 +37,7 @@ export default function useBasenameChain(username?: BaseName) {
// Not connected, default to Sepolia for development, base for other envs
return isDevelopment ? baseSepolia : base;
}, [chains, connectedChain, isDevelopment, username]);
}, [chains, connectedChain, username]);
const basenamePublicClient = getBasenamePublicClient(basenameChain.id);

View File

@@ -1,4 +1,5 @@
import { useAnalytics } from 'apps/web/contexts/Analytics';
import { useErrors } from 'apps/web/contexts/Errors';
import L2ResolverAbi from 'apps/web/src/abis/L2Resolver';
import { USERNAME_L2_RESOLVER_ADDRESSES } from 'apps/web/src/addresses/usernames';
import useBasenameChain from 'apps/web/src/hooks/useBasenameChain';
@@ -37,6 +38,7 @@ export function useRegisterNameCallback(
): UseRegisterNameCallbackReturnValue {
const { address, chainId, isConnected } = useAccount();
const { basenameChain } = useBasenameChain();
const { logError } = useErrors();
const {
data: callBatchId,
writeContractsAsync,
@@ -129,7 +131,7 @@ export function useRegisterNameCallback(
});
}
} catch (e) {
console.error('failed to register name', e);
logError(e, 'Register name transaction canceled');
logEventWithContext('register_name_transaction_canceled', ActionType.change);
}
}, [
@@ -138,6 +140,7 @@ export function useRegisterNameCallback(
capabilities,
discountKey,
isDiscounted,
logError,
logEventWithContext,
name,
normalizedName,