import type { TransactionRequest, TransactionResult, EthereumTransactionRequest, SolanaTransactionRequest, TronTransactionRequest, NetworkRpcMap } from '@meshconnect/uwc-types' import { WalletConnectClient } from './walletconnect-client' import { ConnectionService } from './connection-service' import { EthereumTransactionService } from './ethereum/ethereum-transaction-service' import { SolanaTransactionService } from './solana/solana-transaction-service' import { TronTransactionService } from './tron/tron-transaction-service' /** * Service for handling transactions in WalletConnect */ export class TransactionService { private ethereumService: EthereumTransactionService private solanaService: SolanaTransactionService private tronService: TronTransactionService constructor( private walletConnectClient: WalletConnectClient, private connectionService: ConnectionService, networkRpcMap: NetworkRpcMap = {} ) { this.ethereumService = new EthereumTransactionService() this.solanaService = new SolanaTransactionService(networkRpcMap) this.tronService = new TronTransactionService() } /** * Send a transaction with the connected wallet */ async sendTransaction( request: TransactionRequest ): Promise { const session = this.connectionService.getSession() if (!session) { throw new Error('No active session. Please connect first.') } const activeNetwork = this.connectionService.getActiveNetwork() const activeAddress = this.connectionService.getActiveAddress() if (!activeNetwork) { throw new Error('No active network. Please connect first.') } if (!activeAddress) { throw new Error('No active address. Please connect first.') } const client = await this.walletConnectClient.getClient() // Determine namespace from network ID const namespace = activeNetwork.id.split(':')[0] if (namespace === 'eip155') { return this.ethereumService.sendTransaction( client, session, request as EthereumTransactionRequest, activeNetwork.id ) } else if (namespace === 'solana') { return this.solanaService.sendTransaction( client, session, request as SolanaTransactionRequest, activeNetwork.id, activeAddress ) } else if (namespace === 'tron') { return this.tronService.sendTransaction( client, session, request as TronTransactionRequest, activeNetwork.id, activeAddress ) } else { throw new Error(`Unsupported namespace: ${namespace}`) } } /** * Sign-only path for Solana transactions over WalletConnect. * Mirrors the validation done in sendTransaction but routes to the sign-only Solana flow * instead of signAndSend. Used by fee-payer relay flows where the relay server broadcasts. */ async signSolanaTransactionBytes( serializedTx: Uint8Array ): Promise { const session = this.connectionService.getSession() if (!session) { throw new Error('No active session. Please connect first.') } const activeNetwork = this.connectionService.getActiveNetwork() const activeAddress = this.connectionService.getActiveAddress() if (!activeNetwork) { throw new Error('No active network. Please connect first.') } if (!activeAddress) { throw new Error('No active address. Please connect first.') } const namespace = activeNetwork.id.split(':')[0] if (namespace !== 'solana') { throw new Error( `signSolanaTransactionBytes requires a Solana network (got namespace "${namespace}")` ) } const client = await this.walletConnectClient.getClient() return this.solanaService.signTransactionBytes( client, session, serializedTx, activeNetwork.id, activeAddress ) } }