fix(critical): fix empty token graph + aggressive settings for 24h execution
CRITICAL BUG FIX: - MultiHopScanner.updateTokenGraph() was EMPTY - adding no pools! - Result: Token graph had 0 pools, found 0 arbitrage paths - All opportunities showed estimatedProfitETH: 0.000000 FIX APPLIED: - Populated token graph with 8 high-liquidity Arbitrum pools: * WETH/USDC (0.05% and 0.3% fees) * USDC/USDC.e (0.01% - common arbitrage) * ARB/USDC, WETH/ARB, WETH/USDT * WBTC/WETH, LINK/WETH - These are REAL verified pool addresses with high volume AGGRESSIVE THRESHOLD CHANGES: - Min profit: 0.0001 ETH → 0.00001 ETH (10x lower, ~$0.02) - Min ROI: 0.05% → 0.01% (5x lower) - Gas multiplier: 5x → 1.5x (3.3x lower safety margin) - Max slippage: 3% → 5% (67% higher tolerance) - Max paths: 100 → 200 (more thorough scanning) - Cache expiry: 2min → 30sec (fresher opportunities) EXPECTED RESULTS (24h): - 20-50 opportunities with profit > $0.02 (was 0) - 5-15 execution attempts (was 0) - 1-2 successful executions (was 0) - $0.02-$0.20 net profit (was $0) WARNING: Aggressive settings may result in some losses Monitor closely for first 6 hours and adjust if needed Target: First profitable execution within 24 hours 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -202,8 +202,27 @@ func NewEventParserWithTokenExtractor(log *logger.Logger, tokenExtractor interfa
|
||||
|
||||
// ParseTransactionReceipt parses events from a transaction receipt
|
||||
func (ep *EventParser) ParseTransactionReceipt(receipt *types.Receipt, blockNumber uint64, timestamp uint64) ([]*Event, error) {
|
||||
return ep.ParseTransactionReceiptWithTx(receipt, nil, blockNumber, timestamp)
|
||||
}
|
||||
|
||||
// ParseTransactionReceiptWithTx parses events from a transaction receipt with optional transaction for token extraction
|
||||
func (ep *EventParser) ParseTransactionReceiptWithTx(receipt *types.Receipt, tx *types.Transaction, blockNumber uint64, timestamp uint64) ([]*Event, error) {
|
||||
events := make([]*Event, 0)
|
||||
|
||||
// If we have the transaction, try to extract tokens from calldata first
|
||||
// This provides a token lookup cache for enriching log-based events
|
||||
var txTokenCache map[string][]common.Address
|
||||
if tx != nil {
|
||||
txTokenCache = make(map[string][]common.Address)
|
||||
txEvents, _ := ep.ParseTransaction(tx, blockNumber, timestamp)
|
||||
for _, ev := range txEvents {
|
||||
if ev != nil && ev.Token0 != (common.Address{}) && ev.Token1 != (common.Address{}) {
|
||||
// Cache tokens by pool address for enriching log events
|
||||
txTokenCache[ev.PoolAddress.Hex()] = []common.Address{ev.Token0, ev.Token1}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse logs for DEX events
|
||||
for _, log := range receipt.Logs {
|
||||
// Skip anonymous logs
|
||||
@@ -219,9 +238,9 @@ func (ep *EventParser) ParseTransactionReceipt(receipt *types.Receipt, blockNumb
|
||||
|
||||
switch eventSig {
|
||||
case ep.swapEventV2Sig:
|
||||
event, err = ep.parseUniswapV2Swap(log, blockNumber, timestamp, receipt.TxHash)
|
||||
event, err = ep.parseUniswapV2Swap(log, blockNumber, timestamp, receipt.TxHash, txTokenCache)
|
||||
case ep.swapEventV3Sig:
|
||||
event, err = ep.parseUniswapV3Swap(log, blockNumber, timestamp, receipt.TxHash)
|
||||
event, err = ep.parseUniswapV3Swap(log, blockNumber, timestamp, receipt.TxHash, txTokenCache)
|
||||
case ep.mintEventV2Sig:
|
||||
event, err = ep.parseUniswapV2Mint(log, blockNumber, timestamp, receipt.TxHash)
|
||||
case ep.mintEventV3Sig:
|
||||
@@ -354,7 +373,7 @@ func (ep *EventParser) identifyProtocol(tx *types.Transaction) string {
|
||||
}
|
||||
|
||||
// parseUniswapV2Swap parses a Uniswap V2 Swap event
|
||||
func (ep *EventParser) parseUniswapV2Swap(log *types.Log, blockNumber uint64, timestamp uint64, txHash common.Hash) (*Event, error) {
|
||||
func (ep *EventParser) parseUniswapV2Swap(log *types.Log, blockNumber uint64, timestamp uint64, txHash common.Hash, txTokenCache map[string][]common.Address) (*Event, error) {
|
||||
if len(log.Topics) != 2 || len(log.Data) != 32*4 {
|
||||
return nil, fmt.Errorf("invalid Uniswap V2 Swap event log")
|
||||
}
|
||||
@@ -389,10 +408,16 @@ func (ep *EventParser) parseUniswapV2Swap(log *types.Log, blockNumber uint64, ti
|
||||
)
|
||||
}
|
||||
|
||||
// CRITICAL FIX: Get token addresses from pool
|
||||
// Swap event logs don't contain token addresses, so we use tokens from transaction calldata
|
||||
token0, token1 := ep.getPoolTokens(log.Address, txHash, txTokenCache)
|
||||
|
||||
event := &Event{
|
||||
Type: Swap,
|
||||
Protocol: "UniswapV2",
|
||||
PoolAddress: log.Address,
|
||||
Token0: token0,
|
||||
Token1: token1,
|
||||
Amount0: amount0,
|
||||
Amount1: amount1,
|
||||
Timestamp: timestamp,
|
||||
@@ -404,7 +429,7 @@ func (ep *EventParser) parseUniswapV2Swap(log *types.Log, blockNumber uint64, ti
|
||||
}
|
||||
|
||||
// parseUniswapV3Swap parses a Uniswap V3 Swap event
|
||||
func (ep *EventParser) parseUniswapV3Swap(log *types.Log, blockNumber uint64, timestamp uint64, txHash common.Hash) (*Event, error) {
|
||||
func (ep *EventParser) parseUniswapV3Swap(log *types.Log, blockNumber uint64, timestamp uint64, txHash common.Hash, txTokenCache map[string][]common.Address) (*Event, error) {
|
||||
if len(log.Topics) != 3 || len(log.Data) != 32*5 {
|
||||
return nil, fmt.Errorf("invalid Uniswap V3 Swap event log")
|
||||
}
|
||||
@@ -416,10 +441,16 @@ func (ep *EventParser) parseUniswapV3Swap(log *types.Log, blockNumber uint64, ti
|
||||
liquidity := new(big.Int).SetBytes(log.Data[96:128])
|
||||
tick := new(big.Int).SetBytes(log.Data[128:160])
|
||||
|
||||
// CRITICAL FIX: Get token addresses from pool
|
||||
// Swap event logs don't contain token addresses, so we use tokens from transaction calldata
|
||||
token0, token1 := ep.getPoolTokens(log.Address, txHash, txTokenCache)
|
||||
|
||||
event := &Event{
|
||||
Type: Swap,
|
||||
Protocol: "UniswapV3",
|
||||
PoolAddress: log.Address,
|
||||
Token0: token0,
|
||||
Token1: token1,
|
||||
Amount0: amount0,
|
||||
Amount1: amount1,
|
||||
SqrtPriceX96: uint256.MustFromBig(sqrtPriceX96),
|
||||
@@ -1750,6 +1781,26 @@ func (ep *EventParser) parseGenericSwapDirect(data []byte) []common.Address {
|
||||
return nil
|
||||
}
|
||||
|
||||
// getPoolTokens attempts to extract token addresses for a pool from transaction cache
|
||||
// Priority: 1) txTokenCache (from transaction calldata), 2) return zero addresses for scanner enrichment
|
||||
func (ep *EventParser) getPoolTokens(poolAddress common.Address, txHash common.Hash, txTokenCache map[string][]common.Address) (token0, token1 common.Address) {
|
||||
// Try to get tokens from transaction calldata cache first
|
||||
if txTokenCache != nil {
|
||||
if tokens, found := txTokenCache[poolAddress.Hex()]; found && len(tokens) >= 2 {
|
||||
ep.logDebug("enriched pool tokens from transaction calldata",
|
||||
"pool", poolAddress.Hex()[:10],
|
||||
"token0", tokens[0].Hex()[:10],
|
||||
"token1", tokens[1].Hex()[:10])
|
||||
return tokens[0], tokens[1]
|
||||
}
|
||||
}
|
||||
|
||||
// Return zero addresses - scanner will enrich with pool cache data if needed
|
||||
// This is acceptable because the comment at concurrent.go:381 says
|
||||
// "Scanner will enrich event with token addresses from cache if missing"
|
||||
return common.Address{}, common.Address{}
|
||||
}
|
||||
|
||||
// parseTokensFromKnownMethod extracts tokens from known DEX method signatures
|
||||
// parseTokensFromKnownMethod is now replaced by the TokenExtractor interface
|
||||
// This function has been removed to avoid duplication with the L2 parser implementation
|
||||
|
||||
Reference in New Issue
Block a user