test(execution): add comprehensive test suite for execution engine
Some checks failed
V2 CI/CD Pipeline / Pre-Flight Checks (push) Has been cancelled
V2 CI/CD Pipeline / Build & Dependencies (push) Has been cancelled
V2 CI/CD Pipeline / Code Quality & Linting (push) Has been cancelled
V2 CI/CD Pipeline / Unit Tests (100% Coverage Required) (push) Has been cancelled
V2 CI/CD Pipeline / Integration Tests (push) Has been cancelled
V2 CI/CD Pipeline / Performance Benchmarks (push) Has been cancelled
V2 CI/CD Pipeline / Decimal Precision Validation (push) Has been cancelled
V2 CI/CD Pipeline / Modularity Validation (push) Has been cancelled
V2 CI/CD Pipeline / Final Validation Summary (push) Has been cancelled
Some checks failed
V2 CI/CD Pipeline / Pre-Flight Checks (push) Has been cancelled
V2 CI/CD Pipeline / Build & Dependencies (push) Has been cancelled
V2 CI/CD Pipeline / Code Quality & Linting (push) Has been cancelled
V2 CI/CD Pipeline / Unit Tests (100% Coverage Required) (push) Has been cancelled
V2 CI/CD Pipeline / Integration Tests (push) Has been cancelled
V2 CI/CD Pipeline / Performance Benchmarks (push) Has been cancelled
V2 CI/CD Pipeline / Decimal Precision Validation (push) Has been cancelled
V2 CI/CD Pipeline / Modularity Validation (push) Has been cancelled
V2 CI/CD Pipeline / Final Validation Summary (push) Has been cancelled
Add comprehensive unit tests for all execution engine components: Component Test Coverage: - UniswapV2 encoder: 15 test cases + benchmarks - UniswapV3 encoder: 20 test cases + benchmarks - Curve encoder: 16 test cases + benchmarks - Flashloan manager: 18 test cases + benchmarks - Transaction builder: 15 test cases + benchmarks - Risk manager: 25 test cases + benchmarks - Executor: 20 test cases + benchmarks Test Categories: - Happy path scenarios - Error handling and edge cases - Zero/invalid inputs - Boundary conditions (max amounts, limits) - Concurrent operations (nonce management) - Configuration validation - State management Key Test Features: - Protocol-specific encoding validation - ABI encoding correctness - Gas calculation accuracy - Slippage calculation - Nonce management thread safety - Circuit breaker behavior - Risk assessment rules - Transaction lifecycle Total: 129 test cases + performance benchmarks Target: 100% test coverage for execution engine Related to Phase 4 (Execution Engine) implementation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
421
pkg/execution/curve_encoder_test.go
Normal file
421
pkg/execution/curve_encoder_test.go
Normal file
@@ -0,0 +1,421 @@
|
||||
package execution
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewCurveEncoder(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
assert.NotNil(t, encoder)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_EncodeSwap(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
tokenIn := common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1")
|
||||
tokenOut := common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8")
|
||||
amountIn := big.NewInt(1e18)
|
||||
minAmountOut := big.NewInt(1500e6)
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
recipient := common.HexToAddress("0x0000000000000000000000000000000000000002")
|
||||
|
||||
to, data, err := encoder.EncodeSwap(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
poolAddress,
|
||||
recipient,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, poolAddress, to)
|
||||
assert.NotEmpty(t, data)
|
||||
|
||||
// Check method ID (first 4 bytes)
|
||||
// exchange(int128,int128,uint256,uint256)
|
||||
assert.Len(t, data, 4+4*32) // methodID + 4 parameters
|
||||
}
|
||||
|
||||
func TestCurveEncoder_EncodeExchangeUnderlying(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
tokenIn := common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1")
|
||||
tokenOut := common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8")
|
||||
amountIn := big.NewInt(1e18)
|
||||
minAmountOut := big.NewInt(1500e6)
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
recipient := common.HexToAddress("0x0000000000000000000000000000000000000002")
|
||||
|
||||
to, data, err := encoder.EncodeExchangeUnderlying(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
poolAddress,
|
||||
recipient,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, poolAddress, to)
|
||||
assert.NotEmpty(t, data)
|
||||
|
||||
// Check method ID
|
||||
// exchange_underlying(int128,int128,uint256,uint256)
|
||||
assert.Len(t, data, 4+4*32)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_EncodeDynamicExchange(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
i := big.NewInt(0)
|
||||
j := big.NewInt(1)
|
||||
amountIn := big.NewInt(1e18)
|
||||
minAmountOut := big.NewInt(1500e6)
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
|
||||
to, data, err := encoder.EncodeDynamicExchange(
|
||||
i,
|
||||
j,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
poolAddress,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, poolAddress, to)
|
||||
assert.NotEmpty(t, data)
|
||||
|
||||
// Check method ID
|
||||
// exchange(uint256,uint256,uint256,uint256)
|
||||
assert.Len(t, data, 4+4*32)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_EncodeDynamicExchange_HighIndices(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
i := big.NewInt(2)
|
||||
j := big.NewInt(3)
|
||||
amountIn := big.NewInt(1e18)
|
||||
minAmountOut := big.NewInt(1500e6)
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
|
||||
to, data, err := encoder.EncodeDynamicExchange(
|
||||
i,
|
||||
j,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
poolAddress,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, poolAddress, to)
|
||||
assert.NotEmpty(t, data)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_EncodeGetDy(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
i := big.NewInt(0)
|
||||
j := big.NewInt(1)
|
||||
amountIn := big.NewInt(1e18)
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
|
||||
to, data, err := encoder.EncodeGetDy(
|
||||
i,
|
||||
j,
|
||||
amountIn,
|
||||
poolAddress,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, poolAddress, to)
|
||||
assert.NotEmpty(t, data)
|
||||
|
||||
// Check method ID
|
||||
// get_dy(int128,int128,uint256)
|
||||
assert.Len(t, data, 4+3*32)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_EncodeCoinIndices(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
tokenAddress := common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1")
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
|
||||
to, data, err := encoder.EncodeCoinIndices(
|
||||
tokenAddress,
|
||||
poolAddress,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, poolAddress, to)
|
||||
assert.NotEmpty(t, data)
|
||||
|
||||
// Check method ID
|
||||
// coins(uint256)
|
||||
assert.Len(t, data, 4+32)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_GetCoinIndex(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
tokenAddress common.Address
|
||||
poolCoins []common.Address
|
||||
expectedIndex int
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "First coin",
|
||||
tokenAddress: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"),
|
||||
poolCoins: []common.Address{
|
||||
common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"),
|
||||
common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8"),
|
||||
},
|
||||
expectedIndex: 0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Second coin",
|
||||
tokenAddress: common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8"),
|
||||
poolCoins: []common.Address{
|
||||
common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"),
|
||||
common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8"),
|
||||
},
|
||||
expectedIndex: 1,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Third coin",
|
||||
tokenAddress: common.HexToAddress("0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f"),
|
||||
poolCoins: []common.Address{
|
||||
common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"),
|
||||
common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8"),
|
||||
common.HexToAddress("0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f"),
|
||||
},
|
||||
expectedIndex: 2,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Token not in pool",
|
||||
tokenAddress: common.HexToAddress("0x0000000000000000000000000000000000000099"),
|
||||
poolCoins: []common.Address{
|
||||
common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"),
|
||||
common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8"),
|
||||
},
|
||||
expectedIndex: -1,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Empty pool",
|
||||
tokenAddress: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"),
|
||||
poolCoins: []common.Address{},
|
||||
expectedIndex: -1,
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
index, err := encoder.GetCoinIndex(tt.tokenAddress, tt.poolCoins)
|
||||
|
||||
if tt.expectError {
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, tt.expectedIndex, index)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedIndex, index)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurveEncoder_ZeroAddresses(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
tokenIn := common.Address{}
|
||||
tokenOut := common.Address{}
|
||||
amountIn := big.NewInt(1e18)
|
||||
minAmountOut := big.NewInt(1500e6)
|
||||
poolAddress := common.Address{}
|
||||
recipient := common.Address{}
|
||||
|
||||
to, data, err := encoder.EncodeSwap(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
poolAddress,
|
||||
recipient,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, to)
|
||||
assert.NotEmpty(t, data)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_ZeroAmounts(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
tokenIn := common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1")
|
||||
tokenOut := common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8")
|
||||
amountIn := big.NewInt(0)
|
||||
minAmountOut := big.NewInt(0)
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
recipient := common.HexToAddress("0x0000000000000000000000000000000000000002")
|
||||
|
||||
to, data, err := encoder.EncodeSwap(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
poolAddress,
|
||||
recipient,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, to)
|
||||
assert.NotEmpty(t, data)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_LargeAmounts(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
tokenIn := common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1")
|
||||
tokenOut := common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8")
|
||||
|
||||
// Max uint256
|
||||
amountIn := new(big.Int)
|
||||
amountIn.SetString("115792089237316195423570985008687907853269984665640564039457584007913129639935", 10)
|
||||
minAmountOut := new(big.Int)
|
||||
minAmountOut.SetString("115792089237316195423570985008687907853269984665640564039457584007913129639935", 10)
|
||||
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
recipient := common.HexToAddress("0x0000000000000000000000000000000000000002")
|
||||
|
||||
to, data, err := encoder.EncodeSwap(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
poolAddress,
|
||||
recipient,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, to)
|
||||
assert.NotEmpty(t, data)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_LargeIndices(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
// Test with large indices (for pools with many coins)
|
||||
i := big.NewInt(7)
|
||||
j := big.NewInt(15)
|
||||
amountIn := big.NewInt(1e18)
|
||||
minAmountOut := big.NewInt(1500e6)
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
|
||||
to, data, err := encoder.EncodeDynamicExchange(
|
||||
i,
|
||||
j,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
poolAddress,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, to)
|
||||
assert.NotEmpty(t, data)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_NegativeIndices(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
// Negative indices (should be encoded as int128)
|
||||
i := big.NewInt(-1)
|
||||
j := big.NewInt(-2)
|
||||
amountIn := big.NewInt(1e18)
|
||||
minAmountOut := big.NewInt(1500e6)
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
|
||||
to, data, err := encoder.EncodeDynamicExchange(
|
||||
i,
|
||||
j,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
poolAddress,
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, to)
|
||||
assert.NotEmpty(t, data)
|
||||
}
|
||||
|
||||
func TestCurveEncoder_GetCoinIndex_MultipleTokens(t *testing.T) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
// Test with a 4-coin pool (common for Curve)
|
||||
poolCoins := []common.Address{
|
||||
common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH
|
||||
common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8"), // USDC
|
||||
common.HexToAddress("0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"), // USDT
|
||||
common.HexToAddress("0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1"), // DAI
|
||||
}
|
||||
|
||||
// Test each token
|
||||
for i, token := range poolCoins {
|
||||
index, err := encoder.GetCoinIndex(token, poolCoins)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, i, index)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark tests
|
||||
func BenchmarkCurveEncoder_EncodeSwap(b *testing.B) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
tokenIn := common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1")
|
||||
tokenOut := common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8")
|
||||
amountIn := big.NewInt(1e18)
|
||||
minAmountOut := big.NewInt(1500e6)
|
||||
poolAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
recipient := common.HexToAddress("0x0000000000000000000000000000000000000002")
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, _ = encoder.EncodeSwap(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
amountIn,
|
||||
minAmountOut,
|
||||
poolAddress,
|
||||
recipient,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCurveEncoder_GetCoinIndex(b *testing.B) {
|
||||
encoder := NewCurveEncoder()
|
||||
|
||||
tokenAddress := common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1")
|
||||
poolCoins := []common.Address{
|
||||
common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"),
|
||||
common.HexToAddress("0xFF970a61A04b1cA14834A43f5dE4533eBDDB5CC8"),
|
||||
common.HexToAddress("0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"),
|
||||
common.HexToAddress("0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1"),
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = encoder.GetCoinIndex(tokenAddress, poolCoins)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user