package arbitrum import ( "math/big" "testing" "github.com/ethereum/go-ethereum/common" "github.com/fraktal/mev-beta/internal/logger" "github.com/stretchr/testify/assert" ) // TestCalculateL1DataFee tests L1 data fee calculation func TestCalculateL1DataFee(t *testing.T) { logger := logger.New("info", "text", "") // Test with nil calldata fee := CalculateL1DataFee(nil, logger) assert.Equal(t, big.NewInt(0), fee) // Test with empty calldata fee = CalculateL1DataFee([]byte{}, logger) assert.Equal(t, big.NewInt(0), fee) // Test with sample calldata calldata := []byte("hello world") fee = CalculateL1DataFee(calldata, logger) assert.NotNil(t, fee) assert.True(t, fee.Sign() >= 0) // Test with longer calldata longCalldata := make([]byte, 1000) for i := range longCalldata { longCalldata[i] = byte(i % 256) } fee = CalculateL1DataFee(longCalldata, logger) assert.NotNil(t, fee) assert.True(t, fee.Sign() >= 0) // Fee for longer calldata should be higher than for shorter calldata shortFee := CalculateL1DataFee(calldata, logger) assert.True(t, fee.Cmp(shortFee) >= 0) } // TestCalculateL2Gas tests L2 gas calculation func TestCalculateL2Gas(t *testing.T) { logger := logger.New("info", "text", "") // Test with nil transaction gas := CalculateL2Gas(nil, logger) assert.Equal(t, big.NewInt(0), gas) // Test with transaction with gas limit tx := &RPCTransaction{ Gas: "0x5208", // 21000 in decimal } gas = CalculateL2Gas(tx, logger) assert.Equal(t, big.NewInt(21000), gas) // Test with transaction with zero gas limit txZero := &RPCTransaction{ Gas: "0x0", } gas = CalculateL2Gas(txZero, logger) assert.Equal(t, big.NewInt(0), gas) // Test with malformed gas field txMalformed := &RPCTransaction{ Gas: "invalid_hex", } gas = CalculateL2Gas(txMalformed, logger) assert.Equal(t, big.NewInt(0), gas) } // TestEstimateTotalGasCost tests total gas cost estimation func TestEstimateTotalGasCost(t *testing.T) { logger := logger.New("info", "text", "") // Test with nil parameters totalGas := EstimateTotalGasCost(nil, nil, logger) assert.Equal(t, big.NewInt(0), totalGas) // Test with valid parameters calldata := []byte("sample_transaction_data") tx := &RPCTransaction{ Gas: "0x5208", // 21000 in decimal } totalGas = EstimateTotalGasCost(calldata, tx, logger) assert.NotNil(t, totalGas) assert.True(t, totalGas.Sign() >= 0) // Test components are included in total l1Fee := CalculateL1DataFee(calldata, logger) l2Gas := CalculateL2Gas(tx, logger) // Total should be at least the sum of components // (in reality it might be more complex, but for our test this is sufficient) assert.True(t, totalGas.Cmp(l1Fee) >= 0) assert.True(t, totalGas.Cmp(l2Gas) >= 0) } // TestParseBigInt tests big integer parsing func TestParseBigInt(t *testing.T) { logger := logger.New("info", "text", "") // Test with valid hex string result := parseBigInt("0x1234", logger) assert.Equal(t, big.NewInt(0x1234), result) // Test with valid decimal string result = parseBigInt("1234", logger) assert.Equal(t, big.NewInt(1234), result) // Test with zero result = parseBigInt("0x0", logger) assert.Equal(t, big.NewInt(0), result) // Test with empty string result = parseBigInt("", logger) assert.Equal(t, big.NewInt(0), result) // Test with invalid hex string result = parseBigInt("0xinvalid", logger) assert.Equal(t, big.NewInt(0), result) // Test with invalid decimal string result = parseBigInt("invalid", logger) assert.Equal(t, big.NewInt(0), result) // Test with negative number result = parseBigInt("-1234", logger) assert.Equal(t, big.NewInt(-1234), result) } // TestRPCTransaction_GetSender tests sender extraction from RPC transaction func TestRPCTransaction_GetSender(t *testing.T) { // Test with transaction that has from field tx := &RPCTransaction{ From: "0x1234567890123456789012345678901234567890", } sender := tx.GetSender() assert.Equal(t, common.HexToAddress("0x1234567890123456789012345678901234567890"), sender) // Test with transaction without from field (should return zero address) txNoFrom := &RPCTransaction{} sender = txNoFrom.GetSender() assert.Equal(t, common.Address{}, sender) // Test with invalid address format txInvalid := &RPCTransaction{ From: "invalid_address", } sender = txInvalid.GetSender() assert.Equal(t, common.Address{}, sender) } // TestRPCTransaction_GetTo tests to address extraction from RPC transaction func TestRPCTransaction_GetTo(t *testing.T) { // Test with transaction that has to field tx := &RPCTransaction{ To: "0x1234567890123456789012345678901234567890", } to := tx.GetTo() assert.Equal(t, common.HexToAddress("0x1234567890123456789012345678901234567890"), to) // Test with transaction without to field (should return zero address) txNoTo := &RPCTransaction{} to = txNoTo.GetTo() assert.Equal(t, common.Address{}, to) // Test with invalid address format txInvalid := &RPCTransaction{ To: "invalid_address", } to = txInvalid.GetTo() assert.Equal(t, common.Address{}, to) // Test with contract creation transaction (to field is null/empty) txContractCreation := &RPCTransaction{ To: "", // Contract creation } to = txContractCreation.GetTo() assert.Equal(t, common.Address{}, to) } // TestRPCTransaction_GetValue tests value extraction from RPC transaction func TestRPCTransaction_GetValue(t *testing.T) { logger := logger.New("info", "text", "") // Test with transaction that has value tx := &RPCTransaction{ Value: "0x1234", } value := tx.GetValue(logger) assert.Equal(t, big.NewInt(0x1234), value) // Test with transaction without value txNoValue := &RPCTransaction{} value = txNoValue.GetValue(logger) assert.Equal(t, big.NewInt(0), value) // Test with invalid value txInvalid := &RPCTransaction{ Value: "invalid_value", } value = txInvalid.GetValue(logger) assert.Equal(t, big.NewInt(0), value) // Test with zero value txZero := &RPCTransaction{ Value: "0x0", } value = txZero.GetValue(logger) assert.Equal(t, big.NewInt(0), value) } // TestRPCTransaction_GetGasPrice tests gas price extraction from RPC transaction func TestRPCTransaction_GetGasPrice(t *testing.T) { logger := logger.New("info", "text", "") // Test with transaction that has gasPrice tx := &RPCTransaction{ GasPrice: "0x1234", } gasPrice := tx.GetGasPrice(logger) assert.Equal(t, big.NewInt(0x1234), gasPrice) // Test with transaction that has maxFeePerGas (EIP-1559) txEIP1559 := &RPCTransaction{ MaxFeePerGas: "0x1234", } gasPrice = txEIP1559.GetGasPrice(logger) assert.Equal(t, big.NewInt(0x1234), gasPrice) // Test with transaction that has both (should prefer gasPrice) txBoth := &RPCTransaction{ GasPrice: "0x1234", MaxFeePerGas: "0x5678", } gasPrice = txBoth.GetGasPrice(logger) assert.Equal(t, big.NewInt(0x1234), gasPrice) // Test with transaction without gas price fields txNoGasPrice := &RPCTransaction{} gasPrice = txNoGasPrice.GetGasPrice(logger) assert.Equal(t, big.NewInt(0), gasPrice) // Test with invalid gas price txInvalid := &RPCTransaction{ GasPrice: "invalid_gas_price", } gasPrice = txInvalid.GetGasPrice(logger) assert.Equal(t, big.NewInt(0), gasPrice) } // TestRPCTransaction_GetGasLimit tests gas limit extraction from RPC transaction func TestRPCTransaction_GetGasLimit(t *testing.T) { logger := logger.New("info", "text", "") // Test with transaction that has gas limit tx := &RPCTransaction{ Gas: "0x5208", // 21000 in decimal } gasLimit := tx.GetGasLimit(logger) assert.Equal(t, big.NewInt(21000), gasLimit) // Test with transaction without gas limit txNoGas := &RPCTransaction{} gasLimit = txNoGas.GetGasLimit(logger) assert.Equal(t, big.NewInt(0), gasLimit) // Test with invalid gas limit txInvalid := &RPCTransaction{ Gas: "invalid_gas_limit", } gasLimit = txInvalid.GetGasLimit(logger) assert.Equal(t, big.NewInt(0), gasLimit) // Test with zero gas limit txZero := &RPCTransaction{ Gas: "0x0", } gasLimit = txZero.GetGasLimit(logger) assert.Equal(t, big.NewInt(0), gasLimit) } // TestRPCTransaction_GetNonce tests nonce extraction from RPC transaction func TestRPCTransaction_GetNonce(t *testing.T) { logger := logger.New("info", "text", "") // Test with transaction that has nonce tx := &RPCTransaction{ Nonce: "0x1234", } nonce := tx.GetNonce(logger) assert.Equal(t, uint64(0x1234), nonce) // Test with transaction without nonce txNoNonce := &RPCTransaction{} nonce = txNoNonce.GetNonce(logger) assert.Equal(t, uint64(0), nonce) // Test with invalid nonce txInvalid := &RPCTransaction{ Nonce: "invalid_nonce", } nonce = txInvalid.GetNonce(logger) assert.Equal(t, uint64(0), nonce) // Test with zero nonce txZero := &RPCTransaction{ Nonce: "0x0", } nonce = txZero.GetNonce(logger) assert.Equal(t, uint64(0), nonce) } // TestRPCTransaction_GetInput tests input data extraction from RPC transaction func TestRPCTransaction_GetInput(t *testing.T) { // Test with transaction that has input data inputData := "0x1234567890abcdef" tx := &RPCTransaction{ Input: inputData, } input := tx.GetInput() assert.Equal(t, inputData, input) // Test with transaction without input data txNoInput := &RPCTransaction{} input = txNoInput.GetInput() assert.Equal(t, "", input) // Test with empty input data txEmpty := &RPCTransaction{ Input: "", } input = txEmpty.GetInput() assert.Equal(t, "", input) } // TestRPCTransaction_IsContractCreation tests contract creation detection func TestRPCTransaction_IsContractCreation(t *testing.T) { // Test contract creation transaction (to field is null/empty) txContractCreation := &RPCTransaction{ To: "", // Empty to field indicates contract creation } isCreation := txContractCreation.IsContractCreation() assert.True(t, isCreation) // Test regular transaction (to field is present) txRegular := &RPCTransaction{ To: "0x1234567890123456789012345678901234567890", } isCreation = txRegular.IsContractCreation() assert.False(t, isCreation) // Test with nil to field txNilTo := &RPCTransaction{ To: "", // Nil becomes empty string in JSON unmarshaling } isCreation = txNilTo.IsContractCreation() assert.True(t, isCreation) } // TestCalculateL1DataFeeComponents tests the components of L1 data fee calculation func TestCalculateL1DataFeeComponents(t *testing.T) { logger := logger.New("info", "text", "") // Test calldata cost calculation calldata := []byte{0x00, 0x01, 0x02, 0x03, 0x04} calldataCost := calculateCalldataCost(calldata) assert.True(t, calldataCost >= int64(len(calldata))) // Test with zero bytes (should cost less) zeroBytes := []byte{0x00, 0x00, 0x00} zeroCost := calculateCalldataCost(zeroBytes) assert.True(t, zeroCost >= 0) // Test with non-zero bytes (should cost more) nonZeroBytes := []byte{0x01, 0x02, 0x03} nonZeroCost := calculateCalldataCost(nonZeroBytes) assert.True(t, nonZeroCost >= int64(len(nonZeroBytes))) // Test L1 gas price parsing validL1GasPrice := "0x3b9aca00" // 1 Gwei l1GasPrice := parseL1GasPrice(validL1GasPrice, logger) assert.Equal(t, big.NewInt(1000000000), l1GasPrice) // Test invalid L1 gas price invalidL1GasPrice := "invalid" l1GasPrice = parseL1GasPrice(invalidL1GasPrice, logger) assert.Equal(t, big.NewInt(defaultL1GasPrice), l1GasPrice) // Test L1 fee calculation with parameters calldataCostInt := int64(100) l1GasPriceBig := big.NewInt(1000000000) // 1 Gwei l1Fee := calculateL1Fee(calldataCostInt, l1GasPriceBig, logger) assert.NotNil(t, l1Fee) assert.True(t, l1Fee.Sign() >= 0) } // Helper function to calculate calldata cost (simulating internal logic) func calculateCalldataCost(data []byte) int64 { cost := int64(0) for _, b := range data { if b == 0 { cost += 4 // Cost for zero byte } else { cost += 16 // Cost for non-zero byte } } return cost } // Helper function to parse L1 gas price func parseL1GasPrice(gasPrice string, logger *logger.Logger) *big.Int { if gasPrice == "" { return big.NewInt(defaultL1GasPrice) } result, ok := new(big.Int).SetString(gasPrice, 0) if !ok { logger.Warn("Invalid L1 gas price, using default") return big.NewInt(defaultL1GasPrice) } return result } // Helper function to calculate L1 fee func calculateL1Fee(calldataCost int64, l1GasPrice *big.Int, logger *logger.Logger) *big.Int { // Simplified L1 fee calculation // In reality, this would involve more complex Arbitrum-specific calculations baseFee := big.NewInt(calldataCost) fee := new(big.Int).Mul(baseFee, l1GasPrice) // Apply scaling factor (simplified) scalingFactor := big.NewInt(1000000000) // 1e9 fee.Div(fee, scalingFactor) return fee } // TestGasConstants tests gas-related constants func TestGasConstants(t *testing.T) { // Test that default L1 gas price is reasonable (1 Gwei = 1,000,000,000 wei) assert.Equal(t, int64(1000000000), defaultL1GasPrice) // Test that default L2 gas limit is reasonable assert.Equal(t, int64(30000000), defaultL2GasLimit) // Test that zero byte cost is less than non-zero byte cost assert.True(t, l1ZeroByteCost < l1NonZeroByteCost) }