Additional documentation and testing infrastructure: ## Documentation Added - PROFIT_ROADMAP.md - 4-week profitability roadmap - PRODUCTION_DEPLOYMENT.md - Production deployment guide - docs/FLASH_LOAN_DEPLOYMENT_GUIDE.md - Flash loan implementation - docs/FLASH_LOAN_IMPLEMENTATION_SUMMARY.md - Flash loan summary - docs/BINDING_CONSISTENCY_GUIDE.md - Contract binding guidelines - docs/BINDING_QUICK_START.md - Quick start for bindings - docs/COMPLETE_FORK_TESTING_GUIDE.md - Fork testing guide ## Testing Scripts Added - scripts/generate-test-report.sh - Generate test reports - scripts/monitor-24h-test.sh - 24-hour monitoring - scripts/start-24h-test.sh - Start long-running tests - scripts/stop-24h-test.sh - Stop test runs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
574 lines
15 KiB
Markdown
574 lines
15 KiB
Markdown
# Flash Loan Execution - Deployment & Integration Guide
|
|
|
|
**Status:** Framework Complete, Contracts Ready for Deployment
|
|
|
|
**Last Updated:** October 26, 2025
|
|
|
|
---
|
|
|
|
## 📋 Overview
|
|
|
|
This guide covers the deployment and integration of the MEV bot's flash loan execution system, which enables real arbitrage execution using flash loans from multiple providers.
|
|
|
|
### Architecture Summary
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ MEV Bot Go Process │
|
|
│ │
|
|
│ ┌────────────────┐ ┌──────────────────┐ │
|
|
│ │ Arbitrage │────────▶│ Flash Loan │ │
|
|
│ │ Detector │ │ Provider │ │
|
|
│ └────────────────┘ └────────┬─────────┘ │
|
|
│ │ │
|
|
└──────────────────────────────────────┼───────────────────────┘
|
|
│ RPC Call
|
|
▼
|
|
┌──────────────────────────────────┐
|
|
│ FlashLoanReceiver Contract │
|
|
│ (Deployed on Arbitrum) │
|
|
└────────┬─────────────────────────┘
|
|
│
|
|
┌───────────────────┼──────────────────────┐
|
|
│ │ │
|
|
▼ ▼ ▼
|
|
┌─────────────┐ ┌──────────────┐ ┌──────────────────┐
|
|
│ Balancer │ │ Uniswap V2 │ │ Uniswap V3 │
|
|
│ Vault │ │ Router │ │ Router │
|
|
│ (0% fee) │ │ (0.3% fee) │ │ (0.05%-1% fee) │
|
|
└─────────────┘ └──────────────┘ └──────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Implementation Status
|
|
|
|
### ✅ Complete
|
|
|
|
1. **Solidity Smart Contract**
|
|
- Location: `contracts/balancer/FlashLoanReceiver.sol`
|
|
- Features:
|
|
- Balancer flash loan integration
|
|
- Uniswap V2/V3 swap execution
|
|
- Profit calculation and validation
|
|
- Owner-only access control
|
|
- Emergency withdrawal
|
|
|
|
2. **Go Execution Framework**
|
|
- Location: `pkg/execution/`
|
|
- Files:
|
|
- `executor.go` - Core execution engine (316 lines)
|
|
- `flashloan_providers.go` - Provider implementations (360+ lines)
|
|
- `alerts.go` - Alert system (291 lines)
|
|
|
|
3. **ABI Bindings**
|
|
- Location: `bindings/balancer/vault.go`
|
|
- Generated with abigen for Balancer Vault
|
|
|
|
4. **Calldata Encoding**
|
|
- Function: `encodeArbitragePath()` in flashloan_providers.go
|
|
- Encodes ArbitragePath struct for contract
|
|
|
|
### ⏳ Pending
|
|
|
|
1. **Smart Contract Deployment**
|
|
- Deploy FlashLoanReceiver.sol to Arbitrum
|
|
- Set receiver address in BalancerFlashLoanProvider
|
|
- Fund contract with gas if needed
|
|
|
|
2. **Transaction Signing**
|
|
- Implement private key management
|
|
- Add transaction signer
|
|
- Gas estimation logic
|
|
|
|
3. **ABI Encoding/Decoding**
|
|
- Complete ABI encoding for ArbitragePath struct
|
|
- Parse execution results from contract events
|
|
|
|
4. **Integration Testing**
|
|
- Test on Arbitrum testnet
|
|
- Fork testing with Tenderly/Hardhat
|
|
- Mainnet dry-run testing
|
|
|
|
---
|
|
|
|
## 🚀 Deployment Steps
|
|
|
|
### Prerequisites
|
|
|
|
```bash
|
|
# Install dependencies
|
|
npm install --save-dev hardhat @nomiclabs/hardhat-ethers ethers
|
|
npm install @openzeppelin/contracts
|
|
|
|
# Or use Foundry (recommended for production)
|
|
curl -L https://foundry.paradigm.xyz | bash
|
|
foundryup
|
|
```
|
|
|
|
### Step 1: Compile Contract
|
|
|
|
**Using Hardhat:**
|
|
```bash
|
|
npx hardhat compile contracts/balancer/FlashLoanReceiver.sol
|
|
```
|
|
|
|
**Using Foundry:**
|
|
```bash
|
|
forge build contracts/balancer/FlashLoanReceiver.sol
|
|
```
|
|
|
|
### Step 2: Deploy to Arbitrum
|
|
|
|
**Deployment Script (Hardhat):**
|
|
|
|
```javascript
|
|
// scripts/deploy-flash-receiver.js
|
|
const hre = require("hardhat");
|
|
|
|
async function main() {
|
|
const BALANCER_VAULT = "0xBA12222222228d8Ba445958a75a0704d566BF2C8";
|
|
|
|
console.log("Deploying FlashLoanReceiver...");
|
|
|
|
const FlashLoanReceiver = await hre.ethers.getContractFactory("FlashLoanReceiver");
|
|
const receiver = await FlashLoanReceiver.deploy(BALANCER_VAULT);
|
|
|
|
await receiver.deployed();
|
|
|
|
console.log("✅ FlashLoanReceiver deployed to:", receiver.address);
|
|
console.log(" Owner:", await receiver.owner());
|
|
console.log(" Vault:", await receiver.vault());
|
|
|
|
// Save deployment info
|
|
const fs = require("fs");
|
|
fs.writeFileSync("deployment.json", JSON.stringify({
|
|
address: receiver.address,
|
|
owner: await receiver.owner(),
|
|
vault: BALANCER_VAULT,
|
|
timestamp: new Date().toISOString()
|
|
}, null, 2));
|
|
}
|
|
|
|
main()
|
|
.then(() => process.exit(0))
|
|
.catch((error) => {
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|
|
```
|
|
|
|
**Deploy:**
|
|
```bash
|
|
npx hardhat run scripts/deploy-flash-receiver.js --network arbitrum
|
|
```
|
|
|
|
**Using Foundry:**
|
|
```bash
|
|
forge create contracts/balancer/FlashLoanReceiver.sol:FlashLoanReceiver \
|
|
--rpc-url $ARBITRUM_RPC \
|
|
--private-key $PRIVATE_KEY \
|
|
--constructor-args 0xBA12222222228d8Ba445958a75a0704d566BF2C8 \
|
|
--verify
|
|
```
|
|
|
|
### Step 3: Configure MEV Bot
|
|
|
|
After deployment, update the Go code with the deployed contract address:
|
|
|
|
```go
|
|
// pkg/execution/flashloan_providers.go
|
|
|
|
func NewBalancerFlashLoanProvider(client *ethclient.Client, logger *logger.Logger) *BalancerFlashLoanProvider {
|
|
return &BalancerFlashLoanProvider{
|
|
client: client,
|
|
logger: logger,
|
|
vaultAddress: common.HexToAddress("0xBA12222222228d8Ba445958a75a0704d566BF2C8"),
|
|
// UPDATE THIS with deployed contract address:
|
|
receiverAddress: common.HexToAddress("0xYOUR_DEPLOYED_CONTRACT_ADDRESS"),
|
|
}
|
|
}
|
|
```
|
|
|
|
Or use environment variable:
|
|
```bash
|
|
export FLASH_LOAN_RECEIVER="0xYOUR_DEPLOYED_CONTRACT_ADDRESS"
|
|
```
|
|
|
|
### Step 4: Generate Contract Bindings
|
|
|
|
Generate Go bindings for the deployed contract:
|
|
|
|
```bash
|
|
# Get contract ABI
|
|
cat contracts/balancer/FlashLoanReceiver.sol | \
|
|
solc --abi - > contracts/balancer/FlashLoanReceiver.abi
|
|
|
|
# Generate Go bindings
|
|
abigen --abi contracts/balancer/FlashLoanReceiver.abi \
|
|
--pkg execution \
|
|
--type FlashLoanReceiver \
|
|
--out pkg/execution/flashloan_receiver.go
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 Integration Implementation
|
|
|
|
### Complete the TODO Items
|
|
|
|
**1. Transaction Signing (`pkg/execution/transaction_signer.go` - NEW FILE)**
|
|
|
|
```go
|
|
package execution
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ecdsa"
|
|
"math/big"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
|
)
|
|
|
|
type TransactionSigner struct {
|
|
privateKey *ecdsa.PrivateKey
|
|
chainID *big.Int
|
|
client *ethclient.Client
|
|
}
|
|
|
|
func NewTransactionSigner(privateKeyHex string, client *ethclient.Client) (*TransactionSigner, error) {
|
|
privateKey, err := crypto.HexToECDSA(privateKeyHex)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
chainID, err := client.ChainID(context.Background())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &TransactionSigner{
|
|
privateKey: privateKey,
|
|
chainID: chainID,
|
|
client: client,
|
|
}, nil
|
|
}
|
|
|
|
func (ts *TransactionSigner) SignAndSend(ctx context.Context, tx *types.Transaction) (common.Hash, error) {
|
|
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(ts.chainID), ts.privateKey)
|
|
if err != nil {
|
|
return common.Hash{}, err
|
|
}
|
|
|
|
err = ts.client.SendTransaction(ctx, signedTx)
|
|
if err != nil {
|
|
return common.Hash{}, err
|
|
}
|
|
|
|
return signedTx.Hash(), nil
|
|
}
|
|
|
|
func (ts *TransactionSigner) GetTransactor() (*bind.TransactOpts, error) {
|
|
auth, err := bind.NewKeyedTransactorWithChainID(ts.privateKey, ts.chainID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return auth, nil
|
|
}
|
|
```
|
|
|
|
**2. Complete ABI Encoding**
|
|
|
|
Update `encodeArbitragePath()` to use proper ABI encoding:
|
|
|
|
```go
|
|
import (
|
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
"strings"
|
|
)
|
|
|
|
func (b *BalancerFlashLoanProvider) encodeArbitragePath(
|
|
opportunity *arbitrage.ArbitragePath,
|
|
config *ExecutionConfig,
|
|
) ([]byte, error) {
|
|
// Define ABI for ArbitragePath struct
|
|
arbitragePathABI := `[{
|
|
"components": [
|
|
{"name": "tokens", "type": "address[]"},
|
|
{"name": "exchanges", "type": "address[]"},
|
|
{"name": "fees", "type": "uint24[]"},
|
|
{"name": "isV3", "type": "bool[]"},
|
|
{"name": "minProfit", "type": "uint256"}
|
|
],
|
|
"name": "path",
|
|
"type": "tuple"
|
|
}]`
|
|
|
|
contractABI, err := abi.JSON(strings.NewReader(arbitragePathABI))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Prepare data (same as before)
|
|
numHops := len(opportunity.TokenPath) - 1
|
|
exchanges := make([]common.Address, numHops)
|
|
fees := make([]*big.Int, numHops)
|
|
isV3 := make([]bool, numHops)
|
|
|
|
// ... (populate arrays) ...
|
|
|
|
// Encode using ABI
|
|
encoded, err := contractABI.Pack("path",
|
|
opportunity.TokenPath,
|
|
exchanges,
|
|
fees,
|
|
isV3,
|
|
minProfit,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return encoded, nil
|
|
}
|
|
```
|
|
|
|
**3. Complete ExecuteFlashLoan**
|
|
|
|
```go
|
|
func (b *BalancerFlashLoanProvider) ExecuteFlashLoan(
|
|
ctx context.Context,
|
|
opportunity *arbitrage.ArbitragePath,
|
|
config *ExecutionConfig,
|
|
) (*ExecutionResult, error) {
|
|
startTime := time.Now()
|
|
|
|
// ... (validation and encoding as before) ...
|
|
|
|
// Create contract instance
|
|
receiver, err := NewFlashLoanReceiver(b.receiverAddress, b.client)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get transactor
|
|
auth, err := config.Signer.GetTransactor()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set gas price and limit
|
|
auth.GasPrice = config.MaxGasPrice
|
|
auth.GasLimit = 500000 // Estimate based on path length
|
|
|
|
// Call executeArbitrage
|
|
tx, err := receiver.ExecuteArbitrage(auth, tokens, amounts, userData)
|
|
if err != nil {
|
|
return &ExecutionResult{
|
|
OpportunityID: opportunity.ID,
|
|
Success: false,
|
|
Error: err,
|
|
ExecutionTime: time.Since(startTime),
|
|
}, err
|
|
}
|
|
|
|
// Wait for receipt
|
|
receipt, err := bind.WaitMined(ctx, b.client, tx)
|
|
if err != nil {
|
|
return &ExecutionResult{
|
|
OpportunityID: opportunity.ID,
|
|
Success: false,
|
|
TxHash: tx.Hash(),
|
|
Error: err,
|
|
ExecutionTime: time.Since(startTime),
|
|
}, err
|
|
}
|
|
|
|
// Parse events to get actual profit
|
|
var actualProfit *big.Int
|
|
for _, log := range receipt.Logs {
|
|
event, err := receiver.ParseArbitrageExecuted(*log)
|
|
if err == nil {
|
|
actualProfit = event.Profit
|
|
break
|
|
}
|
|
}
|
|
|
|
return &ExecutionResult{
|
|
OpportunityID: opportunity.ID,
|
|
Success: receipt.Status == 1,
|
|
TxHash: tx.Hash(),
|
|
GasUsed: receipt.GasUsed,
|
|
ActualProfit: actualProfit,
|
|
EstimatedProfit: opportunity.NetProfit,
|
|
ExecutionTime: time.Since(startTime),
|
|
Timestamp: time.Now(),
|
|
}, nil
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## ✅ Testing Strategy
|
|
|
|
### 1. Local Fork Testing
|
|
|
|
```bash
|
|
# Start Hardhat node with Arbitrum fork
|
|
npx hardhat node --fork https://arb1.arbitrum.io/rpc
|
|
|
|
# Deploy contract to local fork
|
|
npx hardhat run scripts/deploy-flash-receiver.js --network localhost
|
|
|
|
# Run Go tests against local fork
|
|
export ARBITRUM_RPC_ENDPOINT="http://localhost:8545"
|
|
export FLASH_LOAN_RECEIVER="0x..."
|
|
go test ./pkg/execution/... -v
|
|
```
|
|
|
|
### 2. Arbitrum Testnet
|
|
|
|
```bash
|
|
# Deploy to Arbitrum Sepolia testnet
|
|
npx hardhat run scripts/deploy-flash-receiver.js --network arbitrum-sepolia
|
|
|
|
# Test with testnet RPC
|
|
export ARBITRUM_RPC_ENDPOINT="https://sepolia-rollup.arbitrum.io/rpc"
|
|
./mev-bot start --dry-run
|
|
```
|
|
|
|
### 3. Mainnet Dry-Run
|
|
|
|
```bash
|
|
# Test on mainnet without executing
|
|
export EXECUTION_MODE="simulation"
|
|
./mev-bot start
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Gas Optimization
|
|
|
|
### Estimated Gas Costs
|
|
|
|
| Operation | Gas Estimate | Cost (@ 0.1 gwei) |
|
|
|-----------|-------------|-------------------|
|
|
| Contract deployment | 1,500,000 | 0.00015 ETH |
|
|
| 2-hop arbitrage | 300,000 | 0.00003 ETH |
|
|
| 3-hop arbitrage | 450,000 | 0.000045 ETH |
|
|
| 4-hop arbitrage | 600,000 | 0.00006 ETH |
|
|
|
|
### Optimization Tips
|
|
|
|
1. **Batch token approvals** - Approve max once instead of per transaction
|
|
2. **Use V3 single-hop when possible** - Lower gas than multi-contract calls
|
|
3. **Optimize path length** - 2-hop paths preferred
|
|
4. **Monitor gas prices** - Only execute when gas < threshold
|
|
|
|
---
|
|
|
|
## 🔐 Security Considerations
|
|
|
|
### Smart Contract Security
|
|
|
|
1. **Access Control**
|
|
- Only owner can call `executeArbitrage()`
|
|
- Only Balancer Vault can call `receiveFlashLoan()`
|
|
|
|
2. **Profit Validation**
|
|
- Minimum profit threshold enforced on-chain
|
|
- Prevents unprofitable execution
|
|
|
|
3. **Emergency Functions**
|
|
- `emergencyWithdraw()` for stuck funds
|
|
- `withdrawProfit()` for profit extraction
|
|
|
|
### Operational Security
|
|
|
|
1. **Private Key Management**
|
|
```bash
|
|
# NEVER commit private keys to git
|
|
# Use environment variables or secret managers
|
|
export EXECUTOR_PRIVATE_KEY="0x..."
|
|
|
|
# Or use hardware wallets (Ledger/Trezor)
|
|
# Or use AWS KMS / Google Cloud KMS
|
|
```
|
|
|
|
2. **Gas Price Limits**
|
|
```go
|
|
config := &ExecutionConfig{
|
|
MaxGasPrice: big.NewInt(1000000000), // 1 gwei max
|
|
// ...
|
|
}
|
|
```
|
|
|
|
3. **Slippage Protection**
|
|
- Set `MaxSlippage` appropriately
|
|
- Default 5% is reasonable for volatile markets
|
|
|
|
---
|
|
|
|
## 📈 Monitoring & Alerts
|
|
|
|
### Integration with Alert System
|
|
|
|
```go
|
|
// In main.go or orchestrator
|
|
alertSystem := execution.NewAlertSystem(&execution.AlertConfig{
|
|
EnableConsoleAlerts: true,
|
|
EnableWebhook: true,
|
|
WebhookURL: os.Getenv("SLACK_WEBHOOK"),
|
|
MinProfitForAlert: big.NewInt(1e16), // 0.01 ETH
|
|
MinROIForAlert: 0.05, // 5%
|
|
}, logger)
|
|
|
|
// Send execution alerts
|
|
result, err := executor.ExecuteOpportunity(ctx, opportunity)
|
|
if err == nil {
|
|
alertSystem.SendExecutionAlert(result)
|
|
}
|
|
```
|
|
|
|
### Dashboard Metrics
|
|
|
|
Add to `monitoring/dashboard.sh`:
|
|
```bash
|
|
# Execution metrics
|
|
EXECUTIONS=$(grep -c "Arbitrage executed successfully" "${LATEST_LOG}")
|
|
EXECUTION_PROFIT=$(grep "profit=" "${LATEST_LOG}" | awk '{sum+=$NF} END {print sum}')
|
|
echo " Executions: ${EXECUTIONS}"
|
|
echo " Total Profit: ${EXECUTION_PROFIT} ETH"
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Next Steps
|
|
|
|
1. **Deploy FlashLoanReceiver contract** to Arbitrum
|
|
2. **Implement transaction signing** in Go
|
|
3. **Complete ABI encoding** for ArbitragePath
|
|
4. **Test on Arbitrum testnet**
|
|
5. **Conduct security audit** of smart contract
|
|
6. **Monitor 24-hour test results** before enabling execution
|
|
7. **Start with small amounts** (0.01-0.1 ETH)
|
|
8. **Scale gradually** as confidence builds
|
|
|
|
---
|
|
|
|
## 📚 Reference
|
|
|
|
- **Balancer Vault:** 0xBA12222222228d8Ba445958a75a0704d566BF2C8
|
|
- **Flash Loan Docs:** https://docs.balancer.fi/reference/contracts/flash-loans.html
|
|
- **Arbitrum RPC:** https://docs.arbitrum.io/build-decentralized-apps/reference/node-providers
|
|
- **Go-Ethereum Docs:** https://geth.ethereum.org/docs
|
|
|
|
---
|
|
|
|
*Last Updated: October 26, 2025*
|
|
*Status: Ready for Deployment*
|