Initial commit

This commit is contained in:
Test User
2025-11-20 15:35:25 -08:00
commit bfbe3ee8b7
59 changed files with 7187 additions and 0 deletions

23
mev-bot/package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "dbis-mev-bot",
"version": "1.0.0",
"description": "DBIS MEV Bot for protective arbitrage and atomic cycles",
"main": "src/bot.ts",
"scripts": {
"start": "tsx src/bot.ts",
"build": "tsc",
"dev": "tsx watch src/bot.ts"
},
"dependencies": {
"ethers": "^6.9.0",
"dotenv": "^16.3.1",
"@flashbots/ethers-provider-bundle": "^1.0.1",
"winston": "^3.11.0"
},
"devDependencies": {
"@types/node": "^20.10.0",
"tsx": "^4.7.0",
"typescript": "^5.3.3"
}
}

161
mev-bot/src/bot.ts Normal file
View File

@@ -0,0 +1,161 @@
import { ethers } from "ethers";
import * as dotenv from "dotenv";
import { AmortizationStrategy } from "./strategy/amortization";
import { ArbitrageStrategy } from "./strategy/arbitrage";
import { DeleverageStrategy } from "./strategy/deleverage";
import { InvariantChecker } from "./utils/invariant-checker";
import { PositionCalculator } from "./utils/position-calculator";
import { BundleBuilder } from "./utils/bundle-builder";
import { FlashRouterClient } from "./providers/flash-router";
import { AaveClient } from "./providers/aave-client";
import { UniswapClient } from "./providers/uniswap-client";
dotenv.config();
/**
* DBIS MEV Bot
* Monitors positions and executes profitable atomic cycles
*/
export class DBISMEVBot {
private provider: ethers.Provider;
private wallet: ethers.Wallet;
private flashRouterClient: FlashRouterClient;
private aaveClient: AaveClient;
private uniswapClient: UniswapClient;
private invariantChecker: InvariantChecker;
private positionCalculator: PositionCalculator;
private bundleBuilder: BundleBuilder;
private amortizationStrategy: AmortizationStrategy;
private arbitrageStrategy: ArbitrageStrategy;
private deleverageStrategy: DeleverageStrategy;
private running = false;
private pollInterval = 5000; // 5 seconds
constructor(
rpcUrl: string,
privateKey: string,
config: BotConfig
) {
this.provider = new ethers.JsonRpcProvider(rpcUrl);
this.wallet = new ethers.Wallet(privateKey, this.provider);
// Initialize clients
this.flashRouterClient = new FlashRouterClient(config.flashRouterAddress, this.wallet);
this.aaveClient = new AaveClient(config.aavePoolAddress, this.provider);
this.uniswapClient = new UniswapClient(config.uniswapRouterAddress, this.wallet);
// Initialize utilities
this.invariantChecker = new InvariantChecker(config.vaultAddress, this.provider);
this.positionCalculator = new PositionCalculator(config.vaultAddress, this.aaveClient, this.provider);
this.bundleBuilder = new BundleBuilder(this.provider);
// Initialize strategies
this.amortizationStrategy = new AmortizationStrategy(
this.flashRouterClient,
this.positionCalculator,
this.invariantChecker
);
this.arbitrageStrategy = new ArbitrageStrategy(
this.uniswapClient,
this.positionCalculator
);
this.deleverageStrategy = new DeleverageStrategy(
this.positionCalculator,
this.invariantChecker
);
}
/**
* Start the bot
*/
async start(): Promise<void> {
this.running = true;
console.log("🚀 DBIS MEV Bot started");
while (this.running) {
try {
await this.tick();
} catch (error) {
console.error("Error in bot tick:", error);
}
await this.sleep(this.pollInterval);
}
}
/**
* Stop the bot
*/
stop(): void {
this.running = false;
console.log("🛑 DBIS MEV Bot stopped");
}
/**
* Main bot loop
*/
private async tick(): Promise<void> {
// Check position health
const position = await this.positionCalculator.getPosition();
// Health factor protection
if (position.healthFactor < 1.1e18) {
console.warn("⚠️ Low health factor detected:", position.healthFactor.toString());
await this.deleverageStrategy.executeIfProfitable();
return;
}
// Check for profitable amortization cycles
const amortizationOpportunity = await this.amortizationStrategy.detectOpportunity();
if (amortizationOpportunity.profitable) {
console.log("💰 Amortization opportunity detected");
await this.amortizationStrategy.execute(amortizationOpportunity);
return;
}
// Check for arbitrage opportunities
const arbitrageOpportunity = await this.arbitrageStrategy.detectOpportunity();
if (arbitrageOpportunity.profitable) {
console.log("💎 Arbitrage opportunity detected");
await this.arbitrageStrategy.execute(arbitrageOpportunity);
return;
}
// No opportunities found
console.log("⏳ No opportunities found, waiting...");
}
private sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
interface BotConfig {
flashRouterAddress: string;
vaultAddress: string;
aavePoolAddress: string;
uniswapRouterAddress: string;
}
// Main entry point
if (require.main === module) {
const rpcUrl = process.env.RPC_URL || "";
const privateKey = process.env.PRIVATE_KEY || "";
const config: BotConfig = {
flashRouterAddress: process.env.FLASH_ROUTER_ADDRESS || "",
vaultAddress: process.env.VAULT_ADDRESS || "",
aavePoolAddress: process.env.AAVE_POOL_ADDRESS || "",
uniswapRouterAddress: process.env.UNISWAP_ROUTER_ADDRESS || ""
};
if (!rpcUrl || !privateKey) {
console.error("Missing required environment variables");
process.exit(1);
}
const bot = new DBISMEVBot(rpcUrl, privateKey, config);
bot.start().catch(console.error);
}

View File

@@ -0,0 +1,28 @@
import { ethers } from "ethers";
/**
* Aave Client
* Interacts with Aave v3 Pool
*/
export class AaveClient {
private poolInterface: ethers.Interface;
constructor(
private poolAddress: string,
private provider: ethers.Provider
) {
this.poolInterface = new ethers.Interface([
"function getUserAccountData(address user) view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)"
]);
}
/**
* Get user account data
*/
async getUserAccountData(userAddress: string): Promise<any> {
const data = this.poolInterface.encodeFunctionData("getUserAccountData", [userAddress]);
const result = await this.provider.call({ to: this.poolAddress, data });
return this.poolInterface.decodeFunctionResult("getUserAccountData", result);
}
}

View File

@@ -0,0 +1,30 @@
import { ethers } from "ethers";
/**
* Flash Router Client
* Interacts with FlashLoanRouter contract
*/
export class FlashRouterClient {
private routerInterface: ethers.Interface;
constructor(
private routerAddress: string,
private wallet: ethers.Wallet
) {
this.routerInterface = new ethers.Interface([
"function flashLoan((address asset, uint256 amount, uint8 provider) params, bytes callbackData)",
"function getFlashLoanFee(address asset, uint256 amount, uint8 provider) view returns (uint256)"
]);
}
/**
* Get flash loan fee
*/
async getFlashLoanFee(asset: string, amount: bigint, provider: number): Promise<bigint> {
const data = this.routerInterface.encodeFunctionData("getFlashLoanFee", [asset, amount, provider]);
const result = await this.wallet.provider.call({ to: this.routerAddress, data });
const decoded = this.routerInterface.decodeFunctionResult("getFlashLoanFee", result);
return decoded[0] as bigint;
}
}

View File

@@ -0,0 +1,21 @@
import { ethers } from "ethers";
/**
* Uniswap Client
* Interacts with Uniswap V3 Router
*/
export class UniswapClient {
constructor(
private routerAddress: string,
private wallet: ethers.Wallet
) {}
/**
* Get quote for swap
*/
async getQuote(tokenIn: string, tokenOut: string, amountIn: bigint): Promise<bigint> {
// Would query Uniswap router for quote
return 0n;
}
}

View File

@@ -0,0 +1,82 @@
import { ethers } from "ethers";
import { FlashRouterClient } from "../providers/flash-router";
import { PositionCalculator } from "../utils/position-calculator";
import { InvariantChecker } from "../utils/invariant-checker";
/**
* Amortization Strategy
* Detects and executes profitable amortization cycles
*/
export class AmortizationStrategy {
constructor(
private flashRouterClient: FlashRouterClient,
private positionCalculator: PositionCalculator,
private invariantChecker: InvariantChecker
) {}
/**
* Detect amortization opportunity
*/
async detectOpportunity(): Promise<AmortizationOpportunity> {
const position = await this.positionCalculator.getPosition();
// Calculate if amortization would be profitable
const estimatedGasCost = ethers.parseEther("0.01"); // Simplified
const estimatedImprovement = await this.estimateImprovement(position);
const profitable = estimatedImprovement.value > estimatedGasCost * 2n; // 2x gas as buffer
return {
profitable,
targetAsset: "0x0000000000000000000000000000000000000000", // Would determine optimal asset
maxLoops: 5,
estimatedImprovement
};
}
/**
* Execute amortization cycle
*/
async execute(opportunity: AmortizationOpportunity): Promise<void> {
// Verify invariants before execution
const valid = await this.invariantChecker.verifyBeforeExecution();
if (!valid) {
throw new Error("Invariants would be violated");
}
// Build transaction
const kernelAddress = process.env.KERNEL_ADDRESS || "";
const kernelInterface = new ethers.Interface([
"function executeAmortizingCycle((address targetAsset, uint256 maxLoops, uint256 minHFImprovement) params) returns (bool success, uint256 cyclesExecuted)"
]);
const params = {
targetAsset: opportunity.targetAsset,
maxLoops: opportunity.maxLoops,
minHFImprovement: ethers.parseEther("0.01") // 1% minimum improvement
};
const data = kernelInterface.encodeFunctionData("executeAmortizingCycle", [params]);
// Send transaction
// Would use Flashbots bundle in production
console.log("Executing amortization cycle...");
}
/**
* Estimate improvement from amortization
*/
private async estimateImprovement(position: any): Promise<{ value: bigint }> {
// Simplified calculation
// Would use simulation to estimate improvement
return { value: ethers.parseEther("0.1") };
}
}
interface AmortizationOpportunity {
profitable: boolean;
targetAsset: string;
maxLoops: number;
estimatedImprovement: { value: bigint };
}

View File

@@ -0,0 +1,43 @@
import { ethers } from "ethers";
import { UniswapClient } from "../providers/uniswap-client";
import { PositionCalculator } from "../utils/position-calculator";
/**
* Arbitrage Strategy
* Detects and executes arbitrage opportunities
*/
export class ArbitrageStrategy {
constructor(
private uniswapClient: UniswapClient,
private positionCalculator: PositionCalculator
) {}
/**
* Detect arbitrage opportunity
*/
async detectOpportunity(): Promise<ArbitrageOpportunity> {
// Simplified: would compare prices across DEXs
return {
profitable: false,
path: [],
amountIn: 0n,
expectedProfit: 0n
};
}
/**
* Execute arbitrage
*/
async execute(opportunity: ArbitrageOpportunity): Promise<void> {
// Execute arbitrage trade
console.log("Executing arbitrage...");
}
}
interface ArbitrageOpportunity {
profitable: boolean;
path: string[];
amountIn: bigint;
expectedProfit: bigint;
}

View File

@@ -0,0 +1,26 @@
import { PositionCalculator } from "../utils/position-calculator";
import { InvariantChecker } from "../utils/invariant-checker";
/**
* Deleverage Strategy
* Protects position by reducing leverage when HF is low
*/
export class DeleverageStrategy {
constructor(
private positionCalculator: PositionCalculator,
private invariantChecker: InvariantChecker
) {}
/**
* Execute deleverage if profitable/necessary
*/
async executeIfProfitable(): Promise<void> {
const position = await this.positionCalculator.getPosition();
if (position.healthFactor < 1.1e18) {
console.log("Executing deleverage...");
// Would execute deleverage transaction
}
}
}

View File

@@ -0,0 +1,26 @@
import { ethers } from "ethers";
/**
* Bundle Builder
* Builds Flashbots bundles for private transaction submission
*/
export class BundleBuilder {
constructor(private provider: ethers.Provider) {}
/**
* Build a Flashbots bundle
*/
async buildBundle(transactions: ethers.TransactionRequest[]): Promise<Bundle> {
// Would build Flashbots bundle
return {
transactions,
blockNumber: 0
};
}
}
interface Bundle {
transactions: ethers.TransactionRequest[];
blockNumber: number;
}

View File

@@ -0,0 +1,75 @@
import { ethers } from "ethers";
/**
* Invariant Checker
* Verifies position invariants before execution
*/
export class InvariantChecker {
private vaultInterface: ethers.Interface;
constructor(
private vaultAddress: string,
private provider: ethers.Provider
) {
this.vaultInterface = new ethers.Interface([
"function verifyPositionImproved(uint256 collateralBefore, uint256 debtBefore, uint256 healthFactorBefore) view returns (bool success)"
]);
}
/**
* Verify invariants before execution
*/
async verifyBeforeExecution(): Promise<boolean> {
// Take snapshot
const snapshot = await this.takeSnapshot();
// Verify position would improve
try {
const data = this.vaultInterface.encodeFunctionData("verifyPositionImproved", [
snapshot.collateral,
snapshot.debt,
snapshot.healthFactor
]);
const result = await this.provider.call({
to: this.vaultAddress,
data
});
const decoded = this.vaultInterface.decodeFunctionResult("verifyPositionImproved", result);
return decoded[0] as boolean;
} catch {
return false;
}
}
/**
* Take position snapshot
*/
private async takeSnapshot(): Promise<PositionSnapshot> {
const vaultInterface = new ethers.Interface([
"function snapshotPosition() returns (uint256 collateralBefore, uint256 debtBefore, uint256 healthFactorBefore)"
]);
const data = vaultInterface.encodeFunctionData("snapshotPosition");
const result = await this.provider.call({
to: this.vaultAddress,
data
});
const decoded = vaultInterface.decodeFunctionResult("snapshotPosition", result);
return {
collateral: decoded[0] as bigint,
debt: decoded[1] as bigint,
healthFactor: decoded[2] as bigint
};
}
}
interface PositionSnapshot {
collateral: bigint;
debt: bigint;
healthFactor: bigint;
}

View File

@@ -0,0 +1,78 @@
import { ethers } from "ethers";
import { AaveClient } from "../providers/aave-client";
/**
* Position Calculator
* Calculates current position metrics
*/
export class PositionCalculator {
private vaultInterface: ethers.Interface;
constructor(
private vaultAddress: string,
private aaveClient: AaveClient,
private provider: ethers.Provider
) {
this.vaultInterface = new ethers.Interface([
"function getTotalCollateralValue() view returns (uint256)",
"function getTotalDebtValue() view returns (uint256)",
"function getHealthFactor() view returns (uint256)",
"function getLTV() view returns (uint256)"
]);
}
/**
* Get current position
*/
async getPosition(): Promise<Position> {
const [collateral, debt, healthFactor, ltv] = await Promise.all([
this.getTotalCollateralValue(),
this.getTotalDebtValue(),
this.getHealthFactor(),
this.getLTV()
]);
return {
collateral,
debt,
healthFactor,
ltv
};
}
private async getTotalCollateralValue(): Promise<bigint> {
const data = this.vaultInterface.encodeFunctionData("getTotalCollateralValue");
const result = await this.provider.call({ to: this.vaultAddress, data });
const decoded = this.vaultInterface.decodeFunctionResult("getTotalCollateralValue", result);
return decoded[0] as bigint;
}
private async getTotalDebtValue(): Promise<bigint> {
const data = this.vaultInterface.encodeFunctionData("getTotalDebtValue");
const result = await this.provider.call({ to: this.vaultAddress, data });
const decoded = this.vaultInterface.decodeFunctionResult("getTotalDebtValue", result);
return decoded[0] as bigint;
}
private async getHealthFactor(): Promise<bigint> {
const data = this.vaultInterface.encodeFunctionData("getHealthFactor");
const result = await this.provider.call({ to: this.vaultAddress, data });
const decoded = this.vaultInterface.decodeFunctionResult("getHealthFactor", result);
return decoded[0] as bigint;
}
private async getLTV(): Promise<bigint> {
const data = this.vaultInterface.encodeFunctionData("getLTV");
const result = await this.provider.call({ to: this.vaultAddress, data });
const decoded = this.vaultInterface.decodeFunctionResult("getLTV", result);
return decoded[0] as bigint;
}
}
interface Position {
collateral: bigint;
debt: bigint;
healthFactor: bigint;
ltv: bigint;
}

9
mev-bot/tsconfig.json Normal file
View File

@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}