diff --git a/src/composables/swap/useSor.ts b/src/composables/swap/useSor.ts index 846ab63399..6c10df99df 100644 --- a/src/composables/swap/useSor.ts +++ b/src/composables/swap/useSor.ts @@ -41,9 +41,9 @@ import { isMainnet } from '../useNetwork'; import { useTokens } from '@/providers/tokens.provider'; import useTransactions, { TransactionAction } from '../useTransactions'; import { SwapQuote } from './types'; -import { captureException } from '@sentry/browser'; import { overflowProtected } from '@/components/_global/BalTextInput/helpers'; import { isUserError } from '../useTransactionErrors'; +import { captureBalancerException } from '@/lib/utils/errors'; type SorState = { validationErrors: { @@ -805,13 +805,16 @@ export default function useSor({ if (!isUserError(error)) { console.trace(error); state.submissionError = t('swapException', ['Balancer']); - captureException(new Error(state.submissionError, { cause: error }), { - level: 'fatal', + + captureBalancerException(error, 'swap', state.submissionError, { extra: { sender: account.value, tokenIn, tokenOut, }, + tags: { + swapType: 'balancer', + }, }); } swapping.value = false; diff --git a/src/lib/utils/errors.ts b/src/lib/utils/errors.ts new file mode 100644 index 0000000000..1ef1774109 --- /dev/null +++ b/src/lib/utils/errors.ts @@ -0,0 +1,80 @@ +import debounce from 'lodash/debounce'; +import { captureException } from '@sentry/browser'; +import { ScopeContext } from '@sentry/types/types/scope'; + +type BalancerExceptionAction = 'swap' | 'joinPool' | 'exitPool'; + +export const captureBalancerException = debounce( + _captureBalancerException, + 1000 +); + +function _captureBalancerException( + error: Error, + action: BalancerExceptionAction, + messagePrefix: string, + captureContext?: Partial +): void { + const { reason, balError } = getReasonAndBalErrorFromError(error); + const tags: { [key: string]: string } = { ...captureContext?.tags, action }; + + if (balError) { + tags.balError = balError; + } + + captureException( + getErrorForAction( + action, + `${balError ? `BAL#${balError} ` : ''}${messagePrefix}: ${reason}`, + error + ), + { + ...captureContext, + extra: { + ...captureContext?.extra, + reason, + balError, + }, + tags, + } + ); +} + +function getReasonAndBalErrorFromError(error: Error): { + reason: string; + balError: string | null; +} { + const reason: string = + (error as { reason?: string }).reason || 'no reason available'; + const balError = reason.match(/BAL#[0-9]{3}/g); + + return { + reason: reason, + balError: balError && balError[0] ? balError[0].slice(-3) : null, + }; +} + +function getErrorForAction( + action: BalancerExceptionAction, + message: string, + originalError: Error +) { + switch (action) { + case 'swap': + return new BatchSwapError(message, { cause: originalError }); + case 'joinPool': + return new JoinPoolError(message, { cause: originalError }); + case 'exitPool': + return new ExitPoolError(message, { cause: originalError }); + } +} + +class BatchSwapError extends Error { + name = 'BatchSwapError'; +} +class JoinPoolError extends Error { + name = 'JoinPoolError'; +} +class ExitPoolError extends Error { + name = 'ExitPoolError'; +} diff --git a/src/services/contracts/vault.service.spec.ts b/src/services/contracts/vault.service.spec.ts index fa9838a735..77a1f5b961 100644 --- a/src/services/contracts/vault.service.spec.ts +++ b/src/services/contracts/vault.service.spec.ts @@ -128,6 +128,7 @@ describe('vault.service', () => { expect.any(Number), // expect.any(Number) refers to the deadline from calculateValidTo(transactionDeadline) ], options: {}, + shouldLogFailure: false, }); }); }); diff --git a/src/services/contracts/vault.service.ts b/src/services/contracts/vault.service.ts index ebf2a75202..3b43b89172 100644 --- a/src/services/contracts/vault.service.ts +++ b/src/services/contracts/vault.service.ts @@ -63,6 +63,7 @@ export default class VaultService { action: 'batchSwap', params: [swapKind, swaps, tokenAddresses, funds, limits, deadline], options, + shouldLogFailure: false, }); } diff --git a/src/services/web3/transactions/concerns/contract.concern.ts b/src/services/web3/transactions/concerns/contract.concern.ts index 2d8eab7253..d701d29f33 100644 --- a/src/services/web3/transactions/concerns/contract.concern.ts +++ b/src/services/web3/transactions/concerns/contract.concern.ts @@ -23,6 +23,7 @@ export type SendTransactionOpts = { action: string; params?: any[]; options?: TransactionRequest; + shouldLogFailure?: boolean; }; export class ContractConcern extends TransactionConcern { @@ -36,6 +37,7 @@ export class ContractConcern extends TransactionConcern { action, params = [], options = {}, + shouldLogFailure = true, }: SendTransactionOpts): Promise { const EthersContract = getEthersContract(); const contractWithSigner = new EthersContract( @@ -69,7 +71,7 @@ export class ContractConcern extends TransactionConcern { } catch (err) { const error = err as WalletError; - if (this.shouldLogFailure(error)) { + if (shouldLogFailure && this.shouldLogFailure(error)) { await this.logFailedTx( error, contractWithSigner,