From 6317f670ab41915118f66f3b091086686c077ea5 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Fri, 13 Oct 2023 16:26:41 +0600 Subject: [PATCH 1/3] fix(swap): handle errors from order posting API --- .../cowswap-frontend/src/api/gnosisProtocol/api.ts | 14 ++++---------- .../api/gnosisProtocol/getIsOrderBookTypedError.ts | 10 ++++++++++ .../src/api/gnosisProtocol/index.ts | 1 + .../src/modules/trade/utils/swapErrorHelper.ts | 10 +++++++++- 4 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 apps/cowswap-frontend/src/api/gnosisProtocol/getIsOrderBookTypedError.ts diff --git a/apps/cowswap-frontend/src/api/gnosisProtocol/api.ts b/apps/cowswap-frontend/src/api/gnosisProtocol/api.ts index 87646e78ea..c4fa3e3061 100644 --- a/apps/cowswap-frontend/src/api/gnosisProtocol/api.ts +++ b/apps/cowswap-frontend/src/api/gnosisProtocol/api.ts @@ -5,7 +5,6 @@ import { CowEnv, EnrichedOrder, NativePriceResponse, - OrderBookApiError, OrderKind, OrderQuoteRequest, OrderQuoteResponse, @@ -25,9 +24,11 @@ import { LegacyFeeQuoteParams as FeeQuoteParams } from 'legacy/state/price/types import { getAppData } from 'modules/appData' -import { ApiErrorCodes, ApiErrorObject } from 'api/gnosisProtocol/errors/OperatorError' +import { ApiErrorCodes } from 'api/gnosisProtocol/errors/OperatorError' import GpQuoteError, { GpQuoteErrorDetails, mapOperatorErrorToQuoteError } from 'api/gnosisProtocol/errors/QuoteError' +import { getIsOrderBookTypedError } from './getIsOrderBookTypedError' + function getProfileUrl(): Partial> { if (isLocal || isDev || isPr || isBarn) { return { @@ -165,7 +166,7 @@ export async function getQuote(params: FeeQuoteParams): Promise { - if (isOrderbookTypedError(error)) { + if (getIsOrderBookTypedError(error)) { const errorObject = mapOperatorErrorToQuoteError(error.body) return Promise.reject(errorObject ? new GpQuoteError(errorObject) : error) @@ -175,13 +176,6 @@ export async function getQuote(params: FeeQuoteParams): Promise - -function isOrderbookTypedError(e: any): e is OrderbookTypedError { - const error = e as OrderbookTypedError - return error.body.errorType !== undefined && error.body.description !== undefined -} - export async function getOrder(chainId: ChainId, orderId: string, env?: CowEnv): Promise { const contextOverride = { chainId, diff --git a/apps/cowswap-frontend/src/api/gnosisProtocol/getIsOrderBookTypedError.ts b/apps/cowswap-frontend/src/api/gnosisProtocol/getIsOrderBookTypedError.ts new file mode 100644 index 0000000000..61726597af --- /dev/null +++ b/apps/cowswap-frontend/src/api/gnosisProtocol/getIsOrderBookTypedError.ts @@ -0,0 +1,10 @@ +import { OrderBookApiError } from '@cowprotocol/cow-sdk' + +import { ApiErrorObject } from './errors/OperatorError' + +export type OrderBookTypedError = OrderBookApiError + +export function getIsOrderBookTypedError(e: any): e is OrderBookTypedError { + const error = e as OrderBookTypedError + return error.body.errorType !== undefined && error.body.description !== undefined +} diff --git a/apps/cowswap-frontend/src/api/gnosisProtocol/index.ts b/apps/cowswap-frontend/src/api/gnosisProtocol/index.ts index ede6377c72..901a8a4395 100644 --- a/apps/cowswap-frontend/src/api/gnosisProtocol/index.ts +++ b/apps/cowswap-frontend/src/api/gnosisProtocol/index.ts @@ -2,6 +2,7 @@ import * as realApi from './api' import * as mockApi from './mock' export type { UnsupportedToken, OrderID } from './api' +export { getIsOrderBookTypedError } from './getIsOrderBookTypedError' const useMock = process.env.REACT_APP_MOCK === 'true' diff --git a/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts b/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts index 9e9e4df301..67018562a8 100644 --- a/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts +++ b/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts @@ -1,11 +1,19 @@ import { getProviderErrorMessage, isRejectRequestProviderError } from '@cowprotocol/common-utils' +import { getIsOrderBookTypedError } from 'api/gnosisProtocol' + export const USER_SWAP_REJECTED_ERROR = 'User rejected signing the order' export function getSwapErrorMessage(error: Error): string { if (isRejectRequestProviderError(error)) { return USER_SWAP_REJECTED_ERROR } else { - return getProviderErrorMessage(error) + const defaultErrorMessage = getProviderErrorMessage(error) + + if (getIsOrderBookTypedError(error)) { + return error.body?.description || defaultErrorMessage + } + + return defaultErrorMessage } } From 679e9fafa4c119c95f5bb531378aa7c32358e307 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Fri, 13 Oct 2023 17:07:00 +0600 Subject: [PATCH 2/3] chore: capitalize first letter of error --- .../src/modules/trade/utils/swapErrorHelper.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts b/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts index 67018562a8..c230032748 100644 --- a/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts +++ b/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts @@ -11,9 +11,15 @@ export function getSwapErrorMessage(error: Error): string { const defaultErrorMessage = getProviderErrorMessage(error) if (getIsOrderBookTypedError(error)) { - return error.body?.description || defaultErrorMessage + return capitalizeFirstLetter(error.body?.description) || defaultErrorMessage } return defaultErrorMessage } } + +function capitalizeFirstLetter(str: string): string { + if (!str) return str + + return str.charAt(0).toUpperCase() + str.slice(1) +} From 346456a68e7ebd5f3c8fc7014eb0ee1c193b7211 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Fri, 13 Oct 2023 18:41:43 +0600 Subject: [PATCH 3/3] chore: move capitalizeFirstLetter to lib --- .../src/modules/trade/utils/swapErrorHelper.ts | 8 +------- libs/common-utils/src/capitalizeFirstLetter.ts | 5 +++++ libs/common-utils/src/index.ts | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 libs/common-utils/src/capitalizeFirstLetter.ts diff --git a/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts b/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts index c230032748..14d0416ed8 100644 --- a/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts +++ b/apps/cowswap-frontend/src/modules/trade/utils/swapErrorHelper.ts @@ -1,4 +1,4 @@ -import { getProviderErrorMessage, isRejectRequestProviderError } from '@cowprotocol/common-utils' +import { capitalizeFirstLetter, getProviderErrorMessage, isRejectRequestProviderError } from '@cowprotocol/common-utils' import { getIsOrderBookTypedError } from 'api/gnosisProtocol' @@ -17,9 +17,3 @@ export function getSwapErrorMessage(error: Error): string { return defaultErrorMessage } } - -function capitalizeFirstLetter(str: string): string { - if (!str) return str - - return str.charAt(0).toUpperCase() + str.slice(1) -} diff --git a/libs/common-utils/src/capitalizeFirstLetter.ts b/libs/common-utils/src/capitalizeFirstLetter.ts new file mode 100644 index 0000000000..263cb0ec2e --- /dev/null +++ b/libs/common-utils/src/capitalizeFirstLetter.ts @@ -0,0 +1,5 @@ +export function capitalizeFirstLetter(str: string): string { + if (!str) return str + + return str.charAt(0).toUpperCase() + str.slice(1) +} diff --git a/libs/common-utils/src/index.ts b/libs/common-utils/src/index.ts index 411a4ccc8b..ef8fd97326 100644 --- a/libs/common-utils/src/index.ts +++ b/libs/common-utils/src/index.ts @@ -50,4 +50,5 @@ export * from './getRandomInt' export * from './isEnoughAmount' export * from './tryParseFractionalAmount' export * from './maxAmountSpend' +export * from './capitalizeFirstLetter' export * from './jotai/atomWithPartialUpdate'