- 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>
189 lines
12 KiB
Go
189 lines
12 KiB
Go
package selectors
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
)
|
|
|
|
type selectorCache struct {
|
|
mu sync.Mutex
|
|
cache map[string]string
|
|
}
|
|
|
|
var cachedSelectors = selectorCache{
|
|
cache: make(map[string]string),
|
|
}
|
|
|
|
// MustSelector returns the canonical 4-byte selector (prefixed with 0x) for a function signature.
|
|
// Panics if the signature cannot be hashed (should never happen for valid signatures).
|
|
func MustSelector(signature string) string {
|
|
cachedSelectors.mu.Lock()
|
|
defer cachedSelectors.mu.Unlock()
|
|
|
|
if sel, ok := cachedSelectors.cache[signature]; ok {
|
|
return sel
|
|
}
|
|
|
|
hash := crypto.Keccak256([]byte(signature))
|
|
if len(hash) < 4 {
|
|
panic(fmt.Sprintf("unable to derive selector for %s", signature))
|
|
}
|
|
|
|
selector := "0x" + hex.EncodeToString(hash[:4])
|
|
cachedSelectors.cache[signature] = selector
|
|
return selector
|
|
}
|
|
|
|
// Uniswap / Pancake / TraderJoe (Uniswap V2-style) selectors
|
|
var (
|
|
UniswapV2SwapExactTokensForTokens = MustSelector("swapExactTokensForTokens(uint256,uint256,address[],address,uint256)")
|
|
UniswapV2SwapTokensForExactTokens = MustSelector("swapTokensForExactTokens(uint256,uint256,address[],address,uint256)")
|
|
UniswapV2SwapExactETHForTokens = MustSelector("swapExactETHForTokens(uint256,address[],address,uint256)")
|
|
UniswapV2SwapTokensForExactETH = MustSelector("swapTokensForExactETH(uint256,uint256,address[],address,uint256)")
|
|
UniswapV2SwapExactTokensForETH = MustSelector("swapExactTokensForETH(uint256,uint256,address[],address,uint256)")
|
|
UniswapV2SwapETHForExactTokens = MustSelector("swapETHForExactTokens(uint256,address[],address,uint256)")
|
|
UniswapV2SwapExactTokensForTokensSupportingFee = MustSelector("swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256,uint256,address[],address,uint256)")
|
|
UniswapV2SwapExactETHForTokensSupportingFee = MustSelector("swapExactETHForTokensSupportingFeeOnTransferTokens(uint256,address[],address,uint256)")
|
|
UniswapV2SwapExactTokensForETHSupportingFee = MustSelector("swapExactTokensForETHSupportingFeeOnTransferTokens(uint256,uint256,address[],address,uint256)")
|
|
UniswapV2AddLiquidity = MustSelector("addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)")
|
|
UniswapV2AddLiquidityETH = MustSelector("addLiquidityETH(address,uint256,uint256,uint256,address,uint256)")
|
|
)
|
|
|
|
// Uniswap V3 / Algebra (Camelot V3, Kyber Elastic) selectors
|
|
var (
|
|
UniswapV3ExactInputSingle = MustSelector("exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))")
|
|
UniswapV3ExactInputSingleLegacy = MustSelector("exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))")
|
|
UniswapV3ExactInput = MustSelector("exactInput((bytes,address,uint256,uint256,uint256))")
|
|
UniswapV3ExactInputLegacy = MustSelector("exactInput((bytes,address,uint256,uint256))")
|
|
UniswapV3ExactOutputSingle = MustSelector("exactOutputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))")
|
|
UniswapV3ExactOutput = MustSelector("exactOutput((bytes,address,uint256,uint256,uint256))")
|
|
UniswapV3ExactOutputBytes = MustSelector("exactOutput(bytes)")
|
|
UniswapV3Multicall = MustSelector("multicall(bytes[])")
|
|
UniswapV3MulticallWithDeadline = MustSelector("multicall(uint256,bytes[])")
|
|
UniswapV3MulticallWithBlockhash = MustSelector("multicall(bytes32,bytes[])")
|
|
UniversalRouterExecute = MustSelector("execute(bytes,bytes[],uint256)")
|
|
UniversalRouterExecutePayable = MustSelector("execute(bytes,bytes[])")
|
|
UniversalRouterExecuteSimple = MustSelector("execute(bytes)")
|
|
)
|
|
|
|
// Balancer V2 selectors
|
|
var (
|
|
BalancerSwap = MustSelector("swap((bytes32,uint8,address,address,uint256,bytes),(address,bool,address,bool),uint256,uint256)")
|
|
BalancerBatchSwap = MustSelector("batchSwap(uint8,(bytes32,uint256,uint256,uint256,bytes)[],address[],(address,bool,address,bool),int256[],uint256)")
|
|
BalancerFlashLoan = MustSelector("flashLoan(address,address[],uint256[],bytes)")
|
|
)
|
|
|
|
// Curve Finance selectors
|
|
var (
|
|
CurveExchange = MustSelector("exchange(int128,int128,uint256,uint256)")
|
|
CurveExchangeUnderlying = MustSelector("exchange_underlying(int128,int128,uint256,uint256)")
|
|
CurveExchangeUint = MustSelector("exchange(uint256,uint256,uint256,uint256)")
|
|
CurveExchangeUnderlyingUint = MustSelector("exchange_underlying(uint256,uint256,uint256,uint256)")
|
|
)
|
|
|
|
// Kyber Elastic (reuses Uniswap V3 style)
|
|
var (
|
|
KyberExactInputSingleLegacy = UniswapV3ExactInputSingleLegacy
|
|
KyberExactInputSingle = UniswapV3ExactInputSingle
|
|
KyberExactInput = UniswapV3ExactInput
|
|
KyberExactOutputSingle = UniswapV3ExactOutputSingle
|
|
KyberExactOutput = UniswapV3ExactOutput
|
|
KyberMulticall = UniswapV3Multicall
|
|
KyberMulticallWithDeadline = UniswapV3MulticallWithDeadline
|
|
KyberMulticallWithBlockhash = UniswapV3MulticallWithBlockhash
|
|
KyberUniversalRouterExecute = UniversalRouterExecute
|
|
KyberUniversalRouterExecutePayable = UniversalRouterExecutePayable
|
|
KyberUniversalRouterExecuteSimple = UniversalRouterExecuteSimple
|
|
)
|
|
|
|
// Kyber Classic shares the Uniswap V2 style router interface.
|
|
var (
|
|
KyberClassicSwapExactTokensForTokens = UniswapV2SwapExactTokensForTokens
|
|
KyberClassicSwapTokensForExactTokens = UniswapV2SwapTokensForExactTokens
|
|
KyberClassicSwapExactETHForTokens = UniswapV2SwapExactETHForTokens
|
|
KyberClassicSwapTokensForExactETH = UniswapV2SwapTokensForExactETH
|
|
KyberClassicSwapExactTokensForETH = UniswapV2SwapExactTokensForETH
|
|
KyberClassicSwapETHForExactTokens = UniswapV2SwapETHForExactTokens
|
|
KyberClassicSwapExactTokensForTokensSupportingFee = UniswapV2SwapExactTokensForTokensSupportingFee
|
|
KyberClassicSwapExactETHForTokensSupportingFee = UniswapV2SwapExactETHForTokensSupportingFee
|
|
KyberClassicSwapExactTokensForETHSupportingFee = UniswapV2SwapExactTokensForETHSupportingFee
|
|
)
|
|
|
|
// PancakeSwap (BSC) uses the Uniswap V2 router interface.
|
|
var (
|
|
PancakeSwapSwapExactTokensForTokens = UniswapV2SwapExactTokensForTokens
|
|
PancakeSwapSwapTokensForExactTokens = UniswapV2SwapTokensForExactTokens
|
|
PancakeSwapSwapExactETHForTokens = UniswapV2SwapExactETHForTokens
|
|
PancakeSwapSwapTokensForExactETH = UniswapV2SwapTokensForExactETH
|
|
PancakeSwapSwapExactTokensForETH = UniswapV2SwapExactTokensForETH
|
|
PancakeSwapSwapETHForExactTokens = UniswapV2SwapETHForExactTokens
|
|
PancakeSwapSwapExactTokensForTokensSupportingFee = UniswapV2SwapExactTokensForTokensSupportingFee
|
|
PancakeSwapSwapExactETHForTokensSupportingFee = UniswapV2SwapExactETHForTokensSupportingFee
|
|
PancakeSwapSwapExactTokensForETHSupportingFee = UniswapV2SwapExactTokensForETHSupportingFee
|
|
PancakeSwapAddLiquidity = UniswapV2AddLiquidity
|
|
PancakeSwapAddLiquidityETH = UniswapV2AddLiquidityETH
|
|
)
|
|
|
|
// Trader Joe V2 (AMM) mirrors the Uniswap V2 router interface.
|
|
var (
|
|
TraderJoeSwapExactTokensForTokens = UniswapV2SwapExactTokensForTokens
|
|
TraderJoeSwapTokensForExactTokens = UniswapV2SwapTokensForExactTokens
|
|
TraderJoeSwapExactETHForTokens = UniswapV2SwapExactETHForTokens
|
|
TraderJoeSwapTokensForExactETH = UniswapV2SwapTokensForExactETH
|
|
TraderJoeSwapExactTokensForETH = UniswapV2SwapExactTokensForETH
|
|
TraderJoeSwapETHForExactTokens = UniswapV2SwapETHForExactTokens
|
|
TraderJoeSwapExactTokensForTokensSupportingFee = UniswapV2SwapExactTokensForTokensSupportingFee
|
|
TraderJoeSwapExactETHForTokensSupportingFee = UniswapV2SwapExactETHForTokensSupportingFee
|
|
TraderJoeSwapExactTokensForETHSupportingFee = UniswapV2SwapExactTokensForETHSupportingFee
|
|
TraderJoeAddLiquidity = UniswapV2AddLiquidity
|
|
TraderJoeAddLiquidityETH = UniswapV2AddLiquidityETH
|
|
)
|
|
|
|
// Trader Joe Liquidity Book router specific selectors.
|
|
var (
|
|
TraderJoeLBSwapExactTokensForTokens = MustSelector("swapExactTokensForTokens(uint256,uint256,(uint256[],uint8[],address[]),address,uint256)")
|
|
TraderJoeLBSwapTokensForExactTokens = MustSelector("swapTokensForExactTokens(uint256,uint256,(uint256[],uint8[],address[]),address,uint256)")
|
|
TraderJoeLBSwapExactTokensForNative = MustSelector("swapExactTokensForNATIVE(uint256,uint256,(uint256[],uint8[],address[]),address,uint256)")
|
|
TraderJoeLBSwapExactNativeForTokens = MustSelector("swapExactNATIVEForTokens(uint256,(uint256[],uint8[],address[]),address,uint256)")
|
|
TraderJoeLBSwapTokensForExactNative = MustSelector("swapTokensForExactNATIVE(uint256,uint256,(uint256[],uint8[],address[]),address,uint256)")
|
|
TraderJoeLBSwapExactTokensForTokensSupportingFee = MustSelector("swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256,uint256,(uint256[],uint8[],address[]),address,uint256)")
|
|
TraderJoeLBSwapExactTokensForNativeSupportingFee = MustSelector("swapExactTokensForNATIVESupportingFeeOnTransferTokens(uint256,uint256,(uint256[],uint8[],address[]),address,uint256)")
|
|
TraderJoeLBSwapExactNativeForTokensSupportingFee = MustSelector("swapExactNATIVEForTokensSupportingFeeOnTransferTokens(uint256,(uint256[],uint8[],address[]),address,uint256)")
|
|
TraderJoeLBLiquidityAdd = MustSelector("addLiquidity((address,address,uint256,uint256,uint256,uint256,uint256,uint256,uint256,int256[],uint256[],uint256[],address,address,uint256))")
|
|
TraderJoeLBLiquidityAddNative = MustSelector("addLiquidityNATIVE((address,address,uint256,uint256,uint256,uint256,uint256,uint256,uint256,int256[],uint256[],uint256[],address,address,uint256))")
|
|
TraderJoeLBLiquidityRemove = MustSelector("removeLiquidity(address,address,uint16,uint256,uint256,uint256[],uint256[],address,uint256)")
|
|
TraderJoeLBLiquidityRemoveNative = MustSelector("removeLiquidityNATIVE(address,uint16,uint256,uint256,uint256[],uint256[],address,uint256)")
|
|
)
|
|
|
|
// Camelot V2 uses Uniswap V2 style selectors; Camelot V3 builds on Algebra (Uniswap V3 equivalent).
|
|
var (
|
|
CamelotV2SwapExactTokensForTokens = UniswapV2SwapExactTokensForTokens
|
|
CamelotV2SwapTokensForExactTokens = UniswapV2SwapTokensForExactTokens
|
|
CamelotV2SwapExactETHForTokens = UniswapV2SwapExactETHForTokens
|
|
CamelotV2SwapTokensForExactETH = UniswapV2SwapTokensForExactETH
|
|
CamelotV2SwapExactTokensForETH = UniswapV2SwapExactTokensForETH
|
|
CamelotV2SwapETHForExactTokens = UniswapV2SwapETHForExactTokens
|
|
CamelotV2SwapExactTokensForTokensSupportingFee = UniswapV2SwapExactTokensForTokensSupportingFee
|
|
CamelotV2SwapExactETHForTokensSupportingFee = UniswapV2SwapExactETHForTokensSupportingFee
|
|
CamelotV2SwapExactTokensForETHSupportingFee = UniswapV2SwapExactTokensForETHSupportingFee
|
|
CamelotV2AddLiquidity = UniswapV2AddLiquidity
|
|
CamelotV2AddLiquidityETH = UniswapV2AddLiquidityETH
|
|
|
|
CamelotV3ExactInputSingle = UniswapV3ExactInputSingle
|
|
CamelotV3ExactInput = UniswapV3ExactInput
|
|
CamelotV3ExactOutputSingle = UniswapV3ExactOutputSingle
|
|
CamelotV3ExactOutput = UniswapV3ExactOutput
|
|
CamelotV3Multicall = UniswapV3Multicall
|
|
CamelotV3MulticallWithDeadline = UniswapV3MulticallWithDeadline
|
|
CamelotV3MulticallWithBlockhash = UniswapV3MulticallWithBlockhash
|
|
)
|
|
|
|
// Additional selectors
|
|
var (
|
|
UniswapV2SwapExactTokensForTokensSupportingFeeLegacy = MustSelector("swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256,uint256,address[],address)")
|
|
NonfungiblePositionManagerMint = MustSelector("mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256))")
|
|
)
|