Files
mev-beta/scripts/identify-pool.go

207 lines
6.8 KiB
Go

package main
import (
"context"
"fmt"
"log"
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
// Pool to identify
poolAddr := common.HexToAddress("0xC6962004f452bE9203591991D15f6b388e09E8D0")
fmt.Println("========================================")
fmt.Printf("Identifying Pool: %s\n", poolAddr.Hex())
fmt.Println("========================================")
fmt.Println()
// Connect to Arbitrum
client, err := ethclient.Dial("https://arb1.arbitrum.io/rpc")
if err != nil {
log.Fatal("Failed to connect:", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// First check if contract exists
code, err := client.CodeAt(ctx, poolAddr, nil)
if err != nil {
log.Fatal("Failed to get contract code:", err)
}
if len(code) == 0 {
fmt.Println("❌ NO CONTRACT AT THIS ADDRESS")
return
}
fmt.Printf("✅ Contract exists (%d bytes)\n", len(code))
fmt.Println()
// Method selectors for detection
selectors := map[string][]byte{
"token0": {0x0d, 0xfe, 0x16, 0x81}, // Common to many DEXs
"token1": {0xd2, 0x12, 0x20, 0xa7}, // Correct selector for token1()
"fee": {0xdd, 0xca, 0x3f, 0x43}, // UniswapV3
"slot0": {0x38, 0x50, 0xc7, 0xbd}, // UniswapV3
"globalState": {0x13, 0xaf, 0x40, 0x35}, // Algebra
"getReserves": {0x09, 0x02, 0xf1, 0xac}, // UniswapV2
"liquidity": {0x1a, 0x68, 0x6d, 0x0f}, // UniswapV3
"factory": {0xc4, 0x5a, 0x01, 0x55}, // Common
"tickSpacing": {0xd0, 0xc9, 0x38, 0x91}, // UniswapV3
"maxLiquidityPerTick": {0x70, 0xcf, 0x75, 0x4a}, // UniswapV3
"sqrtPriceX96": {0x88, 0x5a, 0xdb, 0x02}, // Some V3 variants
"observations": {0x25, 0x2c, 0x09, 0xd7}, // UniswapV3
"feeGrowthGlobal0X128":{0xf3, 0x05, 0x83, 0x99}, // UniswapV3
"feeGrowthGlobal1X128":{0x46, 0x14, 0x16, 0x27}, // UniswapV3
}
fmt.Println("Testing Method Signatures:")
fmt.Println("--------------------------")
results := make(map[string]bool)
tokenAddresses := make(map[string]common.Address)
for name, selector := range selectors {
result, err := client.CallContract(ctx, ethereum.CallMsg{
To: &poolAddr,
Data: selector,
}, nil)
if err == nil && len(result) > 0 {
results[name] = true
fmt.Printf("✅ %s(): SUCCESS", name)
// Extract token addresses if applicable
if name == "token0" || name == "token1" {
if len(result) >= 32 {
addr := common.BytesToAddress(result[12:32])
tokenAddresses[name] = addr
fmt.Printf(" -> %s", addr.Hex())
}
}
// Show fee value
if name == "fee" && len(result) >= 32 {
// Fee is uint24, stored in the last 3 bytes of the 32-byte word
fee := uint32(result[29])<<16 | uint32(result[30])<<8 | uint32(result[31])
fmt.Printf(" -> %d (%.2f%%)", fee, float64(fee)/10000)
}
fmt.Println()
} else {
results[name] = false
if err != nil {
fmt.Printf("❌ %s(): FAILED - %v\n", name, err)
} else {
fmt.Printf("❌ %s(): FAILED - empty result\n", name)
}
}
}
fmt.Println()
fmt.Println("Analysis:")
fmt.Println("---------")
// Analyze results
hasToken0 := results["token0"]
hasToken1 := results["token1"]
hasFee := results["fee"]
hasSlot0 := results["slot0"]
hasGlobalState := results["globalState"]
hasGetReserves := results["getReserves"]
hasLiquidity := results["liquidity"]
hasTickSpacing := results["tickSpacing"]
hasMaxLiquidityPerTick := results["maxLiquidityPerTick"]
hasFeeGrowthGlobal0 := results["feeGrowthGlobal0X128"]
hasFeeGrowthGlobal1 := results["feeGrowthGlobal1X128"]
fmt.Printf("Has token0/token1: %v/%v\n", hasToken0, hasToken1)
fmt.Printf("Has fee: %v\n", hasFee)
fmt.Printf("Has slot0: %v\n", hasSlot0)
fmt.Printf("Has globalState: %v\n", hasGlobalState)
fmt.Printf("Has getReserves: %v\n", hasGetReserves)
fmt.Printf("Has liquidity: %v\n", hasLiquidity)
fmt.Printf("Has tickSpacing: %v\n", hasTickSpacing)
fmt.Printf("Has maxLiquidityPerTick: %v\n", hasMaxLiquidityPerTick)
fmt.Printf("Has feeGrowthGlobal0/1: %v/%v\n", hasFeeGrowthGlobal0, hasFeeGrowthGlobal1)
fmt.Println()
fmt.Println("========================================")
fmt.Println("IDENTIFICATION RESULT:")
fmt.Println("========================================")
// Identification logic
if hasToken0 && hasToken1 && hasSlot0 && hasFee && hasTickSpacing && hasMaxLiquidityPerTick {
fmt.Println("✅ Pool Type: UNISWAP V3")
fmt.Println(" Confidence: 95%")
fmt.Println(" Reason: Has all UniswapV3 signature methods")
if token0, ok := tokenAddresses["token0"]; ok {
fmt.Printf(" Token0: %s\n", token0.Hex())
}
if token1, ok := tokenAddresses["token1"]; ok {
fmt.Printf(" Token1: %s\n", token1.Hex())
}
} else if hasToken0 && hasToken1 && hasGlobalState && !hasSlot0 {
fmt.Println("✅ Pool Type: ALGEBRA-BASED (Camelot/QuickSwap V3)")
fmt.Println(" Confidence: 90%")
fmt.Println(" Reason: Has globalState instead of slot0")
} else if hasToken0 && hasToken1 && hasGetReserves && !hasSlot0 && !hasGlobalState {
fmt.Println("✅ Pool Type: UNISWAP V2 / SUSHISWAP")
fmt.Println(" Confidence: 85%")
fmt.Println(" Reason: Has getReserves, no slot0/globalState")
} else if hasToken0 && hasToken1 {
fmt.Println("⚠️ Pool Type: UNKNOWN DEX")
fmt.Println(" Confidence: 30%")
fmt.Println(" Reason: Has basic token methods but doesn't match known patterns")
} else {
fmt.Println("❌ Pool Type: NOT A STANDARD AMM POOL")
fmt.Println(" Reason: Missing basic token methods")
}
// Additional checks
fmt.Println()
fmt.Println("Additional Information:")
fmt.Println("----------------------")
// Check factory
factorySelector := []byte{0xc4, 0x5a, 0x01, 0x55}
factoryResult, err := client.CallContract(ctx, ethereum.CallMsg{
To: &poolAddr,
Data: factorySelector,
}, nil)
if err == nil && len(factoryResult) >= 32 {
factory := common.BytesToAddress(factoryResult[12:32])
fmt.Printf("Factory: %s\n", factory.Hex())
// Check known factories
knownFactories := map[common.Address]string{
common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"): "UniswapV3 Factory",
common.HexToAddress("0xc35DADB65012eC5796536bD9864eD8773aBc74C4"): "Sushiswap Factory",
common.HexToAddress("0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865"): "PancakeSwap V3 Factory",
}
if name, known := knownFactories[factory]; known {
fmt.Printf(" ✅ Known Factory: %s\n", name)
}
}
// Try to get current price/state
if hasSlot0 {
slot0Selector := []byte{0x38, 0x50, 0xc7, 0xbd}
slot0Result, err := client.CallContract(ctx, ethereum.CallMsg{
To: &poolAddr,
Data: slot0Selector,
}, nil)
if err == nil && len(slot0Result) >= 32 {
fmt.Println("Slot0 data available (price and tick info)")
}
}
}