From 48c67040f4efb9c4a615b7006e85f0bcbb82f2a7 Mon Sep 17 00:00:00 2001 From: VK Date: Thu, 14 May 2026 14:12:17 +0400 Subject: [PATCH 1/9] fix(appkit): rework connectors events --- .../actions/connectors/connectors.test.ts | 10 +++---- .../connectors/watch-connector-by-id.ts | 12 ++++++--- .../actions/connectors/watch-connectors.ts | 12 ++++++--- .../connectors/ton-connect-connector.ts | 26 ++++++++++++------- .../src/core/app-kit/constants/events.ts | 5 ++-- packages/appkit/src/core/app-kit/index.ts | 5 ++-- .../src/core/app-kit/services/app-kit.ts | 7 +++-- .../appkit/src/core/app-kit/types/events.ts | 18 ++++++++----- 8 files changed, 62 insertions(+), 33 deletions(-) diff --git a/demo/examples/src/appkit/actions/connectors/connectors.test.ts b/demo/examples/src/appkit/actions/connectors/connectors.test.ts index 223439185..dfcbdab81 100644 --- a/demo/examples/src/appkit/actions/connectors/connectors.test.ts +++ b/demo/examples/src/appkit/actions/connectors/connectors.test.ts @@ -95,10 +95,9 @@ describe('Connector Actions Examples (Integration)', () => { // Trigger event appKit.emitter.emit( - CONNECTOR_EVENTS.CONNECTED, + CONNECTOR_EVENTS.ADDED, { - wallets: [], - connectorId: 'test', + connector: mockConnector, }, 'test', ); @@ -113,10 +112,9 @@ describe('Connector Actions Examples (Integration)', () => { // Trigger event appKit.emitter.emit( - CONNECTOR_EVENTS.CONNECTED, + CONNECTOR_EVENTS.ADDED, { - wallets: [], - connectorId: 'test', + connector: mockConnector, }, 'test', ); diff --git a/packages/appkit/src/actions/connectors/watch-connector-by-id.ts b/packages/appkit/src/actions/connectors/watch-connector-by-id.ts index 067d86397..757ec9ce9 100644 --- a/packages/appkit/src/actions/connectors/watch-connector-by-id.ts +++ b/packages/appkit/src/actions/connectors/watch-connector-by-id.ts @@ -27,9 +27,15 @@ export const watchConnectorById = ( ): WatchConnectorByIdReturnType => { const { id, onChange } = parameters; - const unsubscribe = appKit.emitter.on(CONNECTOR_EVENTS.CONNECTED, () => { + const handler = (): void => { onChange(getConnectorById(appKit, { id })); - }); + }; - return unsubscribe; + const unsubscribeAdded = appKit.emitter.on(CONNECTOR_EVENTS.ADDED, handler); + const unsubscribeRemoved = appKit.emitter.on(CONNECTOR_EVENTS.REMOVED, handler); + + return () => { + unsubscribeAdded(); + unsubscribeRemoved(); + }; }; diff --git a/packages/appkit/src/actions/connectors/watch-connectors.ts b/packages/appkit/src/actions/connectors/watch-connectors.ts index a4d3b76e2..eabe24535 100644 --- a/packages/appkit/src/actions/connectors/watch-connectors.ts +++ b/packages/appkit/src/actions/connectors/watch-connectors.ts @@ -23,9 +23,15 @@ export type WatchConnectorsReturnType = () => void; export const watchConnectors = (appKit: AppKit, parameters: WatchConnectorsParameters): WatchConnectorsReturnType => { const { onChange } = parameters; - const unsubscribe = appKit.emitter.on(CONNECTOR_EVENTS.CONNECTED, () => { + const handler = (): void => { onChange(getConnectors(appKit)); - }); + }; - return unsubscribe; + const unsubscribeAdded = appKit.emitter.on(CONNECTOR_EVENTS.ADDED, handler); + const unsubscribeRemoved = appKit.emitter.on(CONNECTOR_EVENTS.REMOVED, handler); + + return () => { + unsubscribeAdded(); + unsubscribeRemoved(); + }; }; diff --git a/packages/appkit/src/connectors/tonconnect/connectors/ton-connect-connector.ts b/packages/appkit/src/connectors/tonconnect/connectors/ton-connect-connector.ts index c53507fc1..f3454623e 100644 --- a/packages/appkit/src/connectors/tonconnect/connectors/ton-connect-connector.ts +++ b/packages/appkit/src/connectors/tonconnect/connectors/ton-connect-connector.ts @@ -32,10 +32,16 @@ export const createTonConnectConnector = (config: TonConnectConnectorConfig) => return createConnector(({ eventEmitter, networkManager, ssr }): TonConnectConnector => { let originalTonConnectUI: TonConnectUI | null = null; let unsubscribeTonConnect: (() => void) | null = null; + let unsubscribeDefaultNetwork: (() => void) | null = null; + let destroyed = false; const id = config.id ?? TONCONNECT_DEFAULT_CONNECTOR_ID; const getTonConnectUI = (): TonConnectUI | null => { + if (destroyed) { + return null; + } + if (originalTonConnectUI) { return originalTonConnectUI; } @@ -84,19 +90,17 @@ export const createTonConnectConnector = (config: TonConnectConnectorConfig) => return; } - unsubscribeTonConnect = originalTonConnectUI.onStatusChange((wallet) => { - const wallets = getConnectedWallets(); - - if (wallet) { - eventEmitter.emit(CONNECTOR_EVENTS.CONNECTED, { wallets, connectorId: id }, id); - } else { - eventEmitter.emit(CONNECTOR_EVENTS.DISCONNECTED, { connectorId: id }, id); - } + unsubscribeTonConnect = originalTonConnectUI.onStatusChange(() => { + eventEmitter.emit( + CONNECTOR_EVENTS.WALLETS_UPDATED, + { connectorId: id, wallets: getConnectedWallets() }, + id, + ); }); // Set default network and subscribe to changes originalTonConnectUI.setConnectionNetwork(networkManager.getDefaultNetwork()?.chainId); - eventEmitter.on(NETWORKS_EVENTS.DEFAULT_CHANGED, ({ payload }) => { + unsubscribeDefaultNetwork = eventEmitter.on(NETWORKS_EVENTS.DEFAULT_CHANGED, ({ payload }) => { if (originalTonConnectUI) { originalTonConnectUI.setConnectionNetwork(payload.network?.chainId); } @@ -135,7 +139,11 @@ export const createTonConnectConnector = (config: TonConnectConnectorConfig) => }, destroy() { + destroyed = true; unsubscribeTonConnect?.(); + unsubscribeDefaultNetwork?.(); + unsubscribeTonConnect = null; + unsubscribeDefaultNetwork = null; originalTonConnectUI = null; }, }; diff --git a/packages/appkit/src/core/app-kit/constants/events.ts b/packages/appkit/src/core/app-kit/constants/events.ts index d8c012c55..54d645101 100644 --- a/packages/appkit/src/core/app-kit/constants/events.ts +++ b/packages/appkit/src/core/app-kit/constants/events.ts @@ -10,8 +10,9 @@ * Connector events */ export const CONNECTOR_EVENTS = { - CONNECTED: 'connector:connected', - DISCONNECTED: 'connector:disconnected', + ADDED: 'connector:added', + REMOVED: 'connector:removed', + WALLETS_UPDATED: 'connector:wallets-updated', } as const; /** diff --git a/packages/appkit/src/core/app-kit/index.ts b/packages/appkit/src/core/app-kit/index.ts index 89ee67bcf..92e06e688 100644 --- a/packages/appkit/src/core/app-kit/index.ts +++ b/packages/appkit/src/core/app-kit/index.ts @@ -13,7 +13,8 @@ export type { AppKitConfig } from './types/config'; export type { AppKitEmitter, AppKitEvents, - WalletConnectedPayload, - WalletDisconnectedPayload, + ConnectorAddedPayload, + ConnectorRemovedPayload, + ConnectorWalletsUpdatedPayload, DefaultNetworkChangedPayload, } from './types/events'; diff --git a/packages/appkit/src/core/app-kit/services/app-kit.ts b/packages/appkit/src/core/app-kit/services/app-kit.ts index e99423010..44fe38c01 100644 --- a/packages/appkit/src/core/app-kit/services/app-kit.ts +++ b/packages/appkit/src/core/app-kit/services/app-kit.ts @@ -47,8 +47,7 @@ export class AppKit { this.config = config; this.emitter = new EventEmitter(); - this.emitter.on(CONNECTOR_EVENTS.CONNECTED, this.updateWalletsFromConnectors.bind(this)); - this.emitter.on(CONNECTOR_EVENTS.DISCONNECTED, this.updateWalletsFromConnectors.bind(this)); + this.emitter.on(CONNECTOR_EVENTS.WALLETS_UPDATED, this.updateWalletsFromConnectors.bind(this)); // Use provided networks config or default to mainnet const networks = config.networks ?? { @@ -94,6 +93,8 @@ export class AppKit { } this.connectors.push(connector); + this.updateWalletsFromConnectors(); + this.emitter.emit(CONNECTOR_EVENTS.ADDED, { connector }, 'appkit'); return () => { this.removeConnector(connector); @@ -110,6 +111,8 @@ export class AppKit { if (oldConnector) { oldConnector.destroy(); this.connectors.splice(this.connectors.indexOf(oldConnector), 1); + this.updateWalletsFromConnectors(); + this.emitter.emit(CONNECTOR_EVENTS.REMOVED, { connector: oldConnector }, 'appkit'); } } diff --git a/packages/appkit/src/core/app-kit/types/events.ts b/packages/appkit/src/core/app-kit/types/events.ts index b0b602589..e52c78400 100644 --- a/packages/appkit/src/core/app-kit/types/events.ts +++ b/packages/appkit/src/core/app-kit/types/events.ts @@ -6,19 +6,24 @@ * */ +import type { Connector } from '../../../types/connector'; import type { Network } from '../../../types/network'; import type { CONNECTOR_EVENTS, WALLETS_EVENTS, NETWORKS_EVENTS } from '../constants/events'; import type { SharedKitEvents } from '../../emitter'; import type { EventEmitter } from '../../emitter'; import type { WalletInterface } from '../../../types/wallet'; -export interface WalletConnectedPayload { - wallets: WalletInterface[]; - connectorId: string; +export interface ConnectorAddedPayload { + connector: Connector; } -export interface WalletDisconnectedPayload { +export interface ConnectorRemovedPayload { + connector: Connector; +} + +export interface ConnectorWalletsUpdatedPayload { connectorId: string; + wallets: WalletInterface[]; } export interface DefaultNetworkChangedPayload { @@ -27,8 +32,9 @@ export interface DefaultNetworkChangedPayload { export type AppKitEvents = { // Connector events - [CONNECTOR_EVENTS.CONNECTED]: WalletConnectedPayload; - [CONNECTOR_EVENTS.DISCONNECTED]: WalletDisconnectedPayload; + [CONNECTOR_EVENTS.ADDED]: ConnectorAddedPayload; + [CONNECTOR_EVENTS.REMOVED]: ConnectorRemovedPayload; + [CONNECTOR_EVENTS.WALLETS_UPDATED]: ConnectorWalletsUpdatedPayload; // Wallets events [WALLETS_EVENTS.UPDATED]: { wallets: WalletInterface[] }; From eafb87bafbc375c65cd55e14bd638c8389f5e18b Mon Sep 17 00:00:00 2001 From: VK Date: Thu, 14 May 2026 14:12:25 +0400 Subject: [PATCH 2/9] feat(appkit): delete BalanceBadge --- .../balance-badge/balance-badge.module.css | 21 ------ .../balance-badge/balance-badge.stories.tsx | 68 ------------------- .../balance-badge/balance-badge.tsx | 47 ------------- .../components/balance-badge/index.ts | 9 --- .../src/features/balances/index.ts | 1 - 5 files changed, 146 deletions(-) delete mode 100644 packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.module.css delete mode 100644 packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.stories.tsx delete mode 100644 packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.tsx delete mode 100644 packages/appkit-react/src/features/balances/components/balance-badge/index.ts diff --git a/packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.module.css b/packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.module.css deleted file mode 100644 index f942d9b42..000000000 --- a/packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.module.css +++ /dev/null @@ -1,21 +0,0 @@ -.balance { - composes: labelMedium from "../../../../styles/typography.module.css"; - - width: fit-content; - gap: 12px; - padding: 12px; - color: var(--ta-color-text-secondary); - line-height: 1; -} - -.balanceContainer { - display: flex; - flex-direction: column; - gap: 4px; -} - -.ticker { - composes: labelSemibold from "../../../../styles/typography.module.css"; - color: var(--ta-color-text); - line-height: 1; -} diff --git a/packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.stories.tsx b/packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.stories.tsx deleted file mode 100644 index 38f92775e..000000000 --- a/packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.stories.tsx +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) TonTech. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; - -import { BalanceBadge } from './balance-badge'; - -const meta: Meta = { - title: 'Features/Balances/BalanceBadge', - tags: ['autodocs'], -}; - -export default meta; - -type Story = StoryObj; - -export const TonBalance: Story = { - render: () => ( - - - - - - - - ), -}; - -export const JettonBalance: Story = { - render: () => ( - - - - - - - - ), -}; - -export const ZeroBalance: Story = { - render: () => ( - - - - - - - - ), -}; - -export const LargeBalance: Story = { - render: () => ( - - - - - - - - ), -}; diff --git a/packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.tsx b/packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.tsx deleted file mode 100644 index e3b6942b3..000000000 --- a/packages/appkit-react/src/features/balances/components/balance-badge/balance-badge.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) TonTech. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -import { formatUnits } from '@ton/appkit'; -import type { FC, ComponentProps } from 'react'; -import clsx from 'clsx'; - -import { Block } from '../../../../components/ui/block'; -import styles from './balance-badge.module.css'; -import { Logo } from '../../../../components/ui/logo'; - -const BalanceBadgeContainer: FC> = ({ className, ...props }) => { - return ; -}; - -const BalanceBlock: FC> = ({ className, ...props }) => { - return
; -}; - -const Balance: FC & { balance: string; decimals: number }> = ({ - balance, - decimals, - ...props -}) => { - return {balance ? formatUnits(balance, decimals) : '0'}; -}; - -const BalanceSymbol: FC & { symbol: string }> = ({ className, symbol, ...props }) => { - return ( - - {symbol} - - ); -}; - -export const BalanceBadge = { - Container: BalanceBadgeContainer, - Icon: Logo, - BalanceBlock: BalanceBlock, - Symbol: BalanceSymbol, - Balance: Balance, -}; diff --git a/packages/appkit-react/src/features/balances/components/balance-badge/index.ts b/packages/appkit-react/src/features/balances/components/balance-badge/index.ts deleted file mode 100644 index 916030712..000000000 --- a/packages/appkit-react/src/features/balances/components/balance-badge/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) TonTech. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -export { BalanceBadge } from './balance-badge'; diff --git a/packages/appkit-react/src/features/balances/index.ts b/packages/appkit-react/src/features/balances/index.ts index e5a7a0f1d..cd5ec480d 100644 --- a/packages/appkit-react/src/features/balances/index.ts +++ b/packages/appkit-react/src/features/balances/index.ts @@ -6,7 +6,6 @@ * */ -export * from './components/balance-badge'; export * from './components/send-ton-button'; export * from './components/send-jetton-button'; From 476b166454dd812d5def4e5752691ab233cbba88 Mon Sep 17 00:00:00 2001 From: VK Date: Thu, 14 May 2026 14:12:39 +0400 Subject: [PATCH 3/9] feat(appkit): fix send decimals error --- .../components/send-jetton-button/send-jetton-button.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/appkit-react/src/features/balances/components/send-jetton-button/send-jetton-button.tsx b/packages/appkit-react/src/features/balances/components/send-jetton-button/send-jetton-button.tsx index d9d8cd399..78048a8ef 100644 --- a/packages/appkit-react/src/features/balances/components/send-jetton-button/send-jetton-button.tsx +++ b/packages/appkit-react/src/features/balances/components/send-jetton-button/send-jetton-button.tsx @@ -40,7 +40,7 @@ export const SendJettonButton: FC = ({ throw new Error('Jetton address is required'); } - if (!jetton.decimals) { + if (jetton.decimals === undefined) { throw new Error('Jetton decimals is required'); } @@ -54,7 +54,7 @@ export const SendJettonButton: FC = ({ }, [appKit, recipientAddress, amount, comment, jetton]); const text = useMemo(() => { - if (amount && jetton.decimals) { + if (amount && jetton.decimals !== undefined) { return t('balances.sendJettonWithAmount', { amount: formatUnits(parseUnits(amount, jetton.decimals), jetton.decimals).toString(), symbol: jetton.symbol, @@ -68,7 +68,7 @@ export const SendJettonButton: FC = ({ ); From 7437ad476c5e581706a010bee657ff903bcb01f6 Mon Sep 17 00:00:00 2001 From: VK Date: Thu, 14 May 2026 14:22:13 +0400 Subject: [PATCH 4/9] feat: unified API for providers errors --- .../utils/map-crypto-onramp-error.ts | 14 +++++------ .../src/features/swap/utils/map-swap-error.ts | 10 ++++---- .../appkit-react/src/utils/map-defi-error.ts | 14 +++++------ packages/appkit/src/crypto-onramp/index.ts | 2 +- packages/appkit/src/swap/index.ts | 2 +- packages/walletkit/src/defi/DefiManager.ts | 11 +++++---- .../defi/crypto-onramp/CryptoOnrampManager.ts | 3 ++- .../src/defi/crypto-onramp/errors.ts | 20 ++++++++++------ .../LayerswapCryptoOnrampProvider.ts | 22 ++++++++--------- .../swaps-xyz/SwapsXyzCryptoOnrampProvider.ts | 24 +++++++++---------- packages/walletkit/src/defi/errors.ts | 16 +++++++------ .../src/defi/onramp/OnrampManager.ts | 3 ++- packages/walletkit/src/defi/onramp/errors.ts | 15 ++++++++---- .../defi/onramp/mercuryo/MercuryoProvider.ts | 6 ++--- .../defi/onramp/moonpay/MoonpayProvider.ts | 8 +++---- .../src/defi/onramp/ton-pay/TonPayProvider.ts | 6 ++--- .../walletkit/src/defi/swap/SwapManager.ts | 3 ++- .../defi/swap/dedust/DeDustSwapProvider.ts | 20 ++++++++-------- packages/walletkit/src/defi/swap/errors.ts | 16 +++++++++---- packages/walletkit/src/defi/swap/index.ts | 2 +- .../swap/omniston/OmnistonSwapProvider.ts | 20 +++++++++------- packages/walletkit/src/index.ts | 13 ++++++---- 22 files changed, 140 insertions(+), 110 deletions(-) diff --git a/packages/appkit-react/src/features/onramp/widgets/crypto-onramp/utils/map-crypto-onramp-error.ts b/packages/appkit-react/src/features/onramp/widgets/crypto-onramp/utils/map-crypto-onramp-error.ts index 5654656d6..176c03660 100644 --- a/packages/appkit-react/src/features/onramp/widgets/crypto-onramp/utils/map-crypto-onramp-error.ts +++ b/packages/appkit-react/src/features/onramp/widgets/crypto-onramp/utils/map-crypto-onramp-error.ts @@ -6,7 +6,7 @@ * */ -import { CryptoOnrampError } from '@ton/appkit'; +import { CryptoOnrampError, CryptoOnrampErrorCode } from '@ton/appkit'; import { mapDefiError } from '../../../../../utils/map-defi-error'; @@ -18,17 +18,17 @@ import { mapDefiError } from '../../../../../utils/map-defi-error'; export const mapCryptoOnrampError = (error: unknown): string => { if (error instanceof CryptoOnrampError) { switch (error.code) { - case CryptoOnrampError.REFUND_ADDRESS_REQUIRED: + case CryptoOnrampErrorCode.RefundAddressRequired: return 'cryptoOnramp.refundAddressRequired'; - case CryptoOnrampError.REVERSED_AMOUNT_NOT_SUPPORTED: + case CryptoOnrampErrorCode.ReversedAmountNotSupported: return 'cryptoOnramp.reversedAmountNotSupported'; - case CryptoOnrampError.INVALID_REFUND_ADDRESS: + case CryptoOnrampErrorCode.InvalidRefundAddress: return 'cryptoOnramp.invalidRefundAddress'; - case CryptoOnrampError.QUOTE_FAILED: + case CryptoOnrampErrorCode.QuoteFailed: return 'cryptoOnramp.quoteError'; - case CryptoOnrampError.PROVIDER_ERROR: + case CryptoOnrampErrorCode.ProviderError: return 'cryptoOnramp.providerError'; - case CryptoOnrampError.DEPOSIT_FAILED: + case CryptoOnrampErrorCode.DepositFailed: return 'cryptoOnramp.depositFailed'; } } diff --git a/packages/appkit-react/src/features/swap/utils/map-swap-error.ts b/packages/appkit-react/src/features/swap/utils/map-swap-error.ts index a916adc20..3ef3bcde2 100644 --- a/packages/appkit-react/src/features/swap/utils/map-swap-error.ts +++ b/packages/appkit-react/src/features/swap/utils/map-swap-error.ts @@ -6,7 +6,7 @@ * */ -import { SwapError } from '@ton/appkit'; +import { SwapError, SwapErrorCode } from '@ton/appkit'; import { mapDefiError } from '../../../utils/map-defi-error'; @@ -17,13 +17,13 @@ import { mapDefiError } from '../../../utils/map-defi-error'; export const mapSwapError = (error: unknown): string => { if (error instanceof SwapError) { switch (error.code) { - case SwapError.INVALID_QUOTE: + case SwapErrorCode.InvalidQuote: return 'swap.invalidQuote'; - case SwapError.INSUFFICIENT_LIQUIDITY: + case SwapErrorCode.InsufficientLiquidity: return 'swap.insufficientLiquidity'; - case SwapError.QUOTE_EXPIRED: + case SwapErrorCode.QuoteExpired: return 'swap.quoteExpired'; - case SwapError.BUILD_TX_FAILED: + case SwapErrorCode.BuildTxFailed: return 'swap.buildTxFailed'; } } diff --git a/packages/appkit-react/src/utils/map-defi-error.ts b/packages/appkit-react/src/utils/map-defi-error.ts index 0a3b5ce7a..f46fec947 100644 --- a/packages/appkit-react/src/utils/map-defi-error.ts +++ b/packages/appkit-react/src/utils/map-defi-error.ts @@ -6,7 +6,7 @@ * */ -import { DefiError } from '@ton/appkit'; +import { DefiError, DefiErrorCode } from '@ton/appkit'; /** * Map a thrown error to an i18n key from the `defi.*` namespace. @@ -17,17 +17,17 @@ export const mapDefiError = (error: unknown): string | null => { if (!(error instanceof DefiError)) return null; switch (error.code) { - case DefiError.UNSUPPORTED_NETWORK: + case DefiErrorCode.UnsupportedNetwork: return 'defi.unsupportedNetwork'; - case DefiError.NETWORK_ERROR: + case DefiErrorCode.NetworkError: return 'defi.networkError'; - case DefiError.PROVIDER_NOT_FOUND: + case DefiErrorCode.ProviderNotFound: return 'defi.providerNotFound'; - case DefiError.NO_DEFAULT_PROVIDER: + case DefiErrorCode.NoDefaultProvider: return 'defi.noDefaultProvider'; - case DefiError.INVALID_PROVIDER: + case DefiErrorCode.InvalidProvider: return 'defi.invalidProvider'; - case DefiError.INVALID_PARAMS: + case DefiErrorCode.InvalidParams: return 'defi.invalidParams'; default: return null; diff --git a/packages/appkit/src/crypto-onramp/index.ts b/packages/appkit/src/crypto-onramp/index.ts index e51f9a065..0660cbcc8 100644 --- a/packages/appkit/src/crypto-onramp/index.ts +++ b/packages/appkit/src/crypto-onramp/index.ts @@ -6,7 +6,7 @@ * */ -export { CryptoOnrampProvider, CryptoOnrampManager, CryptoOnrampError } from '@ton/walletkit'; +export { CryptoOnrampProvider, CryptoOnrampManager, CryptoOnrampError, CryptoOnrampErrorCode } from '@ton/walletkit'; export type { CryptoOnrampAPI, diff --git a/packages/appkit/src/swap/index.ts b/packages/appkit/src/swap/index.ts index 4209e845c..5b20d19f1 100644 --- a/packages/appkit/src/swap/index.ts +++ b/packages/appkit/src/swap/index.ts @@ -6,7 +6,7 @@ * */ -export { DefiError, SwapError, SwapProvider, SwapManager } from '@ton/walletkit'; +export { DefiError, DefiErrorCode, SwapError, SwapErrorCode, SwapProvider, SwapManager } from '@ton/walletkit'; export type { SwapToken, diff --git a/packages/walletkit/src/defi/DefiManager.ts b/packages/walletkit/src/defi/DefiManager.ts index 3c61479ac..e94dc46aa 100644 --- a/packages/walletkit/src/defi/DefiManager.ts +++ b/packages/walletkit/src/defi/DefiManager.ts @@ -11,7 +11,8 @@ import type { DefiProvider } from '../api/interfaces'; import { resolveProvider } from '../types'; import type { ProviderInput } from '../types'; import type { ProviderFactoryContext } from '../types/factory'; -import { DefiError } from './errors'; +import type { DefiError } from './errors'; +import { DefiErrorCode } from './errors'; import type { SharedKitEvents } from '../types/emitter'; import type { EventEmitter } from '../core/EventEmitter'; @@ -43,7 +44,7 @@ export abstract class DefiManager< const providerId = provider.providerId; if (!providerId) { - throw this.createError('Provider must have a providerId', DefiError.INVALID_PROVIDER); + throw this.createError('Provider must have a providerId', DefiErrorCode.InvalidProvider); } const oldProvider = this.providers.find((p) => p.providerId === providerId); @@ -83,7 +84,7 @@ export abstract class DefiManager< const provider = this.providers.find((p) => p.providerId === providerId); if (!provider) { - throw this.createError(`Provider '${providerId}' not found`, DefiError.PROVIDER_NOT_FOUND, { + throw this.createError(`Provider '${providerId}' not found`, DefiErrorCode.ProviderNotFound, { provider: providerId, registered: this.providers.map((p) => p.providerId), }); @@ -105,13 +106,13 @@ export abstract class DefiManager< if (!providerName) { throw this.createError( 'No default provider set. Register a provider first.', - DefiError.NO_DEFAULT_PROVIDER, + DefiErrorCode.NoDefaultProvider, ); } const provider = this.providers.find((p) => p.providerId === providerName); if (!provider) { - throw this.createError(`Provider '${providerName}' not found`, DefiError.PROVIDER_NOT_FOUND, { + throw this.createError(`Provider '${providerName}' not found`, DefiErrorCode.ProviderNotFound, { provider: providerName, registered: this.providers.map((p) => p.providerId), }); diff --git a/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts b/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts index ec53b3a92..6a7edf5a2 100644 --- a/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts +++ b/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts @@ -15,6 +15,7 @@ import type { CryptoOnrampStatus, CryptoOnrampStatusParams, } from '../../api/models'; +import type { CryptoOnrampErrorCode } from './errors'; import { CryptoOnrampError } from './errors'; import { globalLogger } from '../../core/Logger'; import { DefiManager } from '../DefiManager'; @@ -127,6 +128,6 @@ export class CryptoOnrampManager extends DefiManager implemen } protected createError(message: string, code: string, details?: unknown): OnrampError { - return new OnrampError(message, code, details); + return new OnrampError(message, code as OnrampErrorCode, details); } } diff --git a/packages/walletkit/src/defi/onramp/errors.ts b/packages/walletkit/src/defi/onramp/errors.ts index 337e919a7..a83067073 100644 --- a/packages/walletkit/src/defi/onramp/errors.ts +++ b/packages/walletkit/src/defi/onramp/errors.ts @@ -8,14 +8,19 @@ import { DefiError } from '../errors'; +export enum OnrampErrorCode { + ProviderError = 'PROVIDER_ERROR', + InvalidParams = 'INVALID_ONRAMP_PARAMS', + QuoteFailed = 'QUOTE_FAILED', + UrlBuildFailed = 'URL_BUILD_FAILED', +} + export class OnrampError extends DefiError { - static readonly PROVIDER_ERROR = 'PROVIDER_ERROR'; - static readonly InvalidParams = 'INVALID_ONRAMP_PARAMS'; - static readonly QUOTE_FAILED = 'QUOTE_FAILED'; - static readonly URL_BUILD_FAILED = 'URL_BUILD_FAILED'; + public readonly code: OnrampErrorCode; - constructor(message: string, code: string, details?: unknown) { + constructor(message: string, code: OnrampErrorCode, details?: unknown) { super(message, code, details); this.name = 'OnrampError'; + this.code = code; } } diff --git a/packages/walletkit/src/defi/onramp/mercuryo/MercuryoProvider.ts b/packages/walletkit/src/defi/onramp/mercuryo/MercuryoProvider.ts index d18c9f15e..ec7974c69 100644 --- a/packages/walletkit/src/defi/onramp/mercuryo/MercuryoProvider.ts +++ b/packages/walletkit/src/defi/onramp/mercuryo/MercuryoProvider.ts @@ -9,7 +9,7 @@ import type { OnrampParams, OnrampQuote, OnrampQuoteParams } from '../../../api/models'; import { Network } from '../../../api/models'; import { OnrampProvider } from '../OnrampProvider'; -import { OnrampError } from '../errors'; +import { OnrampError, OnrampErrorCode } from '../errors'; /** * Custom options for Mercuryo requests @@ -101,7 +101,7 @@ export class MercuryoProvider extends OnrampProvider implements S } protected createError(message: string, code: string, details?: unknown): SwapError { - return new SwapError(message, code, details); + return new SwapError(message, code as SwapErrorCode, details); } } diff --git a/packages/walletkit/src/defi/swap/dedust/DeDustSwapProvider.ts b/packages/walletkit/src/defi/swap/dedust/DeDustSwapProvider.ts index 7a5b96e1e..fe44aacc6 100644 --- a/packages/walletkit/src/defi/swap/dedust/DeDustSwapProvider.ts +++ b/packages/walletkit/src/defi/swap/dedust/DeDustSwapProvider.ts @@ -18,7 +18,7 @@ import type { DeDustSwapResponse } from './DeDustPrivateTypes'; import { SwapProvider } from '../SwapProvider'; import type { SwapQuoteParams, SwapQuote, SwapParams, SwapProviderMetadata } from '../../../api/models'; import { Network } from '../../../api/models'; -import { SwapError } from '../errors'; +import { SwapError, SwapErrorCode } from '../errors'; import { globalLogger } from '../../../core/Logger'; import { tokenToMinter, validateNetwork, isDeDustQuoteMetadata } from './utils'; import type { TransactionRequest } from '../../../api/models'; @@ -167,20 +167,20 @@ export class DeDustSwapProvider extends SwapProvider if (!isSettled) { isSettled = true; - reject(new SwapError('Quote request timed out', SwapError.NETWORK_ERROR)); + reject(new SwapError('Quote request timed out', SwapErrorCode.NetworkError)); } unsubscribe.unsubscribe(); @@ -170,7 +170,9 @@ export class OmnistonSwapProvider extends SwapProvider isSettled = true; clearTimeout(timeoutId); unsubscribe.unsubscribe(); - reject(new SwapError('No quote available for this swap', SwapError.INSUFFICIENT_LIQUIDITY)); + reject( + new SwapError('No quote available for this swap', SwapErrorCode.InsufficientLiquidity), + ); return; } @@ -193,7 +195,7 @@ export class OmnistonSwapProvider extends SwapProvider }); if (quoteEvent.type !== 'quoteUpdated') { - throw new SwapError('Quote data is missing', SwapError.INVALID_QUOTE); + throw new SwapError('Quote data is missing', SwapErrorCode.InvalidQuote); } const quote = quoteEvent.quote; @@ -215,7 +217,7 @@ export class OmnistonSwapProvider extends SwapProvider throw new SwapError( `Omniston quote request failed: ${error instanceof Error ? error.message : 'Unknown error'}`, - SwapError.NETWORK_ERROR, + SwapErrorCode.NetworkError, error, ); } @@ -227,7 +229,7 @@ export class OmnistonSwapProvider extends SwapProvider const metadata = params.quote.metadata; if (!metadata || !isOmnistonQuoteMetadata(metadata)) { - throw new SwapError('Invalid quote: missing Omniston quote data', SwapError.INVALID_QUOTE); + throw new SwapError('Invalid quote: missing Omniston quote data', SwapErrorCode.InvalidQuote); } try { @@ -235,7 +237,7 @@ export class OmnistonSwapProvider extends SwapProvider const now = getUnixtime(); if (omnistonQuote.tradeStartDeadline && omnistonQuote.tradeStartDeadline < now) { - throw new SwapError('Quote has expired, please request a new one', SwapError.QUOTE_EXPIRED); + throw new SwapError('Quote has expired, please request a new one', SwapErrorCode.QuoteExpired); } const userAddress = Address.parse(params.userAddress).toRawString(); @@ -260,7 +262,7 @@ export class OmnistonSwapProvider extends SwapProvider const messages = buildResult?.ton?.messages; if (!messages || messages.length === 0) { - throw new SwapError('Failed to build transaction: no messages returned', SwapError.BUILD_TX_FAILED); + throw new SwapError('Failed to build transaction: no messages returned', SwapErrorCode.BuildTxFailed); } const transaction: TransactionRequest = { @@ -289,7 +291,7 @@ export class OmnistonSwapProvider extends SwapProvider throw new SwapError( `Failed to build Omniston transaction: ${error instanceof Error ? error.message : 'Unknown error'}`, - SwapError.NETWORK_ERROR, + SwapErrorCode.NetworkError, error, ); } diff --git a/packages/walletkit/src/index.ts b/packages/walletkit/src/index.ts index 08e9a4558..a0920c91e 100644 --- a/packages/walletkit/src/index.ts +++ b/packages/walletkit/src/index.ts @@ -19,11 +19,16 @@ export { EventRouter } from './core/EventRouter'; export { RequestProcessor } from './core/RequestProcessor'; export { Initializer } from './core/Initializer'; export { JettonsManager } from './core/JettonsManager'; -export { DefiError } from './defi/errors'; -export { SwapManager, SwapProvider, SwapError } from './defi/swap'; +export { DefiError, DefiErrorCode } from './defi/errors'; +export { SwapManager, SwapProvider, SwapError, SwapErrorCode } from './defi/swap'; export { StakingManager, StakingProvider, StakingError, StakingErrorCode } from './defi/staking'; -export { OnrampManager, OnrampProvider, OnrampError } from './defi/onramp'; -export { CryptoOnrampManager, CryptoOnrampProvider, CryptoOnrampError } from './defi/crypto-onramp'; +export { OnrampManager, OnrampProvider, OnrampError, OnrampErrorCode } from './defi/onramp'; +export { + CryptoOnrampManager, + CryptoOnrampProvider, + CryptoOnrampError, + CryptoOnrampErrorCode, +} from './defi/crypto-onramp'; export { EventEmitter } from './core/EventEmitter'; export type { EventListener, EventPayload, KitEvent } from './core/EventEmitter'; export type { SharedKitEvents } from './types/emitter'; From 2a8a7ea420a22976b98f6bfdeb7f480dedd041b2 Mon Sep 17 00:00:00 2001 From: VK Date: Tue, 26 May 2026 12:07:16 +0400 Subject: [PATCH 5/9] feat(crypto-onramp): error handling --- packages/appkit-react/src/locales/en.ts | 1 + .../src/defi/crypto-onramp/CryptoOnrampManager.ts | 10 +++++++--- .../layerswap/LayerswapCryptoOnrampProvider.ts | 13 +++++++++++++ .../src/defi/crypto-onramp/layerswap/utils.ts | 12 +++++++++--- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/packages/appkit-react/src/locales/en.ts b/packages/appkit-react/src/locales/en.ts index ea491b10a..c26ef2626 100644 --- a/packages/appkit-react/src/locales/en.ts +++ b/packages/appkit-react/src/locales/en.ts @@ -112,6 +112,7 @@ export default { selectMethod: 'Select payment method', searchMethod: 'Search', quoteError: 'Failed to get a quote', + depositFailed: 'Failed to create deposit', tooManyDecimals: 'Too many decimals', providerError: 'Provider error', genericError: 'Something went wrong', diff --git a/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts b/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts index 36f936ee7..b7d3a801b 100644 --- a/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts +++ b/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts @@ -17,8 +17,7 @@ import type { CryptoOnrampStatusParams, CryptoOnrampSupportedCurrencies, } from '../../api/models'; -import type { CryptoOnrampErrorCode } from './errors'; -import { CryptoOnrampError } from './errors'; +import { CryptoOnrampError, CryptoOnrampErrorCode } from './errors'; import { globalLogger } from '../../core/Logger'; import { DefiManager } from '../DefiManager'; @@ -113,7 +112,12 @@ export class CryptoOnrampManager extends DefiManager(); + let anyFulfilled = false; for (const result of results) { if (result.status !== 'fulfilled') continue; + anyFulfilled = true; for (const network of result.value) { const caip2 = slugToCaip2[network.name]; if (!caip2) continue; @@ -334,6 +336,17 @@ export class LayerswapCryptoOnrampProvider extends CryptoOnrampProvider 0) { + const firstRejection = results.find( + (result): result is PromiseRejectedResult => result.status === 'rejected', + ); + throw new CryptoOnrampError( + 'Layerswap: failed to fetch supported sources for all destinations', + CryptoOnrampErrorCode.ProviderError, + firstRejection?.reason, + ); + } + return { source: Array.from(sourceMap.values()), destination }; } diff --git a/packages/walletkit/src/defi/crypto-onramp/layerswap/utils.ts b/packages/walletkit/src/defi/crypto-onramp/layerswap/utils.ts index e7552d99b..923679898 100644 --- a/packages/walletkit/src/defi/crypto-onramp/layerswap/utils.ts +++ b/packages/walletkit/src/defi/crypto-onramp/layerswap/utils.ts @@ -8,7 +8,7 @@ import type { CryptoOnrampDestinationCurrency, CryptoOnrampStatus } from '../../../api/models'; import { Caip2ByNetwork } from '../caip2'; -import { CryptoOnrampErrorCode } from '../errors'; +import { CryptoOnrampError, CryptoOnrampErrorCode } from '../errors'; import type { LayerswapErrorResponse, LayerswapSwapStatus } from './types'; export const LAYERSWAP_DESTINATION_NETWORK = 'TON_MAINNET'; @@ -136,7 +136,10 @@ export const mapStatus = (status: LayerswapSwapStatus | string): CryptoOnrampSta */ export const formatBaseUnits = (base: string, decimals: number): string => { if (!/^\d+$/.test(base)) { - throw new Error(`formatBaseUnits: not a non-negative integer string: "${base}"`); + throw new CryptoOnrampError( + `formatBaseUnits: not a non-negative integer string: "${base}"`, + CryptoOnrampErrorCode.InvalidParams, + ); } if (decimals === 0) return base; const padded = base.padStart(decimals + 1, '0'); @@ -152,7 +155,10 @@ export const formatBaseUnits = (base: string, decimals: number): string => { export const parseBaseUnits = (value: number | string, decimals: number): string => { const str = typeof value === 'number' ? value.toString() : value; if (!/^\d+(\.\d+)?$/.test(str)) { - throw new Error(`parseBaseUnits: not a non-negative decimal: "${str}"`); + throw new CryptoOnrampError( + `parseBaseUnits: not a non-negative decimal: "${str}"`, + CryptoOnrampErrorCode.ProviderError, + ); } const [whole, frac = ''] = str.split('.'); const truncated = frac.slice(0, decimals).padEnd(decimals, '0'); From ae88ab5ddcf46a99beac257bffc9122156256142 Mon Sep 17 00:00:00 2001 From: VK Date: Tue, 26 May 2026 13:27:04 +0400 Subject: [PATCH 6/9] feat(crypto-onramp): delete duplicates --- .../LayerswapCryptoOnrampProvider.ts | 28 ++++++++++++-- .../src/defi/crypto-onramp/layerswap/utils.ts | 38 +------------------ 2 files changed, 25 insertions(+), 41 deletions(-) diff --git a/packages/walletkit/src/defi/crypto-onramp/layerswap/LayerswapCryptoOnrampProvider.ts b/packages/walletkit/src/defi/crypto-onramp/layerswap/LayerswapCryptoOnrampProvider.ts index 0c825674c..6b505722e 100644 --- a/packages/walletkit/src/defi/crypto-onramp/layerswap/LayerswapCryptoOnrampProvider.ts +++ b/packages/walletkit/src/defi/crypto-onramp/layerswap/LayerswapCryptoOnrampProvider.ts @@ -26,13 +26,12 @@ import { DEFAULT_LAYERSWAP_SUPPORTED_CHAINS, LAYERSWAP_DESTINATION_NETWORK, LAYERSWAP_DESTINATION_TOKENS, - formatBaseUnits, isErrorResponse, mapLayerswapErrorCode, mapStatus, - parseBaseUnits, } from './utils'; import type { LayerswapChainConfig } from './utils'; +import { formatUnits, parseUnits } from '../../../utils/units'; const LAYERSWAP_API_URL = 'https://api.layerswap.io/api/v2'; @@ -145,7 +144,17 @@ export class LayerswapCryptoOnrampProvider extends CryptoOnrampProvider 0 ? (data.quote.receive_amount / data.quote.requested_amount).toString() diff --git a/packages/walletkit/src/defi/crypto-onramp/layerswap/utils.ts b/packages/walletkit/src/defi/crypto-onramp/layerswap/utils.ts index 923679898..11004f111 100644 --- a/packages/walletkit/src/defi/crypto-onramp/layerswap/utils.ts +++ b/packages/walletkit/src/defi/crypto-onramp/layerswap/utils.ts @@ -8,7 +8,7 @@ import type { CryptoOnrampDestinationCurrency, CryptoOnrampStatus } from '../../../api/models'; import { Caip2ByNetwork } from '../caip2'; -import { CryptoOnrampError, CryptoOnrampErrorCode } from '../errors'; +import { CryptoOnrampErrorCode } from '../errors'; import type { LayerswapErrorResponse, LayerswapSwapStatus } from './types'; export const LAYERSWAP_DESTINATION_NETWORK = 'TON_MAINNET'; @@ -129,39 +129,3 @@ export const mapStatus = (status: LayerswapSwapStatus | string): CryptoOnrampSta return 'pending'; } }; - -/** - * Format a base-units integer string into a decimal token-units string. - * e.g. formatBaseUnits('2000000', 6) === '2' - */ -export const formatBaseUnits = (base: string, decimals: number): string => { - if (!/^\d+$/.test(base)) { - throw new CryptoOnrampError( - `formatBaseUnits: not a non-negative integer string: "${base}"`, - CryptoOnrampErrorCode.InvalidParams, - ); - } - if (decimals === 0) return base; - const padded = base.padStart(decimals + 1, '0'); - const whole = padded.slice(0, padded.length - decimals); - const frac = padded.slice(padded.length - decimals).replace(/0+$/, ''); - return frac.length > 0 ? `${whole}.${frac}` : whole; -}; - -/** - * Scale a decimal token-units string by 10^decimals and return the integer - * base-units string, truncating any excess fractional digits. - */ -export const parseBaseUnits = (value: number | string, decimals: number): string => { - const str = typeof value === 'number' ? value.toString() : value; - if (!/^\d+(\.\d+)?$/.test(str)) { - throw new CryptoOnrampError( - `parseBaseUnits: not a non-negative decimal: "${str}"`, - CryptoOnrampErrorCode.ProviderError, - ); - } - const [whole, frac = ''] = str.split('.'); - const truncated = frac.slice(0, decimals).padEnd(decimals, '0'); - const combined = `${whole}${truncated}`.replace(/^0+/, ''); - return combined.length > 0 ? combined : '0'; -}; From b077ce2a5fd9856e7aa787dda40879bbc6e363be Mon Sep 17 00:00:00 2001 From: VK Date: Tue, 26 May 2026 13:31:03 +0400 Subject: [PATCH 7/9] feat(crypto-onramp): delete try/catches --- .../LayerswapCryptoOnrampProvider.ts | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/packages/walletkit/src/defi/crypto-onramp/layerswap/LayerswapCryptoOnrampProvider.ts b/packages/walletkit/src/defi/crypto-onramp/layerswap/LayerswapCryptoOnrampProvider.ts index 6b505722e..61da9cfef 100644 --- a/packages/walletkit/src/defi/crypto-onramp/layerswap/LayerswapCryptoOnrampProvider.ts +++ b/packages/walletkit/src/defi/crypto-onramp/layerswap/LayerswapCryptoOnrampProvider.ts @@ -144,18 +144,17 @@ export class LayerswapCryptoOnrampProvider extends CryptoOnrampProvider 0 ? (data.quote.receive_amount / data.quote.requested_amount).toString() From 663fb48202f1aed0c2e293731a4de7fd95f05a04 Mon Sep 17 00:00:00 2001 From: VK Date: Tue, 26 May 2026 14:18:13 +0400 Subject: [PATCH 8/9] feat(crypto-onramp): make defi errors more typesafe --- packages/walletkit/src/defi/DefiManager.ts | 4 +++- .../src/defi/crypto-onramp/CryptoOnrampManager.ts | 14 +++++++++++--- .../walletkit/src/defi/crypto-onramp/errors.ts | 5 +++-- .../walletkit/src/defi/onramp/OnrampManager.ts | 10 +++++++--- packages/walletkit/src/defi/onramp/errors.ts | 5 +++-- .../walletkit/src/defi/staking/StakingManager.ts | 13 +++++++------ packages/walletkit/src/defi/staking/errors.ts | 5 +++-- packages/walletkit/src/defi/swap/SwapManager.ts | 7 ++++--- packages/walletkit/src/defi/swap/errors.ts | 5 +++-- 9 files changed, 44 insertions(+), 24 deletions(-) diff --git a/packages/walletkit/src/defi/DefiManager.ts b/packages/walletkit/src/defi/DefiManager.ts index e94dc46aa..dce689e51 100644 --- a/packages/walletkit/src/defi/DefiManager.ts +++ b/packages/walletkit/src/defi/DefiManager.ts @@ -18,13 +18,15 @@ import type { EventEmitter } from '../core/EventEmitter'; export abstract class DefiManager< T extends DefiProvider, + TError extends DefiError = DefiError, + TErrorCode extends string = string, E extends SharedKitEvents = SharedKitEvents, > implements DefiManagerAPI { public createFactoryContext: () => ProviderFactoryContext; protected providers: T[] = []; protected defaultProviderId?: string; - protected abstract createError(message: string, code: string, details?: unknown): DefiError; + protected abstract createError(message: string, code: TErrorCode | DefiErrorCode, details?: unknown): TError; protected eventEmitter: EventEmitter; constructor(createFactoryContext: () => ProviderFactoryContext) { diff --git a/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts b/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts index b7d3a801b..74d63d33e 100644 --- a/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts +++ b/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts @@ -18,6 +18,7 @@ import type { CryptoOnrampSupportedCurrencies, } from '../../api/models'; import { CryptoOnrampError, CryptoOnrampErrorCode } from './errors'; +import type { DefiErrorCode } from '../errors'; import { globalLogger } from '../../core/Logger'; import { DefiManager } from '../DefiManager'; @@ -29,7 +30,10 @@ const log = globalLogger.createChild('CryptoOnrampManager'); * Allows registration of multiple crypto onramp providers and provides a unified API * for crypto-to-TON onramp operations. Providers can be switched dynamically. */ -export class CryptoOnrampManager extends DefiManager implements CryptoOnrampAPI { +export class CryptoOnrampManager + extends DefiManager + implements CryptoOnrampAPI +{ /** * Get static metadata for a crypto onramp provider * @param providerId - Optional provider id to use @@ -165,7 +169,11 @@ export class CryptoOnrampManager extends DefiManager implements OnrampAPI { +export class OnrampManager + extends DefiManager + implements OnrampAPI +{ /** * Get a quote for onramping fiat to crypto * @param params - Quote parameters @@ -126,7 +130,7 @@ export class OnrampManager extends DefiManager implemen } } - protected createError(message: string, code: string, details?: unknown): OnrampError { - return new OnrampError(message, code as OnrampErrorCode, details); + protected createError(message: string, code: OnrampErrorCode | DefiErrorCode, details?: unknown): OnrampError { + return new OnrampError(message, code, details); } } diff --git a/packages/walletkit/src/defi/onramp/errors.ts b/packages/walletkit/src/defi/onramp/errors.ts index a83067073..27cdc3ba3 100644 --- a/packages/walletkit/src/defi/onramp/errors.ts +++ b/packages/walletkit/src/defi/onramp/errors.ts @@ -6,6 +6,7 @@ * */ +import type { DefiErrorCode } from '../errors'; import { DefiError } from '../errors'; export enum OnrampErrorCode { @@ -16,9 +17,9 @@ export enum OnrampErrorCode { } export class OnrampError extends DefiError { - public readonly code: OnrampErrorCode; + public readonly code: OnrampErrorCode | DefiErrorCode; - constructor(message: string, code: OnrampErrorCode, details?: unknown) { + constructor(message: string, code: OnrampErrorCode | DefiErrorCode, details?: unknown) { super(message, code, details); this.name = 'OnrampError'; this.code = code; diff --git a/packages/walletkit/src/defi/staking/StakingManager.ts b/packages/walletkit/src/defi/staking/StakingManager.ts index d8dd51b9a..f8a69f7ec 100644 --- a/packages/walletkit/src/defi/staking/StakingManager.ts +++ b/packages/walletkit/src/defi/staking/StakingManager.ts @@ -17,6 +17,7 @@ import type { } from '../../api/models'; import type { StakingAPI, StakingProviderInterface } from '../../api/interfaces'; import { StakingError, StakingErrorCode } from './errors'; +import type { DefiErrorCode } from '../errors'; import { globalLogger } from '../../core/Logger'; import { DefiManager } from '../DefiManager'; import type { ProviderFactoryContext } from '../../types/factory'; @@ -29,7 +30,10 @@ const log = globalLogger.createChild('StakingManager'); * Allows registration of multiple staking providers and provides a unified API * for staking operations. Providers can be switched dynamically. */ -export class StakingManager extends DefiManager implements StakingAPI { +export class StakingManager + extends DefiManager + implements StakingAPI +{ constructor(createFactoryContext: () => ProviderFactoryContext) { super(createFactoryContext); } @@ -134,11 +138,8 @@ export class StakingManager extends DefiManager implem } } - protected createError(message: string, code: string, details?: unknown): StakingError { - const errorCode = Object.values(StakingErrorCode).includes(code as StakingErrorCode) - ? (code as StakingErrorCode) - : StakingErrorCode.InvalidParams; + protected createError(message: string, code: StakingErrorCode | DefiErrorCode, details?: unknown): StakingError { log.error(message, { code, details }); - return new StakingError(message, errorCode, details); + return new StakingError(message, code, details); } } diff --git a/packages/walletkit/src/defi/staking/errors.ts b/packages/walletkit/src/defi/staking/errors.ts index 2aa5754b1..1682e2f06 100644 --- a/packages/walletkit/src/defi/staking/errors.ts +++ b/packages/walletkit/src/defi/staking/errors.ts @@ -6,6 +6,7 @@ * */ +import type { DefiErrorCode } from '../errors'; import { DefiError } from '../errors'; export enum StakingErrorCode { @@ -14,9 +15,9 @@ export enum StakingErrorCode { } export class StakingError extends DefiError { - public readonly code: StakingErrorCode; + public readonly code: StakingErrorCode | DefiErrorCode; - constructor(message: string, code: StakingErrorCode, details?: unknown) { + constructor(message: string, code: StakingErrorCode | DefiErrorCode, details?: unknown) { super(message, code, details); this.name = 'StakingError'; this.code = code; diff --git a/packages/walletkit/src/defi/swap/SwapManager.ts b/packages/walletkit/src/defi/swap/SwapManager.ts index 3ae1da73a..99b64d22c 100644 --- a/packages/walletkit/src/defi/swap/SwapManager.ts +++ b/packages/walletkit/src/defi/swap/SwapManager.ts @@ -11,6 +11,7 @@ import type { SwapAPI, SwapProviderInterface } from '../../api/interfaces'; import type { SwapQuoteParams, SwapQuote, SwapParams } from '../../api/models'; import type { SwapErrorCode } from './errors'; import { SwapError } from './errors'; +import type { DefiErrorCode } from '../errors'; import { globalLogger } from '../../core/Logger'; import { DefiManager } from '../DefiManager'; import type { ProviderFactoryContext } from '../../types/factory'; @@ -23,7 +24,7 @@ const log = globalLogger.createChild('SwapManager'); * Allows registration of multiple swap providers and provides a unified API * for swap operations. Providers can be switched dynamically. */ -export class SwapManager extends DefiManager implements SwapAPI { +export class SwapManager extends DefiManager implements SwapAPI { constructor(createFactoryContext: () => ProviderFactoryContext) { super(createFactoryContext); } @@ -89,7 +90,7 @@ export class SwapManager extends DefiManager implements S } } - protected createError(message: string, code: string, details?: unknown): SwapError { - return new SwapError(message, code as SwapErrorCode, details); + protected createError(message: string, code: SwapErrorCode | DefiErrorCode, details?: unknown): SwapError { + return new SwapError(message, code, details); } } diff --git a/packages/walletkit/src/defi/swap/errors.ts b/packages/walletkit/src/defi/swap/errors.ts index 41e775e21..08ffda35e 100644 --- a/packages/walletkit/src/defi/swap/errors.ts +++ b/packages/walletkit/src/defi/swap/errors.ts @@ -6,6 +6,7 @@ * */ +import type { DefiErrorCode } from '../errors'; import { DefiError } from '../errors'; export enum SwapErrorCode { @@ -17,9 +18,9 @@ export enum SwapErrorCode { } export class SwapError extends DefiError { - public readonly code: SwapErrorCode; + public readonly code: SwapErrorCode | DefiErrorCode; - constructor(message: string, code: SwapErrorCode, details?: unknown) { + constructor(message: string, code: SwapErrorCode | DefiErrorCode, details?: unknown) { super(message, code, details); this.name = 'SwapError'; this.code = code; From 87e15f084e332e0432e1c7f30bfbfc0fa1c1bdd8 Mon Sep 17 00:00:00 2001 From: VK Date: Tue, 26 May 2026 14:26:45 +0400 Subject: [PATCH 9/9] feat(crypto-onramp): delete createError --- packages/walletkit/src/defi/DefiManager.ts | 17 +++++---------- .../defi/crypto-onramp/CryptoOnrampManager.ts | 16 ++------------ .../src/defi/crypto-onramp/errors.ts | 5 ++--- .../src/defi/onramp/OnrampManager.ts | 12 +---------- packages/walletkit/src/defi/onramp/errors.ts | 5 ++--- .../src/defi/staking/StakingManager.ts | 21 ++++++------------- packages/walletkit/src/defi/staking/errors.ts | 5 ++--- .../walletkit/src/defi/swap/SwapManager.ts | 9 +------- packages/walletkit/src/defi/swap/errors.ts | 5 ++--- 9 files changed, 23 insertions(+), 72 deletions(-) diff --git a/packages/walletkit/src/defi/DefiManager.ts b/packages/walletkit/src/defi/DefiManager.ts index dce689e51..647dd463c 100644 --- a/packages/walletkit/src/defi/DefiManager.ts +++ b/packages/walletkit/src/defi/DefiManager.ts @@ -11,22 +11,18 @@ import type { DefiProvider } from '../api/interfaces'; import { resolveProvider } from '../types'; import type { ProviderInput } from '../types'; import type { ProviderFactoryContext } from '../types/factory'; -import type { DefiError } from './errors'; -import { DefiErrorCode } from './errors'; +import { DefiError, DefiErrorCode } from './errors'; import type { SharedKitEvents } from '../types/emitter'; import type { EventEmitter } from '../core/EventEmitter'; export abstract class DefiManager< T extends DefiProvider, - TError extends DefiError = DefiError, - TErrorCode extends string = string, E extends SharedKitEvents = SharedKitEvents, > implements DefiManagerAPI { public createFactoryContext: () => ProviderFactoryContext; protected providers: T[] = []; protected defaultProviderId?: string; - protected abstract createError(message: string, code: TErrorCode | DefiErrorCode, details?: unknown): TError; protected eventEmitter: EventEmitter; constructor(createFactoryContext: () => ProviderFactoryContext) { @@ -46,7 +42,7 @@ export abstract class DefiManager< const providerId = provider.providerId; if (!providerId) { - throw this.createError('Provider must have a providerId', DefiErrorCode.InvalidProvider); + throw new DefiError('Provider must have a providerId', DefiErrorCode.InvalidProvider); } const oldProvider = this.providers.find((p) => p.providerId === providerId); @@ -86,7 +82,7 @@ export abstract class DefiManager< const provider = this.providers.find((p) => p.providerId === providerId); if (!provider) { - throw this.createError(`Provider '${providerId}' not found`, DefiErrorCode.ProviderNotFound, { + throw new DefiError(`Provider '${providerId}' not found`, DefiErrorCode.ProviderNotFound, { provider: providerId, registered: this.providers.map((p) => p.providerId), }); @@ -106,15 +102,12 @@ export abstract class DefiManager< const providerName = providerId || this.defaultProviderId; if (!providerName) { - throw this.createError( - 'No default provider set. Register a provider first.', - DefiErrorCode.NoDefaultProvider, - ); + throw new DefiError('No default provider set. Register a provider first.', DefiErrorCode.NoDefaultProvider); } const provider = this.providers.find((p) => p.providerId === providerName); if (!provider) { - throw this.createError(`Provider '${providerName}' not found`, DefiErrorCode.ProviderNotFound, { + throw new DefiError(`Provider '${providerName}' not found`, DefiErrorCode.ProviderNotFound, { provider: providerName, registered: this.providers.map((p) => p.providerId), }); diff --git a/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts b/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts index 74d63d33e..fc862188b 100644 --- a/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts +++ b/packages/walletkit/src/defi/crypto-onramp/CryptoOnrampManager.ts @@ -18,7 +18,6 @@ import type { CryptoOnrampSupportedCurrencies, } from '../../api/models'; import { CryptoOnrampError, CryptoOnrampErrorCode } from './errors'; -import type { DefiErrorCode } from '../errors'; import { globalLogger } from '../../core/Logger'; import { DefiManager } from '../DefiManager'; @@ -30,10 +29,7 @@ const log = globalLogger.createChild('CryptoOnrampManager'); * Allows registration of multiple crypto onramp providers and provides a unified API * for crypto-to-TON onramp operations. Providers can be switched dynamically. */ -export class CryptoOnrampManager - extends DefiManager - implements CryptoOnrampAPI -{ +export class CryptoOnrampManager extends DefiManager implements CryptoOnrampAPI { /** * Get static metadata for a crypto onramp provider * @param providerId - Optional provider id to use @@ -117,7 +113,7 @@ export class CryptoOnrampManager } catch (error) { log.error('Failed to create crypto onramp deposit', { error, params }); if (error instanceof CryptoOnrampError) throw error; - throw this.createError( + throw new CryptoOnrampError( 'Failed to create crypto onramp deposit', CryptoOnrampErrorCode.DepositFailed, error, @@ -168,12 +164,4 @@ export class CryptoOnrampManager throw error; } } - - protected createError( - message: string, - code: CryptoOnrampErrorCode | DefiErrorCode, - details?: unknown, - ): CryptoOnrampError { - return new CryptoOnrampError(message, code, details); - } } diff --git a/packages/walletkit/src/defi/crypto-onramp/errors.ts b/packages/walletkit/src/defi/crypto-onramp/errors.ts index 67010e83f..5de613c1e 100644 --- a/packages/walletkit/src/defi/crypto-onramp/errors.ts +++ b/packages/walletkit/src/defi/crypto-onramp/errors.ts @@ -6,7 +6,6 @@ * */ -import type { DefiErrorCode } from '../errors'; import { DefiError } from '../errors'; export enum CryptoOnrampErrorCode { @@ -26,9 +25,9 @@ export enum CryptoOnrampErrorCode { } export class CryptoOnrampError extends DefiError { - public readonly code: CryptoOnrampErrorCode | DefiErrorCode; + public readonly code: CryptoOnrampErrorCode; - constructor(message: string, code: CryptoOnrampErrorCode | DefiErrorCode, details?: unknown) { + constructor(message: string, code: CryptoOnrampErrorCode, details?: unknown) { super(message, code, details); this.name = 'CryptoOnrampError'; this.code = code; diff --git a/packages/walletkit/src/defi/onramp/OnrampManager.ts b/packages/walletkit/src/defi/onramp/OnrampManager.ts index 1d47a8bdb..3e135db11 100644 --- a/packages/walletkit/src/defi/onramp/OnrampManager.ts +++ b/packages/walletkit/src/defi/onramp/OnrampManager.ts @@ -8,9 +8,6 @@ import type { OnrampAPI, OnrampProviderInterface } from '../../api/interfaces'; import type { OnrampParams, OnrampQuote, OnrampQuoteParams } from '../../api/models'; -import type { OnrampErrorCode } from './errors'; -import { OnrampError } from './errors'; -import type { DefiErrorCode } from '../errors'; import { globalLogger } from '../../core/Logger'; import { DefiManager } from '../DefiManager'; @@ -22,10 +19,7 @@ const log = globalLogger.createChild('OnrampManager'); * Allows registration of multiple onramp providers and provides a unified API * for fiat-to-crypto onramp operations. Providers can be switched dynamically. */ -export class OnrampManager - extends DefiManager - implements OnrampAPI -{ +export class OnrampManager extends DefiManager implements OnrampAPI { /** * Get a quote for onramping fiat to crypto * @param params - Quote parameters @@ -129,8 +123,4 @@ export class OnrampManager throw error; } } - - protected createError(message: string, code: OnrampErrorCode | DefiErrorCode, details?: unknown): OnrampError { - return new OnrampError(message, code, details); - } } diff --git a/packages/walletkit/src/defi/onramp/errors.ts b/packages/walletkit/src/defi/onramp/errors.ts index 27cdc3ba3..a83067073 100644 --- a/packages/walletkit/src/defi/onramp/errors.ts +++ b/packages/walletkit/src/defi/onramp/errors.ts @@ -6,7 +6,6 @@ * */ -import type { DefiErrorCode } from '../errors'; import { DefiError } from '../errors'; export enum OnrampErrorCode { @@ -17,9 +16,9 @@ export enum OnrampErrorCode { } export class OnrampError extends DefiError { - public readonly code: OnrampErrorCode | DefiErrorCode; + public readonly code: OnrampErrorCode; - constructor(message: string, code: OnrampErrorCode | DefiErrorCode, details?: unknown) { + constructor(message: string, code: OnrampErrorCode, details?: unknown) { super(message, code, details); this.name = 'OnrampError'; this.code = code; diff --git a/packages/walletkit/src/defi/staking/StakingManager.ts b/packages/walletkit/src/defi/staking/StakingManager.ts index f8a69f7ec..1d344aee6 100644 --- a/packages/walletkit/src/defi/staking/StakingManager.ts +++ b/packages/walletkit/src/defi/staking/StakingManager.ts @@ -17,7 +17,6 @@ import type { } from '../../api/models'; import type { StakingAPI, StakingProviderInterface } from '../../api/interfaces'; import { StakingError, StakingErrorCode } from './errors'; -import type { DefiErrorCode } from '../errors'; import { globalLogger } from '../../core/Logger'; import { DefiManager } from '../DefiManager'; import type { ProviderFactoryContext } from '../../types/factory'; @@ -30,10 +29,7 @@ const log = globalLogger.createChild('StakingManager'); * Allows registration of multiple staking providers and provides a unified API * for staking operations. Providers can be switched dynamically. */ -export class StakingManager - extends DefiManager - implements StakingAPI -{ +export class StakingManager extends DefiManager implements StakingAPI { constructor(createFactoryContext: () => ProviderFactoryContext) { super(createFactoryContext); } @@ -50,7 +46,7 @@ export class StakingManager log.debug('Received staking quote', quote); return quote; } catch (error) { - throw this.createError('Failed to get staking quote', StakingErrorCode.InvalidParams, { error, params }); + throw new StakingError('Failed to get staking quote', StakingErrorCode.InvalidParams, { error, params }); } } @@ -64,7 +60,7 @@ export class StakingManager try { return await this.getProvider(providerId).buildStakeTransaction(params); } catch (error) { - throw this.createError('Failed to build staking transaction', StakingErrorCode.InvalidParams, { + throw new StakingError('Failed to build staking transaction', StakingErrorCode.InvalidParams, { error, params, }); @@ -91,7 +87,7 @@ export class StakingManager try { return await this.getProvider(providerId).getStakedBalance(userAddress, network); } catch (error) { - throw this.createError('Failed to get staking balance', StakingErrorCode.InvalidParams, { + throw new StakingError('Failed to get staking balance', StakingErrorCode.InvalidParams, { error, userAddress, network, @@ -113,7 +109,7 @@ export class StakingManager try { return await this.getProvider(providerId).getStakingProviderInfo(network); } catch (error) { - throw this.createError('Failed to get staking info', StakingErrorCode.InvalidParams, { error, network }); + throw new StakingError('Failed to get staking info', StakingErrorCode.InvalidParams, { error, network }); } } @@ -131,15 +127,10 @@ export class StakingManager try { return this.getProvider(providerId).getStakingProviderMetadata(network); } catch (error) { - throw this.createError('Failed to get staking metadata', StakingErrorCode.InvalidParams, { + throw new StakingError('Failed to get staking metadata', StakingErrorCode.InvalidParams, { error, network, }); } } - - protected createError(message: string, code: StakingErrorCode | DefiErrorCode, details?: unknown): StakingError { - log.error(message, { code, details }); - return new StakingError(message, code, details); - } } diff --git a/packages/walletkit/src/defi/staking/errors.ts b/packages/walletkit/src/defi/staking/errors.ts index 1682e2f06..2aa5754b1 100644 --- a/packages/walletkit/src/defi/staking/errors.ts +++ b/packages/walletkit/src/defi/staking/errors.ts @@ -6,7 +6,6 @@ * */ -import type { DefiErrorCode } from '../errors'; import { DefiError } from '../errors'; export enum StakingErrorCode { @@ -15,9 +14,9 @@ export enum StakingErrorCode { } export class StakingError extends DefiError { - public readonly code: StakingErrorCode | DefiErrorCode; + public readonly code: StakingErrorCode; - constructor(message: string, code: StakingErrorCode | DefiErrorCode, details?: unknown) { + constructor(message: string, code: StakingErrorCode, details?: unknown) { super(message, code, details); this.name = 'StakingError'; this.code = code; diff --git a/packages/walletkit/src/defi/swap/SwapManager.ts b/packages/walletkit/src/defi/swap/SwapManager.ts index 99b64d22c..7b738d44f 100644 --- a/packages/walletkit/src/defi/swap/SwapManager.ts +++ b/packages/walletkit/src/defi/swap/SwapManager.ts @@ -9,9 +9,6 @@ import type { TransactionRequest } from '../../api/models'; import type { SwapAPI, SwapProviderInterface } from '../../api/interfaces'; import type { SwapQuoteParams, SwapQuote, SwapParams } from '../../api/models'; -import type { SwapErrorCode } from './errors'; -import { SwapError } from './errors'; -import type { DefiErrorCode } from '../errors'; import { globalLogger } from '../../core/Logger'; import { DefiManager } from '../DefiManager'; import type { ProviderFactoryContext } from '../../types/factory'; @@ -24,7 +21,7 @@ const log = globalLogger.createChild('SwapManager'); * Allows registration of multiple swap providers and provides a unified API * for swap operations. Providers can be switched dynamically. */ -export class SwapManager extends DefiManager implements SwapAPI { +export class SwapManager extends DefiManager implements SwapAPI { constructor(createFactoryContext: () => ProviderFactoryContext) { super(createFactoryContext); } @@ -89,8 +86,4 @@ export class SwapManager extends DefiManager