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:
Administrator
2025-11-10 10:14:26 +01:00
parent 1773daffe7
commit 803de231ba
411 changed files with 20390 additions and 8680 deletions

View File

@@ -0,0 +1,346 @@
package calculation_validation
import (
"math/big"
"testing"
)
func TestValidateThresholdCheck(t *testing.T) {
validator := NewProfitValidator(1.0)
tests := []struct {
name string
check *ThresholdCheck
wantValid bool
}{
{
name: "valid executable - profit above threshold",
check: &ThresholdCheck{
NetProfit: big.NewFloat(834.210302),
MinThreshold: big.NewFloat(0.0001),
Passed: true,
},
wantValid: true,
},
{
name: "valid rejection - profit below threshold",
check: &ThresholdCheck{
NetProfit: big.NewFloat(0.00001),
MinThreshold: big.NewFloat(0.0001),
Passed: false,
},
wantValid: true,
},
{
name: "invalid - should pass but marked failed",
check: &ThresholdCheck{
NetProfit: big.NewFloat(1.0),
MinThreshold: big.NewFloat(0.0001),
Passed: false, // Wrong!
},
wantValid: false,
},
{
name: "edge case - profit equals threshold",
check: &ThresholdCheck{
NetProfit: big.NewFloat(0.0001),
MinThreshold: big.NewFloat(0.0001),
Passed: true,
},
wantValid: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
valid := validator.validateThresholdCheck(tt.check)
if valid != tt.wantValid {
t.Errorf("validateThresholdCheck() = %v, want %v", valid, tt.wantValid)
}
})
}
}
func TestValidateThresholdComparison(t *testing.T) {
validator := NewProfitValidator(1.0)
minThresholdWei := big.NewInt(100000000000000) // 0.0001 ETH
tests := []struct {
name string
netProfit *big.Float
shouldExecute bool
wantValid bool
wantExecutable bool
}{
{
name: "bug fix scenario - 834 ETH",
netProfit: big.NewFloat(834.210302),
shouldExecute: true,
wantValid: true,
wantExecutable: true,
},
{
name: "below threshold",
netProfit: big.NewFloat(0.00001),
shouldExecute: false,
wantValid: true,
wantExecutable: false,
},
{
name: "exactly at threshold",
netProfit: big.NewFloat(0.0001),
shouldExecute: true,
wantValid: true,
wantExecutable: true,
},
{
name: "large profit",
netProfit: big.NewFloat(1249.324868),
shouldExecute: true,
wantValid: true,
wantExecutable: true,
},
{
name: "buggy comparison - should reject but marked executable",
netProfit: big.NewFloat(0.00001),
shouldExecute: true, // Wrong!
wantValid: false,
wantExecutable: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := validator.ValidateThresholdComparison(tt.netProfit, minThresholdWei, tt.shouldExecute)
if result.IsValid != tt.wantValid {
t.Errorf("ValidateThresholdComparison() valid = %v, want %v", result.IsValid, tt.wantValid)
if len(result.Errors) > 0 {
t.Logf("Errors: %v", result.Errors)
}
}
})
}
}
func TestValidateV3Calculation(t *testing.T) {
validator := NewProfitValidator(1.0)
tests := []struct {
name string
calc SwapCalculation
wantValid bool
wantWarns bool
}{
{
name: "valid calculation with 0.3% fee",
calc: SwapCalculation{
AmountIn: big.NewInt(1000000),
AmountOut: big.NewInt(995000),
Fee: 3000,
FinalOut: big.NewInt(992015), // ~0.3% less
},
wantValid: true,
wantWarns: false,
},
{
name: "zero output",
calc: SwapCalculation{
AmountIn: big.NewInt(1000000),
AmountOut: big.NewInt(0),
Fee: 3000,
FinalOut: big.NewInt(0),
},
wantValid: true,
wantWarns: true,
},
{
name: "invalid - finalOut > amountOut",
calc: SwapCalculation{
AmountIn: big.NewInt(1000000),
AmountOut: big.NewInt(1000000),
Fee: 3000,
FinalOut: big.NewInt(1100000), // Impossible!
},
wantValid: false,
wantWarns: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := validator.ValidateV3Calculation(tt.calc)
if result.IsValid != tt.wantValid {
t.Errorf("ValidateV3Calculation() valid = %v, want %v", result.IsValid, tt.wantValid)
if len(result.Errors) > 0 {
t.Logf("Errors: %v", result.Errors)
}
}
hasWarnings := len(result.Warnings) > 0
if hasWarnings != tt.wantWarns {
t.Errorf("ValidateV3Calculation() warnings = %v, want %v", hasWarnings, tt.wantWarns)
}
})
}
}
func TestCompareETHtoWei(t *testing.T) {
validator := NewProfitValidator(1.0)
tests := []struct {
name string
ethValue *big.Float
weiValue *big.Int
wantValid bool
}{
{
name: "correct conversion - 1 ETH",
ethValue: big.NewFloat(1.0),
weiValue: big.NewInt(1e18),
wantValid: true,
},
{
name: "correct conversion - 0.0001 ETH",
ethValue: big.NewFloat(0.0001),
weiValue: big.NewInt(1e14),
wantValid: true,
},
{
name: "incorrect conversion - off by factor of 1000",
ethValue: big.NewFloat(1.0),
weiValue: big.NewInt(1e15), // Wrong!
wantValid: false,
},
{
name: "bug scenario - using Int(nil) without scaling",
ethValue: big.NewFloat(834.210302),
weiValue: big.NewInt(834), // Buggy conversion!
wantValid: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := validator.CompareETHtoWei(tt.ethValue, tt.weiValue)
if result.IsValid != tt.wantValid {
t.Errorf("CompareETHtoWei() valid = %v, want %v", result.IsValid, tt.wantValid)
if len(result.Errors) > 0 {
t.Logf("Errors: %v", result.Errors)
}
}
})
}
}
func TestCalculateStatistics(t *testing.T) {
profits := []*big.Float{
big.NewFloat(0.311819),
big.NewFloat(1249.324868),
big.NewFloat(2.166576),
big.NewFloat(1363.860509),
big.NewFloat(83.981698),
}
total, average, max, min := CalculateStatistics(profits)
// Verify total
expectedTotal := 2699.645470 // Sum of all values
totalFloat, _ := total.Float64()
if diff := totalFloat - expectedTotal; diff > 0.0001 || diff < -0.0001 {
t.Errorf("Total = %.6f, want %.6f", totalFloat, expectedTotal)
}
// Verify average
expectedAvg := expectedTotal / 5.0
avgFloat, _ := average.Float64()
if diff := avgFloat - expectedAvg; diff > 0.0001 || diff < -0.0001 {
t.Errorf("Average = %.6f, want %.6f", avgFloat, expectedAvg)
}
// Verify max
maxFloat, _ := max.Float64()
if maxFloat != 1363.860509 {
t.Errorf("Max = %.6f, want 1363.860509", maxFloat)
}
// Verify min
minFloat, _ := min.Float64()
if minFloat != 0.311819 {
t.Errorf("Min = %.6f, want 0.311819", minFloat)
}
}
func TestValidateOpportunity(t *testing.T) {
validator := NewProfitValidator(1.0)
tests := []struct {
name string
opp *OpportunityTestData
wantValid bool
wantErrs int
wantWarns int
}{
{
name: "valid executable opportunity",
opp: &OpportunityTestData{
ID: "test_1",
NetProfitETH: big.NewFloat(1.0),
IsExecutable: true,
RejectReason: "",
ThresholdCheck: &ThresholdCheck{
NetProfit: big.NewFloat(1.0),
MinThreshold: big.NewFloat(0.0001),
Passed: true,
},
},
wantValid: true,
wantErrs: 0,
wantWarns: 0,
},
{
name: "invalid - executable but zero profit",
opp: &OpportunityTestData{
ID: "test_2",
NetProfitETH: big.NewFloat(0.0),
IsExecutable: true,
RejectReason: "",
},
wantValid: false,
wantErrs: 1,
wantWarns: 0,
},
{
name: "warning - executable but has reject reason",
opp: &OpportunityTestData{
ID: "test_3",
NetProfitETH: big.NewFloat(1.0),
IsExecutable: true,
RejectReason: "some reason",
},
wantValid: true,
wantErrs: 0,
wantWarns: 1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := validator.ValidateOpportunity(tt.opp)
if result.IsValid != tt.wantValid {
t.Errorf("ValidateOpportunity() valid = %v, want %v", result.IsValid, tt.wantValid)
}
if len(result.Errors) != tt.wantErrs {
t.Errorf("ValidateOpportunity() errors = %d, want %d: %v", len(result.Errors), tt.wantErrs, result.Errors)
}
if len(result.Warnings) != tt.wantWarns {
t.Errorf("ValidateOpportunity() warnings = %d, want %d: %v", len(result.Warnings), tt.wantWarns, result.Warnings)
}
})
}
}