Skip to main content
Glama
swap-tools.test.tsβ€’9.01 kB
import { SwapTools } from '../../tools/swap' import { AuraAdapter } from '../../core/aura-adapter' import { GuardEngine } from '../../core/guard-engine' import { SwapIntent, SwapQuoteRequest } from '../../types' // Mock dependencies jest.mock('../../core/aura-adapter') jest.mock('../../core/guard-engine') describe('SwapTools', () => { let swapTools: SwapTools let mockAuraAdapter: jest.Mocked<AuraAdapter> let mockGuardEngine: jest.Mocked<GuardEngine> beforeEach(() => { mockAuraAdapter = { parseSwapIntent: jest.fn(), getSwapQuote: jest.fn(), checkAllowance: jest.fn() } as any mockGuardEngine = { validateSimulation: jest.fn() } as any swapTools = new SwapTools(mockAuraAdapter, mockGuardEngine) }) describe('swap.parse', () => { it('should parse natural language swap intent', async () => { const intent: SwapIntent = { text: 'swap 1 ETH to USDC on Base', userAddress: '0x1234567890123456789012345678901234567890' } const expectedParams = { fromToken: 'ETH', toToken: 'USDC', amount: '1', chain: 'base', slippageTolerance: 0.5, userAddress: intent.userAddress } mockAuraAdapter.parseSwapIntent.mockResolvedValue(expectedParams) const result = await swapTools.handleTool('swap.parse', intent) expect(result.success).toBe(true) if (result.success) { expect(result.data).toEqual(expectedParams) } expect(mockAuraAdapter.parseSwapIntent).toHaveBeenCalledWith(intent) }) it('should handle parse errors gracefully', async () => { const intent: SwapIntent = { text: 'invalid swap command' } mockAuraAdapter.parseSwapIntent.mockRejectedValue(new Error('Could not parse amount from intent')) const result = await swapTools.handleTool('swap.parse', intent) expect(result.success).toBe(false) if (!result.success) { expect(result.error?.code).toBe('PARSE_ERROR') } }) }) describe('swap.quote', () => { it('should get swap quote from AURA API', async () => { const request: SwapQuoteRequest = { fromToken: 'ETH', toToken: 'USDC', amount: '1', chain: 'base', slippageTolerance: 0.5 } const mockQuote = { fromToken: { address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', symbol: 'ETH', decimals: 18, amount: '1000000000000000000' }, toToken: { address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', symbol: 'USDC', decimals: 6, amount: '3000000000' }, price: '3000', priceImpact: 0.1, route: { dex: 'Uniswap V3', path: ['0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'], protocols: ['uniswap-v3'] }, estimatedGas: '150000', estimatedGasUsd: 5.0, guaranteedAmount: '2970000000' } mockAuraAdapter.getSwapQuote.mockResolvedValue(mockQuote) mockGuardEngine.validateSimulation.mockReturnValue({ passed: true, triggeredGuards: [], warnings: [] }) const result = await swapTools.handleTool('swap.quote', request) expect(result.success).toBe(true) if (result.success) { expect(result.data).toEqual(mockQuote) } expect(mockAuraAdapter.getSwapQuote).toHaveBeenCalledWith(request) }) it('should block quote if guards fail', async () => { const request: SwapQuoteRequest = { fromToken: 'ETH', toToken: 'USDC', amount: '1', chain: 'base' } const mockQuote = { fromToken: { address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', symbol: 'ETH', decimals: 18, amount: '1000000000000000000' }, toToken: { address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', symbol: 'USDC', decimals: 6, amount: '3000000000' }, price: '3000', priceImpact: 2.5, // High price impact route: { dex: 'Uniswap V3', path: ['0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'] }, estimatedGas: '150000', estimatedGasUsd: 5.0, guaranteedAmount: '2925000000' } mockAuraAdapter.getSwapQuote.mockResolvedValue(mockQuote) mockGuardEngine.validateSimulation.mockReturnValue({ passed: false, triggeredGuards: ['slippage_too_high'], warnings: [] }) const result = await swapTools.handleTool('swap.quote', request) expect(result.success).toBe(false) if (!result.success) { expect(result.error?.code).toBe('GUARD_VIOLATION') expect(result.error?.details?.triggeredGuards).toContain('slippage_too_high') } }) }) describe('swap.prepare', () => { it('should build transaction with real calldata from AURA', async () => { const mockQuote = { fromToken: { address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', symbol: 'ETH', decimals: 18, amount: '1000000000000000000' }, toToken: { address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', symbol: 'USDC', decimals: 6, amount: '3000000000' }, price: '3000', priceImpact: 0.1, route: { dex: 'Uniswap V3', path: ['0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'] }, estimatedGas: '150000', estimatedGasUsd: 5.0, guaranteedAmount: '2970000000' } const mockTxData = { to: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', // Real Uniswap router data: '0xac9650d80000...', // Real calldata value: '1000000000000000000', gasLimit: '150000', spenderAddress: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', needsApproval: false } const mockAuraAdapterWithBuild = mockAuraAdapter as any mockAuraAdapterWithBuild.buildSwapTransaction = jest.fn().mockResolvedValue(mockTxData) const request = { quote: mockQuote, userAddress: '0x1234567890123456789012345678901234567890', slippageTolerance: 0.5 } const result = await swapTools.handleTool('swap.prepare', request) expect(result.success).toBe(true) if (result.success) { // Verify transaction has real data, not placeholders expect(result.data.swapTx.to).not.toBe(mockQuote.route.dex) // Should be contract address, not DEX name expect(result.data.swapTx.to).toBe('0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45') expect(result.data.swapTx.data).not.toBe('0x') // Should have real calldata expect(result.data.swapTx.data).toBe('0xac9650d80000...') } expect(mockAuraAdapterWithBuild.buildSwapTransaction).toHaveBeenCalledWith( mockQuote, request.userAddress, request.slippageTolerance ) }) it('should handle multi-chain correctly', async () => { const mockQuoteBase = { fromToken: { address: '0xEth', symbol: 'ETH', decimals: 18, amount: '1000000000000000000' }, toToken: { address: '0xUSDC', symbol: 'USDC', decimals: 6, amount: '3000000000' }, price: '3000', priceImpact: 0.1, route: { dex: 'Uniswap V3', path: ['0xEth', '0xUSDC'] }, estimatedGas: '150000', estimatedGasUsd: 5.0, guaranteedAmount: '2970000000' } const mockTxDataBase = { to: '0xBaseRouter', data: '0xbasecalldata', value: '1000000000000000000', gasLimit: '150000', spenderAddress: '0xBaseRouter', needsApproval: false } const mockAuraAdapterWithBuild = mockAuraAdapter as any mockAuraAdapterWithBuild.buildSwapTransaction = jest.fn().mockResolvedValue(mockTxDataBase) const result = await swapTools.handleTool('swap.prepare', { quote: mockQuoteBase, userAddress: '0x1234567890123456789012345678901234567890', slippageTolerance: 0.5 }) expect(result.success).toBe(true) // Verify AURA was called to build transaction (not hard-coded logic) expect(mockAuraAdapterWithBuild.buildSwapTransaction).toHaveBeenCalled() }) }) describe('swap.execute', () => { it('should require x402 payment when configured', async () => { const request = { signedTx: '0xsignedtxdata', chain: 'base' } const result = await swapTools.handleTool('swap.execute', request) // Should return payment required (x402) expect('invoiceId' in result).toBe(true) if ('invoiceId' in result) { expect(result.asset).toBe('USDC') } }) }) })

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/antidump/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server