fix(multicall): resolve critical multicall parsing corruption issues

- Added comprehensive bounds checking to prevent buffer overruns in multicall parsing
- Implemented graduated validation system (Strict/Moderate/Permissive) to reduce false positives
- Added LRU caching system for address validation with 10-minute TTL
- Enhanced ABI decoder with missing Universal Router and Arbitrum-specific DEX signatures
- Fixed duplicate function declarations and import conflicts across multiple files
- Added error recovery mechanisms with multiple fallback strategies
- Updated tests to handle new validation behavior for suspicious addresses
- Fixed parser test expectations for improved validation system
- Applied gofmt formatting fixes to ensure code style compliance
- Fixed mutex copying issues in monitoring package by introducing MetricsSnapshot
- Resolved critical security vulnerabilities in heuristic address extraction
- Progress: Updated TODO audit from 10% to 35% complete

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Krypto Kajun
2025-10-17 00:12:55 -05:00
parent f358f49aa9
commit 850223a953
8621 changed files with 79808 additions and 7340 deletions

View File

@@ -25,8 +25,8 @@ func InitConstants() {
q192 = new(big.Int).Exp(big.NewInt(2), big.NewInt(192), nil)
lnBase = math.Log(1.0001)
invLnBase = 1.0 / lnBase
q96Float = new(big.Float).SetInt(q96)
q192Float = new(big.Float).SetInt(q192)
q96Float = new(big.Float).SetPrec(256).SetInt(q96)
q192Float = new(big.Float).SetPrec(256).SetInt(q192)
})
}

View File

@@ -260,39 +260,20 @@ func (p *UniswapV3Pool) callLiquidity(ctx context.Context) (*uint256.Int, error)
// callToken0 calls the token0() function on the pool contract
func (p *UniswapV3Pool) callToken0(ctx context.Context) (common.Address, error) {
// Pack the function call
data, err := p.abi.Pack("token0")
if err != nil {
return common.Address{}, fmt.Errorf("failed to pack token0 call: %w", err)
}
// Make the contract call
msg := ethereum.CallMsg{
To: &p.address,
Data: data,
}
result, err := p.client.CallContract(ctx, msg, nil)
if err != nil {
return common.Address{}, fmt.Errorf("failed to call token0: %w", err)
}
// Unpack the result
var token0 common.Address
err = p.abi.UnpackIntoInterface(&token0, "token0", result)
if err != nil {
return common.Address{}, fmt.Errorf("failed to unpack token0 result: %w", err)
}
return token0, nil
return p.callToken(ctx, "token0")
}
// callToken1 calls the token1() function on the pool contract
func (p *UniswapV3Pool) callToken1(ctx context.Context) (common.Address, error) {
return p.callToken(ctx, "token1")
}
// callToken is a generic function to call token0() or token1() functions on the pool contract
func (p *UniswapV3Pool) callToken(ctx context.Context, tokenFunc string) (common.Address, error) {
// Pack the function call
data, err := p.abi.Pack("token1")
data, err := p.abi.Pack(tokenFunc)
if err != nil {
return common.Address{}, fmt.Errorf("failed to pack token1 call: %w", err)
return common.Address{}, fmt.Errorf("failed to pack %s call: %w", tokenFunc, err)
}
// Make the contract call
@@ -303,17 +284,17 @@ func (p *UniswapV3Pool) callToken1(ctx context.Context) (common.Address, error)
result, err := p.client.CallContract(ctx, msg, nil)
if err != nil {
return common.Address{}, fmt.Errorf("failed to call token1: %w", err)
return common.Address{}, fmt.Errorf("failed to call %s: %w", tokenFunc, err)
}
// Unpack the result
var token1 common.Address
err = p.abi.UnpackIntoInterface(&token1, "token1", result)
var token common.Address
err = p.abi.UnpackIntoInterface(&token, tokenFunc, result)
if err != nil {
return common.Address{}, fmt.Errorf("failed to unpack token1 result: %w", err)
return common.Address{}, fmt.Errorf("failed to unpack %s result: %w", tokenFunc, err)
}
return token1, nil
return token, nil
}
// callFee calls the fee() function on the pool contract

