Skip to content

Commit 3fc8bde

Browse files
authored
Merge pull request #340 from LIT-Protocol/chore/dashboard-sentry-error-tracking
chore(dashboard): user dashboard, better sentry error tracking
2 parents f51cf34 + 88dfaf1 commit 3fc8bde

File tree

19 files changed

+546
-62
lines changed

19 files changed

+546
-62
lines changed

packages/apps/app-dashboard/src/components/user-dashboard/connect/Connect.tsx

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useEffect, useState, useCallback } from 'react';
2+
import * as Sentry from '@sentry/react';
23
import { AUTH_METHOD_TYPE } from '@lit-protocol/constants';
34
import { SessionSigs } from '@lit-protocol/types';
45
import { ThemeType } from './ui/theme';
@@ -81,19 +82,48 @@ export default function ConnectView({ theme, readAuthInfo }: ConnectViewProps) {
8182
if (errorMessage.includes('User rejected') || errorMessage.includes('user rejected')) {
8283
// User cancelled authentication - no action needed
8384
} else {
85+
// Capture the error with full breadcrumb trail
86+
Sentry.captureException(error, {
87+
extra: {
88+
context: 'Connect.authentication',
89+
errorSource: authError
90+
? 'authentication'
91+
: accountsError
92+
? 'accounts'
93+
: sessionError
94+
? 'session'
95+
: 'readAuth',
96+
},
97+
});
8498
setStatusMessage(`Authentication Error: ${errorMessage}`);
8599
setStatusType('error');
86100
}
87101
} else {
88102
setStatusMessage('');
89103
}
90-
}, [error]);
104+
}, [error, authError, accountsError, sessionError, readError]);
91105

