import type { NetworkId, AvailableAddress, WalletMetadata } from '@meshconnect/uwc-types' import { WalletConnectorError } from '@meshconnect/uwc-types' import { getTronWallets, type TronProvider, type TronWeb, type DetectedTronWallet } from '../../tron-discovery' /** * Service for managing Tron wallet connections */ export class TronWalletService { private detectedWallets: DetectedTronWallet[] = [] private connectedProvider: TronProvider | null = null private account: string | null = null /** * Initialize wallet discovery using injectedId paths from expected wallets */ async initializeDiscovery(expectedWallets?: WalletMetadata[]): Promise { this.detectedWallets = await getTronWallets(expectedWallets) } /** * Get detected wallets */ getDetectedWallets(): DetectedTronWallet[] { return this.detectedWallets } /** * Find wallet by UUID */ findWalletByUuid(uuid: string): DetectedTronWallet | undefined { return this.detectedWallets.find(w => w.uuid === uuid) } /** * Resolve the default address from a TronWeb instance. * Bridge providers expose getDefaultAddress() since property access is async * across the Comlink proxy. Native providers use direct property access. */ private async resolveAddress(tronWeb: TronWeb): Promise { if (typeof tronWeb.getDefaultAddress === 'function') { const addr = await tronWeb.getDefaultAddress() return addr?.base58 ? String(addr.base58) : null } return tronWeb.defaultAddress?.base58 ? String(tronWeb.defaultAddress.base58) : null } /** * Check if a Tron wallet is already connected (non-prompting) */ async checkExistingConnection( provider: TronProvider ): Promise { try { if (provider.ready) { return await this.resolveAddress(provider.tronWeb) } return null } catch { return null } } /** * Connect to a Tron wallet */ async connect(provider: TronProvider): Promise { // TronLink and compatible wallets use provider.request for connection if (typeof provider.request === 'function') { await provider.request({ method: 'tron_requestAccounts' }) } // After requesting, check for default address on tronWeb const address = await this.resolveAddress(provider.tronWeb) if (!address) { // Delta C: throw a typed connector error so telemetry classifies this as // source:'connector' (our injected-Tron path), not an unknown-origin error // — the ONC-3172 "Tron connected but exposed no address" class. throw new WalletConnectorError({ type: 'unknown', message: 'No address returned from Tron wallet' }) } this.connectedProvider = provider this.account = address return address } /** * Build available addresses for all supported Tron networks */ buildAvailableAddresses( supportedNetworkIds: string[], address: string ): AvailableAddress[] { const addresses: AvailableAddress[] = [] supportedNetworkIds.forEach(networkId => { if (networkId.startsWith('tron:')) { addresses.push({ address, networkId: networkId as NetworkId }) } }) return addresses } /** * Set connection state */ setConnectionState( provider: TronProvider | null, account: string | null ): void { this.connectedProvider = provider this.account = account } /** * Get current account */ getAccount(): string | null { return this.account } /** * Get connected provider */ getConnectedProvider(): TronProvider | null { return this.connectedProvider } /** * Disconnect (clear state only) */ disconnect(): void { this.connectedProvider = null this.account = null } getTronWalletIdsFromExpectedWallets( expectedWallets: WalletMetadata[] = [] ): string[] { const injectedIds = expectedWallets .map( w => w.extensionInjectedProvider?.namespaceMetaData?.tron?.injectedId ) .filter((id): id is string => !!id) return injectedIds } }