View File

@@ -0,0 +1,28 @@
// Package uniswap provides mathematical functions for Uniswap V3 calculations.
package uniswap
import "math/big"
// SqrtPriceX96ToPriceOptimizedCached provides the same functionality as SqrtPriceX96ToPriceAdvanced
// This alias is maintained for API compatibility with existing code that might reference this function
func SqrtPriceX96ToPriceOptimizedCached(sqrtPriceX96 *big.Int) *big.Float {
return SqrtPriceX96ToPriceAdvanced(sqrtPriceX96)
}
// PriceToSqrtPriceX96OptimizedCached provides the same functionality as PriceToSqrtPriceX96Advanced
// This alias is maintained for API compatibility with existing code that might reference this function
func PriceToSqrtPriceX96OptimizedCached(price *big.Float) *big.Int {
return PriceToSqrtPriceX96Advanced(price)
}
// TickToSqrtPriceX96OptimizedCached provides the same functionality as TickToSqrtPriceX96Advanced
// This alias is maintained for API compatibility with existing code that might reference this function
func TickToSqrtPriceX96OptimizedCached(tick int) *big.Int {
return TickToSqrtPriceX96Advanced(tick)
}
// SqrtPriceX96ToTickOptimizedCached provides the same functionality as SqrtPriceX96ToTickAdvanced
// This alias is maintained for API compatibility with existing code that might reference this function
func SqrtPriceX96ToTickOptimizedCached(sqrtPriceX96 *big.Int) int {
return SqrtPriceX96ToTickAdvanced(sqrtPriceX96)
}

View File

@@ -0,0 +1,47 @@
package uniswap
import (
"math/big"
"testing"
)
func BenchmarkSqrtPriceX96ToPriceOptimizedCached(b *testing.B) {
// Create a test sqrtPriceX96 value
sqrtPriceX96 := new(big.Int)
sqrtPriceX96.SetString("79228162514264337593543950336", 10) // 2^96
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = SqrtPriceX96ToPriceOptimizedCached(sqrtPriceX96)
}
}
func BenchmarkPriceToSqrtPriceX96OptimizedCached(b *testing.B) {
// Create a test price value
price := new(big.Float).SetFloat64(1.0)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = PriceToSqrtPriceX96OptimizedCached(price)
}
}
func BenchmarkTickToSqrtPriceX96OptimizedCached(b *testing.B) {
tick := 100000
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = TickToSqrtPriceX96OptimizedCached(tick)
}
}
func BenchmarkSqrtPriceX96ToTickOptimizedCached(b *testing.B) {
// Create a test sqrtPriceX96 value
sqrtPriceX96 := new(big.Int)
sqrtPriceX96.SetString("79228162514264337593543950336", 10) // 2^96
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = SqrtPriceX96ToTickOptimizedCached(sqrtPriceX96)
}
}

View File

