From 8c3c805525e297073d25d02c5bd12403843b659b Mon Sep 17 00:00:00 2001 From: VK Date: Mon, 20 Apr 2026 13:56:44 +0400 Subject: [PATCH 1/4] feat(tac): start plugin manager --- .../src/core/app-kit/services/app-kit.ts | 19 +++++++++ .../appkit/src/core/app-kit/types/config.ts | 6 +++ .../appkit/src/core/plugin-manager/index.ts | 9 +++++ .../plugin-manager/services/plugin-manager.ts | 40 +++++++++++++++++++ packages/appkit/src/index.ts | 2 + packages/appkit/src/types/plugin.ts | 22 ++++++++++ 6 files changed, 98 insertions(+) create mode 100644 packages/appkit/src/core/plugin-manager/index.ts create mode 100644 packages/appkit/src/core/plugin-manager/services/plugin-manager.ts create mode 100644 packages/appkit/src/types/plugin.ts 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 eca376c72..accd88635 100644 --- a/packages/appkit/src/core/app-kit/services/app-kit.ts +++ b/packages/appkit/src/core/app-kit/services/app-kit.ts @@ -11,7 +11,9 @@ import type { ProviderInput, SwapProviderInterface, StakingProviderInterface } f import { StakingManager } from '../../../staking'; import type { Connector, ConnectorFactoryContext, ConnectorInput } from '../../../types/connector'; +import type { AppKitPlugin, PluginInput } from '../../../types/plugin'; import { EventEmitter } from '../../emitter'; +import { PluginManager } from '../../plugin-manager'; import { CONNECTOR_EVENTS, WALLETS_EVENTS } from '../constants/events'; import type { AppKitEmitter, AppKitEvents } from '../types/events'; import type { WalletInterface } from '../../../types/wallet'; @@ -30,6 +32,7 @@ export class AppKit { readonly walletsManager: WalletsManager; readonly swapManager: SwapManager; readonly stakingManager: StakingManager; + readonly pluginManager: PluginManager; readonly networkManager: AppKitNetworkManager; readonly streamingManager: StreamingManager; @@ -53,6 +56,7 @@ export class AppKit { this.swapManager = new SwapManager(() => this.createFactoryContext()); this.stakingManager = new StakingManager(() => this.createFactoryContext()); this.streamingManager = new StreamingManager(() => this.createFactoryContext()); + this.pluginManager = new PluginManager(this.emitter); if (config.connectors) { config.connectors.forEach((input) => { @@ -65,6 +69,12 @@ export class AppKit { this.registerProvider(input); }); } + + if (config.plugins) { + config.plugins.forEach((input) => { + this.addPlugin(input); + }); + } } createFactoryContext(): ConnectorFactoryContext { @@ -103,6 +113,15 @@ export class AppKit { } } + /** + * Add a plugin + */ + addPlugin(input: PluginInput): void { + const plugin: AppKitPlugin = typeof input === 'function' ? input(this.createFactoryContext()) : input; + plugin.init(this.createFactoryContext()); + this.pluginManager.register(plugin.id, plugin); + } + /** * Add a provider */ diff --git a/packages/appkit/src/core/app-kit/types/config.ts b/packages/appkit/src/core/app-kit/types/config.ts index d2cc0b2e0..1ad530a8a 100644 --- a/packages/appkit/src/core/app-kit/types/config.ts +++ b/packages/appkit/src/core/app-kit/types/config.ts @@ -10,6 +10,7 @@ import type { NetworkAdapters, ProviderInput } from '@ton/walletkit'; import type { ConnectorInput } from '../../../types/connector'; import type { Network } from '../../../types/network'; +import type { PluginInput } from '../../../types/plugin'; /** * Configuration for AppKit @@ -38,6 +39,11 @@ export interface AppKitConfig { providers?: ProviderInput[]; + /** + * Plugins that register extensions into AppKit. + */ + plugins?: PluginInput[]; + /** * Enable server-side rendering support */ diff --git a/packages/appkit/src/core/plugin-manager/index.ts b/packages/appkit/src/core/plugin-manager/index.ts new file mode 100644 index 000000000..bbc29dfd6 --- /dev/null +++ b/packages/appkit/src/core/plugin-manager/index.ts @@ -0,0 +1,9 @@ +/** + * 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 { PluginManager } from './services/plugin-manager'; diff --git a/packages/appkit/src/core/plugin-manager/services/plugin-manager.ts b/packages/appkit/src/core/plugin-manager/services/plugin-manager.ts new file mode 100644 index 000000000..976d6d6cc --- /dev/null +++ b/packages/appkit/src/core/plugin-manager/services/plugin-manager.ts @@ -0,0 +1,40 @@ +/** + * 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 { PLUGIN_EVENTS } from '../../app-kit/constants/events'; +import type { AppKitEmitter } from '../../app-kit/types/events'; + +/** + * Manages plugins registered in AppKit. + * Stores plugin instances by id so typed wrappers can retrieve them. + */ +export class PluginManager { + private readonly plugins = new Map(); + private readonly emitter: AppKitEmitter; + + constructor(emitter: AppKitEmitter) { + this.emitter = emitter; + } + + register(key: string, plugin: T): void { + this.plugins.set(key, plugin); + this.emitter.emit(PLUGIN_EVENTS.REGISTERED, { pluginId: key, pluginType: key }, 'appkit'); + } + + get(key: string): T | undefined { + return this.plugins.get(key) as T | undefined; + } + + has(key: string): boolean { + return this.plugins.has(key); + } + + remove(key: string): boolean { + return this.plugins.delete(key); + } +} diff --git a/packages/appkit/src/index.ts b/packages/appkit/src/index.ts index c5c3702dc..c3a0cd1cb 100644 --- a/packages/appkit/src/index.ts +++ b/packages/appkit/src/index.ts @@ -28,6 +28,7 @@ // Core export * from './core/app-kit'; export * from './core/emitter'; +export * from './core/plugin-manager'; export * from './core/network'; export * from './core/streaming'; export * from './connectors/tonconnect'; @@ -40,6 +41,7 @@ export * from './actions'; // Types export * from './types/connector'; +export * from './types/plugin'; export * from './types/balance'; export * from './types/wallet'; export * from './types/query'; diff --git a/packages/appkit/src/types/plugin.ts b/packages/appkit/src/types/plugin.ts new file mode 100644 index 000000000..e3f25e94f --- /dev/null +++ b/packages/appkit/src/types/plugin.ts @@ -0,0 +1,22 @@ +/** + * 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 { ConnectorFactoryContext } from './connector'; + +/** + * Plugin that extends AppKit with custom functionality. + * After init, the plugin instance is stored in PluginManager by its id. + */ +export interface AppKitPlugin { + readonly id: string; + init(context: ConnectorFactoryContext): void | Promise; + destroy?(): void; +} + +/** A plugin instance or a factory that creates one */ +export type PluginInput = AppKitPlugin | ((ctx: ConnectorFactoryContext) => AppKitPlugin); From 5bf5a7ee46b70f860752b8102b0fcb17a5e9f385 Mon Sep 17 00:00:00 2001 From: VK Date: Wed, 29 Apr 2026 18:48:26 +0400 Subject: [PATCH 2/4] feat(appkit): start custom plugins --- .../actions/providers/get-custom-provider.ts | 24 +++++++++ .../actions/providers/providers.test.ts | 44 ++++++++++++++++ .../appkit/hooks/providers/providers.test.tsx | 52 +++++++++++++++++++ .../hooks/providers/use-custom-provider.tsx | 26 ++++++++++ packages/appkit-react/docs/hooks.md | 14 +++++ .../providers/hooks/use-custom-provider.ts | 20 +++++++ .../src/features/providers}/index.ts | 2 +- packages/appkit-react/src/index.ts | 1 + packages/appkit/docs/actions.md | 12 +++++ packages/appkit/src/actions/index.ts | 5 ++ .../actions/providers/get-custom-provider.ts | 26 ++++++++++ .../actions/providers/register-provider.ts | 3 +- .../actions/staking/get-staking-manager.ts | 3 +- .../src/actions/swap/get-swap-manager.ts | 3 +- .../src/core/app-kit/constants/events.ts | 7 --- packages/appkit/src/core/app-kit/index.ts | 3 +- .../src/core/app-kit/services/app-kit.ts | 37 +++++-------- .../appkit/src/core/app-kit/types/config.ts | 6 --- .../appkit/src/core/app-kit/types/events.ts | 10 +--- .../plugin-manager/services/plugin-manager.ts | 40 -------------- packages/appkit/src/core/providers/index.ts | 20 +++++++ .../services/custom-providers-manager.ts | 37 +++++++++++++ .../core/providers/types/custom-provider.ts | 22 ++++++++ .../{ => core/providers}/types/provider.ts | 9 ++-- packages/appkit/src/index.ts | 3 +- packages/appkit/src/swap/index.ts | 1 + packages/appkit/src/types/plugin.ts | 22 -------- packages/walletkit/src/index.ts | 3 +- template/packages/appkit-react/docs/hooks.md | 6 +++ template/packages/appkit/docs/actions.md | 6 +++ 30 files changed, 342 insertions(+), 125 deletions(-) create mode 100644 demo/examples/src/appkit/actions/providers/get-custom-provider.ts create mode 100644 demo/examples/src/appkit/actions/providers/providers.test.ts create mode 100644 demo/examples/src/appkit/hooks/providers/providers.test.tsx create mode 100644 demo/examples/src/appkit/hooks/providers/use-custom-provider.tsx create mode 100644 packages/appkit-react/src/features/providers/hooks/use-custom-provider.ts rename packages/{appkit/src/core/plugin-manager => appkit-react/src/features/providers}/index.ts (71%) create mode 100644 packages/appkit/src/actions/providers/get-custom-provider.ts delete mode 100644 packages/appkit/src/core/plugin-manager/services/plugin-manager.ts create mode 100644 packages/appkit/src/core/providers/index.ts create mode 100644 packages/appkit/src/core/providers/services/custom-providers-manager.ts create mode 100644 packages/appkit/src/core/providers/types/custom-provider.ts rename packages/appkit/src/{ => core/providers}/types/provider.ts (52%) delete mode 100644 packages/appkit/src/types/plugin.ts diff --git a/demo/examples/src/appkit/actions/providers/get-custom-provider.ts b/demo/examples/src/appkit/actions/providers/get-custom-provider.ts new file mode 100644 index 000000000..83b242525 --- /dev/null +++ b/demo/examples/src/appkit/actions/providers/get-custom-provider.ts @@ -0,0 +1,24 @@ +/** + * 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 { AppKit, CustomProvider } from '@ton/appkit'; +import { getCustomProvider } from '@ton/appkit'; + +interface TacProvider extends CustomProvider { + sendCrossChainTransaction: (params: unknown) => Promise; +} + +export const getCustomProviderExample = (appKit: AppKit) => { + // SAMPLE_START: GET_CUSTOM_PROVIDER + const tac = getCustomProvider(appKit, { id: 'tac' }); + + if (tac) { + console.log('TAC provider is available'); + } + // SAMPLE_END: GET_CUSTOM_PROVIDER +}; diff --git a/demo/examples/src/appkit/actions/providers/providers.test.ts b/demo/examples/src/appkit/actions/providers/providers.test.ts new file mode 100644 index 000000000..c91b96a15 --- /dev/null +++ b/demo/examples/src/appkit/actions/providers/providers.test.ts @@ -0,0 +1,44 @@ +/** + * 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 { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { AppKit } from '@ton/appkit'; +import { Network } from '@ton/walletkit'; + +import { getCustomProviderExample } from './get-custom-provider'; + +describe('Provider Actions Examples (Integration)', () => { + let appKit: AppKit; + let consoleSpy: ReturnType; + + beforeEach(() => { + vi.clearAllMocks(); + consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); + + appKit = new AppKit({ + networks: { [Network.mainnet().chainId]: {} }, + }); + }); + + afterEach(() => { + consoleSpy.mockRestore(); + }); + + describe('getCustomProviderExample', () => { + it('should log when custom provider is available', () => { + appKit.registerProvider({ providerId: 'tac', type: 'custom' as const }); + getCustomProviderExample(appKit); + expect(consoleSpy).toHaveBeenCalledWith('TAC provider is available'); + }); + + it('should not log when provider is not registered', () => { + getCustomProviderExample(appKit); + expect(consoleSpy).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/demo/examples/src/appkit/hooks/providers/providers.test.tsx b/demo/examples/src/appkit/hooks/providers/providers.test.tsx new file mode 100644 index 000000000..6d2e31a7f --- /dev/null +++ b/demo/examples/src/appkit/hooks/providers/providers.test.tsx @@ -0,0 +1,52 @@ +/** + * 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. + * + */ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { render, screen, cleanup } from '@testing-library/react'; +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; + +import { createWrapper } from '../../../__tests__/test-utils'; +import { UseCustomProviderExample } from './use-custom-provider'; + +describe('Provider Hooks Examples', () => { + let mockAppKit: any; + + beforeEach(() => { + cleanup(); + vi.clearAllMocks(); + + mockAppKit = { + emitter: { on: vi.fn(() => () => {}), off: vi.fn() }, + connectors: [], + customProvidersManager: { getProvider: vi.fn().mockReturnValue(undefined) }, + }; + }); + + afterEach(() => { + cleanup(); + }); + + describe('UseCustomProviderExample', () => { + it('should show not registered message when provider is absent', () => { + render(, { wrapper: createWrapper(mockAppKit) }); + expect(screen.getByText('TAC provider not registered')).toBeDefined(); + }); + + it('should show ready message when provider is registered', () => { + mockAppKit.customProvidersManager.getProvider = vi.fn().mockReturnValue({ + providerId: 'tac', + type: 'custom', + sendCrossChainTransaction: vi.fn(), + }); + + render(, { wrapper: createWrapper(mockAppKit) }); + expect(screen.getByText('TAC provider is ready')).toBeDefined(); + }); + }); +}); diff --git a/demo/examples/src/appkit/hooks/providers/use-custom-provider.tsx b/demo/examples/src/appkit/hooks/providers/use-custom-provider.tsx new file mode 100644 index 000000000..4cdc850c8 --- /dev/null +++ b/demo/examples/src/appkit/hooks/providers/use-custom-provider.tsx @@ -0,0 +1,26 @@ +/** + * 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 { CustomProvider } from '@ton/appkit'; +import { useCustomProvider } from '@ton/appkit-react'; + +interface TacProvider extends CustomProvider { + sendCrossChainTransaction: (params: unknown) => Promise; +} + +export const UseCustomProviderExample = () => { + // SAMPLE_START: USE_CUSTOM_PROVIDER + const tac = useCustomProvider('tac'); + + if (!tac) { + return
TAC provider not registered
; + } + + return
TAC provider is ready
; + // SAMPLE_END: USE_CUSTOM_PROVIDER +}; diff --git a/packages/appkit-react/docs/hooks.md b/packages/appkit-react/docs/hooks.md index b01154a4a..ed3c24de2 100644 --- a/packages/appkit-react/docs/hooks.md +++ b/packages/appkit-react/docs/hooks.md @@ -985,4 +985,18 @@ return ( ); ``` +### `useCustomProvider` + +Hook to get a registered custom provider by id. + +```tsx +const tac = useCustomProvider('tac'); + +if (!tac) { + return
TAC provider not registered
; +} + +return
TAC provider is ready
; +``` + diff --git a/packages/appkit-react/src/features/providers/hooks/use-custom-provider.ts b/packages/appkit-react/src/features/providers/hooks/use-custom-provider.ts new file mode 100644 index 000000000..08c237ffd --- /dev/null +++ b/packages/appkit-react/src/features/providers/hooks/use-custom-provider.ts @@ -0,0 +1,20 @@ +/** + * 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 { getCustomProvider } from '@ton/appkit'; +import type { CustomProvider } from '@ton/appkit'; + +import { useAppKit } from '../../../hooks/use-app-kit'; + +/** + * Hook to get a registered custom provider by id. + */ +export const useCustomProvider = (id: string): T | undefined => { + const appKit = useAppKit(); + return getCustomProvider(appKit, { id }); +}; diff --git a/packages/appkit/src/core/plugin-manager/index.ts b/packages/appkit-react/src/features/providers/index.ts similarity index 71% rename from packages/appkit/src/core/plugin-manager/index.ts rename to packages/appkit-react/src/features/providers/index.ts index bbc29dfd6..bf6a551a6 100644 --- a/packages/appkit/src/core/plugin-manager/index.ts +++ b/packages/appkit-react/src/features/providers/index.ts @@ -6,4 +6,4 @@ * */ -export { PluginManager } from './services/plugin-manager'; +export { useCustomProvider } from './hooks/use-custom-provider'; diff --git a/packages/appkit-react/src/index.ts b/packages/appkit-react/src/index.ts index e44576dce..c13ca8314 100644 --- a/packages/appkit-react/src/index.ts +++ b/packages/appkit-react/src/index.ts @@ -28,3 +28,4 @@ export * from './features/wallets'; export * from './features/swap'; export * from './features/signing'; export * from './features/staking'; +export * from './features/providers'; diff --git a/packages/appkit/docs/actions.md b/packages/appkit/docs/actions.md index 8ed695e8c..f42e153cd 100644 --- a/packages/appkit/docs/actions.md +++ b/packages/appkit/docs/actions.md @@ -703,3 +703,15 @@ const unsubscribe = watchSelectedWallet(appKit, { // Later: unsubscribe(); ``` + +### `getCustomProvider` + +Get a registered custom provider by id. + +```tsx +const tac = getCustomProvider(appKit, { id: 'tac' }); + +if (tac) { + console.log('TAC provider is available'); +} +``` diff --git a/packages/appkit/src/actions/index.ts b/packages/appkit/src/actions/index.ts index db575b2b2..b5093c091 100644 --- a/packages/appkit/src/actions/index.ts +++ b/packages/appkit/src/actions/index.ts @@ -107,6 +107,11 @@ export { transferNft, type TransferNftParameters, type TransferNftReturnType } f // Providers export { registerProvider, type RegisterProviderOptions } from './providers/register-provider'; +export { + getCustomProvider, + type GetCustomProviderOptions, + type GetCustomProviderReturnType, +} from './providers/get-custom-provider'; // Signing export { signText, type SignTextParameters, type SignTextReturnType } from './signing/sign-text'; diff --git a/packages/appkit/src/actions/providers/get-custom-provider.ts b/packages/appkit/src/actions/providers/get-custom-provider.ts new file mode 100644 index 000000000..696b66a33 --- /dev/null +++ b/packages/appkit/src/actions/providers/get-custom-provider.ts @@ -0,0 +1,26 @@ +/** + * 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 { AppKit } from '../../core/app-kit'; +import type { CustomProvider } from '../../core/providers'; + +export interface GetCustomProviderOptions { + id: string; +} + +export type GetCustomProviderReturnType = T | undefined; + +/** + * Get a registered custom provider by id + */ +export const getCustomProvider = ( + appKit: AppKit, + options: GetCustomProviderOptions, +): GetCustomProviderReturnType => { + return appKit.customProvidersManager.getProvider(options.id); +}; diff --git a/packages/appkit/src/actions/providers/register-provider.ts b/packages/appkit/src/actions/providers/register-provider.ts index 341c9d333..02a7f8c27 100644 --- a/packages/appkit/src/actions/providers/register-provider.ts +++ b/packages/appkit/src/actions/providers/register-provider.ts @@ -6,8 +6,7 @@ * */ -import type { ProviderInput } from '@ton/walletkit'; - +import type { ProviderInput } from '../../core/providers'; import type { AppKit } from '../../core/app-kit'; export type RegisterProviderOptions = ProviderInput; diff --git a/packages/appkit/src/actions/staking/get-staking-manager.ts b/packages/appkit/src/actions/staking/get-staking-manager.ts index d5243498f..6af8021bc 100644 --- a/packages/appkit/src/actions/staking/get-staking-manager.ts +++ b/packages/appkit/src/actions/staking/get-staking-manager.ts @@ -6,8 +6,7 @@ * */ -import type { StakingManager } from '@ton/walletkit'; - +import type { StakingManager } from '../../staking'; import type { AppKit } from '../../core/app-kit'; export type GetStakingManagerReturnType = StakingManager; diff --git a/packages/appkit/src/actions/swap/get-swap-manager.ts b/packages/appkit/src/actions/swap/get-swap-manager.ts index 191a0e563..c83bce646 100644 --- a/packages/appkit/src/actions/swap/get-swap-manager.ts +++ b/packages/appkit/src/actions/swap/get-swap-manager.ts @@ -6,8 +6,7 @@ * */ -import type { SwapManager } from '@ton/walletkit'; - +import type { SwapManager } from '../../swap'; import type { AppKit } from '../../core/app-kit'; export type GetSwapManagerReturnType = SwapManager; diff --git a/packages/appkit/src/core/app-kit/constants/events.ts b/packages/appkit/src/core/app-kit/constants/events.ts index e8e6a52c5..d8c012c55 100644 --- a/packages/appkit/src/core/app-kit/constants/events.ts +++ b/packages/appkit/src/core/app-kit/constants/events.ts @@ -29,10 +29,3 @@ export const NETWORKS_EVENTS = { UPDATED: 'networks:updated', DEFAULT_CHANGED: 'networks:default-changed', } as const; - -/** - * Plugin events - */ -export const PLUGIN_EVENTS = { - REGISTERED: 'plugin:registered', -} as const; diff --git a/packages/appkit/src/core/app-kit/index.ts b/packages/appkit/src/core/app-kit/index.ts index 8af994de2..89ee67bcf 100644 --- a/packages/appkit/src/core/app-kit/index.ts +++ b/packages/appkit/src/core/app-kit/index.ts @@ -7,7 +7,7 @@ */ export { AppKit } from './services/app-kit'; -export { CONNECTOR_EVENTS, WALLETS_EVENTS, PLUGIN_EVENTS, NETWORKS_EVENTS } from './constants/events'; +export { CONNECTOR_EVENTS, WALLETS_EVENTS, NETWORKS_EVENTS } from './constants/events'; export type { AppKitConfig } from './types/config'; export type { @@ -15,6 +15,5 @@ export type { AppKitEvents, WalletConnectedPayload, WalletDisconnectedPayload, - PluginRegisteredPayload, 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 accd88635..048a396ac 100644 --- a/packages/appkit/src/core/app-kit/services/app-kit.ts +++ b/packages/appkit/src/core/app-kit/services/app-kit.ts @@ -7,13 +7,14 @@ */ import { SwapManager, StreamingManager } from '@ton/walletkit'; -import type { ProviderInput, SwapProviderInterface, StakingProviderInterface } from '@ton/walletkit'; +import type { ProviderInput } from '@ton/walletkit'; -import { StakingManager } from '../../../staking'; import type { Connector, ConnectorFactoryContext, ConnectorInput } from '../../../types/connector'; -import type { AppKitPlugin, PluginInput } from '../../../types/plugin'; +import { StakingManager } from '../../../staking'; +import type { StakingProviderInterface } from '../../../staking'; +import { CustomProvidersManager } from '../../providers'; +import type { CustomProvider, CustomProviderInput, SwapProviderInterface } from '../../providers'; import { EventEmitter } from '../../emitter'; -import { PluginManager } from '../../plugin-manager'; import { CONNECTOR_EVENTS, WALLETS_EVENTS } from '../constants/events'; import type { AppKitEmitter, AppKitEvents } from '../types/events'; import type { WalletInterface } from '../../../types/wallet'; @@ -32,7 +33,7 @@ export class AppKit { readonly walletsManager: WalletsManager; readonly swapManager: SwapManager; readonly stakingManager: StakingManager; - readonly pluginManager: PluginManager; + readonly customProvidersManager: CustomProvidersManager; readonly networkManager: AppKitNetworkManager; readonly streamingManager: StreamingManager; @@ -55,8 +56,8 @@ export class AppKit { this.swapManager = new SwapManager(() => this.createFactoryContext()); this.stakingManager = new StakingManager(() => this.createFactoryContext()); + this.customProvidersManager = new CustomProvidersManager(() => this.createFactoryContext()); this.streamingManager = new StreamingManager(() => this.createFactoryContext()); - this.pluginManager = new PluginManager(this.emitter); if (config.connectors) { config.connectors.forEach((input) => { @@ -69,12 +70,6 @@ export class AppKit { this.registerProvider(input); }); } - - if (config.plugins) { - config.plugins.forEach((input) => { - this.addPlugin(input); - }); - } } createFactoryContext(): ConnectorFactoryContext { @@ -114,18 +109,9 @@ export class AppKit { } /** - * Add a plugin + * Register a provider (swap, staking, or custom) */ - addPlugin(input: PluginInput): void { - const plugin: AppKitPlugin = typeof input === 'function' ? input(this.createFactoryContext()) : input; - plugin.init(this.createFactoryContext()); - this.pluginManager.register(plugin.id, plugin); - } - - /** - * Add a provider - */ - registerProvider(input: ProviderInput): void { + registerProvider(input: ProviderInput | CustomProviderInput): void { const provider = typeof input === 'function' ? input(this.createFactoryContext()) : input; switch (provider.type) { case 'swap': @@ -134,8 +120,11 @@ export class AppKit { case 'staking': this.stakingManager.registerProvider(provider as StakingProviderInterface); break; + case 'custom': + this.customProvidersManager.registerProvider(provider as CustomProvider); + break; default: - throw new Error('Unknown provider type'); + throw new Error(`Unknown provider type: ${provider.type}`); } } diff --git a/packages/appkit/src/core/app-kit/types/config.ts b/packages/appkit/src/core/app-kit/types/config.ts index 1ad530a8a..d2cc0b2e0 100644 --- a/packages/appkit/src/core/app-kit/types/config.ts +++ b/packages/appkit/src/core/app-kit/types/config.ts @@ -10,7 +10,6 @@ import type { NetworkAdapters, ProviderInput } from '@ton/walletkit'; import type { ConnectorInput } from '../../../types/connector'; import type { Network } from '../../../types/network'; -import type { PluginInput } from '../../../types/plugin'; /** * Configuration for AppKit @@ -39,11 +38,6 @@ export interface AppKitConfig { providers?: ProviderInput[]; - /** - * Plugins that register extensions into AppKit. - */ - plugins?: PluginInput[]; - /** * Enable server-side rendering support */ diff --git a/packages/appkit/src/core/app-kit/types/events.ts b/packages/appkit/src/core/app-kit/types/events.ts index 4f83abca9..99cc247d0 100644 --- a/packages/appkit/src/core/app-kit/types/events.ts +++ b/packages/appkit/src/core/app-kit/types/events.ts @@ -7,7 +7,7 @@ */ import type { SharedKitEvents } from '../../emitter'; -import type { CONNECTOR_EVENTS, WALLETS_EVENTS, PLUGIN_EVENTS, NETWORKS_EVENTS } from '../constants/events'; +import type { CONNECTOR_EVENTS, WALLETS_EVENTS, NETWORKS_EVENTS } from '../constants/events'; import type { Network } from '../../../types/network'; import type { EventEmitter } from '../../emitter'; import type { WalletInterface } from '../../../types/wallet'; @@ -21,11 +21,6 @@ export interface WalletDisconnectedPayload { connectorId: string; } -export interface PluginRegisteredPayload { - pluginId: string; - pluginType: string; -} - export interface DefaultNetworkChangedPayload { network: Network | undefined; } @@ -42,9 +37,6 @@ export type AppKitEvents = { // Networks events [NETWORKS_EVENTS.UPDATED]: Record; [NETWORKS_EVENTS.DEFAULT_CHANGED]: DefaultNetworkChangedPayload; - - // Plugin events - [PLUGIN_EVENTS.REGISTERED]: PluginRegisteredPayload; } & SharedKitEvents; export type AppKitEmitter = EventEmitter; diff --git a/packages/appkit/src/core/plugin-manager/services/plugin-manager.ts b/packages/appkit/src/core/plugin-manager/services/plugin-manager.ts deleted file mode 100644 index 976d6d6cc..000000000 --- a/packages/appkit/src/core/plugin-manager/services/plugin-manager.ts +++ /dev/null @@ -1,40 +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 { PLUGIN_EVENTS } from '../../app-kit/constants/events'; -import type { AppKitEmitter } from '../../app-kit/types/events'; - -/** - * Manages plugins registered in AppKit. - * Stores plugin instances by id so typed wrappers can retrieve them. - */ -export class PluginManager { - private readonly plugins = new Map(); - private readonly emitter: AppKitEmitter; - - constructor(emitter: AppKitEmitter) { - this.emitter = emitter; - } - - register(key: string, plugin: T): void { - this.plugins.set(key, plugin); - this.emitter.emit(PLUGIN_EVENTS.REGISTERED, { pluginId: key, pluginType: key }, 'appkit'); - } - - get(key: string): T | undefined { - return this.plugins.get(key) as T | undefined; - } - - has(key: string): boolean { - return this.plugins.has(key); - } - - remove(key: string): boolean { - return this.plugins.delete(key); - } -} diff --git a/packages/appkit/src/core/providers/index.ts b/packages/appkit/src/core/providers/index.ts new file mode 100644 index 000000000..8020d9a34 --- /dev/null +++ b/packages/appkit/src/core/providers/index.ts @@ -0,0 +1,20 @@ +/** + * 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 { CustomProvidersManager } from './services/custom-providers-manager'; + +export * from './types/provider'; +export * from './types/custom-provider'; + +export type { + BaseProvider, + ProviderInput, + ProviderFactory, + ProviderFactoryContext, + SwapProviderInterface, +} from '@ton/walletkit'; diff --git a/packages/appkit/src/core/providers/services/custom-providers-manager.ts b/packages/appkit/src/core/providers/services/custom-providers-manager.ts new file mode 100644 index 000000000..f2c158d2e --- /dev/null +++ b/packages/appkit/src/core/providers/services/custom-providers-manager.ts @@ -0,0 +1,37 @@ +/** + * 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 { ProviderFactoryContext, ProviderInput } from '@ton/walletkit'; + +import type { CustomProvider } from '../types/custom-provider'; + +export class CustomProvidersManager { + private readonly providers = new Map(); + private readonly factoryContext: () => ProviderFactoryContext; + + constructor(factoryContext: () => ProviderFactoryContext) { + this.factoryContext = factoryContext; + } + + registerProvider(input: ProviderInput): void { + const provider = typeof input === 'function' ? input(this.factoryContext()) : input; + this.providers.set(provider.providerId, provider); + } + + getProvider(id: string): T | undefined { + return this.providers.get(id) as T | undefined; + } + + hasProvider(id: string): boolean { + return this.providers.has(id); + } + + getRegisteredProviders(): string[] { + return Array.from(this.providers.keys()); + } +} diff --git a/packages/appkit/src/core/providers/types/custom-provider.ts b/packages/appkit/src/core/providers/types/custom-provider.ts new file mode 100644 index 000000000..3e5f2784e --- /dev/null +++ b/packages/appkit/src/core/providers/types/custom-provider.ts @@ -0,0 +1,22 @@ +/** + * 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 { BaseProvider } from '@ton/walletkit'; + +/** + * A provider with custom functionality registered by a third party. + * Extend this interface to add your own methods. + * + * @example + * interface TacProvider extends CustomProvider { + * sendCrossChainTransaction(params: TacParams): Promise; + * } + */ +export interface CustomProvider extends BaseProvider { + readonly type: 'custom'; +} diff --git a/packages/appkit/src/types/provider.ts b/packages/appkit/src/core/providers/types/provider.ts similarity index 52% rename from packages/appkit/src/types/provider.ts rename to packages/appkit/src/core/providers/types/provider.ts index 51d5748df..d732873e1 100644 --- a/packages/appkit/src/types/provider.ts +++ b/packages/appkit/src/core/providers/types/provider.ts @@ -6,9 +6,8 @@ * */ -import type { SwapProviderInterface, StakingProviderInterface } from '@ton/walletkit'; +import type { SwapProviderInterface } from '../../../swap'; +import type { StakingProviderInterface } from '../../../staking'; +import type { CustomProvider } from './custom-provider'; -/** - * Provider configuration - */ -export type Provider = SwapProviderInterface | StakingProviderInterface; +export type Provider = SwapProviderInterface | StakingProviderInterface | CustomProvider; diff --git a/packages/appkit/src/index.ts b/packages/appkit/src/index.ts index c3a0cd1cb..b621c2b6b 100644 --- a/packages/appkit/src/index.ts +++ b/packages/appkit/src/index.ts @@ -28,7 +28,7 @@ // Core export * from './core/app-kit'; export * from './core/emitter'; -export * from './core/plugin-manager'; +export * from './core/providers'; export * from './core/network'; export * from './core/streaming'; export * from './connectors/tonconnect'; @@ -41,7 +41,6 @@ export * from './actions'; // Types export * from './types/connector'; -export * from './types/plugin'; export * from './types/balance'; export * from './types/wallet'; export * from './types/query'; diff --git a/packages/appkit/src/swap/index.ts b/packages/appkit/src/swap/index.ts index 083337c6a..fd63d7a28 100644 --- a/packages/appkit/src/swap/index.ts +++ b/packages/appkit/src/swap/index.ts @@ -7,6 +7,7 @@ */ export type { + SwapProviderInterface, SwapToken, TokenAmount, SwapParams, diff --git a/packages/appkit/src/types/plugin.ts b/packages/appkit/src/types/plugin.ts deleted file mode 100644 index e3f25e94f..000000000 --- a/packages/appkit/src/types/plugin.ts +++ /dev/null @@ -1,22 +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 { ConnectorFactoryContext } from './connector'; - -/** - * Plugin that extends AppKit with custom functionality. - * After init, the plugin instance is stored in PluginManager by its id. - */ -export interface AppKitPlugin { - readonly id: string; - init(context: ConnectorFactoryContext): void | Promise; - destroy?(): void; -} - -/** A plugin instance or a factory that creates one */ -export type PluginInput = AppKitPlugin | ((ctx: ConnectorFactoryContext) => AppKitPlugin); diff --git a/packages/walletkit/src/index.ts b/packages/walletkit/src/index.ts index a3bc2841f..238cc30a7 100644 --- a/packages/walletkit/src/index.ts +++ b/packages/walletkit/src/index.ts @@ -172,4 +172,5 @@ export type { TonApiStreamingProviderConfig } from './streaming/tonapi'; export { StreamingManager } from './streaming'; export type { StreamingProvider, StreamingProviderFactory } from './api/interfaces/StreamingProvider'; export type { StreamingAPI } from './api/interfaces/StreamingAPI'; -export type { ProviderFactoryContext } from './types/factory'; +export { createProvider } from './types/factory'; +export type { ProviderFactoryContext, ProviderInput, ProviderFactory } from './types/factory'; diff --git a/template/packages/appkit-react/docs/hooks.md b/template/packages/appkit-react/docs/hooks.md index 13a4c057e..c21c4dea4 100644 --- a/template/packages/appkit-react/docs/hooks.md +++ b/template/packages/appkit-react/docs/hooks.md @@ -252,4 +252,10 @@ Hook to get and set the currently selected wallet. %%demo/examples/src/appkit/hooks/wallets#USE_SELECTED_WALLET%% +### `useCustomProvider` + +Hook to get a registered custom provider by id. + +%%demo/examples/src/appkit/hooks/providers#USE_CUSTOM_PROVIDER%% + diff --git a/template/packages/appkit/docs/actions.md b/template/packages/appkit/docs/actions.md index ad33b0014..af91905a8 100644 --- a/template/packages/appkit/docs/actions.md +++ b/template/packages/appkit/docs/actions.md @@ -339,3 +339,9 @@ Watch for changes in the list of connected wallets. Watch for changes in the selected wallet. %%demo/examples/src/appkit/actions/wallets#WATCH_SELECTED_WALLET%% + +### `getCustomProvider` + +Get a registered custom provider by id. + +%%demo/examples/src/appkit/actions/providers#GET_CUSTOM_PROVIDER%% From 0a18b78816de134a270e5eb0faec89d0a6814084 Mon Sep 17 00:00:00 2001 From: VK Date: Wed, 29 Apr 2026 20:11:34 +0400 Subject: [PATCH 3/4] feat(tac): add appkit-tac --- apps/appkit-minter/package.json | 1 + .../appkit-minter/src/core/configs/app-kit.ts | 6 + .../src/features/tac/components/tac-card.tsx | 53 +++ apps/appkit-minter/src/features/tac/index.ts | 9 + apps/appkit-minter/src/pages/minter-page.tsx | 2 + packages/appkit-tac/package.json | 55 +++ .../src/actions/get-smart-account-address.ts | 41 ++ .../src/actions/get-tac-provider.ts | 18 + .../src/hooks/use-smart-account-address.ts | 30 ++ packages/appkit-tac/src/index.ts | 19 + .../appkit-tac/src/provider/tac-provider.ts | 22 ++ packages/appkit-tac/tsconfig.cjs.json | 10 + packages/appkit-tac/tsconfig.json | 19 + .../src/core/app-kit/services/app-kit.ts | 4 +- pnpm-lock.yaml | 350 ++++++++++++++++++ 15 files changed, 637 insertions(+), 2 deletions(-) create mode 100644 apps/appkit-minter/src/features/tac/components/tac-card.tsx create mode 100644 apps/appkit-minter/src/features/tac/index.ts create mode 100644 packages/appkit-tac/package.json create mode 100644 packages/appkit-tac/src/actions/get-smart-account-address.ts create mode 100644 packages/appkit-tac/src/actions/get-tac-provider.ts create mode 100644 packages/appkit-tac/src/hooks/use-smart-account-address.ts create mode 100644 packages/appkit-tac/src/index.ts create mode 100644 packages/appkit-tac/src/provider/tac-provider.ts create mode 100644 packages/appkit-tac/tsconfig.cjs.json create mode 100644 packages/appkit-tac/tsconfig.json diff --git a/apps/appkit-minter/package.json b/apps/appkit-minter/package.json index c5d5806c3..815ef99e4 100644 --- a/apps/appkit-minter/package.json +++ b/apps/appkit-minter/package.json @@ -14,6 +14,7 @@ "typecheck": "tsc --noEmit -p tsconfig.app.json" }, "dependencies": { + "@tac/appkit-provider": "workspace:*", "@ston-fi/omniston-sdk": "^0.7.9", "@tailwindcss/vite": "^4.2.2", "@ton/appkit": "workspace:*", diff --git a/apps/appkit-minter/src/core/configs/app-kit.ts b/apps/appkit-minter/src/core/configs/app-kit.ts index f412bdac7..0c5c31ae0 100644 --- a/apps/appkit-minter/src/core/configs/app-kit.ts +++ b/apps/appkit-minter/src/core/configs/app-kit.ts @@ -17,6 +17,8 @@ import { import { DeDustSwapProvider } from '@ton/appkit/swap/dedust'; import { OmnistonSwapProvider } from '@ton/appkit/swap/omniston'; import { createTonstakersProvider } from '@ton/appkit/staking/tonstakers'; +import { TacSdk, Network as TacNetwork } from '@tonappchain/sdk'; +import { createTacProvider } from '@tac/appkit-provider'; import { ENV_TON_API_KEY_TESTNET, ENV_TON_API_KEY_MAINNET } from '@/core/configs/env'; @@ -51,6 +53,10 @@ export const appKit = new AppKit({ providers: [new DeDustSwapProvider(), new OmnistonSwapProvider(), createTonstakersProvider({})], }); +TacSdk.create({ network: TacNetwork.TESTNET }).then((sdk) => { + appKit.registerProvider(createTacProvider(sdk)); +}); + // TODO: replace in normal config appKit.streamingManager.registerProvider( createTonCenterStreamingProvider({ network: Network.mainnet(), apiKey: ENV_TON_API_KEY_MAINNET }), diff --git a/apps/appkit-minter/src/features/tac/components/tac-card.tsx b/apps/appkit-minter/src/features/tac/components/tac-card.tsx new file mode 100644 index 000000000..34451b621 --- /dev/null +++ b/apps/appkit-minter/src/features/tac/components/tac-card.tsx @@ -0,0 +1,53 @@ +/** + * 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 { useState } from 'react'; +import type { FC } from 'react'; +import { useSmartAccountAddress } from '@tac/appkit-provider'; + +import { Card } from '@/core/components'; + +export const TacCard: FC = () => { + const [applicationAddress, setApplicationAddress] = useState(''); + + const { data: smartAccountAddress, isLoading, isError, error } = useSmartAccountAddress(applicationAddress); + + return ( + +
+
+ + setApplicationAddress(e.target.value)} + placeholder="0x..." + className="w-full rounded-lg border border-border bg-input px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:border-ring focus:ring-2 focus:ring-ring" + /> +
+ +
+
+ Smart Account Address + + {isLoading && '…'} + {isError && {error?.message ?? '—'}} + {!isLoading && !isError && (smartAccountAddress ?? '—')} + +
+
+
+
+ ); +}; diff --git a/apps/appkit-minter/src/features/tac/index.ts b/apps/appkit-minter/src/features/tac/index.ts new file mode 100644 index 000000000..5c182b9b2 --- /dev/null +++ b/apps/appkit-minter/src/features/tac/index.ts @@ -0,0 +1,9 @@ +/** + * 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 * from './components/tac-card'; diff --git a/apps/appkit-minter/src/pages/minter-page.tsx b/apps/appkit-minter/src/pages/minter-page.tsx index 429683429..93699042b 100644 --- a/apps/appkit-minter/src/pages/minter-page.tsx +++ b/apps/appkit-minter/src/pages/minter-page.tsx @@ -17,6 +17,7 @@ import { Card, Layout } from '@/core/components'; import { SwapButton } from '@/features/swap'; import { StakingCard } from '@/features/staking'; import { SignMessageCard } from '@/features/signing'; +import { TacCard } from '@/features/tac'; export const MinterPage: React.FC = () => { const [wallet] = useSelectedWallet(); @@ -53,6 +54,7 @@ export const MinterPage: React.FC = () => { + )} diff --git a/packages/appkit-tac/package.json b/packages/appkit-tac/package.json new file mode 100644 index 000000000..b41853ad0 --- /dev/null +++ b/packages/appkit-tac/package.json @@ -0,0 +1,55 @@ +{ + "name": "@tac/appkit-provider", + "version": "0.0.1", + "description": "TAC cross-chain provider for @ton/appkit", + "repository": { + "type": "git", + "url": "https://github.com/ton-connect/kit" + }, + "sideEffects": false, + "main": "dist/cjs/index.js", + "module": "dist/esm/index.js", + "types": "dist/cjs/index.d.ts", + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/cjs/index.d.ts", + "default": "./dist/cjs/index.js" + } + } + }, + "scripts": { + "build": "pnpm build:clean && pnpm build:cjs && pnpm build:esm", + "build:clean": "rimraf dist", + "build:esm": "tsc -p tsconfig.json", + "build:cjs": "tsc -p tsconfig.cjs.json", + "quality": "pnpm typecheck", + "typecheck": "tsc --noEmit", + "clean": "rimraf .turbo dist node_modules" + }, + "dependencies": { + "@ton/appkit": "workspace:*", + "@ton/appkit-react": "workspace:*" + }, + "peerDependencies": { + "@tanstack/react-query": ">=5.0.0", + "@tonappchain/sdk": ">=0.7.0", + "react": ">=18.0.0" + }, + "devDependencies": { + "@tanstack/react-query": "catalog:", + "@tonappchain/sdk": "^0.7.2", + "@types/react": "catalog:", + "react": "catalog:", + "rimraf": "^6.0.1", + "typescript": "~5.9.3" + }, + "keywords": [], + "author": "", + "license": "MIT", + "packageManager": "pnpm@10.15.0" +} diff --git a/packages/appkit-tac/src/actions/get-smart-account-address.ts b/packages/appkit-tac/src/actions/get-smart-account-address.ts new file mode 100644 index 000000000..c5b4245c9 --- /dev/null +++ b/packages/appkit-tac/src/actions/get-smart-account-address.ts @@ -0,0 +1,41 @@ +/** + * 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 { getSelectedWallet } from '@ton/appkit'; +import type { AppKit } from '@ton/appkit'; + +import { getTacProvider } from './get-tac-provider'; + +export interface GetSmartAccountAddressOptions { + /** EVM address of the target application contract */ + applicationAddress: string; +} + +export type GetSmartAccountAddressReturnType = Promise; + +/** + * Get the TAC smart account address for a given TON wallet and EVM application. + * The smart account acts as a proxy for the user on TAC EVM. + */ +export const getSmartAccountAddress = async ( + appKit: AppKit, + options: GetSmartAccountAddressOptions, +): GetSmartAccountAddressReturnType => { + const provider = getTacProvider(appKit); + + if (!provider) { + throw new Error('TAC provider is not registered'); + } + + const selectedWallet = getSelectedWallet(appKit); + if (!selectedWallet) { + throw new Error('Wallet is not selected'); + } + + return provider.sdk.getSmartAccountAddressForTvmWallet(selectedWallet.getAddress(), options.applicationAddress); +}; diff --git a/packages/appkit-tac/src/actions/get-tac-provider.ts b/packages/appkit-tac/src/actions/get-tac-provider.ts new file mode 100644 index 000000000..2ffc4de8c --- /dev/null +++ b/packages/appkit-tac/src/actions/get-tac-provider.ts @@ -0,0 +1,18 @@ +/** + * 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 { getCustomProvider } from '@ton/appkit'; +import type { AppKit } from '@ton/appkit'; + +import type { TacProvider } from '../provider/tac-provider'; + +export type GetTacProviderReturnType = TacProvider | undefined; + +export const getTacProvider = (appKit: AppKit): GetTacProviderReturnType => { + return getCustomProvider(appKit, { id: 'tac' }); +}; diff --git a/packages/appkit-tac/src/hooks/use-smart-account-address.ts b/packages/appkit-tac/src/hooks/use-smart-account-address.ts new file mode 100644 index 000000000..11895dde6 --- /dev/null +++ b/packages/appkit-tac/src/hooks/use-smart-account-address.ts @@ -0,0 +1,30 @@ +/** + * 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 { useQuery } from '@tanstack/react-query'; +import type { UseQueryResult } from '@tanstack/react-query'; +import { useAppKit, useAddress } from '@ton/appkit-react'; + +import { getSmartAccountAddress } from '../actions/get-smart-account-address'; + +export type UseSmartAccountAddressReturnType = UseQueryResult; + +/** + * Hook to get the TAC smart account address for the connected wallet and an EVM application. + * Re-runs automatically when the selected wallet changes. + */ +export const useSmartAccountAddress = (applicationAddress: string): UseSmartAccountAddressReturnType => { + const appKit = useAppKit(); + const address = useAddress(); + + return useQuery({ + queryKey: ['tac', 'smart-account-address', address, applicationAddress], + queryFn: () => getSmartAccountAddress(appKit, { applicationAddress }), + enabled: !!address && !!applicationAddress, + }); +}; diff --git a/packages/appkit-tac/src/index.ts b/packages/appkit-tac/src/index.ts new file mode 100644 index 000000000..61dd628d0 --- /dev/null +++ b/packages/appkit-tac/src/index.ts @@ -0,0 +1,19 @@ +/** + * 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 { createTacProvider } from './provider/tac-provider'; +export type { TacProvider } from './provider/tac-provider'; + +export { getTacProvider, type GetTacProviderReturnType } from './actions/get-tac-provider'; +export { + getSmartAccountAddress, + type GetSmartAccountAddressOptions, + type GetSmartAccountAddressReturnType, +} from './actions/get-smart-account-address'; + +export { useSmartAccountAddress, type UseSmartAccountAddressReturnType } from './hooks/use-smart-account-address'; diff --git a/packages/appkit-tac/src/provider/tac-provider.ts b/packages/appkit-tac/src/provider/tac-provider.ts new file mode 100644 index 000000000..f1e4c5b9d --- /dev/null +++ b/packages/appkit-tac/src/provider/tac-provider.ts @@ -0,0 +1,22 @@ +/** + * 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 { CustomProvider } from '@ton/appkit'; +import type { TacSdk } from '@tonappchain/sdk'; + +export interface TacProvider extends CustomProvider { + readonly providerId: 'tac'; + readonly type: 'custom'; + readonly sdk: TacSdk; +} + +export const createTacProvider = (sdk: TacSdk): TacProvider => ({ + providerId: 'tac', + type: 'custom', + sdk, +}); diff --git a/packages/appkit-tac/tsconfig.cjs.json b/packages/appkit-tac/tsconfig.cjs.json new file mode 100644 index 000000000..9e24a8040 --- /dev/null +++ b/packages/appkit-tac/tsconfig.cjs.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "outDir": "dist/cjs", + "declaration": true, + "declarationDir": "dist/cjs" + } +} diff --git a/packages/appkit-tac/tsconfig.json b/packages/appkit-tac/tsconfig.json new file mode 100644 index 000000000..af9749600 --- /dev/null +++ b/packages/appkit-tac/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "bundler", + "outDir": "dist/esm", + "declaration": true, + "declarationDir": "dist/esm", + "target": "es2020", + "baseUrl": "./", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitAny": true, + "skipLibCheck": true, + "declarationMap": true + }, + "exclude": ["**/*.spec.ts", "**/*.config.ts", "node_modules", "dist"], + "include": ["src/**/*"] +} 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 048a396ac..65906f32c 100644 --- a/packages/appkit/src/core/app-kit/services/app-kit.ts +++ b/packages/appkit/src/core/app-kit/services/app-kit.ts @@ -13,7 +13,7 @@ import type { Connector, ConnectorFactoryContext, ConnectorInput } from '../../. import { StakingManager } from '../../../staking'; import type { StakingProviderInterface } from '../../../staking'; import { CustomProvidersManager } from '../../providers'; -import type { CustomProvider, CustomProviderInput, SwapProviderInterface } from '../../providers'; +import type { CustomProvider, SwapProviderInterface } from '../../providers'; import { EventEmitter } from '../../emitter'; import { CONNECTOR_EVENTS, WALLETS_EVENTS } from '../constants/events'; import type { AppKitEmitter, AppKitEvents } from '../types/events'; @@ -111,7 +111,7 @@ export class AppKit { /** * Register a provider (swap, staking, or custom) */ - registerProvider(input: ProviderInput | CustomProviderInput): void { + registerProvider(input: ProviderInput): void { const provider = typeof input === 'function' ? input(this.createFactoryContext()) : input; switch (provider.type) { case 'swap': diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 620bcaf16..1acd87d50 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,6 +87,9 @@ importers: '@ston-fi/omniston-sdk': specifier: ^0.7.9 version: 0.7.9 + '@tac/appkit-provider': + specifier: workspace:* + version: link:../../packages/appkit-tac '@tailwindcss/vite': specifier: ^4.2.2 version: 4.2.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.3)) @@ -711,6 +714,34 @@ importers: specifier: ^0.26.0 version: 0.26.0(rollup@4.59.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.3)) + packages/appkit-tac: + dependencies: + '@ton/appkit': + specifier: workspace:* + version: link:../appkit + '@ton/appkit-react': + specifier: workspace:* + version: link:../appkit-react + devDependencies: + '@tanstack/react-query': + specifier: 'catalog:' + version: 5.99.0(react@19.2.3) + '@tonappchain/sdk': + specifier: ^0.7.2 + version: 0.7.2(@ton/core@0.63.1(@ton/crypto@3.3.0))(@ton/crypto@3.3.0)(@ton/ton@16.2.4(@ton/core@0.63.1(@ton/crypto@3.3.0))(@ton/crypto@3.3.0))(@tonconnect/ui@2.4.4)(ethers@6.16.0)(ton-crypto@3.2.0) + '@types/react': + specifier: 'catalog:' + version: 19.2.14 + react: + specifier: 'catalog:' + version: 19.2.3 + rimraf: + specifier: ^6.0.1 + version: 6.1.3 + typescript: + specifier: ~5.9.3 + version: 5.9.3 + packages/mcp: dependencies: '@modelcontextprotocol/sdk': @@ -924,6 +955,9 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + '@adraffy/ens-normalize@1.10.1': + resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} + '@apidevtools/json-schema-ref-parser@14.0.1': resolution: {integrity: sha512-Oc96zvmxx1fqoSEdUmfmvvb59/KDOnUoJ7s2t7bISyAn0XEz57LCCw8k2Y4Pf3mwKaZLMciESALORLgfe2frCw==} engines: {node: '>= 16'} @@ -940,6 +974,17 @@ packages: peerDependencies: openapi-types: '>=7' + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/types@3.973.8': + resolution: {integrity: sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==} + engines: {node: '>=20.0.0'} + '@babel/code-frame@7.10.4': resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} @@ -1536,6 +1581,10 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + '@craftzdog/react-native-buffer@6.1.1': resolution: {integrity: sha512-YXJ0Jr4V+Hk2CZXpQw0A0NJeuiW2Rv6rAAutJCZ2k/JG13vLsppUibkJ8exSMxODtH9yJUrLiR96rilG3pFZ4Q==} @@ -2493,10 +2542,20 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@noble/curves@1.2.0': + resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} + '@noble/curves@1.9.7': resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} engines: {node: ^14.21.3 || >=16} + '@noble/ed25519@1.7.5': + resolution: {integrity: sha512-xuS0nwRMQBvSxDa7UxMb61xTiH3MxTgUfhyPUALVIe0FlOAz4sjELwyDRyUvqeEYfRSG9qNjFIycqLZppg4RSA==} + + '@noble/hashes@1.3.2': + resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} + engines: {node: '>= 16'} + '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} @@ -2517,6 +2576,9 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@orbs-network/ton-access@2.3.3': + resolution: {integrity: sha512-b1miCPts7wBG9JKYgzXIRZQm/LMy5Uk1mNK8NzlcXHL3HRHJkkFbuYJGuj3IkWCiIicW3Ipp4sYnn3Fwo4oB0g==} + '@oxc-project/types@0.124.0': resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} @@ -3627,6 +3689,22 @@ packages: '@sinonjs/fake-timers@15.1.1': resolution: {integrity: sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==} + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/types@4.14.1': + resolution: {integrity: sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -3880,6 +3958,12 @@ packages: '@ton/crypto@3.3.0': resolution: {integrity: sha512-/A6CYGgA/H36OZ9BbTaGerKtzWp50rg67ZCH2oIjV1NcrBaCK9Z343M+CxedvM7Haf3f/Ee9EhxyeTp0GKMUpA==} + '@ton/ton@15.4.0': + resolution: {integrity: sha512-f19y2Rez88KZK+lv3CT3ghXi07LcToJtJhlgRSfK+3GzjdIcoW/wbmXG1ffi6fkc8W2LO5z6Q3gZaIEvNGnz6w==} + peerDependencies: + '@ton/core': '>=0.62.0 <1.0.0' + '@ton/crypto': '>=3.2.0' + '@ton/ton@16.2.4': resolution: {integrity: sha512-GWCNKizQm7MM99XNQGr+zWWdSfbFu/WLeQYm7tMIQDNKpAYEpLDKJUKuK/yrz763DBbnTDAFeq1NWAEy8rAOaQ==} peerDependencies: @@ -3890,6 +3974,20 @@ packages: resolution: {tarball: https://codeload.github.com/the-ton-tech/toolchain/tar.gz/31376da778155bd0984d68abf2a46dce417bacb8} version: 1.5.0 + '@tonappchain/adnl@1.0.4': + resolution: {integrity: sha512-0qd25AJsoxXeJ0R5xhv8rLKQ/lWxfuBIaIsSRV79v0r1LpJw/YwHX8TJWaTOhWlJja2xCPpLC8dJwa+je5w4wg==} + + '@tonappchain/sdk@0.7.2': + resolution: {integrity: sha512-TqhEWOLgxAuK2qvCTpEx8fFEQ2a6SzRXL6Uyjd/X334F5UMkq8ojgK+6AULq7wspDAkol7Q0upnppIfqnD8f0A==} + peerDependencies: + '@ton/ton': '>=15' + '@tonconnect/ui': '>=2' + ethers: '>=6' + ton-crypto: '>=3' + + '@tonappchain/ton-lite-client@3.0.6': + resolution: {integrity: sha512-euXQCF1gYRCZt470Ek8I+mzNYQFquSoEay5P8bZDhZW53zVSnM36yFFexeCCEUGdiN8EJa1oOq9i9x32GZsmQQ==} + '@tonconnect/bridge-sdk@0.2.4': resolution: {integrity: sha512-W7fDoo8aT9FYnGPPLqh4Giiu1M5FP3GW4A+AeDB/xfTzM9XsO9aoWoSfrR1+QuNl2OmvtvneCFv4MnowM9+feg==} @@ -3987,6 +4085,9 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/bn.js@5.2.0': + resolution: {integrity: sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -4044,9 +4145,15 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + '@types/node@22.7.5': + resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@types/node@25.6.0': resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} + '@types/pegjs@0.10.6': + resolution: {integrity: sha512-eLYXDbZWXh2uxf+w8sXS8d6KSoXTswfps6fvCUuVAGN8eRpfe7h9eSRydxiSJvo9Bf+GzifsDOr9TMQlmJdmkw==} + '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: @@ -4442,6 +4549,12 @@ packages: resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} engines: {node: '>=12.0'} + aes-js@3.1.2: + resolution: {integrity: sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==} + + aes-js@4.0.0-beta.5: + resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -4925,6 +5038,9 @@ packages: caniuse-lite@1.0.30001777: resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} + case-shift@2.5.3: + resolution: {integrity: sha512-6SdS9W5xu82Kj1Z6f14h0zsbWTdXGtD0RftPNnqbAFFqqlzX1SMFi1E1NDIBg5LC2m9EYWWPUV80nTb3iu2e6Q==} + chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} @@ -5026,6 +5142,10 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} @@ -5185,6 +5305,11 @@ packages: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + create-ecdh@4.0.4: resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} @@ -5748,6 +5873,10 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + ethers@6.16.0: + resolution: {integrity: sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==} + engines: {node: '>=14.0.0'} + event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -6749,6 +6878,9 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} + isomorphic-fetch@3.0.0: + resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==} + isomorphic-timers-promises@1.0.1: resolution: {integrity: sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==} engines: {node: '>=10'} @@ -7208,6 +7340,9 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru_map@0.4.1: + resolution: {integrity: sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg==} + lucide-react@0.562.0: resolution: {integrity: sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==} peerDependencies: @@ -7891,6 +8026,11 @@ packages: resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} engines: {node: '>= 0.10'} + pegjs@0.10.0: + resolution: {integrity: sha512-qI5+oFNEGi3L5HAxDwN2LA4Gg7irF70Zs25edhjld9QemOgp0CbvMtbFcMvFtEo1OityPrcCzkQFB8JP/hxgow==} + engines: {node: '>=0.10'} + hasBin: true + perfect-debounce@2.1.0: resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} @@ -9037,6 +9177,9 @@ packages: resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==} hasBin: true + symbol.inspect@1.0.1: + resolution: {integrity: sha512-YQSL4duoHmLhsTD1Pw8RW6TZ5MaTX5rXJnqacJottr2P2LZBF/Yvrc3ku4NUpMOm8aM0KOCqM+UAkMA5HWQCzQ==} + synckit@0.11.12: resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} @@ -9184,6 +9327,15 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + ton-crypto-primitives@2.0.0: + resolution: {integrity: sha512-K+qKjpS0h9sPW6oExcpxnzuQ7nEgHEiDKwIqE/jWD25o8iFGe3FWj1gKxFNbKE9wwYKc5IV8FwrU+raF0KO5nQ==} + + ton-crypto@3.2.0: + resolution: {integrity: sha512-fltdBNQ45gARMuGMEOjPZWPJ5eSql8p3CA0Dj7tPv5lhU5ziT8SxXLAzDraR9HJ8YpjBHLVvYyhMLRiEwxgtMQ==} + + ton-tl@1.0.1: + resolution: {integrity: sha512-dAHJSWEW0CRNm/sdWVhola9/OZc/yHmLOXlSNr9I6l0WaVZmGhwkmDuzvMm1ZJ3Dvhf5tYN+iAUSSgmf8Q+P0g==} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -9271,6 +9423,9 @@ packages: resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} engines: {node: '>=6'} + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -9405,6 +9560,9 @@ packages: underscore@1.13.8: resolution: {integrity: sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==} + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici-types@7.19.2: resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} @@ -10065,6 +10223,8 @@ snapshots: '@adobe/css-tools@4.4.4': {} + '@adraffy/ens-normalize@1.10.1': {} + '@apidevtools/json-schema-ref-parser@14.0.1': dependencies: '@types/json-schema': 7.0.15 @@ -10084,6 +10244,23 @@ snapshots: call-me-maybe: 1.0.2 openapi-types: 12.1.3 + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.8 + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.8 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.973.8': + dependencies: + '@smithy/types': 4.14.1 + tslib: 2.8.1 + '@babel/code-frame@7.10.4': dependencies: '@babel/highlight': 7.25.9 @@ -10859,6 +11036,9 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 + '@colors/colors@1.5.0': + optional: true + '@craftzdog/react-native-buffer@6.1.1(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.1.0))(react@19.1.0)': dependencies: ieee754: 1.2.1 @@ -12045,10 +12225,18 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@noble/curves@1.2.0': + dependencies: + '@noble/hashes': 1.3.2 + '@noble/curves@1.9.7': dependencies: '@noble/hashes': 1.8.0 + '@noble/ed25519@1.7.5': {} + + '@noble/hashes@1.3.2': {} + '@noble/hashes@1.8.0': {} '@noble/hashes@2.0.1': {} @@ -12065,6 +12253,12 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@orbs-network/ton-access@2.3.3': + dependencies: + isomorphic-fetch: 3.0.0 + transitivePeerDependencies: + - encoding + '@oxc-project/types@0.124.0': {} '@pkgjs/parseargs@0.11.0': @@ -13396,6 +13590,24 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/types@4.14.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + '@standard-schema/spec@1.1.0': {} '@ston-fi/omniston-sdk@0.7.9': @@ -13732,6 +13944,18 @@ snapshots: jssha: 3.2.0 tweetnacl: 1.0.3 + '@ton/ton@15.4.0(@ton/core@0.63.1(@ton/crypto@3.3.0))(@ton/crypto@3.3.0)': + dependencies: + '@ton/core': 0.63.1(@ton/crypto@3.3.0) + '@ton/crypto': 3.3.0 + axios: 1.15.0 + dataloader: 2.2.3 + symbol.inspect: 1.0.1 + teslabot: 1.5.0 + zod: 3.25.76 + transitivePeerDependencies: + - debug + '@ton/ton@16.2.4(@ton/core@0.63.1(@ton/crypto@3.3.0))(@ton/crypto@3.3.0)': dependencies: '@ton/core': 0.63.1(@ton/crypto@3.3.0) @@ -13763,6 +13987,55 @@ snapshots: - supports-color - typescript + '@tonappchain/adnl@1.0.4': + dependencies: + '@noble/ed25519': 1.7.5 + '@noble/hashes': 1.8.0 + aes-js: 3.1.2 + buffer: 6.0.3 + events: 3.3.0 + isomorphic-ws: 5.0.0(ws@8.20.0) + ws: 8.20.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@tonappchain/sdk@0.7.2(@ton/core@0.63.1(@ton/crypto@3.3.0))(@ton/crypto@3.3.0)(@ton/ton@16.2.4(@ton/core@0.63.1(@ton/crypto@3.3.0))(@ton/crypto@3.3.0))(@tonconnect/ui@2.4.4)(ethers@6.16.0)(ton-crypto@3.2.0)': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@orbs-network/ton-access': 2.3.3 + '@ton/ton': 16.2.4(@ton/core@0.63.1(@ton/crypto@3.3.0))(@ton/crypto@3.3.0) + '@tonappchain/ton-lite-client': 3.0.6(@ton/core@0.63.1(@ton/crypto@3.3.0))(@ton/crypto@3.3.0) + '@tonconnect/ui': 2.4.4 + bn.js: 5.2.3 + cli-table3: 0.6.5 + dotenv: 16.4.7 + ethers: 6.16.0 + ton-crypto: 3.2.0 + transitivePeerDependencies: + - '@ton/core' + - '@ton/crypto' + - bufferutil + - debug + - encoding + - utf-8-validate + + '@tonappchain/ton-lite-client@3.0.6(@ton/core@0.63.1(@ton/crypto@3.3.0))(@ton/crypto@3.3.0)': + dependencies: + '@ton/ton': 15.4.0(@ton/core@0.63.1(@ton/crypto@3.3.0))(@ton/crypto@3.3.0) + '@tonappchain/adnl': 1.0.4 + dataloader: 2.2.3 + lru_map: 0.4.1 + teslabot: 1.5.0 + ton-tl: 1.0.1 + tweetnacl: 1.0.3 + transitivePeerDependencies: + - '@ton/core' + - '@ton/crypto' + - bufferutil + - debug + - utf-8-validate + '@tonconnect/bridge-sdk@0.2.4': dependencies: '@tonconnect/isomorphic-eventsource': 0.0.2 @@ -13922,6 +14195,10 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@types/bn.js@5.2.0': + dependencies: + '@types/node': 25.6.0 + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -13977,10 +14254,16 @@ snapshots: '@types/node@12.20.55': {} + '@types/node@22.7.5': + dependencies: + undici-types: 6.19.8 + '@types/node@25.6.0': dependencies: undici-types: 7.19.2 + '@types/pegjs@0.10.6': {} + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: '@types/react': 19.2.14 @@ -14480,6 +14763,10 @@ snapshots: adm-zip@0.5.16: {} + aes-js@3.1.2: {} + + aes-js@4.0.0-beta.5: {} + agent-base@7.1.4: {} agent-base@9.0.0: {} @@ -15088,6 +15375,8 @@ snapshots: caniuse-lite@1.0.30001777: {} + case-shift@2.5.3: {} + chai@5.3.3: dependencies: assertion-error: 2.0.1 @@ -15191,6 +15480,12 @@ snapshots: cli-spinners@2.9.2: {} + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + cli-width@4.1.0: {} client-only@0.0.1: {} @@ -15350,6 +15645,8 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + crc-32@1.2.2: {} + create-ecdh@4.0.4: dependencies: bn.js: 4.12.3 @@ -15992,6 +16289,19 @@ snapshots: etag@1.8.1: {} + ethers@6.16.0: + dependencies: + '@adraffy/ens-normalize': 1.10.1 + '@noble/curves': 1.2.0 + '@noble/hashes': 1.3.2 + '@types/node': 22.7.5 + aes-js: 4.0.0-beta.5 + tslib: 2.7.0 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + event-target-shim@5.0.1: {} events@3.3.0: {} @@ -17032,12 +17342,23 @@ snapshots: isobject@3.0.1: {} + isomorphic-fetch@3.0.0: + dependencies: + node-fetch: 2.7.0 + whatwg-fetch: 3.6.20 + transitivePeerDependencies: + - encoding + isomorphic-timers-promises@1.0.1: {} isomorphic-ws@5.0.0(ws@8.17.1): dependencies: ws: 8.17.1 + isomorphic-ws@5.0.0(ws@8.20.0): + dependencies: + ws: 8.20.0 + istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@5.2.1: @@ -17686,6 +18007,8 @@ snapshots: dependencies: yallist: 3.1.1 + lru_map@0.4.1: {} + lucide-react@0.562.0(react@19.2.3): dependencies: react: 19.2.3 @@ -18603,6 +18926,8 @@ snapshots: sha.js: 2.4.12 to-buffer: 1.2.2 + pegjs@0.10.0: {} + perfect-debounce@2.1.0: {} picocolors@1.1.1: {} @@ -20035,6 +20360,8 @@ snapshots: transitivePeerDependencies: - encoding + symbol.inspect@1.0.1: {} + synckit@0.11.12: dependencies: '@pkgr/core': 0.2.9 @@ -20171,6 +20498,25 @@ snapshots: toidentifier@1.0.1: {} + ton-crypto-primitives@2.0.0: + dependencies: + jssha: 3.2.0 + + ton-crypto@3.2.0: + dependencies: + jssha: 3.2.0 + ton-crypto-primitives: 2.0.0 + tweetnacl: 1.0.3 + + ton-tl@1.0.1: + dependencies: + '@types/bn.js': 5.2.0 + '@types/pegjs': 0.10.6 + bn.js: 5.2.3 + case-shift: 2.5.3 + crc-32: 1.2.2 + pegjs: 0.10.0 + totalist@3.0.1: {} tr46@0.0.3: {} @@ -20260,6 +20606,8 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 + tslib@2.7.0: {} + tslib@2.8.1: {} tsx@4.21.0: @@ -20398,6 +20746,8 @@ snapshots: underscore@1.13.8: {} + undici-types@6.19.8: {} + undici-types@7.19.2: {} undici@6.23.0: {} From ab067094d513ea4eca5b6dd29bde79d3c624ffbb Mon Sep 17 00:00:00 2001 From: VK Date: Wed, 29 Apr 2026 20:26:16 +0400 Subject: [PATCH 4/4] feat(tac): rework createTacProvider --- apps/appkit-minter/src/core/configs/app-kit.ts | 13 +++++++------ .../src/actions/get-smart-account-address.ts | 3 ++- packages/appkit-tac/src/provider/tac-provider.ts | 9 +++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/appkit-minter/src/core/configs/app-kit.ts b/apps/appkit-minter/src/core/configs/app-kit.ts index 0c5c31ae0..e53a1f76e 100644 --- a/apps/appkit-minter/src/core/configs/app-kit.ts +++ b/apps/appkit-minter/src/core/configs/app-kit.ts @@ -17,7 +17,7 @@ import { import { DeDustSwapProvider } from '@ton/appkit/swap/dedust'; import { OmnistonSwapProvider } from '@ton/appkit/swap/omniston'; import { createTonstakersProvider } from '@ton/appkit/staking/tonstakers'; -import { TacSdk, Network as TacNetwork } from '@tonappchain/sdk'; +import { Network as TacNetwork } from '@tonappchain/sdk'; import { createTacProvider } from '@tac/appkit-provider'; import { ENV_TON_API_KEY_TESTNET, ENV_TON_API_KEY_MAINNET } from '@/core/configs/env'; @@ -50,11 +50,12 @@ export const appKit = new AppKit({ }, }), ], - providers: [new DeDustSwapProvider(), new OmnistonSwapProvider(), createTonstakersProvider({})], -}); - -TacSdk.create({ network: TacNetwork.TESTNET }).then((sdk) => { - appKit.registerProvider(createTacProvider(sdk)); + providers: [ + new DeDustSwapProvider(), + new OmnistonSwapProvider(), + createTonstakersProvider({}), + createTacProvider({ network: TacNetwork.TESTNET }), + ], }); // TODO: replace in normal config diff --git a/packages/appkit-tac/src/actions/get-smart-account-address.ts b/packages/appkit-tac/src/actions/get-smart-account-address.ts index c5b4245c9..e46a772ec 100644 --- a/packages/appkit-tac/src/actions/get-smart-account-address.ts +++ b/packages/appkit-tac/src/actions/get-smart-account-address.ts @@ -37,5 +37,6 @@ export const getSmartAccountAddress = async ( throw new Error('Wallet is not selected'); } - return provider.sdk.getSmartAccountAddressForTvmWallet(selectedWallet.getAddress(), options.applicationAddress); + const sdk = await provider.sdk; + return sdk.getSmartAccountAddressForTvmWallet(selectedWallet.getAddress(), options.applicationAddress); }; diff --git a/packages/appkit-tac/src/provider/tac-provider.ts b/packages/appkit-tac/src/provider/tac-provider.ts index f1e4c5b9d..7b37c8947 100644 --- a/packages/appkit-tac/src/provider/tac-provider.ts +++ b/packages/appkit-tac/src/provider/tac-provider.ts @@ -7,16 +7,17 @@ */ import type { CustomProvider } from '@ton/appkit'; -import type { TacSdk } from '@tonappchain/sdk'; +import { TacSdk } from '@tonappchain/sdk'; +import type { SDKParams } from '@tonappchain/sdk'; export interface TacProvider extends CustomProvider { readonly providerId: 'tac'; readonly type: 'custom'; - readonly sdk: TacSdk; + readonly sdk: Promise; } -export const createTacProvider = (sdk: TacSdk): TacProvider => ({ +export const createTacProvider = (params: SDKParams): TacProvider => ({ providerId: 'tac', type: 'custom', - sdk, + sdk: TacSdk.create(params), });