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) } }