92106
// Register with WebAuthn
93107
async function handleRegisterWithWebAuthn(displayName: string) {
94-
const newPKP = await registerWebAuthn(displayName);
95-
if (newPKP) {
96-
setuserPKP(newPKP);
108+
try {
109+
const newPKP = await registerWebAuthn(displayName);
110+
if (newPKP) {
111+
setuserPKP(newPKP);
112+
}
113+
} catch (error) {
114+
// Error will be logged by the effect that monitors authError/accountsError
115+
// The registerWebAuthn error is already breadcrumbed in lit.ts
116+
console.error('Failed to register WebAuthn:', error);
117+
Sentry.captureException(error, {
118+
extra: {
119+
context: 'Connect.registerWebAuthn',
120+
displayName,
121+
},
122+
});
123+
setStatusMessage(
124+
`Registration failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
125+
);
126+
setStatusType('error');
97127
}
98128
}
99129

packages/apps/app-dashboard/src/components/user-dashboard/connect/ConnectPage.tsx

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useState, useCallback, useRef, useEffect } from 'react';
22
import { useNavigate } from 'react-router-dom';
3+
import * as Sentry from '@sentry/react';
34
import { getClient } from '@lit-protocol/vincent-contracts-sdk';
45
import { IRelayPKP } from '@lit-protocol/types';
56
import { ConnectInfoMap } from '@/hooks/user-dashboard/connect/useConnectInfo';
@@ -149,7 +150,13 @@ export function ConnectPage({
149150
} catch (error) {
150151
setLocalError(error instanceof Error ? error.message : 'Failed to mint PKP');
151152
setIsConnectProcessing(false);
152-
throw error;
153+
Sentry.captureException(error, {
154+
extra: {
155+
context: 'ConnectPage.mintPKPToExistingPKP',
156+
userPKPTokenId: readAuthInfo.authInfo.userPKP.tokenId,
157+
},
158+
});
159+
return;
153160
}
154161
}
155162

@@ -199,19 +206,31 @@ export function ConnectPage({
199206
: 'Failed after addPayee attempt',
200207
);
201208
setIsConnectProcessing(false);
202-
throw retryError;
209+
Sentry.captureException(retryError, {
210+
extra: {
211+
context: 'ConnectPage.addPermittedActions.retryAfterAddPayee',
212+
agentPKPTokenId: agentPKP.tokenId,
213+
},
214+
});
215+
return;
203216
}
204217
} else if (isInsufficientFunds) {
205-
// Insufficient funds - show helpful message with faucet link
218+
// Insufficient funds - show helpful message with faucet link (don't log to Sentry - expected)
206219
const customMessage = `Insufficient testnet funds. Authentication Address (testnet only): ${readAuthInfo.authInfo.userPKP.ethAddress}. Please fund it with the faucet here:`;
207220
setLocalError(customMessage);
208221
setIsConnectProcessing(false);
209-
throw new Error(customMessage);
222+
return;
210223
} else {
211224
// Other error - log to Sentry and fail
225+
Sentry.captureException(error, {
226+
extra: {
227+
context: 'ConnectPage.addPermittedActions',
228+
agentPKPTokenId: agentPKP.tokenId,
229+
},
230+
});
212231
setLocalError(error instanceof Error ? error.message : 'Failed to add permitted actions');
213232
setIsConnectProcessing(false);
214-
throw error;
233+
return;
215234
}
216235
}
217236

@@ -231,9 +250,17 @@ export function ConnectPage({
231250
setLocalSuccess('Permissions granted successfully!');
232251
console.log('agentPKP:', agentPKP);
233252
} catch (error) {
253+
Sentry.captureException(error, {
254+
extra: {
255+
context: 'ConnectPage.permitApp',
256+
agentPKPAddress: agentPKP.ethAddress,
257+
appId: connectInfoMap.app.appId,
258+
appVersion: connectInfoMap.app.activeVersion,
259+
},
260+
});
234261
setLocalError(error instanceof Error ? error.message : 'Failed to permit app');
235262
setIsConnectProcessing(false);
236-
throw error;
263+
return;
237264
}
238265
} else {
239266
setLocalError('Some of your permissions are not valid. Please check the form and try again.');

packages/apps/app-dashboard/src/components/user-dashboard/connect/RepermitConnect.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useState, useCallback, useEffect } from 'react';
22
import { useNavigate } from 'react-router-dom';
3+
import * as Sentry from '@sentry/react';
34
import { getClient } from '@lit-protocol/vincent-contracts-sdk';
45
import { IRelayPKP } from '@lit-protocol/types';
56
import { PKPEthersWallet } from '@lit-protocol/pkp-ethers';
@@ -92,6 +93,14 @@ export function RepermitConnect({
9293
} catch (error) {
9394
setLocalError(error instanceof Error ? error.message : 'Failed to re-permit app');
9495
setIsConnectProcessing(false);
96+
Sentry.captureException(error, {
97+
extra: {
98+
context: 'RepermitConnect.handleAccept',
99+
appId: appData.appId,
100+
pkpAddress: previouslyPermittedPKP.ethAddress,
101+
},
102+
});
103+
return;
95104
}
96105
}, [readAuthInfo, previouslyPermittedPKP, appData]);
97106

packages/apps/app-dashboard/src/components/user-dashboard/dashboard/PermittedAppsWrapper.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ export function PermittedAppsWrapper() {
6464

6565
// Handle errors
6666
if (appsError || permissionsError) {
67-
const errorMessage = String(permissionsError || appsError || 'An error occurred');
68-
return <GeneralErrorScreen errorDetails={errorMessage} />;
67+
const error = permissionsError || appsError || new Error('An error occurred');
68+
return <GeneralErrorScreen errorDetails={String(error)} />;
6969
}
7070

7171
const isUserAuthed = authInfo?.userPKP && sessionSigs;

packages/apps/app-dashboard/src/components/user-dashboard/dashboard/UpdateVersionPage.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useState, useCallback, useRef } from 'react';
2+
import * as Sentry from '@sentry/react';
23
import { getClient } from '@lit-protocol/vincent-contracts-sdk';
34
import { IRelayPKP } from '@lit-protocol/types';
45
import { ConnectInfoMap } from '@/hooks/user-dashboard/connect/useConnectInfo';
@@ -117,7 +118,7 @@ export function UpdateVersionPage({
117118
appVersion: Number(connectInfoMap.app.activeVersion),
118119
permissionData: selectedFormData,
119120
});
120-
121+
121122
setLocalStatus(null);
122123
// Show success state for 3 seconds, then redirect or reload
123124
setLocalSuccess('Version updated successfully!');
@@ -134,6 +135,13 @@ export function UpdateVersionPage({
134135
} catch (error) {
135136
setLocalError(error instanceof Error ? error.message : 'Failed to update version');
136137
setLocalStatus(null);
138+
Sentry.captureException(error, {
139+
extra: {
140+
context: 'UpdateVersionPage.handleAccept',
141+
appId: connectInfoMap.app.appId,
142+
newVersion: connectInfoMap.app.activeVersion,
143+
},
144+
});
137145
return;
138146
}
139147
} else {

packages/apps/app-dashboard/src/components/user-dashboard/dashboard/UserPermissionPage.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useState, useCallback, useRef, useEffect } from 'react';
2+
import * as Sentry from '@sentry/react';
23
import { getClient, PermissionData } from '@lit-protocol/vincent-contracts-sdk';
34
import { IRelayPKP } from '@lit-protocol/types';
45
import { ConnectInfoMap } from '@/hooks/user-dashboard/connect/useConnectInfo';
@@ -216,6 +217,13 @@ export function AppPermissionPage({
216217
} catch (error) {
217218
setLocalError(error instanceof Error ? error.message : 'Failed to permit app');
218219
setLocalStatus(null);
220+
Sentry.captureException(error, {
221+
extra: {
222+
context: 'UserPermissionPage.handleSubmit',
223+
appId: connectInfoMap.app.appId,
224+
permittedVersion,
225+
},
226+
});
219227
return;
220228
}
221229
} else {
@@ -259,7 +267,7 @@ export function AppPermissionPage({
259267
appId: Number(connectInfoMap.app.appId),
260268
appVersion: Number(permittedVersion),
261269
});
262-
270+
263271
setLocalStatus(null);
264272
// Show success state until redirect
265273
setLocalSuccess('App unpermitted successfully!');
@@ -270,6 +278,13 @@ export function AppPermissionPage({
270278
} catch (error) {
271279
setLocalError(error instanceof Error ? error.message : 'Failed to unpermit app');
272280
setLocalStatus(null);
281+
Sentry.captureException(error, {
282+
extra: {
283+
context: 'UserPermissionPage.handleUnpermit',
284+
appId: connectInfoMap.app.appId,
285+
permittedVersion,
286+
},
287+
});
273288
}
274289
}, [readAuthInfo, connectInfoMap.app, permittedVersion]);
275290

packages/apps/app-dashboard/src/components/user-dashboard/withdraw/WalletConnect/WalletConnect.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { IRelayPKP, SessionSigs } from '@lit-protocol/types';
2+
import * as Sentry from '@sentry/react';
23
import { Button } from '@/components/shared/ui/button';
34
import { Input } from '@/components/shared/ui/input';
45
import StatusMessage from '@/components/user-dashboard/connect/StatusMessage';
@@ -8,8 +9,8 @@ import React from 'react';
89
import { theme } from '@/components/user-dashboard/connect/ui/theme';
910

1011
// Custom hooks
11-
import { useWalletConnectSession } from '../../../../hooks/user-dashboard/WalletConnect/useWalletConnectSession';
12-
import { useWalletConnectRequests } from '../../../../hooks/user-dashboard/WalletConnect/useWalletConnectRequests';
12+
import { useWalletConnectSession } from '@/hooks/user-dashboard/WalletConnect/useWalletConnectSession';
13+
import { useWalletConnectRequests } from '@/hooks/user-dashboard/WalletConnect/useWalletConnectRequests';
1314

1415
// UI Components
1516
import { SessionProposal } from './SessionProposal';
@@ -84,6 +85,7 @@ export default function WalletConnectPage(params: {
8485
setStatus({ message: 'Successfully paired with dApp', type: 'success' });
8586
} catch (error) {
8687
console.error('WalletConnect error:', error);
88+
Sentry.captureException(error);
8789
setStatus({
8890
message:
8991
error instanceof Error ? error.message : 'Failed to connect. Invalid URI format.',
@@ -114,6 +116,7 @@ export default function WalletConnectPage(params: {
114116
type: 'success',
115117
});
116118
} catch (error) {
119+
Sentry.captureException(error);
117120
setStatus({
118121
message: error instanceof Error ? error.message : 'Failed to approve request',
119122
type: 'error',
@@ -129,6 +132,7 @@ export default function WalletConnectPage(params: {
129132
await handleRejectRequest(request);
130133
setStatus({ message: 'Request rejected', type: 'success' });
131134
} catch (error) {
135+
Sentry.captureException(error);
132136
setStatus({
133137
message: error instanceof Error ? error.message : 'Failed to reject request',
134138
type: 'error',

packages/apps/app-dashboard/src/components/user-dashboard/withdraw/manual/ManualWithdrawForm.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useCallback, useState, useEffect } from 'react';
2+
import * as Sentry from '@sentry/react';
23
import { SessionSigs, IRelayPKP } from '@lit-protocol/types';
34
import { LIT_CHAINS } from '@lit-protocol/constants';
45
import StatusMessage from '@/components/user-dashboard/connect/StatusMessage';
@@ -80,7 +81,8 @@ export const ManualWithdraw: React.FC<ManualWithdrawProps> = ({ sessionSigs, age
8081
};
8182
setNativeToken(token);
8283
showStatus('Balance successfully fetched', 'success');
83-
} catch (error: unknown) {
84+
} catch (error) {
85+
Sentry.captureException(error);
8486
showStatus(`Error: ${(error as Error).message || 'Error fetching balance'}`, 'error');
8587
} finally {
8688
setLoading(false);

packages/apps/app-dashboard/src/hooks/user-dashboard/WalletConnect/useWalletConnectRequests.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useState, useEffect, useCallback } from 'react';
2+
import * as Sentry from '@sentry/react';
23
import { LIT_CHAINS } from '@lit-protocol/constants';
34
import { PKPEthersWallet } from '@lit-protocol/pkp-ethers';
45
import {
@@ -118,6 +119,16 @@ export function useWalletConnectRequests(client: any, currentWalletAddress: stri
118119
return { success: true, method };
119120
} catch (error) {
120121
console.error('Failed to approve request:', error);
122+
Sentry.addBreadcrumb({
123+
category: 'walletconnect.request',
124+
message: 'Failed to approve WalletConnect request',
125+
level: 'error',
126+
data: {
127+
requestId: request?.id,
128+
requestMethod: request?.params?.request?.method,
129+
error: error instanceof Error ? error.message : String(error),
130+
},
131+
});
121132

122133
if (request?.id && request?.topic) {
123134
try {
@@ -136,6 +147,16 @@ export function useWalletConnectRequests(client: any, currentWalletAddress: stri
136147
});
137148
} catch (responseError) {
138149
console.error('Failed to send error response:', responseError);
150+
Sentry.addBreadcrumb({
151+
category: 'walletconnect.request',
152+
message: 'Failed to send error response to dApp',
153+
level: 'warning',
154+
data: {
155+
requestId: request?.id,
156+
error:
157+
responseError instanceof Error ? responseError.message : String(responseError),
158+
},
159+
});
139160
}
140161
}
141162

@@ -244,6 +265,15 @@ async function handleSendTransaction(pkpWallet: PKPEthersWallet, methodParams: a
244265
}
245266
} catch (feeError) {
246267
console.error('Failed to fetch fee data:', feeError);
268+
Sentry.addBreadcrumb({
269+
category: 'walletconnect.transaction',
270+
message: 'Failed to fetch fee data for transaction',
271+
level: 'error',
272+
data: {
273+
chainId,
274+
error: feeError instanceof Error ? feeError.message : String(feeError),
275+
},
276+
});
247277
throw new Error('Failed to fetch fee data');
248278
}
249279
}

0 commit comments

Comments
 (0)