Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { WalletService } from '../../services/wallet';
import { getTestWallet } from '../../services/wallet/__mocks__/wallet.fixtures';
import { ConfirmationInterfaceKey } from '../../ui/confirmation/api';
import { ConfirmationUXController } from '../../ui/confirmation/controller';
import * as errorsUtils from '../../utils/errors';
import { logger } from '../../utils/logger';
import * as snapUtils from '../../utils/snap';
Comment on lines +52 to 54

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this import is indeed used.

const trackTransactionAddedSpy = jest.spyOn(
    snapUtils,
    'trackTransactionAdded',
  );
  const trackTransactionRejectedSpy = jest.spyOn(
    snapUtils,
    'trackTransactionRejected',
  );
  const trackTransactionApprovedSpy = jest.spyOn(
    snapUtils,
    'trackTransactionApproved',
  );

import { AccountResolver } from '../accountResolver';
Expand Down Expand Up @@ -543,7 +544,7 @@ describe('ConfirmSendHandler', () => {
);
createValidatedSendTransaction.mockRejectedValueOnce(xdrParseError);
const trackErrorSpy = jest
.spyOn(snapUtils, 'trackError')
.spyOn(errorsUtils, 'trackError')
.mockResolvedValue(undefined);

expect(await handler.handle(baseRequest())).toStrictEqual({
Expand All @@ -558,7 +559,7 @@ describe('ConfirmSendHandler', () => {
const unexpectedError = new Error('unexpected');
createValidatedSendTransaction.mockRejectedValueOnce(unexpectedError);
const trackErrorSpy = jest
.spyOn(snapUtils, 'trackError')
.spyOn(errorsUtils, 'trackError')
.mockResolvedValue(undefined);

expect(await handler.handle(baseRequest())).toStrictEqual({
Expand All @@ -574,7 +575,7 @@ describe('ConfirmSendHandler', () => {
new TransactionValidationException('x'),
);
const trackErrorSpy = jest
.spyOn(snapUtils, 'trackError')
.spyOn(errorsUtils, 'trackError')
.mockResolvedValue(undefined);

expect(await handler.handle(baseRequest())).toStrictEqual({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import type { Struct } from '@metamask/superstruct';
import type { Json } from '@metamask/utils';

import type { KnownCaip2ChainId } from '../../api';
import { trackError } from '../../utils/errors';
import { validateRequest, validateResponse } from '../../utils/requestResponse';
import { trackError } from '../../utils/snap';
import type {
AccountResolver,
ResolvedKeyringAndWalletOnly,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import type { KnownCaip19Sep41AssetId } from '../../api';
import { KnownCaip2ChainId } from '../../api';
import { NATIVE_ASSET_SYMBOL, STELLAR_DECIMAL_PLACES } from '../../constants';
import { bufferToUint8Array } from '../../utils/buffer';
import * as errorsUtils from '../../utils/errors';
import { logger } from '../../utils/logger';
import * as snapUtils from '../../utils/snap';
import type { StellarKeyringAccount } from '../account';
import { generateStellarKeyringAccount } from '../account/__mocks__/account.fixtures';
import {
Expand Down Expand Up @@ -200,7 +200,7 @@ describe('OnChainAccountSynchronizeService', () => {

const setupTest = () => {
jest.mocked(emitSnapKeyringEvent).mockResolvedValue(undefined);
jest.spyOn(snapUtils, 'trackError').mockResolvedValue(undefined);
jest.spyOn(errorsUtils, 'trackError').mockResolvedValue(undefined);
};

const buildActivatedAccountPair = (
Expand Down Expand Up @@ -974,7 +974,7 @@ describe('OnChainAccountSynchronizeService', () => {
mockSep41Assets,
);

expect(snapUtils.trackError).toHaveBeenCalledWith(
expect(errorsUtils.trackError).toHaveBeenCalledWith(
expect.objectContaining({
message: 'sep41 fetch temporarily unavailable',
}),
Expand Down Expand Up @@ -1144,7 +1144,7 @@ describe('OnChainAccountSynchronizeService', () => {
);

expect(saveManySpy).toHaveBeenCalled();
expect(snapUtils.trackError).toHaveBeenCalledWith(emitError);
expect(errorsUtils.trackError).toHaveBeenCalledWith(emitError);
expect(logger.warn).toHaveBeenCalledWith(
'[💼 OnChainAccountSynchronizeService]',
'Failed to emit keyring events after synchronize',
Expand Down
1 change: 0 additions & 1 deletion packages/stellar-wallet-snap/src/utils/__mocks__/snap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,4 @@ export const {
trackTransactionFinalized,
trackSecurityAlertDetected,
trackSecurityScanCompleted,
trackError,
} = actual;
13 changes: 7 additions & 6 deletions packages/stellar-wallet-snap/src/utils/errors.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createWithCatchAndThrowSnapError } from '@metamask/snap-networks-utils';
import { createSnapErrorHandling } from '@metamask/snap-networks-utils';
import type { Struct } from '@metamask/superstruct';
import { assert, enums, object, type } from '@metamask/superstruct';

import { logger } from './logger';
import { trackError } from './snap';
import { getSnapProvider } from './snap';

export { isSnapRpcError } from '@metamask/snap-networks-utils';
export type { SnapRpcError } from '@metamask/snap-networks-utils';
Expand Down Expand Up @@ -252,7 +252,8 @@ export function isStellarSnapException(
return error instanceof StellarSnapException;
}

export const withCatchAndThrowSnapError = createWithCatchAndThrowSnapError({
logError: logger.error.bind(logger),
trackError,
});
export const { trackError, withCatchAndThrowSnapError } =
createSnapErrorHandling({
getSnapProvider,
logError: logger.error.bind(logger),
});
37 changes: 1 addition & 36 deletions packages/stellar-wallet-snap/src/utils/snap.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { JsonSLIP10Node } from '@metamask/key-tree';
import type { EntropySourceId } from '@metamask/keyring-api';
import { deserialize, serialize } from '@metamask/snap-networks-utils';
import type { Serializable } from '@metamask/snap-networks-utils';
import { getJsonError, UserRejectedRequestError } from '@metamask/snaps-sdk';
import { deserialize, serialize } from '@metamask/snap-networks-utils';
import type {
ComponentOrElement,
DialogResult,
Expand All @@ -14,7 +13,6 @@ import type {
SnapsProvider,
UpdateInterfaceResult,
} from '@metamask/snaps-sdk';
import { ensureError } from '@metamask/utils';

import { StellarSnapException } from './errors';
import { logger } from './logger';
Expand Down Expand Up @@ -631,36 +629,3 @@ export async function trackSecurityScanCompleted(properties: {
has_security_alerts: properties.hasSecurityAlerts,
});
}

/**
* Track an error in MetaMask via Sentry (`snap_trackError`).
*
* RPC failures are caught and logged but never rethrown, so this is
* safe to call from already-failing error-handling paths without risk
* of masking the original failure.
*
* @param error - The error to report to Sentry.
* @returns The Sentry event ID on success, or `undefined` on failure or if the error is skipped.
*/
export async function trackError(
error: Error | unknown,
): Promise<string | undefined> {
if (error instanceof UserRejectedRequestError) {
return undefined;
}

try {
let errorToTrack = error;

if (!(error instanceof Error)) {
errorToTrack = ensureError(error);
}
return await getSnapProvider().request({
method: 'snap_trackError',
params: { error: getJsonError(errorToTrack) },
});
} catch (rpcError) {
logger.warn({ rpcError }, 'Failed to track error via snap_trackError');
return undefined;
}
}