diff --git a/scripts/known-failing-hive-tests.txt b/scripts/known-failing-hive-tests.txt
index 8b1b62be06b0..9a04671e37bb 100644
--- a/scripts/known-failing-hive-tests.txt
+++ b/scripts/known-failing-hive-tests.txt
@@ -10,6 +10,7 @@ eth_simulateV1/ethSimulate-check-invalid-nonce (nethermind)
eth_simulateV1/ethSimulate-gas-fees-and-value-error-38014-with-validation (nethermind)
eth_simulateV1/ethSimulate-simple-no-funds-with-validation (nethermind)
eth_simulateV1/ethSimulate-simple-no-funds-with-validation-without-nonces (nethermind)
+eth_simulateV1/ethSimulate-simple-send-from-contract-with-validation (nethermind)
# graphql
diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs
index 2ee6e297c9fc..f8fc9ed74a16 100644
--- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs
+++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsBlocksAndTransactions.cs
@@ -702,4 +702,141 @@ public async Task eth_simulateV1_intrinsic_gas_returns_spec_error_code_and_messa
Assert.That(result.Result!.Error, Is.EqualTo(SimulateErrorMessages.IntrinsicGas));
}
+ ///
+ /// Regression test: eth_simulateV1 with validation:true and a nonce below the account's current
+ /// nonce must return -38010 (NonceTooLow).
+ ///
+ [Test]
+ public async Task eth_simulateV1_nonce_too_low_returns_spec_error_code()
+ {
+ TestRpcBlockchain chain = await EthRpcSimulateTestsBase.CreateChain();
+
+ // Set the account's nonce to 10, then send a tx with nonce 0 (below current).
+ SimulatePayload payload = new()
+ {
+ BlockStateCalls =
+ [
+ new()
+ {
+ StateOverrides = new Dictionary
+ {
+ { TestItem.AddressA, new AccountOverride { Balance = 1.Ether, Nonce = 10 } }
+ },
+ Calls =
+ [
+ new LegacyTransactionForRpc
+ {
+ From = TestItem.AddressA,
+ To = TestItem.AddressB,
+ Value = UInt256.Zero,
+ Nonce = 0,
+ GasPrice = UInt256.Zero,
+ Gas = 21_000
+ }
+ ]
+ }
+ ],
+ Validation = true
+ };
+
+ ResultWrapper>> result =
+ chain.EthRpcModule.eth_simulateV1(payload, BlockParameter.Latest);
+
+ Assert.That(result.ErrorCode, Is.EqualTo(ErrorCodes.NonceTooLow));
+ }
+
+ ///
+ /// Regression test: eth_simulateV1 with validation:true and a nonce above the account's current
+ /// nonce must return -38011 (NonceTooHigh).
+ ///
+ [Test]
+ public async Task eth_simulateV1_nonce_too_high_returns_spec_error_code()
+ {
+ TestRpcBlockchain chain = await EthRpcSimulateTestsBase.CreateChain();
+
+ // Account nonce is 0; send a tx with nonce 100 (way above current).
+ SimulatePayload payload = new()
+ {
+ BlockStateCalls =
+ [
+ new()
+ {
+ StateOverrides = new Dictionary
+ {
+ { TestItem.AddressA, new AccountOverride { Balance = 1.Ether } }
+ },
+ Calls =
+ [
+ new LegacyTransactionForRpc
+ {
+ From = TestItem.AddressA,
+ To = TestItem.AddressB,
+ Value = UInt256.Zero,
+ Nonce = 100,
+ GasPrice = UInt256.Zero,
+ Gas = 21_000
+ }
+ ]
+ }
+ ],
+ Validation = true
+ };
+
+ ResultWrapper>> result =
+ chain.EthRpcModule.eth_simulateV1(payload, BlockParameter.Latest);
+
+ Assert.That(result.ErrorCode, Is.EqualTo(ErrorCodes.NonceTooHigh));
+ }
+
+ ///
+ /// Regression test: eth_simulateV1 with validation:true and a sender address that has deployed
+ /// code (EIP-3607) must return -38024 (SenderIsNotEoa).
+ ///
+ [Test]
+ public async Task eth_simulateV1_sender_is_not_eoa_returns_spec_error_code()
+ {
+ OverridableReleaseSpec spec = new(London.Instance) { IsEip3607Enabled = true };
+ TestSpecProvider specProvider = new(spec) { AllowTestChainOverride = false };
+ TestRpcBlockchain chain = await TestRpcBlockchain.ForTest(new TestRpcBlockchain()).Build(specProvider);
+
+ // Override TestItem.AddressC with contract code — makes it a non-EOA sender.
+ SimulatePayload payload = new()
+ {
+ BlockStateCalls =
+ [
+ new()
+ {
+ StateOverrides = new Dictionary
+ {
+ {
+ TestItem.AddressC,
+ new AccountOverride
+ {
+ Balance = 1.Ether,
+ Code = Bytes.FromHexString("0x60006000")
+ }
+ }
+ },
+ Calls =
+ [
+ new LegacyTransactionForRpc
+ {
+ From = TestItem.AddressC,
+ To = TestItem.AddressB,
+ Value = UInt256.Zero,
+ GasPrice = UInt256.Zero,
+ Gas = 21_000
+ }
+ ]
+ }
+ ],
+ Validation = true
+ };
+
+ ResultWrapper>> result =
+ chain.EthRpcModule.eth_simulateV1(payload, BlockParameter.Latest);
+
+ Assert.That(result.ErrorCode, Is.EqualTo(ErrorCodes.SenderIsNotEoa));
+ }
+
}
diff --git a/src/Nethermind/Nethermind.JsonRpc/ErrorCodes.cs b/src/Nethermind/Nethermind.JsonRpc/ErrorCodes.cs
index d981d9169868..bdc798a89f80 100644
--- a/src/Nethermind/Nethermind.JsonRpc/ErrorCodes.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/ErrorCodes.cs
@@ -122,28 +122,43 @@ public static class ErrorCodes
///
public const int Default = -32000;
+ ///
+ /// Transaction nonce is lower than the account's current nonce — eth_simulateV1 spec error
+ ///
+ public const int NonceTooLow = -38010;
+
+ ///
+ /// Transaction nonce is higher than the account's current nonce — eth_simulateV1 spec error
+ ///
+ public const int NonceTooHigh = -38011;
+
///
/// Transaction maxFeePerGas is below the block base fee — eth_simulateV1 spec error
///
public const int FeeCapBelowBaseFee = -38012;
///
- /// Transaction gas limit is below the intrinsic gas cost
+ /// Transaction gas limit is below the intrinsic gas cost — eth_simulateV1 spec error
///
public const int IntrinsicGas = -38013;
///
- /// Not enough value to cover transaction costs
+ /// Not enough value to cover transaction costs — eth_simulateV1 spec error
///
public const int InsufficientFunds = -38014;
///
- /// Gas limit reached
+ /// Gas limit reached — eth_simulateV1 spec error
///
public const int BlockGasLimitReached = -38015;
///
- /// EIP-3860. Code size is to big
+ /// Sender account has deployed code (is not an EOA) — eth_simulateV1 spec error
+ ///
+ public const int SenderIsNotEoa = -38024;
+
+ ///
+ /// EIP-3860. Code size is too big — eth_simulateV1 spec error
///
public const int MaxInitCodeSizeExceeded = -38025;
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs
index eec1f4ba985e..66cc6205cc22 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs
@@ -255,11 +255,11 @@ private static int MapSimulateErrorCode(TransactionResult txResult)
TransactionResult.ErrorType.MaxFeePerGasBelowBaseFee
or TransactionResult.ErrorType.MinerPremiumNegative => ErrorCodes.FeeCapBelowBaseFee,
TransactionResult.ErrorType.NonceOverflow => ErrorCodes.InternalError,
- TransactionResult.ErrorType.SenderHasDeployedCode => ErrorCodes.InvalidParams,
+ TransactionResult.ErrorType.SenderHasDeployedCode => ErrorCodes.SenderIsNotEoa,
TransactionResult.ErrorType.SenderNotSpecified => ErrorCodes.InternalError,
TransactionResult.ErrorType.TransactionSizeOverMaxInitCodeSize => ErrorCodes.MaxInitCodeSizeExceeded,
- TransactionResult.ErrorType.TransactionNonceTooHigh => ErrorCodes.InternalError,
- TransactionResult.ErrorType.TransactionNonceTooLow => ErrorCodes.InternalError,
+ TransactionResult.ErrorType.TransactionNonceTooHigh => ErrorCodes.NonceTooHigh,
+ TransactionResult.ErrorType.TransactionNonceTooLow => ErrorCodes.NonceTooLow,
_ => ErrorCodes.InternalError
};
}