@@ -0,0 +1,79 @@
package uniswap
import (
"math/big"
"testing"
"github.com/stretchr/testify/assert"
)
func TestSqrtPriceX96ToPriceOptimizedCached(t *testing.T) {
// Test with sqrtPriceX96 = 2^96 (should give price = 1.0)
sqrtPriceX96 := new(big.Int)
sqrtPriceX96.SetString("79228162514264337593543950336", 10) // 2^96
result := SqrtPriceX96ToPriceOptimizedCached(sqrtPriceX96)
expected := new(big.Float).SetFloat64(1.0)
resultFloat, _ := result.Float64()
expectedFloat, _ := expected.Float64()
assert.InDelta(t, expectedFloat, resultFloat, 0.0001, "Result should be close to 1.0")
}
func TestPriceToSqrtPriceX96OptimizedCached(t *testing.T) {
// Test with price = 1.0 (should give sqrtPriceX96 = 2^96)
price := new(big.Float).SetFloat64(1.0)
result := PriceToSqrtPriceX96OptimizedCached(price)
expected, _ := new(big.Int).SetString("79228162514264337593543950336", 10) // 2^96
// Allow for small differences due to floating point precision
diff := new(big.Int).Sub(expected, result)
assert.True(t, diff.Cmp(big.NewInt(1000000000000)) < 0, "Result should be close to 2^96")
}
func TestTickToSqrtPriceX96OptimizedCached(t *testing.T) {
// Test with tick = 0 (should give sqrtPriceX96 = 2^96)
tick := 0
result := TickToSqrtPriceX96OptimizedCached(tick)
expected, _ := new(big.Int).SetString("79228162514264337593543950336", 10) // 2^96
// Allow for small differences due to floating point precision
diff := new(big.Int).Sub(expected, result)
assert.True(t, diff.Cmp(big.NewInt(1000000000000)) < 0, "Result should be close to 2^96 for tick 0")
}
func TestSqrtPriceX96ToTickOptimizedCached(t *testing.T) {
// Test with sqrtPriceX96 = 2^96 (should give tick = 0)
sqrtPriceX96 := new(big.Int)
sqrtPriceX96.SetString("79228162514264337593543950336", 10) // 2^96
result := SqrtPriceX96ToTickOptimizedCached(sqrtPriceX96)
expected := 0
assert.Equal(t, expected, result, "Result should be 0 for sqrtPriceX96 = 2^96")
}
func TestOptimizedCachedRoundTripConversions(t *testing.T) {
// Test sqrtPriceX96 -> price -> sqrtPriceX96 round trip with optimized cached functions
// Since these functions are aliases to the Advanced versions, this tests the same functionality
sqrtPriceX96 := new(big.Int)
sqrtPriceX96.SetString("79228162514264337593543950336", 10) // 2^96 (price = 1.0)
price := SqrtPriceX96ToPriceOptimizedCached(sqrtPriceX96)
resultSqrtPriceX96 := PriceToSqrtPriceX96OptimizedCached(price)
// Allow for small differences due to floating point precision
diff := new(big.Int).Sub(sqrtPriceX96, resultSqrtPriceX96)
assert.True(t, diff.Cmp(big.NewInt(1000000000000)) < 0, "Round trip conversion should be accurate")
// Test tick -> sqrtPriceX96 -> tick round trip with optimized cached functions
tick := 100000
sqrtPrice := TickToSqrtPriceX96OptimizedCached(tick)
resultTick := SqrtPriceX96ToTickOptimizedCached(sqrtPrice)
// Allow for small differences due to floating point precision
assert.InDelta(t, tick, resultTick, 1, "Round trip tick conversion should be accurate")
}

View File

@@ -32,19 +32,15 @@ func SqrtPriceX96ToPrice(sqrtPriceX96 *big.Int) *big.Float {
}
// Convert to big.Float for precision
sqrtPrice := new(big.Float).SetInt(sqrtPriceX96)
sqrtPrice := new(big.Float).SetPrec(256).SetInt(sqrtPriceX96)
// Calculate sqrtPrice^2
price := new(big.Float).Mul(sqrtPrice, sqrtPrice)
price := new(big.Float).SetPrec(256)
price.Mul(sqrtPrice, sqrtPrice)
// Divide by 2^192 using global cached constant
price.Quo(price, GetQ192Float())
// Validate result is reasonable (not extremely high or low)
priceFloat, _ := price.Float64()
if priceFloat > 1e20 || priceFloat < 1e-20 { // Extremely high/low prices are likely errors
return new(big.Float).SetFloat64(1.0) // Default to 1.0 as safe fallback
}
denominator := new(big.Float).SetPrec(256).SetInt(GetQ192())
price.Quo(price, denominator)
return price
}
@@ -57,10 +53,12 @@ func PriceToSqrtPriceX96(price *big.Float) *big.Int {
initConstants()
// Calculate sqrt(price)
sqrtPrice := new(big.Float).Sqrt(price)
input := new(big.Float).SetPrec(256).Copy(price)
sqrtPrice := new(big.Float).SetPrec(256).Sqrt(input)
// Multiply by 2^96 using global cached constant
sqrtPrice.Mul(sqrtPrice, GetQ96Float())
multiplier := new(big.Float).SetPrec(256).SetInt(GetQ96())
sqrtPrice.Mul(sqrtPrice, multiplier)
// Convert to big.Int
sqrtPriceX96 := new(big.Int)