feat: create v2-prep branch with comprehensive planning
Restructured project for V2 refactor: **Structure Changes:** - Moved all V1 code to orig/ folder (preserved with git mv) - Created docs/planning/ directory - Added orig/README_V1.md explaining V1 preservation **Planning Documents:** - 00_V2_MASTER_PLAN.md: Complete architecture overview - Executive summary of critical V1 issues - High-level component architecture diagrams - 5-phase implementation roadmap - Success metrics and risk mitigation - 07_TASK_BREAKDOWN.md: Atomic task breakdown - 99+ hours of detailed tasks - Every task < 2 hours (atomic) - Clear dependencies and success criteria - Organized by implementation phase **V2 Key Improvements:** - Per-exchange parsers (factory pattern) - Multi-layer strict validation - Multi-index pool cache - Background validation pipeline - Comprehensive observability **Critical Issues Addressed:** - Zero address tokens (strict validation + cache enrichment) - Parsing accuracy (protocol-specific parsers) - No audit trail (background validation channel) - Inefficient lookups (multi-index cache) - Stats disconnection (event-driven metrics) Next Steps: 1. Review planning documents 2. Begin Phase 1: Foundation (P1-001 through P1-010) 3. Implement parsers in Phase 2 4. Build cache system in Phase 3 5. Add validation pipeline in Phase 4 6. Migrate and test in Phase 5 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1898
orig/pkg/events/parser.go
Normal file
1898
orig/pkg/events/parser.go
Normal file
File diff suppressed because it is too large
Load Diff
197
orig/pkg/events/parser_test.go
Normal file
197
orig/pkg/events/parser_test.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEventTypeString(t *testing.T) {
|
||||
assert.Equal(t, "Unknown", Unknown.String())
|
||||
assert.Equal(t, "Swap", Swap.String())
|
||||
assert.Equal(t, "AddLiquidity", AddLiquidity.String())
|
||||
assert.Equal(t, "RemoveLiquidity", RemoveLiquidity.String())
|
||||
assert.Equal(t, "NewPool", NewPool.String())
|
||||
assert.Equal(t, "Unknown", EventType(999).String()) // Test unknown value
|
||||
}
|
||||
|
||||
func TestNewEventParser(t *testing.T) {
|
||||
parser := NewEventParser()
|
||||
assert.NotNil(t, parser)
|
||||
assert.NotNil(t, parser.knownPools)
|
||||
assert.NotEmpty(t, parser.knownPools)
|
||||
}
|
||||
|
||||
func TestIsDEXInteraction(t *testing.T) {
|
||||
parser := NewEventParser()
|
||||
|
||||
// Test with Uniswap V2 factory address
|
||||
tx1 := types.NewTransaction(0, parser.UniswapV2Factory, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.True(t, parser.IsDEXInteraction(tx1))
|
||||
|
||||
// Test with Uniswap V3 factory address
|
||||
tx2 := types.NewTransaction(0, parser.UniswapV3Factory, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.True(t, parser.IsDEXInteraction(tx2))
|
||||
|
||||
// Test with SushiSwap factory address
|
||||
tx3 := types.NewTransaction(0, parser.SushiSwapFactory, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.True(t, parser.IsDEXInteraction(tx3))
|
||||
|
||||
// Test with Uniswap V2 router address
|
||||
tx4 := types.NewTransaction(0, parser.UniswapV2Router02, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.True(t, parser.IsDEXInteraction(tx4))
|
||||
|
||||
// Test with a known pool address
|
||||
poolAddr := common.HexToAddress("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640")
|
||||
parser.AddKnownPool(poolAddr, "UniswapV3")
|
||||
tx5 := types.NewTransaction(0, poolAddr, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.True(t, parser.IsDEXInteraction(tx5))
|
||||
|
||||
// Test with a random address (should be false)
|
||||
randomAddr := common.HexToAddress("0x1234567890123456789012345678901234567890")
|
||||
tx6 := types.NewTransaction(0, randomAddr, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.False(t, parser.IsDEXInteraction(tx6))
|
||||
|
||||
// Test with contract creation transaction (nil To address)
|
||||
tx7 := types.NewContractCreation(0, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.False(t, parser.IsDEXInteraction(tx7))
|
||||
}
|
||||
|
||||
func TestIdentifyProtocol(t *testing.T) {
|
||||
parser := NewEventParser()
|
||||
|
||||
// Test with Uniswap V2 factory address
|
||||
tx1 := types.NewTransaction(0, parser.UniswapV2Factory, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.Equal(t, "UniswapV2", parser.identifyProtocol(tx1))
|
||||
|
||||
// Test with Uniswap V3 factory address
|
||||
tx2 := types.NewTransaction(0, parser.UniswapV3Factory, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.Equal(t, "UniswapV3", parser.identifyProtocol(tx2))
|
||||
|
||||
// Test with SushiSwap factory address
|
||||
tx3 := types.NewTransaction(0, parser.SushiSwapFactory, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.Equal(t, "SushiSwap", parser.identifyProtocol(tx3))
|
||||
|
||||
// Test with Uniswap V2 router address
|
||||
tx4 := types.NewTransaction(0, parser.UniswapV2Router02, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.Equal(t, "UniswapV2", parser.identifyProtocol(tx4))
|
||||
|
||||
// Test with a known pool address
|
||||
poolAddr := common.HexToAddress("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640")
|
||||
parser.AddKnownPool(poolAddr, "UniswapV3")
|
||||
tx5 := types.NewTransaction(0, poolAddr, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.Equal(t, "UniswapV3", parser.identifyProtocol(tx5))
|
||||
|
||||
// Test with a random address (should be Unknown)
|
||||
randomAddr := common.HexToAddress("0x1234567890123456789012345678901234567890")
|
||||
tx6 := types.NewTransaction(0, randomAddr, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.Equal(t, "Unknown", parser.identifyProtocol(tx6))
|
||||
|
||||
// Test with contract creation transaction (nil To address)
|
||||
tx7 := types.NewContractCreation(0, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
assert.Equal(t, "Unknown", parser.identifyProtocol(tx7))
|
||||
}
|
||||
|
||||
func TestAddKnownPoolAndGetKnownPools(t *testing.T) {
|
||||
parser := NewEventParser()
|
||||
initialCount := len(parser.GetKnownPools())
|
||||
|
||||
// Add a new pool
|
||||
addr := common.HexToAddress("0x1234567890123456789012345678901234567890")
|
||||
parser.AddKnownPool(addr, "TestProtocol")
|
||||
|
||||
// Check that the pool was added
|
||||
pools := parser.GetKnownPools()
|
||||
assert.Equal(t, initialCount+1, len(pools))
|
||||
assert.Equal(t, "TestProtocol", pools[addr])
|
||||
|
||||
// Add another pool
|
||||
addr2 := common.HexToAddress("0xabcdefabcdefabcdefabcdefabcdefabcdefabcd")
|
||||
parser.AddKnownPool(addr2, "AnotherProtocol")
|
||||
|
||||
// Check that both pools are in the map
|
||||
pools = parser.GetKnownPools()
|
||||
assert.Equal(t, initialCount+2, len(pools))
|
||||
assert.Equal(t, "TestProtocol", pools[addr])
|
||||
assert.Equal(t, "AnotherProtocol", pools[addr2])
|
||||
}
|
||||
|
||||
func TestParseTransaction(t *testing.T) {
|
||||
parser := NewEventParser()
|
||||
|
||||
// Create a realistic swap transaction data
|
||||
// This represents a Uniswap V3 exactInputSingle call
|
||||
data := make([]byte, 260) // Function selector (4) + 8 parameters * 32 bytes (256)
|
||||
// Function selector for exactInputSingle (first 4 bytes)
|
||||
copy(data[0:4], []byte{0x41, 0x4b, 0xf3, 0x89}) // exactInputSingle selector
|
||||
|
||||
// Match exact offsets that the parser expects:
|
||||
// tokenIn at data[12:32] (parser expects this)
|
||||
copy(data[12:32], common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48").Bytes())
|
||||
|
||||
// tokenOut at data[44:64] (parser expects this)
|
||||
copy(data[44:64], common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1").Bytes())
|
||||
|
||||
// fee at data[64:96] (parser expects this)
|
||||
fee := big.NewInt(3000)
|
||||
feeBytes := make([]byte, 32)
|
||||
fee.FillBytes(feeBytes)
|
||||
copy(data[64:96], feeBytes)
|
||||
|
||||
// amountIn at data[160:192] (parser expects this)
|
||||
amountIn := big.NewInt(1000000000)
|
||||
amountInBytes := make([]byte, 32)
|
||||
amountIn.FillBytes(amountInBytes)
|
||||
copy(data[160:192], amountInBytes)
|
||||
|
||||
// amountOutMin at data[192:224] (parser expects this)
|
||||
amountOutMin := big.NewInt(1000000000000000000) // 1 ETH
|
||||
amountOutMinBytes := make([]byte, 32)
|
||||
amountOutMin.FillBytes(amountOutMinBytes)
|
||||
copy(data[192:224], amountOutMinBytes)
|
||||
|
||||
// Create a transaction to a known router
|
||||
tx := types.NewTransaction(0, parser.UniswapV3Router, big.NewInt(0), 300000, big.NewInt(1000000000), data)
|
||||
blockNumber := uint64(12345)
|
||||
timestamp := uint64(1620000000)
|
||||
|
||||
// Parse the transaction
|
||||
events, err := parser.ParseTransaction(tx, blockNumber, timestamp)
|
||||
|
||||
// The transaction should parse without error but may not generate events
|
||||
// if it doesn't meet significance thresholds or other criteria
|
||||
assert.NoError(t, err)
|
||||
|
||||
// The parser may return 0 events if the transaction doesn't meet criteria
|
||||
// or 1+ events if it does. Both are valid outcomes for this test.
|
||||
assert.GreaterOrEqual(t, len(events), 0)
|
||||
|
||||
if len(events) > 0 {
|
||||
event := events[0]
|
||||
assert.Equal(t, blockNumber, event.BlockNumber)
|
||||
assert.Equal(t, timestamp, event.Timestamp)
|
||||
assert.Equal(t, tx.Hash(), event.TransactionHash)
|
||||
// The parser appends the parsed fee to the protocol name
|
||||
// The actual fee value being parsed may differ due to encoding
|
||||
assert.Contains(t, event.Protocol, "UniswapV3_fee_")
|
||||
assert.NotEmpty(t, event.Protocol)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTransactionNonDEX(t *testing.T) {
|
||||
parser := NewEventParser()
|
||||
|
||||
// Create a transaction that doesn't interact with a DEX
|
||||
randomAddr := common.HexToAddress("0x1234567890123456789012345678901234567890")
|
||||
tx := types.NewTransaction(0, randomAddr, big.NewInt(0), 0, big.NewInt(0), nil)
|
||||
blockNumber := uint64(12345)
|
||||
timestamp := uint64(1620000000)
|
||||
|
||||
// Parse the transaction
|
||||
events, err := parser.ParseTransaction(tx, blockNumber, timestamp)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, events, 0)
|
||||
}
|
||||
Reference in New Issue
Block a user