Completed clean root directory structure: - Root now contains only: .git, .env, docs/, orig/ - Moved all remaining files and directories to orig/: - Config files (.claude, .dockerignore, .drone.yml, etc.) - All .env variants (except active .env) - Git config (.gitconfig, .github, .gitignore, etc.) - Tool configs (.golangci.yml, .revive.toml, etc.) - Documentation (*.md files, @prompts) - Build files (Dockerfiles, Makefile, go.mod, go.sum) - Docker compose files - All source directories (scripts, tests, tools, etc.) - Runtime directories (logs, monitoring, reports) - Dependency files (node_modules, lib, cache) - Special files (--delete) - Removed empty runtime directories (bin/, data/) V2 structure is now clean: - docs/planning/ - V2 planning documents - orig/ - Complete V1 codebase preserved - .env - Active environment config (not in git) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
514 lines
17 KiB
Go
514 lines
17 KiB
Go
//go:build integration && legacy && forked
|
|
// +build integration,legacy,forked
|
|
|
|
package integration_test
|
|
|
|
import (
|
|
"context"
|
|
"math/big"
|
|
"testing"
|
|
"time"
|
|
|
|
"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/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/fraktal/mev-beta/bindings/arbitrage"
|
|
arbService "github.com/fraktal/mev-beta/pkg/arbitrage"
|
|
"github.com/fraktal/mev-beta/pkg/mev"
|
|
"github.com/fraktal/mev-beta/pkg/oracle"
|
|
"github.com/fraktal/mev-beta/pkg/uniswap"
|
|
)
|
|
|
|
func TestEndToEndProfitValidation(t *testing.T) {
|
|
client, cleanup := setupForkedArbitrum(t)
|
|
defer cleanup()
|
|
|
|
// Deploy arbitrage contract
|
|
privateKey, err := crypto.GenerateKey()
|
|
require.NoError(t, err)
|
|
|
|
auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(42161))
|
|
require.NoError(t, err)
|
|
|
|
contractAddr, tx, contract, err := arbitrage.DeployArbitrageExecutor(
|
|
auth,
|
|
client,
|
|
common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"), // Uniswap V3 Factory
|
|
common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
receipt, err := bind.WaitMined(ctx, client, tx)
|
|
require.NoError(t, err)
|
|
require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status)
|
|
|
|
t.Run("Real Market Arbitrage Opportunity", func(t *testing.T) {
|
|
// Real Arbitrum pool addresses with different fee tiers
|
|
wethUsdcPool05 := common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443") // 0.05%
|
|
wethUsdcPool30 := common.HexToAddress("0x17c14D2c404D167802b16C450d3c99F88F2c4F4d") // 0.3%
|
|
|
|
// Get current prices from both pools
|
|
price1, err := uniswap.GetPoolPrice(client, wethUsdcPool05)
|
|
require.NoError(t, err)
|
|
|
|
price2, err := uniswap.GetPoolPrice(client, wethUsdcPool30)
|
|
require.NoError(t, err)
|
|
|
|
t.Logf("Pool 1 (0.05%%) price: %s", price1.String())
|
|
t.Logf("Pool 2 (0.30%%) price: %s", price2.String())
|
|
|
|
// Calculate price difference
|
|
priceDiff := new(big.Int).Sub(price1, price2)
|
|
if priceDiff.Sign() < 0 {
|
|
priceDiff.Neg(priceDiff)
|
|
}
|
|
|
|
// Calculate percentage difference
|
|
priceDiffPercent := new(big.Int).Div(
|
|
new(big.Int).Mul(priceDiff, big.NewInt(10000)),
|
|
price1,
|
|
)
|
|
|
|
t.Logf("Price difference: %s (%s basis points)", priceDiff.String(), priceDiffPercent.String())
|
|
|
|
// Test arbitrage opportunity detection
|
|
swapAmount := big.NewInt(1000000000000000000) // 1 ETH
|
|
|
|
opportunity, err := contract.DetectArbitrageOpportunity(nil, wethUsdcPool05, wethUsdcPool30, swapAmount)
|
|
require.NoError(t, err)
|
|
|
|
if opportunity.Profitable {
|
|
t.Logf("Arbitrage opportunity detected!")
|
|
t.Logf("Estimated profit: %s ETH", new(big.Float).Quo(
|
|
new(big.Float).SetInt(opportunity.EstimatedProfit),
|
|
new(big.Float).SetInt(big.NewInt(1000000000000000000)),
|
|
).String())
|
|
|
|
// Validate minimum profit threshold
|
|
minProfit := big.NewInt(10000000000000000) // 0.01 ETH minimum
|
|
assert.GreaterOrEqual(t, opportunity.EstimatedProfit.Cmp(minProfit), 0,
|
|
"Profit should meet minimum threshold")
|
|
|
|
// Test gas cost calculation
|
|
gasPrice, err := client.SuggestGasPrice(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
estimatedGas := big.NewInt(300000) // Estimated gas for arbitrage
|
|
gasCost := new(big.Int).Mul(gasPrice, estimatedGas)
|
|
|
|
netProfit := new(big.Int).Sub(opportunity.EstimatedProfit, gasCost)
|
|
t.Logf("Gas cost: %s ETH", new(big.Float).Quo(
|
|
new(big.Float).SetInt(gasCost),
|
|
new(big.Float).SetInt(big.NewInt(1000000000000000000)),
|
|
).String())
|
|
t.Logf("Net profit: %s ETH", new(big.Float).Quo(
|
|
new(big.Float).SetInt(netProfit),
|
|
new(big.Float).SetInt(big.NewInt(1000000000000000000)),
|
|
).String())
|
|
|
|
assert.Greater(t, netProfit.Sign(), 0, "Net profit should be positive after gas costs")
|
|
} else {
|
|
t.Log("No profitable arbitrage opportunity detected in current market conditions")
|
|
}
|
|
})
|
|
|
|
t.Run("Simulate Large Trade Impact", func(t *testing.T) {
|
|
// Simulate a large trade that creates arbitrage opportunity
|
|
wethUsdcPool := common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443")
|
|
|
|
// Large swap amount that should create price impact
|
|
largeSwapAmount := new(big.Int)
|
|
largeSwapAmount.SetString("100000000000000000000", 10) // 100 ETH
|
|
|
|
// Calculate price impact
|
|
priceImpact, err := contract.CalculatePriceImpact(nil, wethUsdcPool, largeSwapAmount, true)
|
|
require.NoError(t, err)
|
|
|
|
t.Logf("Price impact for 100 ETH swap: %s basis points", priceImpact.String())
|
|
|
|
// Price impact should be significant for large trades
|
|
assert.Greater(t, priceImpact.Uint64(), uint64(100), "Large trades should have measurable price impact")
|
|
|
|
// Test if this creates arbitrage opportunities
|
|
if priceImpact.Uint64() > 500 { // More than 5% price impact
|
|
// This should create profitable arbitrage opportunities
|
|
t.Log("Large trade creates significant arbitrage opportunity")
|
|
}
|
|
})
|
|
|
|
t.Run("Multi-Pool Arbitrage Chain", func(t *testing.T) {
|
|
// Test arbitrage opportunities across multiple pools
|
|
pools := []common.Address{
|
|
common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"), // WETH/USDC 0.05%
|
|
common.HexToAddress("0x17c14D2c404D167802b16C450d3c99F88F2c4F4d"), // WETH/USDC 0.3%
|
|
common.HexToAddress("0x641C00A822e8b671738d32a431a4Fb6074E5c79d"), // WETH/USDT 0.05%
|
|
}
|
|
|
|
swapAmount := big.NewInt(5000000000000000000) // 5 ETH
|
|
|
|
totalOpportunities := 0
|
|
totalPotentialProfit := big.NewInt(0)
|
|
|
|
for i := 0; i < len(pools); i++ {
|
|
for j := i + 1; j < len(pools); j++ {
|
|
opportunity, err := contract.DetectArbitrageOpportunity(nil, pools[i], pools[j], swapAmount)
|
|
require.NoError(t, err)
|
|
|
|
if opportunity.Profitable {
|
|
totalOpportunities++
|
|
totalPotentialProfit.Add(totalPotentialProfit, opportunity.EstimatedProfit)
|
|
|
|
t.Logf("Opportunity between pool %d and %d: %s ETH profit",
|
|
i, j, new(big.Float).Quo(
|
|
new(big.Float).SetInt(opportunity.EstimatedProfit),
|
|
new(big.Float).SetInt(big.NewInt(1000000000000000000)),
|
|
).String())
|
|
}
|
|
}
|
|
}
|
|
|
|
t.Logf("Total opportunities found: %d", totalOpportunities)
|
|
t.Logf("Total potential profit: %s ETH", new(big.Float).Quo(
|
|
new(big.Float).SetInt(totalPotentialProfit),
|
|
new(big.Float).SetInt(big.NewInt(1000000000000000000)),
|
|
).String())
|
|
})
|
|
}
|
|
|
|
func TestRealWorldGasOptimization(t *testing.T) {
|
|
client, cleanup := setupForkedArbitrum(t)
|
|
defer cleanup()
|
|
|
|
t.Run("Gas Price Strategy Optimization", func(t *testing.T) {
|
|
// Get current network conditions
|
|
gasPrice, err := client.SuggestGasPrice(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
// Get latest block for base fee (EIP-1559)
|
|
header, err := client.HeaderByNumber(context.Background(), nil)
|
|
require.NoError(t, err)
|
|
|
|
baseFee := header.BaseFee
|
|
t.Logf("Current gas price: %s gwei", new(big.Int).Div(gasPrice, big.NewInt(1000000000)))
|
|
t.Logf("Current base fee: %s gwei", new(big.Int).Div(baseFee, big.NewInt(1000000000)))
|
|
|
|
// Test MEV competition analysis
|
|
analyzer := mev.NewCompetitionAnalyzer(client)
|
|
|
|
opportunity := &mev.MEVOpportunity{
|
|
Type: mev.TypeArbitrage,
|
|
EstimatedProfit: big.NewInt(50000000000000000), // 0.05 ETH
|
|
RequiredGasLimit: big.NewInt(300000),
|
|
PoolAddress: common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"),
|
|
Timestamp: time.Now(),
|
|
}
|
|
|
|
ctx := context.Background()
|
|
competition, err := analyzer.AnalyzeCompetition(ctx, opportunity)
|
|
require.NoError(t, err)
|
|
|
|
strategy, err := analyzer.CalculateOptimalBid(ctx, opportunity, competition)
|
|
require.NoError(t, err)
|
|
|
|
t.Logf("Recommended priority fee: %s gwei",
|
|
new(big.Int).Div(strategy.PriorityFeePerGas, big.NewInt(1000000000)))
|
|
t.Logf("Max fee per gas: %s gwei",
|
|
new(big.Int).Div(strategy.MaxFeePerGas, big.NewInt(1000000000)))
|
|
t.Logf("Expected profit after gas: %s ETH",
|
|
new(big.Float).Quo(
|
|
new(big.Float).SetInt(strategy.ExpectedProfit),
|
|
new(big.Float).SetInt(big.NewInt(1000000000000000000)),
|
|
).String())
|
|
|
|
// Validate strategy is profitable
|
|
assert.Greater(t, strategy.ExpectedProfit.Sign(), 0, "Strategy should be profitable after gas costs")
|
|
assert.LessOrEqual(t, strategy.MaxFeePerGas.Cmp(new(big.Int).Mul(baseFee, big.NewInt(3))), 0,
|
|
"Max fee should not exceed 3x base fee for reasonable execution")
|
|
})
|
|
|
|
t.Run("Gas Limit Optimization", func(t *testing.T) {
|
|
// Test different gas limits for arbitrage execution
|
|
gasLimits := []*big.Int{
|
|
big.NewInt(250000),
|
|
big.NewInt(300000),
|
|
big.NewInt(400000),
|
|
big.NewInt(500000),
|
|
}
|
|
|
|
profit := big.NewInt(80000000000000000) // 0.08 ETH base profit
|
|
gasPrice := big.NewInt(10000000000) // 10 gwei
|
|
|
|
bestGasLimit := big.NewInt(0)
|
|
bestNetProfit := big.NewInt(0)
|
|
|
|
for _, gasLimit := range gasLimits {
|
|
gasCost := new(big.Int).Mul(gasPrice, gasLimit)
|
|
netProfit := new(big.Int).Sub(profit, gasCost)
|
|
|
|
t.Logf("Gas limit %s: Net profit %s ETH",
|
|
gasLimit.String(),
|
|
new(big.Float).Quo(
|
|
new(big.Float).SetInt(netProfit),
|
|
new(big.Float).SetInt(big.NewInt(1000000000000000000)),
|
|
).String())
|
|
|
|
if netProfit.Cmp(bestNetProfit) > 0 {
|
|
bestNetProfit.Set(netProfit)
|
|
bestGasLimit.Set(gasLimit)
|
|
}
|
|
}
|
|
|
|
t.Logf("Optimal gas limit: %s", bestGasLimit.String())
|
|
assert.Greater(t, bestGasLimit.Uint64(), uint64(0), "Should find optimal gas limit")
|
|
})
|
|
}
|
|
|
|
func TestRealMarketConditions(t *testing.T) {
|
|
client, cleanup := setupForkedArbitrum(t)
|
|
defer cleanup()
|
|
|
|
t.Run("Market Volatility Impact", func(t *testing.T) {
|
|
// Test arbitrage detection under different market conditions
|
|
service, err := arbService.NewArbitrageService(client)
|
|
require.NoError(t, err)
|
|
|
|
// Create events representing different market conditions
|
|
volatileEvents := []*arbService.SimpleSwapEvent{
|
|
// Small trade - normal market
|
|
{
|
|
TxHash: common.HexToHash("0x1"),
|
|
Pool: common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"),
|
|
Token0: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"),
|
|
Token1: common.HexToAddress("0xaf88d065e77c8cC2239327C5EDb3A432268e5831"),
|
|
Amount0: big.NewInt(1000000000000000000), // 1 ETH
|
|
Amount1: big.NewInt(-2000000000), // -2000 USDC
|
|
SqrtPriceX96: func() *big.Int { x, _ := new(big.Int).SetString("79228162514264337593543950336", 10); return x }(),
|
|
},
|
|
// Large trade - volatile market
|
|
{
|
|
TxHash: common.HexToHash("0x2"),
|
|
Pool: common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"),
|
|
Token0: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"),
|
|
Token1: common.HexToAddress("0xaf88d065e77c8cC2239327C5EDb3A432268e5831"),
|
|
Amount0: func() *big.Int { x, _ := new(big.Int).SetString("50000000000000000000", 10); return x }(), // 50 ETH
|
|
Amount1: big.NewInt(-100000000000), // -100,000 USDC
|
|
SqrtPriceX96: func() *big.Int { x, _ := new(big.Int).SetString("80000000000000000000000000000", 10); return x }(),
|
|
},
|
|
}
|
|
|
|
detectedOpportunities := 0
|
|
for i, event := range volatileEvents {
|
|
err := service.ProcessSwapEvent(event)
|
|
require.NoError(t, err)
|
|
|
|
// Check if this event would trigger arbitrage detection
|
|
if service.IsSignificantSwap(event) {
|
|
detectedOpportunities++
|
|
t.Logf("Event %d triggered arbitrage detection (amount: %s ETH)",
|
|
i+1, new(big.Float).Quo(
|
|
new(big.Float).SetInt(event.Amount0),
|
|
new(big.Float).SetInt(big.NewInt(1000000000000000000)),
|
|
).String())
|
|
}
|
|
}
|
|
|
|
assert.Greater(t, detectedOpportunities, 0, "Should detect opportunities in volatile market")
|
|
})
|
|
|
|
t.Run("Oracle Price Validation", func(t *testing.T) {
|
|
// Test oracle-based price validation for arbitrage
|
|
priceOracle := oracle.NewPriceOracle(client)
|
|
|
|
// WETH/USDC price from different sources
|
|
wethAddress := common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1")
|
|
usdcAddress := common.HexToAddress("0xaf88d065e77c8cC2239327C5EDb3A432268e5831")
|
|
|
|
ctx := context.Background()
|
|
|
|
// Get price from Uniswap V3
|
|
uniPrice, err := priceOracle.GetUniswapV3Price(ctx, wethAddress, usdcAddress, 500)
|
|
require.NoError(t, err)
|
|
|
|
// Get price from alternative DEX (SushiSwap)
|
|
sushiPrice, err := priceOracle.GetSushiSwapPrice(ctx, wethAddress, usdcAddress)
|
|
require.NoError(t, err)
|
|
|
|
t.Logf("Uniswap V3 WETH/USDC price: %s", uniPrice.String())
|
|
t.Logf("SushiSwap WETH/USDC price: %s", sushiPrice.String())
|
|
|
|
// Calculate price deviation
|
|
priceDiff := new(big.Int).Sub(uniPrice, sushiPrice)
|
|
if priceDiff.Sign() < 0 {
|
|
priceDiff.Neg(priceDiff)
|
|
}
|
|
|
|
deviationPercent := new(big.Int).Div(
|
|
new(big.Int).Mul(priceDiff, big.NewInt(10000)),
|
|
uniPrice,
|
|
)
|
|
|
|
t.Logf("Price deviation: %s basis points", deviationPercent.String())
|
|
|
|
// Significant price deviation indicates arbitrage opportunity
|
|
if deviationPercent.Uint64() > 50 { // More than 0.5%
|
|
t.Log("Significant price deviation detected - potential arbitrage opportunity")
|
|
assert.Greater(t, deviationPercent.Uint64(), uint64(50), "Price deviation indicates opportunity")
|
|
} else {
|
|
t.Log("Prices are aligned - no immediate arbitrage opportunity")
|
|
}
|
|
})
|
|
|
|
t.Run("Liquidity Depth Analysis", func(t *testing.T) {
|
|
// Test liquidity depth for arbitrage execution
|
|
pools := []common.Address{
|
|
common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"), // WETH/USDC 0.05%
|
|
common.HexToAddress("0x17c14D2c404D167802b16C450d3c99F88F2c4F4d"), // WETH/USDC 0.3%
|
|
}
|
|
|
|
for i, pool := range pools {
|
|
liquidity, err := uniswap.GetPoolLiquidity(client, pool)
|
|
require.NoError(t, err)
|
|
|
|
t.Logf("Pool %d liquidity: %s", i+1, liquidity.String())
|
|
|
|
// Minimum liquidity threshold for profitable arbitrage
|
|
minLiquidity := new(big.Int)
|
|
minLiquidity.SetString("1000000000000000000000", 10) // 1000 ETH equivalent
|
|
if liquidity.Cmp(minLiquidity) >= 0 {
|
|
t.Logf("Pool %d has sufficient liquidity for large arbitrage", i+1)
|
|
} else {
|
|
t.Logf("Pool %d has limited liquidity - small arbitrage only", i+1)
|
|
}
|
|
|
|
assert.Greater(t, liquidity.Uint64(), uint64(0), "Pool should have measurable liquidity")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestProfitabilityUnderStress(t *testing.T) {
|
|
client, cleanup := setupForkedArbitrum(t)
|
|
defer cleanup()
|
|
|
|
t.Run("High Gas Price Environment", func(t *testing.T) {
|
|
// Simulate high gas price conditions (network congestion)
|
|
highGasPrice := big.NewInt(50000000000) // 50 gwei
|
|
|
|
opportunity := &mev.MEVOpportunity{
|
|
Type: mev.TypeArbitrage,
|
|
EstimatedProfit: big.NewInt(30000000000000000), // 0.03 ETH
|
|
RequiredGasLimit: big.NewInt(300000),
|
|
PoolAddress: common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"),
|
|
Timestamp: time.Now(),
|
|
}
|
|
|
|
gasCost := new(big.Int).Mul(highGasPrice, opportunity.RequiredGasLimit)
|
|
netProfit := new(big.Int).Sub(opportunity.EstimatedProfit, gasCost)
|
|
|
|
t.Logf("High gas environment - Gas cost: %s ETH, Net profit: %s ETH",
|
|
new(big.Float).Quo(new(big.Float).SetInt(gasCost), new(big.Float).SetInt(big.NewInt(1e18))),
|
|
new(big.Float).Quo(new(big.Float).SetInt(netProfit), new(big.Float).SetInt(big.NewInt(1e18))))
|
|
|
|
if netProfit.Sign() > 0 {
|
|
t.Log("Arbitrage remains profitable even with high gas prices")
|
|
} else {
|
|
t.Log("High gas prices make arbitrage unprofitable")
|
|
}
|
|
})
|
|
|
|
t.Run("MEV Competition Pressure", func(t *testing.T) {
|
|
// Simulate competitive MEV environment
|
|
analyzer := mev.NewCompetitionAnalyzer(client)
|
|
|
|
opportunity := &mev.MEVOpportunity{
|
|
Type: mev.TypeArbitrage,
|
|
EstimatedProfit: big.NewInt(100000000000000000), // 0.1 ETH
|
|
RequiredGasLimit: big.NewInt(300000),
|
|
PoolAddress: common.HexToAddress("0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443"),
|
|
Timestamp: time.Now(),
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
// Simulate different competition levels
|
|
competitionLevels := []string{"low", "medium", "high", "extreme"}
|
|
|
|
for _, level := range competitionLevels {
|
|
// Mock competition metrics based on level
|
|
competition := &mev.CompetitionMetrics{
|
|
CompetitorCount: getCompetitorCount(level),
|
|
AveragePriorityFee: getAveragePriorityFee(level),
|
|
SuccessRate: getSuccessRate(level),
|
|
RecentOpportunities: 10,
|
|
}
|
|
|
|
strategy, err := analyzer.CalculateOptimalBid(ctx, opportunity, competition)
|
|
require.NoError(t, err)
|
|
|
|
t.Logf("Competition level %s: Priority fee %s gwei, Expected profit %s ETH",
|
|
level,
|
|
new(big.Int).Div(strategy.PriorityFeePerGas, big.NewInt(1e9)),
|
|
new(big.Float).Quo(new(big.Float).SetInt(strategy.ExpectedProfit), new(big.Float).SetInt(big.NewInt(1e18))))
|
|
|
|
// Even under extreme competition, some profit should remain
|
|
if level != "extreme" {
|
|
assert.Greater(t, strategy.ExpectedProfit.Sign(), 0,
|
|
"Should maintain profitability under %s competition", level)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// Helper functions for stress testing
|
|
|
|
func getCompetitorCount(level string) int {
|
|
switch level {
|
|
case "low":
|
|
return 2
|
|
case "medium":
|
|
return 5
|
|
case "high":
|
|
return 10
|
|
case "extreme":
|
|
return 20
|
|
default:
|
|
return 3
|
|
}
|
|
}
|
|
|
|
func getAveragePriorityFee(level string) *big.Int {
|
|
switch level {
|
|
case "low":
|
|
return big.NewInt(2000000000) // 2 gwei
|
|
case "medium":
|
|
return big.NewInt(5000000000) // 5 gwei
|
|
case "high":
|
|
return big.NewInt(10000000000) // 10 gwei
|
|
case "extreme":
|
|
return big.NewInt(25000000000) // 25 gwei
|
|
default:
|
|
return big.NewInt(3000000000) // 3 gwei
|
|
}
|
|
}
|
|
|
|
func getSuccessRate(level string) float64 {
|
|
switch level {
|
|
case "low":
|
|
return 0.9
|
|
case "medium":
|
|
return 0.7
|
|
case "high":
|
|
return 0.4
|
|
case "extreme":
|
|
return 0.1
|
|
default:
|
|
return 0.8
|
|
}
|
|
}
|