refactor: move all remaining files to orig/ directory
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>
This commit is contained in:
239
orig/tests/calculation-validation/validator.go
Normal file
239
orig/tests/calculation-validation/validator.go
Normal file
@@ -0,0 +1,239 @@
|
||||
package calculation_validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// ProfitValidator validates arbitrage profit calculations
|
||||
type ProfitValidator struct {
|
||||
weiPerEth *big.Int
|
||||
tolerance float64 // Acceptable percentage difference
|
||||
}
|
||||
|
||||
// NewProfitValidator creates a new profit validator
|
||||
func NewProfitValidator(tolerancePercent float64) *ProfitValidator {
|
||||
return &ProfitValidator{
|
||||
weiPerEth: big.NewInt(1e18),
|
||||
tolerance: tolerancePercent,
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateOpportunity validates an opportunity's profit calculation
|
||||
func (pv *ProfitValidator) ValidateOpportunity(opp *OpportunityTestData) *ValidationResult {
|
||||
result := &ValidationResult{
|
||||
OpportunityID: opp.ID,
|
||||
IsValid: true,
|
||||
Errors: []string{},
|
||||
Warnings: []string{},
|
||||
}
|
||||
|
||||
// Validate threshold check
|
||||
if opp.ThresholdCheck != nil {
|
||||
thresholdValid := pv.validateThresholdCheck(opp.ThresholdCheck)
|
||||
if !thresholdValid {
|
||||
result.Errors = append(result.Errors, "threshold check failed")
|
||||
result.IsValid = false
|
||||
}
|
||||
}
|
||||
|
||||
// Validate profit values
|
||||
if opp.NetProfitETH != nil {
|
||||
result.ExpectedProfit = opp.NetProfitETH
|
||||
|
||||
// Check if profit is positive
|
||||
if opp.NetProfitETH.Sign() <= 0 && opp.IsExecutable {
|
||||
result.Errors = append(result.Errors, "executable opportunity has non-positive profit")
|
||||
result.IsValid = false
|
||||
}
|
||||
|
||||
// Check if profit meets threshold
|
||||
if opp.ThresholdCheck != nil && opp.IsExecutable {
|
||||
if opp.NetProfitETH.Cmp(opp.ThresholdCheck.MinThreshold) < 0 {
|
||||
result.Errors = append(result.Errors, "executable opportunity below minimum threshold")
|
||||
result.IsValid = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate rejection reason consistency
|
||||
if opp.IsExecutable && opp.RejectReason != "" {
|
||||
result.Warnings = append(result.Warnings, "executable opportunity has reject reason")
|
||||
}
|
||||
|
||||
if !opp.IsExecutable && opp.RejectReason == "" {
|
||||
result.Warnings = append(result.Warnings, "non-executable opportunity missing reject reason")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// validateThresholdCheck validates a threshold check calculation
|
||||
func (pv *ProfitValidator) validateThresholdCheck(check *ThresholdCheck) bool {
|
||||
if check == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify the comparison is correct
|
||||
expected := check.NetProfit.Cmp(check.MinThreshold) >= 0
|
||||
if expected != check.Passed {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ValidateV3Calculation validates a V3 swap calculation
|
||||
func (pv *ProfitValidator) ValidateV3Calculation(calc SwapCalculation) *ValidationResult {
|
||||
result := &ValidationResult{
|
||||
OpportunityID: "v3_calculation",
|
||||
IsValid: true,
|
||||
Errors: []string{},
|
||||
Warnings: []string{},
|
||||
}
|
||||
|
||||
// Check for zero outputs
|
||||
if calc.AmountOut.Sign() == 0 && calc.AmountIn.Sign() > 0 {
|
||||
result.Warnings = append(result.Warnings, "zero output with non-zero input")
|
||||
}
|
||||
|
||||
// Check if finalOut matches amountOut (should be slightly less due to fees)
|
||||
if calc.FinalOut.Cmp(calc.AmountOut) > 0 {
|
||||
result.Errors = append(result.Errors, "finalOut greater than amountOut (impossible)")
|
||||
result.IsValid = false
|
||||
}
|
||||
|
||||
// Calculate expected fee deduction
|
||||
expectedFee := pv.calculateV3Fee(calc.AmountOut, calc.Fee)
|
||||
expectedFinalOut := new(big.Int).Sub(calc.AmountOut, expectedFee)
|
||||
|
||||
// Check if finalOut is within tolerance
|
||||
diff := new(big.Int).Sub(expectedFinalOut, calc.FinalOut)
|
||||
diff.Abs(diff)
|
||||
|
||||
// Allow 1% difference for rounding
|
||||
tolerance := new(big.Int).Div(calc.FinalOut, big.NewInt(100))
|
||||
if diff.Cmp(tolerance) > 0 && calc.FinalOut.Sign() > 0 {
|
||||
result.Warnings = append(result.Warnings,
|
||||
fmt.Sprintf("finalOut differs from expected: got %s, expected ~%s",
|
||||
calc.FinalOut.String(), expectedFinalOut.String()))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// calculateV3Fee calculates the fee for a V3 swap
|
||||
func (pv *ProfitValidator) calculateV3Fee(amount *big.Int, feeTier uint32) *big.Int {
|
||||
// Fee tiers: 500 = 0.05%, 3000 = 0.3%, 10000 = 1%
|
||||
fee := new(big.Int).Mul(amount, big.NewInt(int64(feeTier)))
|
||||
fee.Div(fee, big.NewInt(1000000))
|
||||
return fee
|
||||
}
|
||||
|
||||
// ValidateBatch validates multiple opportunities and generates a report
|
||||
func (pv *ProfitValidator) ValidateBatch(opportunities []*OpportunityTestData) *TestReport {
|
||||
report := &TestReport{
|
||||
ValidationResults: []*ValidationResult{},
|
||||
}
|
||||
|
||||
var totalError float64
|
||||
errorCount := 0
|
||||
|
||||
for _, opp := range opportunities {
|
||||
result := pv.ValidateOpportunity(opp)
|
||||
report.ValidationResults = append(report.ValidationResults, result)
|
||||
|
||||
if result.IsValid {
|
||||
report.ValidCalculations++
|
||||
} else {
|
||||
report.InvalidCalculations++
|
||||
}
|
||||
|
||||
if result.PercentError > 0 {
|
||||
totalError += result.PercentError
|
||||
errorCount++
|
||||
}
|
||||
|
||||
// Track max error
|
||||
if result.Difference != nil {
|
||||
if report.MaxError == nil || result.Difference.Cmp(report.MaxError) > 0 {
|
||||
report.MaxError = new(big.Float).Set(result.Difference)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
report.TotalOpportunities = len(opportunities)
|
||||
if errorCount > 0 {
|
||||
report.AveragePercentError = totalError / float64(errorCount)
|
||||
}
|
||||
|
||||
return report
|
||||
}
|
||||
|
||||
// CompareETHtoWei validates ETH to wei conversion
|
||||
func (pv *ProfitValidator) CompareETHtoWei(ethValue *big.Float, weiValue *big.Int) *ValidationResult {
|
||||
result := &ValidationResult{
|
||||
OpportunityID: "eth_wei_conversion",
|
||||
IsValid: true,
|
||||
Errors: []string{},
|
||||
}
|
||||
|
||||
// Convert ETH to wei
|
||||
expectedWei := new(big.Float).Mul(ethValue, new(big.Float).SetInt(pv.weiPerEth))
|
||||
expectedWeiInt, _ := expectedWei.Int(nil)
|
||||
|
||||
// Compare
|
||||
if expectedWeiInt.Cmp(weiValue) != 0 {
|
||||
result.IsValid = false
|
||||
result.Errors = append(result.Errors,
|
||||
fmt.Sprintf("ETH to wei conversion mismatch: %s ETH should be %s wei, got %s wei",
|
||||
ethValue.String(), expectedWeiInt.String(), weiValue.String()))
|
||||
|
||||
// Calculate difference
|
||||
diff := new(big.Int).Sub(expectedWeiInt, weiValue)
|
||||
result.Difference = new(big.Float).SetInt(diff)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ValidateThresholdComparison validates that a profit threshold comparison was done correctly
|
||||
// This is the CRITICAL validation for the bug we fixed
|
||||
func (pv *ProfitValidator) ValidateThresholdComparison(
|
||||
netProfitETH *big.Float,
|
||||
minProfitThresholdWei *big.Int,
|
||||
wasExecutable bool,
|
||||
) *ValidationResult {
|
||||
result := &ValidationResult{
|
||||
OpportunityID: "threshold_comparison",
|
||||
IsValid: true,
|
||||
Errors: []string{},
|
||||
}
|
||||
|
||||
// Convert threshold from wei to ETH for comparison
|
||||
minProfitETH := new(big.Float).Quo(
|
||||
new(big.Float).SetInt(minProfitThresholdWei),
|
||||
new(big.Float).SetInt(pv.weiPerEth),
|
||||
)
|
||||
|
||||
// Expected result: netProfitETH >= minProfitETH
|
||||
expectedExecutable := netProfitETH.Cmp(minProfitETH) >= 0
|
||||
|
||||
if expectedExecutable != wasExecutable {
|
||||
result.IsValid = false
|
||||
result.Errors = append(result.Errors,
|
||||
fmt.Sprintf("threshold comparison incorrect: %.6f ETH vs %.6f ETH threshold, should be executable=%v, got executable=%v",
|
||||
mustFloat64(netProfitETH), mustFloat64(minProfitETH), expectedExecutable, wasExecutable))
|
||||
}
|
||||
|
||||
result.ExpectedProfit = netProfitETH
|
||||
result.CalculatedProfit = minProfitETH
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// mustFloat64 safely converts big.Float to float64
|
||||
func mustFloat64(f *big.Float) float64 {
|
||||
val, _ := f.Float64()
|
||||
return val
|
||||
}
|
||||
Reference in New Issue
Block a user