Skip to main content
Glama

DeFi Trading Agent MCP Server

by edkdev

execute_swap

Facilitates swap transactions on DeFi platforms by executing trades using pre-fetched quote data, enabling efficient and precise trade automation across multiple blockchains.

Instructions

Execute a swap transaction (requires quote data)

Input Schema

NameRequiredDescriptionDefault
quoteDataYesQuote data from get_swap_quote

Input Schema (JSON Schema)

{ "properties": { "quoteData": { "description": "Quote data from get_swap_quote", "type": "object" } }, "required": [ "quoteData" ], "type": "object" }

Implementation Reference

  • Main handler function for execute_swap tool. Validates quoteData and user private key, extracts chainId, calls blockchainService.signAndBroadcastTransaction to execute the swap.
    async executeSwap(quoteData) { if (!quoteData) { throw new Error("Quote data is required for swap execution"); } if (!this.userPrivateKey) { throw new Error("User private key is required for swap execution"); } try { // Extract chain ID from quote data const chainId = quoteData.chainId || quoteData.transaction?.chainId; if (!chainId) { throw new Error("Chain ID not found in quote data"); } console.log("šŸš€ Executing swap transaction..."); // Sign and broadcast the transaction using blockchain service const result = await this.blockchain.signAndBroadcastTransaction( chainId, quoteData ); return { message: "Swap executed successfully", data: result, nextSteps: [ "1. Transaction has been broadcasted to the blockchain", "2. Wait for confirmation (usually 1-3 minutes)", "3. Check transaction status on block explorer", `4. Transaction hash: ${result.hash}`, ], }; } catch (error) { throw new Error(`Swap execution failed: ${error.message}`); } }
  • JSON schema defining the input for execute_swap tool: requires quoteData object from get_swap_quote.
    { name: TOOL_NAMES.EXECUTE_SWAP, description: "Execute a swap transaction (requires quote data)", inputSchema: { type: "object", properties: { quoteData: { type: "object", description: "Quote data from get_swap_quote", }, }, required: ["quoteData"], }, },
  • src/index.js:992-994 (registration)
    MCP server registration: maps 'execute_swap' tool calls to toolService.executeSwap(quoteData). TOOL_NAMES.EXECUTE_SWAP resolves to 'execute_swap'.
    case TOOL_NAMES.EXECUTE_SWAP: result = await toolService.executeSwap(args.quoteData); break;
  • Core helper function that implements the swap execution logic: signs Permit2 EIP-712 message if needed, embeds signature in transaction calldata, handles token allowance, signs and broadcasts the legacy transaction using ethers.js.
    async signAndBroadcastTransaction(chainId, quoteData) { try { if (!this.wallet) { throw new Error("No private key configured for transaction signing"); } const connectedWallet = this.getConnectedWallet(chainId); const { transaction, permit2, sellToken, sellAmount } = quoteData; if (!transaction) { throw new Error("No transaction data found in quote"); } console.log(`šŸš€ Processing transaction for chain ${chainId}:`, { hasTransaction: !!transaction, hasPermit2: !!permit2, transactionTo: transaction.to, transactionValue: transaction.value || "0", }); // Step 1: Handle token allowance for Permit2 (if needed) const PERMIT2_CONTRACT = "0x000000000022D473030F116dDEE9F6B43aC78BA3"; let allowanceResult = null; if (permit2 && sellToken && sellAmount) { console.log("šŸ” Checking token allowance for Permit2..."); try { allowanceResult = await this.ensureTokenAllowance( chainId, sellToken, PERMIT2_CONTRACT, sellAmount ); if (allowanceResult.approved) { console.log("āœ… Token allowance set for Permit2 contract"); } else { console.log("āœ… Sufficient token allowance already exists"); } } catch (error) { console.warn( "āš ļø Token allowance check failed, proceeding anyway:", error.message ); // Continue with swap execution even if allowance check fails // The transaction will fail if allowance is actually insufficient } } // Step 2: Prepare transaction data - start with original data let transactionData = transaction.data; // Step 3: Handle Permit2 signature if present let permit2Signature = null; if (permit2 && permit2.eip712) { console.log("šŸ” Processing Permit2 signature..."); permit2Signature = await this.signPermit2Message(permit2); console.log("āœ… Permit2 signature created"); const signature = permit2Signature.signature; // Ensure signature has 0x prefix and is properly formatted const cleanSignature = signature.startsWith("0x") ? signature : "0x" + signature; // Validate signature format (should be 65 bytes = 130 hex chars + 0x prefix = 132 total) if (cleanSignature.length !== 132) { throw new Error(`Invalid signature length: expected 132 chars (65 bytes), got ${cleanSignature.length}`); } // Calculate signature size in bytes (following viem's size() function logic) const signatureBytes = ethers.getBytes(cleanSignature); const signatureSize = signatureBytes.length; // Should be 65 bytes // Create signature length as 32-byte unsigned big-endian integer (following viem's numberToHex) const signatureLengthInHex = ethers.zeroPadValue( ethers.toBeHex(signatureSize), 32 ); // Append signature length and signature data to transaction data (following viem's concat) transactionData = ethers.concat([ transaction.data, signatureLengthInHex, cleanSignature, ]); console.log("šŸ”§ Permit2 signature embedded in transaction data:", { originalDataLength: transaction.data.length, signatureSize: signatureSize, newDataLength: ethers.hexlify(transactionData).length, signatureLengthHex: ethers.hexlify(signatureLengthInHex).substring(0, 20) + "...", signaturePreview: cleanSignature.substring(0, 20) + "...", }); } // Step 4: Validate quote data if (!transaction.gas) { throw new Error("No gas estimate found in quote data"); } if (!transaction.gasPrice) { throw new Error("No gasPrice found in quote data"); } // Step 5: Get nonce const nonce = await this.getTransactionCount( chainId, connectedWallet.address ); // Step 6: Create legacy transaction with embedded Permit2 signature const legacyTxData = { to: transaction.to, data: transactionData, // Use modified data with embedded signature value: transaction.value || "0", gasLimit: transaction.gas, gasPrice: transaction.gasPrice, nonce: nonce, type: 0, // Force legacy transaction }; console.log("šŸš€ Sending transaction with Permit2 signature embedded:", { to: legacyTxData.to, gasLimit: legacyTxData.gasLimit, gasPrice: legacyTxData.gasPrice, nonce: legacyTxData.nonce, type: "legacy", hasPermit2Embedded: !!permit2Signature, dataLength: transactionData.length, allowanceHandled: !!allowanceResult, }); // Step 7: Sign and send transaction console.log("šŸš€ Broadcasting transaction to network..."); const signedTx = await connectedWallet.sendTransaction(legacyTxData); console.log(`āœ… Transaction broadcasted: ${signedTx.hash}`); // Return transaction details return { hash: signedTx.hash, from: signedTx.from, to: signedTx.to, value: signedTx.value?.toString(), gasLimit: signedTx.gasLimit?.toString(), gasPrice: signedTx.gasPrice?.toString(), nonce: signedTx.nonce?.toString(), chainId: signedTx.chainId?.toString(), type: signedTx.type?.toString(), permit2Signed: !!permit2Signature, permit2Hash: permit2Signature?.hash, permit2Embedded: !!permit2Signature, allowanceResult: allowanceResult, steps: [ "1. āœ… Token allowance checked/set for Permit2", "2. āœ… Permit2 EIP-712 message signed", "3. āœ… Signature embedded in transaction data", "4. āœ… Transaction broadcasted to network", ], }; } catch (error) { console.error("Transaction signing/broadcasting failed:", error); throw new Error( `Failed to sign and broadcast transaction: ${error.message}` ); } }
  • src/constants.js:2-6 (registration)
    Constant definition mapping EXECUTE_SWAP to tool name string 'execute_swap', used in MCP server registration.
    export const TOOL_NAMES = { // Agg API Tools GET_SWAP_PRICE: "get_swap_price", GET_SWAP_QUOTE: "get_swap_quote", EXECUTE_SWAP: "execute_swap",

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/edkdev/defi-trading-mcp'

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