import { describe, it, expect, beforeEach, vi } from 'vitest' import { EthereumTransactionService } from './ethereum-transaction-service' import type { EVMNativeTransferRequest, EVMContractCallRequest, EVMDataTransferRequest } from '@meshconnect/uwc-types' import type { EthereumProvider } from '../../eip6963-discovery' describe('EthereumTransactionService', () => { let service: EthereumTransactionService let mockProvider: EthereumProvider beforeEach(() => { vi.clearAllMocks() service = new EthereumTransactionService() mockProvider = { request: vi.fn().mockResolvedValue('0xtxhash') } as any }) describe('sendTransaction routing', () => { it('should route native transfer to sendNativeTransaction', async () => { const request: EVMNativeTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', amount: BigInt('1000000000000000000'), gasConfig: { gasLimit: 21000 } } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) it('should route contract call to sendContractCall', async () => { const request: EVMContractCallRequest = { from: '0x1234567890123456789012345678901234567890', contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', abi: [ { inputs: [ { name: 'recipient', type: 'address' }, { name: 'amount', type: 'uint256' } ], name: 'transfer', outputs: [{ name: '', type: 'bool' }], stateMutability: 'nonpayable', type: 'function' } ], functionName: 'transfer', args: ['0x0987654321098765432109876543210987654321', BigInt(1000000)] } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) it('should route data transfer to sendDataTransfer', async () => { const request: EVMDataTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', data: '0xa9059cbb', chainId: '1' } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) it('should throw error for invalid request type', async () => { const invalidRequest = { from: '0x1234567890123456789012345678901234567890' } as any await expect( service.sendTransaction(invalidRequest, mockProvider) ).rejects.toThrow('Invalid transaction request type') }) }) describe('sendNativeTransaction', () => { it('should send native transaction successfully', async () => { const request: EVMNativeTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', amount: BigInt('1000000000000000000') } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) it('should handle transaction with gas config', async () => { const request: EVMNativeTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', amount: BigInt('500000000000000000'), gasConfig: { gasLimit: 21000, maxFeePerGas: 50000000000, maxPriorityFeePerGas: 2000000000 } } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) }) describe('sendContractCall', () => { it('should send contract call successfully', async () => { const request: EVMContractCallRequest = { from: '0x1234567890123456789012345678901234567890', contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', abi: [ { inputs: [ { name: 'recipient', type: 'address' }, { name: 'amount', type: 'uint256' } ], name: 'transfer', outputs: [{ name: '', type: 'bool' }], stateMutability: 'nonpayable', type: 'function' } ], functionName: 'transfer', args: ['0x0987654321098765432109876543210987654321', BigInt(1000000)] } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) it('should send payable contract call with value', async () => { const request: EVMContractCallRequest = { from: '0x1234567890123456789012345678901234567890', contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', abi: [ { inputs: [], name: 'deposit', outputs: [], stateMutability: 'payable', type: 'function' } ], functionName: 'deposit', args: [], value: BigInt('1000000000000000000') } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) }) describe('sendDataTransfer', () => { it('should send data transfer successfully', async () => { const request: EVMDataTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', data: '0xa9059cbb000000000000000000000000123456789012345678901234567890123456789000000000000000000000000000000000000000000000000000000000000f4240', chainId: '1' } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) it('should send data transfer with value', async () => { const request: EVMDataTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', data: '0xa9059cbb', chainId: '1', value: BigInt('500000000000000000') } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) it('should send data transfer with gas config', async () => { const request: EVMDataTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', data: '0x00', chainId: '137', gasConfig: { gasLimit: 100000, maxFeePerGas: 50000000000, maxPriorityFeePerGas: 2000000000 } } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) it('should send data transfer on different chains', async () => { const chains = ['1', '137', '8453', '42161', '10'] // Ethereum, Polygon, Base, Arbitrum, Optimism for (const chainId of chains) { const request: EVMDataTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', data: '0xa9059cbb', chainId } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') } }) it('should handle empty data field', async () => { const request: EVMDataTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', data: '0x', chainId: '1' } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) it('should handle complex encoded data', async () => { const complexData = '0x' + 'a'.repeat(1000) const request: EVMDataTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', data: complexData, chainId: '1' } const result = await service.sendTransaction(request, mockProvider) expect(result).toBe('0xtxhash') }) }) describe('error handling', () => { it('should handle transaction errors', async () => { const mockError = new Error('Transaction failed') mockProvider.request = vi.fn().mockRejectedValue(mockError) const request: EVMDataTransferRequest = { from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', data: '0xa9059cbb', chainId: '1' } await expect( service.sendTransaction(request, mockProvider) ).rejects.toThrow() }) }) })