transaction.tsβ’6.03 kB
import { GuardEngine } from '../core/guard-engine.js'
import {
TxSimulateRequest,
TxSimulateResponse,
TxExecuteRequest,
TxExecuteResponse,
X402PaymentRequired,
McpResponse
} from '../types/index.js'
export class TransactionTools {
constructor(private guardEngine: GuardEngine) {}
async handleTool(name: string, args: any): Promise<McpResponse | X402PaymentRequired> {
switch (name) {
case 'tx.simulate':
return await this.simulate(args as TxSimulateRequest)
case 'tx.execute':
return await this.execute(args as TxExecuteRequest)
default:
throw new Error(`Unknown transaction tool: ${name}`)
}
}
private async simulate(request: TxSimulateRequest): Promise<McpResponse<TxSimulateResponse>> {
try {
// Simulate the transaction
const simulation = await this.performSimulation(request)
// Check guardrails
const guardResult = this.guardEngine.validateSimulation(simulation, request.txParams || {})
// Update simulation with guard results
simulation.guardsTriggered = guardResult.triggeredGuards
// If guards failed, return error
if (!guardResult.passed) {
return {
success: false,
error: {
code: 'GUARD_VIOLATION',
message: `Simulation blocked by guards: ${guardResult.triggeredGuards.join(', ')}`,
details: {
triggeredGuards: guardResult.triggeredGuards,
warnings: guardResult.warnings
}
},
metadata: {
timestamp: new Date().toISOString()
}
}
}
return {
success: true,
data: simulation,
metadata: {
timestamp: new Date().toISOString(),
requestId: `simulate_${Date.now()}`
}
}
} catch (error) {
return {
success: false,
error: {
code: 'SIMULATION_ERROR',
message: error instanceof Error ? error.message : String(error)
},
metadata: {
timestamp: new Date().toISOString()
}
}
}
}
private async execute(request: TxExecuteRequest): Promise<McpResponse<TxExecuteResponse> | X402PaymentRequired> {
try {
// Check guardrails first
const guardResult = this.guardEngine.validateExecution(request)
if (!guardResult.passed) {
return {
success: false,
error: {
code: 'GUARD_VIOLATION',
message: `Transaction blocked by guards: ${guardResult.triggeredGuards.join(', ')}`,
details: {
triggeredGuards: guardResult.triggeredGuards,
warnings: guardResult.warnings
}
},
metadata: {
timestamp: new Date().toISOString()
}
}
}
// Check if payment is required (x402)
const requiresPayment = this.shouldRequirePayment(request)
if (requiresPayment && !request.paymentProof) {
// Return HTTP 402 Payment Required
return {
invoiceId: `inv_${Date.now()}`,
amount: '0.50',
asset: 'USDC',
receiver: process.env.X402_RECEIVER || '0x0000000000000000000000000000000000000000',
description: 'Transaction execution fee'
} as X402PaymentRequired
}
// Verify payment proof if provided
if (request.paymentProof) {
const paymentValid = await this.verifyPaymentProof(request.paymentProof)
if (!paymentValid) {
return {
success: false,
error: {
code: 'INVALID_PAYMENT_PROOF',
message: 'Payment proof verification failed'
},
metadata: {
timestamp: new Date().toISOString()
}
}
}
}
// Execute the transaction
const execution = await this.performExecution(request)
return {
success: true,
data: execution,
metadata: {
timestamp: new Date().toISOString(),
requestId: `execute_${Date.now()}`
}
}
} catch (error) {
return {
success: false,
error: {
code: 'EXECUTION_ERROR',
message: error instanceof Error ? error.message : String(error)
},
metadata: {
timestamp: new Date().toISOString()
}
}
}
}
private async performSimulation(request: TxSimulateRequest): Promise<TxSimulateResponse> {
// This would integrate with actual transaction simulation
// For now, return mock data
const baseFee = 0.001 // 0.001 ETH base fee
const gasPrice = 20 // 20 gwei
const gasLimit = 150000 // Standard gas limit
const feeUsd = baseFee * 2000 // Assuming ETH = $2000
const slippagePct = Math.random() * 0.5 // Random slippage between 0-0.5%
return {
ok: true,
est: {
feeUsd,
slippagePct,
avgPrice: 2000 // Mock ETH price
},
guardsTriggered: []
}
}
private async performExecution(request: TxExecuteRequest): Promise<TxExecuteResponse> {
// This would integrate with actual transaction execution
// For now, return mock data
const mockTxHash = `0x${Math.random().toString(16).substring(2, 66)}`
return {
status: 'submitted',
txHash: mockTxHash,
route: 'AURA:uniswap-v3',
notes: 'Transaction submitted successfully'
}
}
private shouldRequirePayment(request: TxExecuteRequest): boolean {
// Determine if payment is required based on transaction value, type, etc.
// For demo purposes, require payment for transactions over $100
const txValue = request.txParams?.value || 0
return txValue > 100
}
private async verifyPaymentProof(paymentProof: any): Promise<boolean> {
// This would verify the payment proof on-chain
// For now, return true for demo purposes
return true
}
}