Completed clean root directory structure: - Root now contains only: .git, .env, docs/, orig/ - Moved all remaining files and directories to orig/: - Config files (.claude, .dockerignore, .drone.yml, etc.) - All .env variants (except active .env) - Git config (.gitconfig, .github, .gitignore, etc.) - Tool configs (.golangci.yml, .revive.toml, etc.) - Documentation (*.md files, @prompts) - Build files (Dockerfiles, Makefile, go.mod, go.sum) - Docker compose files - All source directories (scripts, tests, tools, etc.) - Runtime directories (logs, monitoring, reports) - Dependency files (node_modules, lib, cache) - Special files (--delete) - Removed empty runtime directories (bin/, data/) V2 structure is now clean: - docs/planning/ - V2 planning documents - orig/ - Complete V1 codebase preserved - .env - Active environment config (not in git) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
173 lines
4.9 KiB
Go
173 lines
4.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"math/big"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum"
|
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
|
)
|
|
|
|
const uniswapV3PoolABI = `[
|
|
{"name":"token0","type":"function","inputs":[],"outputs":[{"name":"","type":"address"}]},
|
|
{"name":"token1","type":"function","inputs":[],"outputs":[{"name":"","type":"address"}]},
|
|
{"name":"fee","type":"function","inputs":[],"outputs":[{"name":"","type":"uint24"}]},
|
|
{"name":"liquidity","type":"function","inputs":[],"outputs":[{"name":"","type":"uint128"}]},
|
|
{"name":"slot0","type":"function","inputs":[],"outputs":[{"name":"sqrtPriceX96","type":"uint160"},{"name":"tick","type":"int24"},{"name":"observationIndex","type":"uint16"},{"name":"observationCardinality","type":"uint16"},{"name":"observationCardinalityNext","type":"uint16"},{"name":"feeProtocol","type":"uint8"},{"name":"unlocked","type":"bool"}]}
|
|
]`
|
|
|
|
func main() {
|
|
// Connect to Arbitrum
|
|
client, err := ethclient.Dial("https://arb1.arbitrum.io/rpc")
|
|
if err != nil {
|
|
log.Fatal("Failed to connect:", err)
|
|
}
|
|
|
|
// Parse the ABI
|
|
poolABI, err := abi.JSON(strings.NewReader(uniswapV3PoolABI))
|
|
if err != nil {
|
|
log.Fatal("Failed to parse ABI:", err)
|
|
}
|
|
|
|
fmt.Println("Testing UniswapV3 Pool Calls")
|
|
fmt.Println("============================")
|
|
fmt.Println()
|
|
|
|
// Test known good pools
|
|
goodPools := []struct {
|
|
address string
|
|
name string
|
|
}{
|
|
{"0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443", "WETH/USDC.e 0.05%"},
|
|
{"0x641C00A822e8b671738d32a431a4Fb6074E5c79d", "USDT/WETH 0.05%"},
|
|
{"0x2f5e87C9312fa29aed5c179E456625D79015299c", "WBTC/WETH 0.05%"},
|
|
{"0x6f38e884725a116C9C7fBF208e79FE8828a2595F", "WETH/USDC 0.05%"},
|
|
}
|
|
|
|
fmt.Println("Testing Known Good UniswapV3 Pools:")
|
|
fmt.Println("-----------------------------------")
|
|
for _, pool := range goodPools {
|
|
testPool(client, poolABI, pool.address, pool.name)
|
|
}
|
|
|
|
// Test problematic pools from blacklist
|
|
blacklistedPools := []string{
|
|
"0x7760cfd39f8fc36239c7299851d8b334cc5acbed",
|
|
"0xe0571fecab07216cae82a0af3f44e7ea7aff8426",
|
|
"0x8d17b1ce5132b327981dcea21cb183b9a3e1c177",
|
|
}
|
|
|
|
fmt.Println("\nTesting Blacklisted Pools:")
|
|
fmt.Println("--------------------------")
|
|
for _, pool := range blacklistedPools {
|
|
testPool(client, poolABI, pool, "Blacklisted")
|
|
}
|
|
}
|
|
|
|
func testPool(client *ethclient.Client, poolABI abi.ABI, poolHex string, name string) {
|
|
poolAddress := common.HexToAddress(poolHex)
|
|
fmt.Printf("\nPool: %s (%s)\n", poolHex[:10]+"...", name)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
// Check if contract exists
|
|
code, err := client.CodeAt(ctx, poolAddress, nil)
|
|
if err != nil || len(code) == 0 {
|
|
fmt.Println(" ❌ No contract at this address")
|
|
return
|
|
}
|
|
fmt.Printf(" ✅ Contract exists (%d bytes)\n", len(code))
|
|
|
|
// Test token0()
|
|
token0Data, err := poolABI.Pack("token0")
|
|
if err != nil {
|
|
fmt.Printf(" ❌ Failed to pack token0: %v\n", err)
|
|
return
|
|
}
|
|
|
|
result, err := client.CallContract(ctx, ethereum.CallMsg{
|
|
To: &poolAddress,
|
|
Data: token0Data,
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
fmt.Printf(" ❌ token0() failed: %v\n", err)
|
|
} else {
|
|
var token0 common.Address
|
|
err = poolABI.UnpackIntoInterface(&token0, "token0", result)
|
|
if err != nil {
|
|
fmt.Printf(" ❌ Failed to unpack token0: %v\n", err)
|
|
} else {
|
|
fmt.Printf(" ✅ token0: %s\n", token0.Hex())
|
|
}
|
|
}
|
|
|
|
// Test token1()
|
|
token1Data, err := poolABI.Pack("token1")
|
|
if err != nil {
|
|
fmt.Printf(" ❌ Failed to pack token1: %v\n", err)
|
|
return
|
|
}
|
|
|
|
result, err = client.CallContract(ctx, ethereum.CallMsg{
|
|
To: &poolAddress,
|
|
Data: token1Data,
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
fmt.Printf(" ❌ token1() failed: %v\n", err)
|
|
} else {
|
|
var token1 common.Address
|
|
err = poolABI.UnpackIntoInterface(&token1, "token1", result)
|
|
if err != nil {
|
|
fmt.Printf(" ❌ Failed to unpack token1: %v\n", err)
|
|
} else {
|
|
fmt.Printf(" ✅ token1: %s\n", token1.Hex())
|
|
}
|
|
}
|
|
|
|
// Test fee()
|
|
feeData, err := poolABI.Pack("fee")
|
|
if err != nil {
|
|
fmt.Printf(" ❌ Failed to pack fee: %v\n", err)
|
|
return
|
|
}
|
|
|
|
result, err = client.CallContract(ctx, ethereum.CallMsg{
|
|
To: &poolAddress,
|
|
Data: feeData,
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
fmt.Printf(" ❌ fee() failed: %v\n", err)
|
|
} else {
|
|
var fee *big.Int
|
|
err = poolABI.UnpackIntoInterface(&fee, "fee", result)
|
|
if err != nil {
|
|
fmt.Printf(" ❌ Failed to unpack fee: %v\n", err)
|
|
} else {
|
|
fmt.Printf(" ✅ fee: %d (%.2f%%)\n", fee, float64(fee.Int64())/10000)
|
|
}
|
|
}
|
|
|
|
// Test using raw selectors
|
|
fmt.Println(" Testing with raw selectors:")
|
|
token0Selector := []byte{0x0d, 0xfe, 0x16, 0x81}
|
|
result, err = client.CallContract(ctx, ethereum.CallMsg{
|
|
To: &poolAddress,
|
|
Data: token0Selector,
|
|
}, nil)
|
|
if err != nil {
|
|
fmt.Printf(" ❌ Raw token0() failed: %v\n", err)
|
|
} else if len(result) >= 32 {
|
|
fmt.Printf(" ✅ Raw token0(): 0x%x\n", result[12:32])
|
|
}
|
|
}
|