[Phase 4] External Simulation API Integration (Optional Enhancement)
- Dominant language
- JavaScript
- Stars
- 2
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
## Overview
Integrate external transaction simulation APIs for enhanced threat detection and more detailed transaction analysis. This phase is optional but recommended for production-grade security.
## Parent Issue
#140 - Implement Transaction Simulation for Enhanced Wallet Security
## Dependencies
- Requires #141 (Phase 1: Basic On-Chain Simulation)
- Can be done in parallel with #142 and #143
## Background
While on-chain simulation (Phase 1) provides basic functionality, external simulation APIs offer:
- More detailed execution traces
- ML-based threat detection
- Pre-built scam databases
- Better error messages and debugging
- State diff visualization
## Simulation API Comparison
| Provider | Strengths | Pricing | Best For |
|----------|-----------|---------|----------|
| **Tenderly** | Full traces, state diffs, debugging | Free tier available | Development & debugging |
| **Blowfish** | Security-focused, phishing detection | API key required | Security-first wallets |
| **Blockaid** | ML-based, real-time threat intel | Enterprise | Large-scale protection |
| **Alchemy** | Simple API, good infra | Free tier | Quick integration |
## Recommended: Tenderly Integration
Tenderly is recommended for MVP due to:
- Generous free tier (5,000 simulations/month)
- Excellent documentation
- Full execution trace with state diffs
- JavaScript SDK available
### Tenderly SDK Integration
```javascript
// frontend/src/lib/tenderlySimulator.js
import { Tenderly, Network } from '@tenderly/sdk'
const tenderly = new Tenderly({
accessKey: process.env.TENDERLY_ACCESS_KEY,
accountName: process.env.TENDERLY_ACCOUNT,
projectName: process.env.TENDERLY_PROJECT,
network: Network.SEPOLIA, // or MAINNET
})
/**
* Simulate transaction using Tenderly
*/
export async function simulateWithTenderly(transaction) {
const simulation = await tenderly.simulator.simulateTransaction({
transaction: {
from: transaction.from,
to: transaction.to,
input: transaction.data,
value: transaction.value,
gas: transaction.gas,
gas_price: transaction.gasPrice,
},
blockNumber: 'latest',
})
return {
success: simulation.simulation.status,
gasUsed: simulation.simulation.gas_used,
logs: simulation.simulation.logs,
trace: simulation.simulation.trace,
stateDiff: simulation.simulation.state_diff,
error: simulation.simulation.error_message,
}
}
/**
* Simulate UserOperation bundle
*/
export async function simulateUserOpWithTenderly(userOp, entryPointAddress) {
// Encode the handleOps call
const handleOpsCalldata = encodeHandleOps([userOp], beneficiary)
const simulation = await tenderly.simulator.simulateTransaction({
transaction: {
from: bundlerAddress, // Simulated bundler
to: entryPointAddress,
input: handleOpsCalldata,
value: '0x0',
gas: 10000000,
},
blockNumber: 'latest',
})
return parseUserOpSimulation(simulation)
}
```
### Parse Tenderly State Diffs
```javascript
/**
* Parse Tenderly state diff into balance changes
*/
function parseStateDiff(stateDiff, accountAddress) {
const balanceChanges = []
for (const [address, changes] of Object.entries(stateDiff)) {
// ETH balance change
if (changes.balance) {
balanceChanges.push({
token: 'ETH',
before: changes.balance.before,
after: changes.balance.after,
})
}
// ERC20 balance changes (storage slot parsing)
if (changes.storage) {
for (const [slot, value] of Object.entries(changes.storage)) {
const tokenChange = parseERC20StorageChange(address, slot, value, accountAddress)
if (tokenChange) {
balanceChanges.push(tokenChange)
}
}
}
}
return balanceChanges
}
```
## Alternative: Blowfish Integration
Blowfish specializes in security and provides:
- Pre-built phishing detection
- Scam token database
- Human-readable transaction summaries
```javascript
// frontend/src/lib/blowfishSimulator.js
const BLOWFISH_API = 'https://api.blowfish.xyz'
export async function scanWithBlowfish(transaction, userAddress) {
const response = await fetch(`${BLOWFISH_API}/ethereum/v0/mainnet/scan/transactions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': process.env.BLOWFISH_API_KEY,
},
body: JSON.stringify({
userAccount: userAddress,
metadata: { origin: 'https://ethaura.app' },
txObjects: [transaction],
}),
})
const result = await response.json()
return {
action: result.action, // 'BLOCK', 'WARN', 'NONE'
warnings: result.warnings,
simulationResults: result.simulationResults,
humanReadable: result.aggregated?.humanReadableDiff,
}
}
```
## Architecture: Hybrid Approach
Use a hybrid approach with fallback:
```javascript
// frontend/src/lib/transactionSimulator.js
/**
* Simulate transaction with fallback strategy
* 1. Try external API (Tenderly/Blowfish)
* 2. Fall back to on-chain simulation if API fails
*/
export async function simulateTransaction(userOp, options = {}) {
const { useExternalAPI = true, provider, entryPointAddress } = options
if (useExternalAPI) {
try {
// Try Tenderly first
const result = await simulateWithTenderly(userOp)
return { ...result, source: 'tenderly' }
} catch (error) {
console.warn('Tenderly simulation failed, falling back to on-chain:', error)
}
}
// Fallback to on-chain simulation
const result = await simulateUserOperation(userOp, provider, entryPointAddress)
return { ...result, source: 'onchain' }
}
```
## Tasks
### Tenderly Integration
- [ ] Set up Tenderly account and project
- [ ] Add Tenderly SDK dependency
- [ ] Create `frontend/src/lib/tenderlySimulator.js`
- [ ] Implement `simulateWithTenderly()` for regular transactions
- [ ] Implement `simulateUserOpWithTenderly()` for UserOperations
- [ ] Parse state diffs into balance changes
- [ ] Handle Tenderly API errors gracefully
- [ ] Add rate limiting and caching
### Blowfish Integration (Optional)
- [ ] Set up Blowfish API access
- [ ] Create `frontend/src/lib/blowfishSimulator.js`
- [ ] Implement `scanWithBlowfish()` for security scanning
- [ ] Parse Blowfish warnings into our warning format
- [ ] Display human-readable transaction summaries
### Hybrid Architecture
- [ ] Implement fallback strategy (API → on-chain)
- [ ] Add configuration for simulation provider preference
- [ ] Handle network-specific API availability
- [ ] Add simulation source indicator in UI
### Configuration & Environment
- [ ] Add environment variables for API keys:
```
TENDERLY_ACCESS_KEY=
TENDERLY_ACCOUNT=
TENDERLY_PROJECT=
BLOWFISH_API_KEY=
```
- [ ] Document API key setup in README
- [ ] Add fallback toggle in settings
### Caching & Performance
- [ ] Cache simulation results (short TTL: 30s)
- [ ] Deduplicate identical simulation requests
- [ ] Add request timeout handling
- [ ] Implement retry logic for transient failures
## Files to Create
1. **`frontend/src/lib/tenderlySimulator.js`** - Tenderly integration
2. **`frontend/src/lib/blowfishSimulator.js`** - Blowfish integration (optional)
3. **`frontend/src/lib/simulationCache.js`** - Caching layer
## Files to Modify
1. **`frontend/src/lib/transactionSimulator.js`** - Add external API fallback
2. **`frontend/.env.example`** - Add API key variables
3. **`frontend/src/components/SimulationStatus.jsx`** - Show simulation source
## Acceptance Criteria
- [ ] Tenderly simulation works for regular transactions
- [ ] Tenderly simulation works for UserOperations
- [ ] State diffs are parsed into balance changes
- [ ] Fallback to on-chain simulation works when API fails
- [ ] API errors don't block transaction flow
- [ ] Simulation results are cached appropriately
- [ ] API keys are properly secured (not exposed to client)
## Testing
- [ ] Test Tenderly simulation on Sepolia
- [ ] Test fallback when Tenderly is unavailable
- [ ] Test caching behavior
- [ ] Test rate limiting handling
- [ ] Compare results between Tenderly and on-chain simulation
## Security Considerations
### API Key Security
**Option 1: Backend Proxy (Recommended)**
```javascript
// Don't expose API keys to frontend
// Create a backend endpoint to proxy simulation requests
app.post('/api/simulate', async (req, res) => {
const result = await tenderly.simulator.simulateTransaction(req.body)
res.json(result)
})
```
**Option 2: Serverless Function**
```javascript
// Use Vercel/Netlify serverless function
// frontend/api/simulate.js
export default async function handler(req, res) {
// API key is in server environment, not exposed
const tenderly = new Tenderly({ accessKey: process.env.TENDERLY_KEY })
// ...
}
```
### Rate Limiting
- Implement client-side rate limiting
- Queue requests to avoid hitting API limits
- Show warning if approaching limits
## Cost Estimation
| Provider | Free Tier | Paid |
|----------|-----------|------|
| Tenderly | 5,000 sims/month | $0.01/sim |
| Blowfish | Contact sales | Enterprise |
| Alchemy | 10,000 sims/month | Pay as you go |
For MVP, Tenderly's free tier should be sufficient.
## Estimated Effort
**Medium** - 2-3 days for Tenderly integration
**High** - 4-5 days for full hybrid approach with Blowfish
## Priority
**Medium** - This is an enhancement phase. The core simulation (Phase 1-3) provides sufficient security for MVP.
## Labels
`security`, `enhancement`, `frontend`, `integration`
Contributor guide
Assessment
This issue has not been assessed yet.