- 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>
97 lines
2.7 KiB
Go
97 lines
2.7 KiB
Go
package parser
|
|
|
|
import (
|
|
"math/big"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
const uniswapV3RouterABI = `[
|
|
{
|
|
"name":"multicall",
|
|
"type":"function",
|
|
"stateMutability":"payable",
|
|
"inputs":[
|
|
{"name":"deadline","type":"uint256"},
|
|
{"name":"data","type":"bytes[]"}
|
|
],
|
|
"outputs":[]
|
|
},
|
|
{
|
|
"name":"exactInputSingle",
|
|
"type":"function",
|
|
"stateMutability":"payable",
|
|
"inputs":[
|
|
{
|
|
"name":"params",
|
|
"type":"tuple",
|
|
"components":[
|
|
{"name":"tokenIn","type":"address"},
|
|
{"name":"tokenOut","type":"address"},
|
|
{"name":"fee","type":"uint24"},
|
|
{"name":"recipient","type":"address"},
|
|
{"name":"deadline","type":"uint256"},
|
|
{"name":"amountIn","type":"uint256"},
|
|
{"name":"amountOutMinimum","type":"uint256"},
|
|
{"name":"sqrtPriceLimitX96","type":"uint160"}
|
|
]
|
|
}
|
|
],
|
|
"outputs":[{"name":"","type":"uint256"}]
|
|
}
|
|
]`
|
|
|
|
type exactInputSingleParams struct {
|
|
TokenIn common.Address `abi:"tokenIn"`
|
|
TokenOut common.Address `abi:"tokenOut"`
|
|
Fee *big.Int `abi:"fee"`
|
|
Recipient common.Address `abi:"recipient"`
|
|
Deadline *big.Int `abi:"deadline"`
|
|
AmountIn *big.Int `abi:"amountIn"`
|
|
AmountOutMinimum *big.Int `abi:"amountOutMinimum"`
|
|
SqrtPriceLimitX96 *big.Int `abi:"sqrtPriceLimitX96"`
|
|
}
|
|
|
|
func TestDecodeUniswapV3Multicall(t *testing.T) {
|
|
decoder, err := NewABIDecoder()
|
|
require.NoError(t, err)
|
|
|
|
routerABI, err := abi.JSON(strings.NewReader(uniswapV3RouterABI))
|
|
require.NoError(t, err)
|
|
|
|
tokenIn := common.HexToAddress("0xaf88d065e77c8cc2239327c5edb3a432268e5831")
|
|
tokenOut := common.HexToAddress("0x82af49447d8a07e3bd95bd0d56f35241523fbab1")
|
|
|
|
params := exactInputSingleParams{
|
|
TokenIn: tokenIn,
|
|
TokenOut: tokenOut,
|
|
Fee: big.NewInt(500),
|
|
Recipient: common.HexToAddress("0x1111111254eeb25477b68fb85ed929f73a960582"),
|
|
Deadline: big.NewInt(0),
|
|
AmountIn: big.NewInt(1_000_000),
|
|
AmountOutMinimum: big.NewInt(950_000),
|
|
SqrtPriceLimitX96: big.NewInt(0),
|
|
}
|
|
|
|
innerCall, err := routerABI.Pack("exactInputSingle", params)
|
|
require.NoError(t, err)
|
|
|
|
multicallPayload, err := routerABI.Pack("multicall", big.NewInt(0), [][]byte{innerCall})
|
|
require.NoError(t, err)
|
|
|
|
rawSwap, err := decoder.DecodeSwapTransaction("uniswap_v3", multicallPayload)
|
|
require.NoError(t, err)
|
|
|
|
swap, ok := rawSwap.(*SwapEvent)
|
|
require.True(t, ok, "expected SwapEvent from multicall decode")
|
|
|
|
require.Equal(t, tokenIn, swap.TokenIn)
|
|
require.Equal(t, tokenOut, swap.TokenOut)
|
|
require.Equal(t, big.NewInt(1_000_000), swap.AmountIn)
|
|
require.Equal(t, big.NewInt(950_000), swap.AmountOut)
|
|
}
|