From 2f7e5b5f99794e19de1ae7b97094b3a2e4b87081 Mon Sep 17 00:00:00 2001 From: Alex Mubarakshin Date: Fri, 3 Jan 2025 12:12:49 +0200 Subject: [PATCH 1/2] feat(core): Provide error cause to errors --- packages/core/src/contract/deploy-contract.ts | 2 +- packages/core/src/contract/write-contract.ts | 2 +- packages/core/src/shared/errors/errors.ts | 4 +++- .../core/src/shared/errors/return-error.ts | 21 ++++++++++++++++--- .../core/src/shared/errors/syntax-errors.ts | 18 ++++++++++------ packages/core/src/shared/errors/ton-errors.ts | 12 +++++++---- .../core/src/shared/errors/user-errors.ts | 9 +++++--- packages/core/src/wallet/send-transaction.ts | 2 +- 8 files changed, 50 insertions(+), 20 deletions(-) diff --git a/packages/core/src/contract/deploy-contract.ts b/packages/core/src/contract/deploy-contract.ts index 30534f7..752f149 100644 --- a/packages/core/src/contract/deploy-contract.ts +++ b/packages/core/src/contract/deploy-contract.ts @@ -68,6 +68,6 @@ export async function deployContract ( } catch (error) { console.error('err', error); // TODO: add more error handlers for different scenarios - return returnError('UserRejectedTransactionError'); + return returnError('UserRejectedTransactionError', error as Error); } } diff --git a/packages/core/src/contract/write-contract.ts b/packages/core/src/contract/write-contract.ts index cf48c0b..67f8a33 100644 --- a/packages/core/src/contract/write-contract.ts +++ b/packages/core/src/contract/write-contract.ts @@ -53,7 +53,7 @@ export async function writeContract ( +export const returnError = ( type: TYPE, + cause?: Error ): DataOrError => { - const error = new supportedErrors[type](); + const nativeTonErrors: SupportedErrorsKeys[] = ['TonConnectError', 'TonConnectUIError'] as const; + + const errorClass = supportedErrors[type] + + if (nativeTonErrors.includes(type)) { + const error = new errorClass(); + + return { data: undefined, error: error as SupportedErrors[TYPE] }; + } + + const error = new errorClass(cause as any); return { data: undefined, error: error as SupportedErrors[TYPE] }; }; diff --git a/packages/core/src/shared/errors/syntax-errors.ts b/packages/core/src/shared/errors/syntax-errors.ts index cee98bb..24223f2 100644 --- a/packages/core/src/shared/errors/syntax-errors.ts +++ b/packages/core/src/shared/errors/syntax-errors.ts @@ -6,44 +6,50 @@ export class SyntaxError extends Error { } export class ConnectFunctionUnavailableError extends SyntaxError { - constructor() { + constructor(cause?: Error) { super('This function is not available for UI-based wallet connections. Use `createWalletClientUI` instead'); this.name = 'ConnectFunctionUnavailableError'; + this.cause = cause; } } export class ConnectUIFunctionUnavailableError extends SyntaxError { - constructor() { + constructor(cause?: Error) { super('This function is only available for UI-based wallet connections'); this.name = 'ConnectUIFunctionUnavailableError'; + this.cause = cause; } } export class ConnectUIFunctionUnavailableInNodeError extends SyntaxError { - constructor() { + constructor(cause?: Error) { super('This function is not available in the server environment. Please you `createWalletClient` instead or, if you use Next.js, call `createWalletClientUI` in `useEffect` hook or in the event handler, so it creates a wallet client when the `window` is available.'); this.name = 'ConnectUIFunctionUnavailableInNodeError'; + this.cause = cause; } } export class ReconnectFunctionUnavailableError extends SyntaxError { - constructor() { + constructor(cause?: Error) { super('The reconnect is not available for UI-based wallet connections. Pass `restoreConnection: true` to the `createWalletClientUI` function to enable it'); this.name = 'ReconnectFunctionUnavailableError'; + this.cause = cause; } } export class IncorrectContractError extends SyntaxError { - constructor() { + constructor(cause?: Error) { super('The contract is incorrect. Provide the contract class compiled from your Tact or Func files'); this.name = 'IncorrectContractError'; + this.cause = cause; } } export class MissingContractAddressError extends SyntaxError { - constructor() { + constructor(cause?: Error) { super('The contract address is not provided to the walletClient. Call `setAddress` first'); this.name = 'MissingContractAddressError'; + this.cause = cause; } } diff --git a/packages/core/src/shared/errors/ton-errors.ts b/packages/core/src/shared/errors/ton-errors.ts index 746f025..4918332 100644 --- a/packages/core/src/shared/errors/ton-errors.ts +++ b/packages/core/src/shared/errors/ton-errors.ts @@ -16,30 +16,34 @@ export class TonError extends Error { } export class TonWalletConnectionError extends TonError { - constructor() { + constructor(cause?: Error) { super('Wallet connection failed'); this.name = 'TonWalletConnectionError'; + this.cause = cause; } } export class TonWalletDisconnectError extends TonError { - constructor() { + constructor(cause?: Error) { super('Could not disconnect from the wallet'); this.name = 'TonWalletDisconnectError'; + this.cause = cause; } } export class TonReadError extends TonError { - constructor() { + constructor(cause?: Error) { super('Cannot process the read request. Either the request returned a non-zero exit code or the data could not be parsed'); this.name = 'TonReadError'; + this.cause = cause; } } export class TonRateLimitError extends TonError { - constructor() { + constructor(cause?: Error) { super('Rate limit is exceeded. Provide the `authKey` to the public client with a better Ton Center plan to get more requests per second'); this.name = 'TonRateLimitError'; + this.cause = cause; } } diff --git a/packages/core/src/shared/errors/user-errors.ts b/packages/core/src/shared/errors/user-errors.ts index 7f0fe29..c5fd1d1 100644 --- a/packages/core/src/shared/errors/user-errors.ts +++ b/packages/core/src/shared/errors/user-errors.ts @@ -6,22 +6,25 @@ export class UserError extends Error { } export class UserUnauthorizedError extends UserError { - constructor() { + constructor(cause?: Error) { super('Not authorized. Please, connect the wallet first'); this.name = 'UserUnauthorizedError'; + this.cause = cause; } } export class UserRejectedConnectionError extends UserError { - constructor() { + constructor(cause?: Error) { super('User rejected the connection to their wallet'); this.name = 'UserRejectedConnectionError'; + this.cause = cause; } } export class UserRejectedTransactionError extends UserError { - constructor() { + constructor(cause?: Error) { super('User rejected the transaction request from their wallet'); this.name = 'UserRejectedTransactionError'; + this.cause = cause; } } diff --git a/packages/core/src/wallet/send-transaction.ts b/packages/core/src/wallet/send-transaction.ts index a483330..2f3d046 100644 --- a/packages/core/src/wallet/send-transaction.ts +++ b/packages/core/src/wallet/send-transaction.ts @@ -32,6 +32,6 @@ export async function sendTransaction ( const hash = bocToHash(res.boc); return returnData(hash); } catch (error) { - return returnError('UserRejectedTransactionError'); + return returnError('UserRejectedTransactionError', error as Error); } } From 902637156a165d406d4990732d52c371cbe00c6a Mon Sep 17 00:00:00 2001 From: Alex Mubarakshin Date: Fri, 3 Jan 2025 14:22:17 +0200 Subject: [PATCH 2/2] refactor(errors): update error handling to accept unknown types for causes --- packages/core/src/contract/read-contract.ts | 6 +++--- packages/core/src/contract/write-contract.ts | 2 +- packages/core/src/shared/errors/return-error.ts | 2 +- packages/core/src/shared/errors/syntax-errors.ts | 12 ++++++------ packages/core/src/shared/errors/ton-errors.ts | 8 ++++---- packages/core/src/shared/errors/user-errors.ts | 6 +++--- packages/core/src/wallet/send-transaction.ts | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/core/src/contract/read-contract.ts b/packages/core/src/contract/read-contract.ts index 6284240..9fec28d 100644 --- a/packages/core/src/contract/read-contract.ts +++ b/packages/core/src/contract/read-contract.ts @@ -41,9 +41,9 @@ export async function readContract ); } catch (error) { - return returnError('TonReadError'); + return returnError('TonReadError', error); } } diff --git a/packages/core/src/contract/write-contract.ts b/packages/core/src/contract/write-contract.ts index 67f8a33..e919257 100644 --- a/packages/core/src/contract/write-contract.ts +++ b/packages/core/src/contract/write-contract.ts @@ -53,7 +53,7 @@ export async function writeContract ( type: TYPE, - cause?: Error + cause?: unknown ): DataOrError => { const nativeTonErrors: SupportedErrorsKeys[] = ['TonConnectError', 'TonConnectUIError'] as const; diff --git a/packages/core/src/shared/errors/syntax-errors.ts b/packages/core/src/shared/errors/syntax-errors.ts index 24223f2..7567d20 100644 --- a/packages/core/src/shared/errors/syntax-errors.ts +++ b/packages/core/src/shared/errors/syntax-errors.ts @@ -6,7 +6,7 @@ export class SyntaxError extends Error { } export class ConnectFunctionUnavailableError extends SyntaxError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('This function is not available for UI-based wallet connections. Use `createWalletClientUI` instead'); this.name = 'ConnectFunctionUnavailableError'; this.cause = cause; @@ -14,7 +14,7 @@ export class ConnectFunctionUnavailableError extends SyntaxError { } export class ConnectUIFunctionUnavailableError extends SyntaxError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('This function is only available for UI-based wallet connections'); this.name = 'ConnectUIFunctionUnavailableError'; this.cause = cause; @@ -23,7 +23,7 @@ export class ConnectUIFunctionUnavailableError extends SyntaxError { export class ConnectUIFunctionUnavailableInNodeError extends SyntaxError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('This function is not available in the server environment. Please you `createWalletClient` instead or, if you use Next.js, call `createWalletClientUI` in `useEffect` hook or in the event handler, so it creates a wallet client when the `window` is available.'); this.name = 'ConnectUIFunctionUnavailableInNodeError'; this.cause = cause; @@ -31,7 +31,7 @@ export class ConnectUIFunctionUnavailableInNodeError extends SyntaxError { } export class ReconnectFunctionUnavailableError extends SyntaxError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('The reconnect is not available for UI-based wallet connections. Pass `restoreConnection: true` to the `createWalletClientUI` function to enable it'); this.name = 'ReconnectFunctionUnavailableError'; this.cause = cause; @@ -39,7 +39,7 @@ export class ReconnectFunctionUnavailableError extends SyntaxError { } export class IncorrectContractError extends SyntaxError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('The contract is incorrect. Provide the contract class compiled from your Tact or Func files'); this.name = 'IncorrectContractError'; this.cause = cause; @@ -47,7 +47,7 @@ export class IncorrectContractError extends SyntaxError { } export class MissingContractAddressError extends SyntaxError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('The contract address is not provided to the walletClient. Call `setAddress` first'); this.name = 'MissingContractAddressError'; this.cause = cause; diff --git a/packages/core/src/shared/errors/ton-errors.ts b/packages/core/src/shared/errors/ton-errors.ts index 4918332..c180d98 100644 --- a/packages/core/src/shared/errors/ton-errors.ts +++ b/packages/core/src/shared/errors/ton-errors.ts @@ -16,7 +16,7 @@ export class TonError extends Error { } export class TonWalletConnectionError extends TonError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('Wallet connection failed'); this.name = 'TonWalletConnectionError'; this.cause = cause; @@ -24,7 +24,7 @@ export class TonWalletConnectionError extends TonError { } export class TonWalletDisconnectError extends TonError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('Could not disconnect from the wallet'); this.name = 'TonWalletDisconnectError'; this.cause = cause; @@ -32,7 +32,7 @@ export class TonWalletDisconnectError extends TonError { } export class TonReadError extends TonError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('Cannot process the read request. Either the request returned a non-zero exit code or the data could not be parsed'); this.name = 'TonReadError'; this.cause = cause; @@ -40,7 +40,7 @@ export class TonReadError extends TonError { } export class TonRateLimitError extends TonError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('Rate limit is exceeded. Provide the `authKey` to the public client with a better Ton Center plan to get more requests per second'); this.name = 'TonRateLimitError'; this.cause = cause; diff --git a/packages/core/src/shared/errors/user-errors.ts b/packages/core/src/shared/errors/user-errors.ts index c5fd1d1..f07299a 100644 --- a/packages/core/src/shared/errors/user-errors.ts +++ b/packages/core/src/shared/errors/user-errors.ts @@ -6,7 +6,7 @@ export class UserError extends Error { } export class UserUnauthorizedError extends UserError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('Not authorized. Please, connect the wallet first'); this.name = 'UserUnauthorizedError'; this.cause = cause; @@ -14,7 +14,7 @@ export class UserUnauthorizedError extends UserError { } export class UserRejectedConnectionError extends UserError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('User rejected the connection to their wallet'); this.name = 'UserRejectedConnectionError'; this.cause = cause; @@ -22,7 +22,7 @@ export class UserRejectedConnectionError extends UserError { } export class UserRejectedTransactionError extends UserError { - constructor(cause?: Error) { + constructor(cause?: unknown) { super('User rejected the transaction request from their wallet'); this.name = 'UserRejectedTransactionError'; this.cause = cause; diff --git a/packages/core/src/wallet/send-transaction.ts b/packages/core/src/wallet/send-transaction.ts index 2f3d046..e4e5e6b 100644 --- a/packages/core/src/wallet/send-transaction.ts +++ b/packages/core/src/wallet/send-transaction.ts @@ -32,6 +32,6 @@ export async function sendTransaction ( const hash = bocToHash(res.boc); return returnData(hash); } catch (error) { - return returnError('UserRejectedTransactionError', error as Error); + return returnError('UserRejectedTransactionError', error); } }