fix(critical): eliminate uint256 max overflow by fixing signed int256 parsing across all event parsers
This commit resolves the uint256 max overflow causing amounts to display as +11579208923... Root cause: UniswapV3 uses signed int256 for amounts, but multiple parsers treated them as unsigned Files fixed: - pkg/events/parser.go: Fixed broken signed int conversion (line 392-396) - pkg/pools/discovery.go: Added signed parsing for UniswapV3 (lines 415-420, 705-710) Impact: Eliminates e+59 to e+70 overflow values, enables accurate arbitrage calculations
This commit is contained in:
@@ -18,6 +18,27 @@ import (
|
||||
"github.com/fraktal/mev-beta/pkg/uniswap"
|
||||
)
|
||||
|
||||
// parseSignedInt256 correctly parses a signed 256-bit integer from 32 bytes
|
||||
// This is critical for UniswapV3 events which use int256 for amounts
|
||||
func parseSignedInt256(data []byte) *big.Int {
|
||||
if len(data) != 32 {
|
||||
return big.NewInt(0)
|
||||
}
|
||||
|
||||
value := new(big.Int).SetBytes(data)
|
||||
|
||||
// Check if the value is negative (MSB set)
|
||||
if len(data) > 0 && data[0]&0x80 != 0 {
|
||||
// Convert from two's complement
|
||||
// Subtract 2^256 to get the negative value
|
||||
maxUint256 := new(big.Int)
|
||||
maxUint256.Lsh(big.NewInt(1), 256)
|
||||
value.Sub(value, maxUint256)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// EventType represents the type of DEX event
|
||||
type EventType int
|
||||
|
||||
@@ -388,21 +409,13 @@ func (ep *EventParser) parseUniswapV3Swap(log *types.Log, blockNumber uint64, ti
|
||||
return nil, fmt.Errorf("invalid Uniswap V3 Swap event log")
|
||||
}
|
||||
|
||||
// Parse the data fields
|
||||
amount0 := new(big.Int).SetBytes(log.Data[0:32])
|
||||
amount1 := new(big.Int).SetBytes(log.Data[32:64])
|
||||
// Parse the data fields - UniswapV3 uses signed int256 for amounts
|
||||
amount0 := parseSignedInt256(log.Data[0:32])
|
||||
amount1 := parseSignedInt256(log.Data[32:64])
|
||||
sqrtPriceX96 := new(big.Int).SetBytes(log.Data[64:96])
|
||||
liquidity := new(big.Int).SetBytes(log.Data[96:128])
|
||||
tick := new(big.Int).SetBytes(log.Data[128:160])
|
||||
|
||||
// Convert to signed values if needed
|
||||
if amount0.Cmp(big.NewInt(0)) > 0x7fffffffffffffff {
|
||||
amount0 = amount0.Sub(amount0, new(big.Int).Lsh(big.NewInt(1), 256))
|
||||
}
|
||||
if amount1.Cmp(big.NewInt(0)) > 0x7fffffffffffffff {
|
||||
amount1 = amount1.Sub(amount1, new(big.Int).Lsh(big.NewInt(1), 256))
|
||||
}
|
||||
|
||||
event := &Event{
|
||||
Type: Swap,
|
||||
Protocol: "UniswapV3",
|
||||
|
||||
@@ -21,6 +21,27 @@ import (
|
||||
"github.com/fraktal/mev-beta/pkg/uniswap"
|
||||
)
|
||||
|
||||
// parseSignedInt256 correctly parses a signed 256-bit integer from 32 bytes
|
||||
// This is critical for UniswapV3 events which use int256 for amounts
|
||||
func parseSignedInt256(data []byte) *big.Int {
|
||||
if len(data) != 32 {
|
||||
return big.NewInt(0)
|
||||
}
|
||||
|
||||
value := new(big.Int).SetBytes(data)
|
||||
|
||||
// Check if the value is negative (MSB set)
|
||||
if len(data) > 0 && data[0]&0x80 != 0 {
|
||||
// Convert from two's complement
|
||||
// Subtract 2^256 to get the negative value
|
||||
maxUint256 := new(big.Int)
|
||||
maxUint256.Lsh(big.NewInt(1), 256)
|
||||
value.Sub(value, maxUint256)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// Pool represents a discovered liquidity pool
|
||||
type Pool struct {
|
||||
Address string `json:"address"`
|
||||
@@ -412,9 +433,12 @@ func (pd *PoolDiscovery) parseSwapData(data, protocol string) *SwapData {
|
||||
}
|
||||
|
||||
case "UniswapV3":
|
||||
// Uniswap V3 has different swap event structure
|
||||
amountIn = new(big.Int).SetBytes(dataBytes[0:32])
|
||||
amountOut = new(big.Int).SetBytes(dataBytes[32:64])
|
||||
// Uniswap V3 uses signed int256 for amounts
|
||||
amountIn = parseSignedInt256(dataBytes[0:32])
|
||||
amountOut = parseSignedInt256(dataBytes[32:64])
|
||||
// Convert to absolute values for display
|
||||
amountIn = new(big.Int).Abs(amountIn)
|
||||
amountOut = new(big.Int).Abs(amountOut)
|
||||
|
||||
default:
|
||||
// Generic parsing
|
||||
@@ -485,7 +509,7 @@ func (pd *PoolDiscovery) handleLiquidityEvent(poolAddress string, topics []inter
|
||||
return
|
||||
}
|
||||
|
||||
eventData := pd.parseLiquidityData(data, eventType)
|
||||
eventData := pd.parseLiquidityData(data, eventType, pool.Protocol)
|
||||
if eventData == nil {
|
||||
return
|
||||
}
|
||||
@@ -661,7 +685,7 @@ func (pd *PoolDiscovery) discoverPoolFromSwap(poolAddress, txHash string) {
|
||||
}
|
||||
|
||||
// parseLiquidityData parses liquidity event data
|
||||
func (pd *PoolDiscovery) parseLiquidityData(data, eventType string) *SwapData {
|
||||
func (pd *PoolDiscovery) parseLiquidityData(data, eventType, protocol string) *SwapData {
|
||||
if len(data) < 2 {
|
||||
return nil
|
||||
}
|
||||
@@ -675,8 +699,20 @@ func (pd *PoolDiscovery) parseLiquidityData(data, eventType string) *SwapData {
|
||||
return nil
|
||||
}
|
||||
|
||||
amount0 := new(big.Int).SetBytes(dataBytes[0:32])
|
||||
amount1 := new(big.Int).SetBytes(dataBytes[32:64])
|
||||
var amount0, amount1 *big.Int
|
||||
|
||||
// UniswapV3 uses signed int256 for liquidity amounts
|
||||
if protocol == "UniswapV3" {
|
||||
amount0 = parseSignedInt256(dataBytes[0:32])
|
||||
amount1 = parseSignedInt256(dataBytes[32:64])
|
||||
// Convert to absolute values
|
||||
amount0 = new(big.Int).Abs(amount0)
|
||||
amount1 = new(big.Int).Abs(amount1)
|
||||
} else {
|
||||
// V2 and others use unsigned uint256
|
||||
amount0 = new(big.Int).SetBytes(dataBytes[0:32])
|
||||
amount1 = new(big.Int).SetBytes(dataBytes[32:64])
|
||||
}
|
||||
|
||||
return &SwapData{
|
||||
AmountIn: amount0,
|
||||
|
||||
Reference in New Issue
Block a user