From 5772b9dbde8f88718ec5c6409f444d6e5b4e4e03 Mon Sep 17 00:00:00 2001
From: PG Herveou <pgherveou@gmail.com>
Date: Thu, 23 Jan 2025 10:57:06 +0100
Subject: [PATCH] [pallet-revive] fee estimation fixes (#7281)

- Fix the EVM fee cost estimation.
The estimation shown in EVM wallet was using Native instead of EVM
decimals
- Remove the precise code length estimation in dry run call.
Over-estimating is fine, since extra gas is refunded anyway.
- Ensure that the estimated fee calculated from gas_price x gas use the
encoded weight & deposit limit instead of the exact one calculated by
the dry-run. Else we can end up with a fee that is lower than the actual
fee paid by the user

---------

Co-authored-by: command-bot <>
---
 .../assets/asset-hub-westend/src/lib.rs       |   6 +-
 prdoc/pr_7281.prdoc                           |  13 ++
 substrate/bin/node/runtime/src/lib.rs         |   4 +
 .../rpc/examples/js/src/build-contracts.ts    |   2 +-
 .../rpc/examples/js/src/geth-diff.test.ts     | 162 +++++++++---------
 .../frame/revive/rpc/examples/js/src/util.ts  |  11 +-
 .../frame/revive/rpc/revive_chain.metadata    | Bin 661585 -> 671115 bytes
 substrate/frame/revive/rpc/src/client.rs      |  17 +-
 .../frame/revive/src/benchmarking/mod.rs      |   6 +-
 substrate/frame/revive/src/evm/gas_encoder.rs |  11 ++
 substrate/frame/revive/src/evm/runtime.rs     |  64 +++----
 substrate/frame/revive/src/exec.rs            |   6 +-
 substrate/frame/revive/src/lib.rs             | 129 ++++++++------
 substrate/frame/revive/src/primitives.rs      |   8 +
 14 files changed, 249 insertions(+), 190 deletions(-)
 create mode 100644 prdoc/pr_7281.prdoc

diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
index f56c4568f2d..ecbe1fb0e62 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
@@ -129,7 +129,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	spec_name: alloc::borrow::Cow::Borrowed("westmint"),
 	impl_name: alloc::borrow::Cow::Borrowed("westmint"),
 	authoring_version: 1,
-	spec_version: 1_017_005,
+	spec_version: 1_017_006,
 	impl_version: 0,
 	apis: RUNTIME_API_VERSIONS,
 	transaction_version: 16,
@@ -2189,6 +2189,10 @@ impl_runtime_apis! {
 			Revive::evm_balance(&address)
 		}
 
+		fn block_gas_limit() -> U256 {
+			Revive::evm_block_gas_limit()
+		}
+
 		fn nonce(address: H160) -> Nonce {
 			let account = <Runtime as pallet_revive::Config>::AddressMapper::to_account_id(&address);
 			System::account_nonce(account)
diff --git a/prdoc/pr_7281.prdoc b/prdoc/pr_7281.prdoc
new file mode 100644
index 00000000000..33e04c419ba
--- /dev/null
+++ b/prdoc/pr_7281.prdoc
@@ -0,0 +1,13 @@
+title: '[pallet-revive] fix eth fee estimation'
+doc:
+- audience: Runtime Dev
+  description: |-
+    Fix EVM fee cost estimation.
+    The current estimation was shown in Native and not EVM decimal currency.
+crates:
+- name: asset-hub-westend-runtime
+  bump: minor
+- name: pallet-revive-eth-rpc
+  bump: minor
+- name: pallet-revive
+  bump: minor
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 26f4dacf9a1..220929fdfd8 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -3301,6 +3301,10 @@ impl_runtime_apis! {
 			Revive::evm_balance(&address)
 		}
 
+		fn block_gas_limit() -> U256 {
+			Revive::evm_block_gas_limit()
+		}
+
 		fn nonce(address: H160) -> Nonce {
 			let account = <Runtime as pallet_revive::Config>::AddressMapper::to_account_id(&address);
 			System::account_nonce(account)
diff --git a/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts b/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts
index f26f275ec3d..b162b8be0ad 100644
--- a/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts
+++ b/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts
@@ -55,7 +55,7 @@ for (const file of input) {
 	}
 
 	console.log('Compiling with revive...')
-	const reviveOut = await compile(input, { bin: 'resolc' })
+	const reviveOut = await compile(input)
 
 	for (const contracts of Object.values(reviveOut.contracts)) {
 		for (const [name, contract] of Object.entries(contracts)) {
diff --git a/substrate/frame/revive/rpc/examples/js/src/geth-diff.test.ts b/substrate/frame/revive/rpc/examples/js/src/geth-diff.test.ts
index 86b8ec50bd6..2a4ff2edcdf 100644
--- a/substrate/frame/revive/rpc/examples/js/src/geth-diff.test.ts
+++ b/substrate/frame/revive/rpc/examples/js/src/geth-diff.test.ts
@@ -12,62 +12,64 @@ import { ErrorsAbi } from '../abi/Errors'
 import { FlipperCallerAbi } from '../abi/FlipperCaller'
 import { FlipperAbi } from '../abi/Flipper'
 import { Subprocess, spawn } from 'bun'
+import { fail } from 'node:assert'
 
 const procs: Subprocess[] = []
-beforeAll(async () => {
-	if (!process.env.USE_LIVE_SERVERS) {
-		procs.push(
-			// Run geth on port 8546
-			await (async () => {
-				killProcessOnPort(8546)
-				const proc = spawn(
-					'geth --http --http.api web3,eth,debug,personal,net --http.port 8546 --dev --verbosity 0'.split(
-						' '
-					),
-					{ stdout: Bun.file('/tmp/geth.out.log'), stderr: Bun.file('/tmp/geth.err.log') }
-				)
+if (!process.env.USE_LIVE_SERVERS) {
+	procs.push(
+		// Run geth on port 8546
+		await (async () => {
+			killProcessOnPort(8546)
+			console.log('Starting geth')
+			const proc = spawn(
+				'geth --http --http.api web3,eth,debug,personal,net --http.port 8546 --dev --verbosity 0'.split(
+					' '
+				),
+				{ stdout: Bun.file('/tmp/geth.out.log'), stderr: Bun.file('/tmp/geth.err.log') }
+			)
 
-				await waitForHealth('http://localhost:8546').catch()
-				return proc
-			})(),
-			//Run the substate node
-			(() => {
-				killProcessOnPort(9944)
-				return spawn(
-					[
-						'./target/debug/substrate-node',
-						'--dev',
-						'-l=error,evm=debug,sc_rpc_server=info,runtime::revive=debug',
-					],
-					{
-						stdout: Bun.file('/tmp/kitchensink.out.log'),
-						stderr: Bun.file('/tmp/kitchensink.err.log'),
-						cwd: polkadotSdkPath,
-					}
-				)
-			})(),
-			// Run eth-rpc on 8545
-			await (async () => {
-				killProcessOnPort(8545)
-				const proc = spawn(
-					[
-						'./target/debug/eth-rpc',
-						'--dev',
-						'--node-rpc-url=ws://localhost:9944',
-						'-l=rpc-metrics=debug,eth-rpc=debug',
-					],
-					{
-						stdout: Bun.file('/tmp/eth-rpc.out.log'),
-						stderr: Bun.file('/tmp/eth-rpc.err.log'),
-						cwd: polkadotSdkPath,
-					}
-				)
-				await waitForHealth('http://localhost:8545').catch()
-				return proc
-			})()
-		)
-	}
-})
+			await waitForHealth('http://localhost:8546').catch()
+			return proc
+		})(),
+		//Run the substate node
+		(() => {
+			killProcessOnPort(9944)
+			console.log('Starting substrate node')
+			return spawn(
+				[
+					'./target/debug/substrate-node',
+					'--dev',
+					'-l=error,evm=debug,sc_rpc_server=info,runtime::revive=debug',
+				],
+				{
+					stdout: Bun.file('/tmp/kitchensink.out.log'),
+					stderr: Bun.file('/tmp/kitchensink.err.log'),
+					cwd: polkadotSdkPath,
+				}
+			)
+		})(),
+		// Run eth-rpc on 8545
+		await (async () => {
+			killProcessOnPort(8545)
+			console.log('Starting eth-rpc')
+			const proc = spawn(
+				[
+					'./target/debug/eth-rpc',
+					'--dev',
+					'--node-rpc-url=ws://localhost:9944',
+					'-l=rpc-metrics=debug,eth-rpc=debug',
+				],
+				{
+					stdout: Bun.file('/tmp/eth-rpc.out.log'),
+					stderr: Bun.file('/tmp/eth-rpc.err.log'),
+					cwd: polkadotSdkPath,
+				}
+			)
+			await waitForHealth('http://localhost:8545').catch()
+			return proc
+		})()
+	)
+}
 
 afterEach(() => {
 	jsonRpcErrors.length = 0
@@ -88,7 +90,7 @@ for (const env of envs) {
 			{
 				const hash = await env.serverWallet.deployContract({
 					abi: ErrorsAbi,
-					bytecode: getByteCode('errors', env.evm),
+					bytecode: getByteCode('Errors', env.evm),
 				})
 				const deployReceipt = await env.serverWallet.waitForTransactionReceipt({ hash })
 				if (!deployReceipt.contractAddress)
@@ -99,7 +101,7 @@ for (const env of envs) {
 			{
 				const hash = await env.serverWallet.deployContract({
 					abi: FlipperAbi,
-					bytecode: getByteCode('flipper', env.evm),
+					bytecode: getByteCode('Flipper', env.evm),
 				})
 				const deployReceipt = await env.serverWallet.waitForTransactionReceipt({ hash })
 				if (!deployReceipt.contractAddress)
@@ -111,7 +113,7 @@ for (const env of envs) {
 				const hash = await env.serverWallet.deployContract({
 					abi: FlipperCallerAbi,
 					args: [flipperAddr],
-					bytecode: getByteCode('flipperCaller', env.evm),
+					bytecode: getByteCode('FlipperCaller', env.evm),
 				})
 				const deployReceipt = await env.serverWallet.waitForTransactionReceipt({ hash })
 				if (!deployReceipt.contractAddress)
@@ -121,13 +123,13 @@ for (const env of envs) {
 		})
 
 		test('triggerAssertError', async () => {
-			expect.assertions(3)
 			try {
 				await env.accountWallet.readContract({
 					address: errorsAddr,
 					abi: ErrorsAbi,
 					functionName: 'triggerAssertError',
 				})
+				fail('Expect call to fail')
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(3)
@@ -139,13 +141,13 @@ for (const env of envs) {
 		})
 
 		test('triggerRevertError', async () => {
-			expect.assertions(3)
 			try {
 				await env.accountWallet.readContract({
 					address: errorsAddr,
 					abi: ErrorsAbi,
 					functionName: 'triggerRevertError',
 				})
+				fail('Expect call to fail')
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(3)
@@ -157,13 +159,13 @@ for (const env of envs) {
 		})
 
 		test('triggerDivisionByZero', async () => {
-			expect.assertions(3)
 			try {
 				await env.accountWallet.readContract({
 					address: errorsAddr,
 					abi: ErrorsAbi,
 					functionName: 'triggerDivisionByZero',
 				})
+				expect.assertions(3)
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(3)
@@ -177,13 +179,13 @@ for (const env of envs) {
 		})
 
 		test('triggerOutOfBoundsError', async () => {
-			expect.assertions(3)
 			try {
 				await env.accountWallet.readContract({
 					address: errorsAddr,
 					abi: ErrorsAbi,
 					functionName: 'triggerOutOfBoundsError',
 				})
+				fail('Expect call to fail')
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(3)
@@ -197,13 +199,13 @@ for (const env of envs) {
 		})
 
 		test('triggerCustomError', async () => {
-			expect.assertions(3)
 			try {
 				await env.accountWallet.readContract({
 					address: errorsAddr,
 					abi: ErrorsAbi,
 					functionName: 'triggerCustomError',
 				})
+				fail('Expect call to fail')
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(3)
@@ -215,15 +217,15 @@ for (const env of envs) {
 		})
 
 		test('eth_call (not enough funds)', async () => {
-			expect.assertions(3)
 			try {
-				await env.accountWallet.simulateContract({
+				await env.emptyWallet.simulateContract({
 					address: errorsAddr,
 					abi: ErrorsAbi,
 					functionName: 'valueMatch',
 					value: parseEther('10'),
 					args: [parseEther('10')],
 				})
+				fail('Expect call to fail')
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(-32000)
@@ -233,12 +235,15 @@ for (const env of envs) {
 		})
 
 		test('eth_call transfer (not enough funds)', async () => {
-			expect.assertions(3)
+			const value = parseEther('10')
+			const balance = await env.emptyWallet.getBalance(env.emptyWallet.account)
+			expect(balance, 'Balance should be less than 10').toBeLessThan(value)
 			try {
-				await env.accountWallet.sendTransaction({
+				await env.emptyWallet.sendTransaction({
 					to: '0x75E480dB528101a381Ce68544611C169Ad7EB342',
-					value: parseEther('10'),
+					value,
 				})
+				fail('Expect call to fail')
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(-32000)
@@ -248,15 +253,15 @@ for (const env of envs) {
 		})
 
 		test('eth_estimate (not enough funds)', async () => {
-			expect.assertions(3)
 			try {
-				await env.accountWallet.estimateContractGas({
+				await env.emptyWallet.estimateContractGas({
 					address: errorsAddr,
 					abi: ErrorsAbi,
 					functionName: 'valueMatch',
 					value: parseEther('10'),
 					args: [parseEther('10')],
 				})
+				fail('Expect call to fail')
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(-32000)
@@ -266,15 +271,15 @@ for (const env of envs) {
 		})
 
 		test('eth_estimate call caller (not enough funds)', async () => {
-			expect.assertions(3)
 			try {
-				await env.accountWallet.estimateContractGas({
+				await env.emptyWallet.estimateContractGas({
 					address: errorsAddr,
 					abi: ErrorsAbi,
 					functionName: 'valueMatch',
 					value: parseEther('10'),
 					args: [parseEther('10')],
 				})
+				fail('Expect call to fail')
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(-32000)
@@ -284,7 +289,6 @@ for (const env of envs) {
 		})
 
 		test('eth_estimate (revert)', async () => {
-			expect.assertions(3)
 			try {
 				await env.serverWallet.estimateContractGas({
 					address: errorsAddr,
@@ -293,6 +297,7 @@ for (const env of envs) {
 					value: parseEther('11'),
 					args: [parseEther('10')],
 				})
+				fail('Expect call to fail')
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(3)
@@ -313,17 +318,16 @@ for (const env of envs) {
 		})
 
 		test('eth_estimate (not enough funds to cover gas specified)', async () => {
-			expect.assertions(4)
+			let balance = await env.serverWallet.getBalance(env.emptyWallet.account)
+			expect(balance).toBe(0n)
 			try {
-				let balance = await env.serverWallet.getBalance(env.accountWallet.account)
-				expect(balance).toBe(0n)
-
-				await env.accountWallet.estimateContractGas({
+				await env.emptyWallet.estimateContractGas({
 					address: errorsAddr,
 					abi: ErrorsAbi,
 					functionName: 'setState',
 					args: [true],
 				})
+				fail('Expect call to fail')
 			} catch (err) {
 				const lastJsonRpcError = jsonRpcErrors.pop()
 				expect(lastJsonRpcError?.code).toBe(-32000)
@@ -333,7 +337,7 @@ for (const env of envs) {
 		})
 
 		test('eth_estimate (no gas specified)', async () => {
-			let balance = await env.serverWallet.getBalance(env.accountWallet.account)
+			let balance = await env.serverWallet.getBalance(env.emptyWallet.account)
 			expect(balance).toBe(0n)
 
 			const data = encodeFunctionData({
@@ -342,12 +346,12 @@ for (const env of envs) {
 				args: [true],
 			})
 
-			await env.accountWallet.request({
+			await env.emptyWallet.request({
 				method: 'eth_estimateGas',
 				params: [
 					{
 						data,
-						from: env.accountWallet.account.address,
+						from: env.emptyWallet.account.address,
 						to: errorsAddr,
 					},
 				],
diff --git a/substrate/frame/revive/rpc/examples/js/src/util.ts b/substrate/frame/revive/rpc/examples/js/src/util.ts
index bdc64eea1ef..2991bdfe636 100644
--- a/substrate/frame/revive/rpc/examples/js/src/util.ts
+++ b/substrate/frame/revive/rpc/examples/js/src/util.ts
@@ -85,7 +85,16 @@ export async function createEnv(name: 'geth' | 'kitchensink') {
 		chain,
 	}).extend(publicActions)
 
-	return { serverWallet, accountWallet, evm: name == 'geth' }
+	const emptyWallet = createWalletClient({
+		account: privateKeyToAccount(
+			'0x4450c571bae82da0528ecf76fcf7079e12ecc46dc873c9cacb6db8b75ed22f41',
+			{ nonceManager }
+		),
+		transport,
+		chain,
+	}).extend(publicActions)
+
+	return { serverWallet, emptyWallet, accountWallet, evm: name == 'geth' }
 }
 
 export function wait(ms: number) {
diff --git a/substrate/frame/revive/rpc/revive_chain.metadata b/substrate/frame/revive/rpc/revive_chain.metadata
index a03c95b4944f663225642b1678ef66aaccec3fb5..ff365892a265e1fd9b59f6811ea1c59642b65d91 100644
GIT binary patch
delta 25763
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
B%I^RG

delta 15939
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

diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs
index 7a72f8e26b0..440972c7a68 100644
--- a/substrate/frame/revive/rpc/src/client.rs
+++ b/substrate/frame/revive/rpc/src/client.rs
@@ -18,7 +18,6 @@
 //! and is used by the rpc server to query and send transactions to the substrate chain.
 use crate::{
 	extract_receipts_from_block,
-	runtime::gas_from_fee,
 	subxt_client::{
 		revive::calls::types::EthTransact, runtime_types::pallet_revive::storage::ContractInfo,
 	},
@@ -649,8 +648,7 @@ impl Client {
 		hydrated_transactions: bool,
 	) -> Result<Block, ClientError> {
 		let runtime_api = self.api.runtime_api().at(block.hash());
-		let max_fee = Self::weight_to_fee(&runtime_api, self.max_block_weight()).await?;
-		let gas_limit = gas_from_fee(max_fee);
+		let gas_limit = Self::block_gas_limit(&runtime_api).await?;
 
 		let header = block.header();
 		let timestamp = extract_block_timestamp(&block).await.unwrap_or_default();
@@ -695,16 +693,13 @@ impl Client {
 	}
 
 	/// Convert a weight to a fee.
-	async fn weight_to_fee(
+	async fn block_gas_limit(
 		runtime_api: &subxt::runtime_api::RuntimeApi<SrcChainConfig, OnlineClient<SrcChainConfig>>,
-		weight: Weight,
-	) -> Result<Balance, ClientError> {
-		let payload = subxt_client::apis()
-			.transaction_payment_api()
-			.query_weight_to_fee(weight.into());
+	) -> Result<U256, ClientError> {
+		let payload = subxt_client::apis().revive_api().block_gas_limit();
 
-		let fee = runtime_api.call(payload).await?;
-		Ok(fee)
+		let gas_limit = runtime_api.call(payload).await?;
+		Ok(*gas_limit)
 	}
 
 	/// Get the chain ID.
diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs
index 16bdd6d1a18..a19ed28dd9b 100644
--- a/substrate/frame/revive/src/benchmarking/mod.rs
+++ b/substrate/frame/revive/src/benchmarking/mod.rs
@@ -27,7 +27,7 @@ use crate::{
 	exec::{Key, MomentOf},
 	limits,
 	storage::WriteOutcome,
-	Pallet as Contracts, *,
+	ConversionPrecision, Pallet as Contracts, *,
 };
 use alloc::{vec, vec::Vec};
 use codec::{Encode, MaxEncodedLen};
@@ -1771,7 +1771,9 @@ mod benchmarks {
 		assert!(ContractInfoOf::<T>::get(&addr).is_some());
 		assert_eq!(
 			T::Currency::balance(&account_id),
-			Pallet::<T>::min_balance() + Pallet::<T>::convert_evm_to_native(value.into()).unwrap()
+			Pallet::<T>::min_balance() +
+				Pallet::<T>::convert_evm_to_native(value.into(), ConversionPrecision::Exact)
+					.unwrap()
 		);
 		Ok(())
 	}
diff --git a/substrate/frame/revive/src/evm/gas_encoder.rs b/substrate/frame/revive/src/evm/gas_encoder.rs
index ffdf8b13c04..8853e77e958 100644
--- a/substrate/frame/revive/src/evm/gas_encoder.rs
+++ b/substrate/frame/revive/src/evm/gas_encoder.rs
@@ -72,6 +72,12 @@ pub trait GasEncoder<Balance>: private::Sealed {
 	/// Decodes the weight and deposit from the encoded gas value.
 	/// Returns `None` if the gas value is invalid
 	fn decode(gas: U256) -> Option<(Weight, Balance)>;
+
+	/// Returns the encoded values of the specified weight and deposit.
+	fn as_encoded_values(weight: Weight, deposit: Balance) -> (Weight, Balance) {
+		let encoded = Self::encode(U256::zero(), weight, deposit);
+		Self::decode(encoded).expect("encoded values should be decodable; qed")
+	}
 }
 
 impl<Balance> GasEncoder<Balance> for ()
@@ -148,6 +154,11 @@ mod test {
 
 		assert!(decoded_deposit >= deposit);
 		assert!(deposit * 2 >= decoded_deposit);
+
+		assert_eq!(
+			(decoded_weight, decoded_deposit),
+			<() as GasEncoder<u64>>::as_encoded_values(weight, deposit)
+		);
 	}
 
 	#[test]
diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs
index 0e5fc3da545..09bfbf380c6 100644
--- a/substrate/frame/revive/src/evm/runtime.rs
+++ b/substrate/frame/revive/src/evm/runtime.rs
@@ -20,7 +20,8 @@ use crate::{
 		api::{GenericTransaction, TransactionSigned},
 		GasEncoder,
 	},
-	AccountIdOf, AddressMapper, BalanceOf, Config, MomentOf, Weight, LOG_TARGET,
+	AccountIdOf, AddressMapper, BalanceOf, Config, ConversionPrecision, MomentOf, Pallet,
+	LOG_TARGET,
 };
 use alloc::vec::Vec;
 use codec::{Decode, Encode};
@@ -34,8 +35,8 @@ use sp_core::{Get, H256, U256};
 use sp_runtime::{
 	generic::{self, CheckedExtrinsic, ExtrinsicFormat},
 	traits::{
-		self, AtLeast32BitUnsigned, Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata,
-		IdentifyAccount, Member, TransactionExtension,
+		self, Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, Member,
+		TransactionExtension,
 	},
 	transaction_validity::{InvalidTransaction, TransactionValidityError},
 	OpaqueExtrinsic, RuntimeDebug, Saturating,
@@ -56,34 +57,6 @@ type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
 /// - Not too low, enabling users to adjust the gas price to define a tip.
 pub const GAS_PRICE: u32 = 1_000u32;
 
-/// Convert a `Balance` into a gas value, using the fixed `GAS_PRICE`.
-/// The gas is calculated as `balance / GAS_PRICE`, rounded up to the nearest integer.
-pub fn gas_from_fee<Balance>(fee: Balance) -> U256
-where
-	u32: Into<Balance>,
-	Balance: Into<U256> + AtLeast32BitUnsigned + Copy,
-{
-	let gas_price = GAS_PRICE.into();
-	let remainder = fee % gas_price;
-	if remainder.is_zero() {
-		(fee / gas_price).into()
-	} else {
-		(fee.saturating_add(gas_price) / gas_price).into()
-	}
-}
-
-/// Convert a `Weight` into a gas value, using the fixed `GAS_PRICE`.
-/// and the `Config::WeightPrice` to compute the fee.
-/// The gas is calculated as `fee / GAS_PRICE`, rounded up to the nearest integer.
-pub fn gas_from_weight<T: Config>(weight: Weight) -> U256
-where
-	BalanceOf<T>: Into<U256>,
-{
-	use sp_runtime::traits::Convert;
-	let fee: BalanceOf<T> = T::WeightPrice::convert(weight);
-	gas_from_fee(fee)
-}
-
 /// Wraps [`generic::UncheckedExtrinsic`] to support checking unsigned
 /// [`crate::Call::eth_transact`] extrinsic.
 #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
@@ -346,11 +319,14 @@ pub trait EthExtra {
 			return Err(InvalidTransaction::Call);
 		}
 
-		let value = crate::Pallet::<Self::Config>::convert_evm_to_native(value.unwrap_or_default())
-			.map_err(|err| {
-				log::debug!(target: LOG_TARGET, "Failed to convert value to native: {err:?}");
-				InvalidTransaction::Call
-			})?;
+		let value = crate::Pallet::<Self::Config>::convert_evm_to_native(
+			value.unwrap_or_default(),
+			ConversionPrecision::Exact,
+		)
+		.map_err(|err| {
+			log::debug!(target: LOG_TARGET, "Failed to convert value to native: {err:?}");
+			InvalidTransaction::Call
+		})?;
 
 		let data = input.unwrap_or_default().0;
 
@@ -393,17 +369,21 @@ pub trait EthExtra {
 		let nonce = nonce.unwrap_or_default().try_into().map_err(|_| InvalidTransaction::Call)?;
 
 		// Fees calculated with the fixed `GAS_PRICE`
-		// When we dry-run the transaction, we set the gas to `Fee / GAS_PRICE`
+		// When we dry-run the transaction, we set the gas to `fee / GAS_PRICE`
 		let eth_fee_no_tip = U256::from(GAS_PRICE)
 			.saturating_mul(gas)
 			.try_into()
 			.map_err(|_| InvalidTransaction::Call)?;
 
-		// Fees with the actual gas_price from the transaction.
-		let eth_fee: BalanceOf<Self::Config> = U256::from(gas_price.unwrap_or_default())
-			.saturating_mul(gas)
-			.try_into()
-			.map_err(|_| InvalidTransaction::Call)?;
+		// Fees calculated from the gas and gas_price of the transaction.
+		let eth_fee = Pallet::<Self::Config>::convert_evm_to_native(
+			U256::from(gas_price.unwrap_or_default()).saturating_mul(gas),
+			ConversionPrecision::RoundUp,
+		)
+		.map_err(|err| {
+			log::debug!(target: LOG_TARGET, "Failed to compute eth_fee: {err:?}");
+			InvalidTransaction::Call
+		})?;
 
 		let info = call.get_dispatch_info();
 		let function: CallOf<Self::Config> = call.into();
diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs
index d2ef6c9c7ba..14ab917c0d4 100644
--- a/substrate/frame/revive/src/exec.rs
+++ b/substrate/frame/revive/src/exec.rs
@@ -24,8 +24,8 @@ use crate::{
 	storage::{self, meter::Diff, WriteOutcome},
 	tracing::if_tracing,
 	transient_storage::TransientStorage,
-	BalanceOf, CodeInfo, CodeInfoOf, Config, ContractInfo, ContractInfoOf, Error, Event,
-	ImmutableData, ImmutableDataOf, Pallet as Contracts,
+	BalanceOf, CodeInfo, CodeInfoOf, Config, ContractInfo, ContractInfoOf, ConversionPrecision,
+	Error, Event, ImmutableData, ImmutableDataOf, Pallet as Contracts,
 };
 use alloc::vec::Vec;
 use core::{fmt::Debug, marker::PhantomData, mem};
@@ -1273,7 +1273,7 @@ where
 		to: &T::AccountId,
 		value: U256,
 	) -> ExecResult {
-		let value = crate::Pallet::<T>::convert_evm_to_native(value)?;
+		let value = crate::Pallet::<T>::convert_evm_to_native(value, ConversionPrecision::Exact)?;
 		if value.is_zero() {
 			return Ok(Default::default());
 		}
diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs
index c36cb3f47ca..7f4565a9f08 100644
--- a/substrate/frame/revive/src/lib.rs
+++ b/substrate/frame/revive/src/lib.rs
@@ -41,10 +41,7 @@ pub mod tracing;
 pub mod weights;
 
 use crate::{
-	evm::{
-		runtime::{gas_from_fee, GAS_PRICE},
-		GasEncoder, GenericTransaction,
-	},
+	evm::{runtime::GAS_PRICE, GasEncoder, GenericTransaction},
 	exec::{AccountIdOf, ExecError, Executable, Ext, Key, Stack as ExecStack},
 	gas::GasMeter,
 	storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager},
@@ -1140,16 +1137,20 @@ where
 		if tx.nonce.is_none() {
 			tx.nonce = Some(<System<T>>::account_nonce(&origin).into());
 		}
+		if tx.chain_id.is_none() {
+			tx.chain_id = Some(T::ChainId::get().into());
+		}
 		if tx.gas_price.is_none() {
 			tx.gas_price = Some(GAS_PRICE.into());
 		}
-		if tx.chain_id.is_none() {
-			tx.chain_id = Some(T::ChainId::get().into());
+		if tx.gas.is_none() {
+			tx.gas = Some(Self::evm_block_gas_limit());
 		}
 
 		// Convert the value to the native balance type.
 		let evm_value = tx.value.unwrap_or_default();
-		let native_value = match Self::convert_evm_to_native(evm_value) {
+		let native_value = match Self::convert_evm_to_native(evm_value, ConversionPrecision::Exact)
+		{
 			Ok(v) => v,
 			Err(_) => return Err(EthTransactError::Message("Failed to convert value".into())),
 		};
@@ -1206,12 +1207,16 @@ where
 					data,
 					eth_gas: Default::default(),
 				};
-				// Get the dispatch info of the call.
+
+				let (gas_limit, storage_deposit_limit) = T::EthGasEncoder::as_encoded_values(
+					result.gas_required,
+					result.storage_deposit,
+				);
 				let dispatch_call: <T as Config>::RuntimeCall = crate::Call::<T>::call {
 					dest,
 					value: native_value,
-					gas_limit: result.gas_required,
-					storage_deposit_limit: result.storage_deposit,
+					gas_limit,
+					storage_deposit_limit,
 					data: input.clone(),
 				}
 				.into();
@@ -1264,11 +1269,15 @@ where
 				};
 
 				// Get the dispatch info of the call.
+				let (gas_limit, storage_deposit_limit) = T::EthGasEncoder::as_encoded_values(
+					result.gas_required,
+					result.storage_deposit,
+				);
 				let dispatch_call: <T as Config>::RuntimeCall =
 					crate::Call::<T>::instantiate_with_code {
 						value: native_value,
-						gas_limit: result.gas_required,
-						storage_deposit_limit: result.storage_deposit,
+						gas_limit,
+						storage_deposit_limit,
 						code: code.to_vec(),
 						data: data.to_vec(),
 						salt: None,
@@ -1278,38 +1287,26 @@ where
 			},
 		};
 
-		// The transaction fees depend on the extrinsic's length, which in turn is influenced by
-		// the encoded length of the gas limit specified in the transaction (tx.gas).
-		// We iteratively compute the fee by adjusting tx.gas until the fee stabilizes.
-		// with a maximum of 3 iterations to avoid an infinite loop.
-		for _ in 0..3 {
-			let Ok(unsigned_tx) = tx.clone().try_into_unsigned() else {
-				log::debug!(target: LOG_TARGET, "Failed to convert to unsigned");
-				return Err(EthTransactError::Message("Invalid transaction".into()));
-			};
-
-			let eth_dispatch_call =
-				crate::Call::<T>::eth_transact { payload: unsigned_tx.dummy_signed_payload() };
-			let encoded_len = utx_encoded_size(eth_dispatch_call);
-			let fee = pallet_transaction_payment::Pallet::<T>::compute_fee(
-				encoded_len,
-				&dispatch_info,
-				0u32.into(),
-			)
-			.into();
-			let eth_gas = gas_from_fee(fee);
-			let eth_gas =
-				T::EthGasEncoder::encode(eth_gas, result.gas_required, result.storage_deposit);
-
-			if eth_gas == result.eth_gas {
-				log::trace!(target: LOG_TARGET, "bare_eth_call: encoded_len: {encoded_len:?} eth_gas: {eth_gas:?}");
-				break;
-			}
-			result.eth_gas = eth_gas;
-			tx.gas = Some(eth_gas.into());
-			log::debug!(target: LOG_TARGET, "Adjusting Eth gas to: {eth_gas:?}");
-		}
+		let Ok(unsigned_tx) = tx.clone().try_into_unsigned() else {
+			return Err(EthTransactError::Message("Invalid transaction".into()));
+		};
 
+		let eth_dispatch_call =
+			crate::Call::<T>::eth_transact { payload: unsigned_tx.dummy_signed_payload() };
+
+		let encoded_len = utx_encoded_size(eth_dispatch_call);
+		let fee = pallet_transaction_payment::Pallet::<T>::compute_fee(
+			encoded_len,
+			&dispatch_info,
+			0u32.into(),
+		)
+		.into();
+		let eth_gas = Self::evm_fee_to_gas(fee);
+		let eth_gas =
+			T::EthGasEncoder::encode(eth_gas, result.gas_required, result.storage_deposit);
+
+		log::trace!(target: LOG_TARGET, "bare_eth_call: encoded_len: {encoded_len:?} eth_gas: {eth_gas:?}");
+		result.eth_gas = eth_gas;
 		Ok(result)
 	}
 
@@ -1319,6 +1316,29 @@ where
 		Self::convert_native_to_evm(T::Currency::reducible_balance(&account, Preserve, Polite))
 	}
 
+	/// Convert an EVM fee into a gas value, using the fixed `GAS_PRICE`.
+	/// The gas is calculated as `fee / GAS_PRICE`, rounded up to the nearest integer.
+	pub fn evm_fee_to_gas(fee: BalanceOf<T>) -> U256 {
+		let fee = Self::convert_native_to_evm(fee);
+		let gas_price = GAS_PRICE.into();
+		let (quotient, remainder) = fee.div_mod(gas_price);
+		if remainder.is_zero() {
+			quotient
+		} else {
+			quotient + U256::one()
+		}
+	}
+
+	pub fn evm_block_gas_limit() -> U256 {
+		let max_block_weight = T::BlockWeights::get()
+			.get(DispatchClass::Normal)
+			.max_total
+			.unwrap_or_else(|| T::BlockWeights::get().max_block);
+
+		let fee = T::WeightPrice::convert(max_block_weight);
+		Self::evm_fee_to_gas(fee)
+	}
+
 	/// A generalized version of [`Self::upload_code`].
 	///
 	/// It is identical to [`Self::upload_code`] and only differs in the information it returns.
@@ -1379,16 +1399,22 @@ where
 	}
 
 	/// Convert an EVM balance to a native balance.
-	fn convert_evm_to_native(value: U256) -> Result<BalanceOf<T>, Error<T>> {
+	fn convert_evm_to_native(
+		value: U256,
+		precision: ConversionPrecision,
+	) -> Result<BalanceOf<T>, Error<T>> {
 		if value.is_zero() {
 			return Ok(Zero::zero())
 		}
-		let ratio = T::NativeToEthRatio::get().into();
-		let res = value.checked_div(ratio).expect("divisor is non-zero; qed");
-		if res.saturating_mul(ratio) == value {
-			res.try_into().map_err(|_| Error::<T>::BalanceConversionFailed)
-		} else {
-			Err(Error::<T>::DecimalPrecisionLoss)
+
+		let (quotient, remainder) = value.div_mod(T::NativeToEthRatio::get().into());
+		match (precision, remainder.is_zero()) {
+			(ConversionPrecision::Exact, false) => Err(Error::<T>::DecimalPrecisionLoss),
+			(_, true) => quotient.try_into().map_err(|_| Error::<T>::BalanceConversionFailed),
+			(_, false) => quotient
+				.saturating_add(U256::one())
+				.try_into()
+				.map_err(|_| Error::<T>::BalanceConversionFailed),
 		}
 	}
 }
@@ -1417,6 +1443,9 @@ sp_api::decl_runtime_apis! {
 		Nonce: Codec,
 		BlockNumber: Codec,
 	{
+		/// Returns the block gas limit.
+		fn block_gas_limit() -> U256;
+
 		/// Returns the free balance of the given `[H160]` address, using EVM decimals.
 		fn balance(address: H160) -> U256;
 
diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs
index 9c149c7cc38..e2900bd027b 100644
--- a/substrate/frame/revive/src/primitives.rs
+++ b/substrate/frame/revive/src/primitives.rs
@@ -108,6 +108,14 @@ pub enum EthTransactError {
 	Message(String),
 }
 
+/// Precision used for converting between Native and EVM balances.
+pub enum ConversionPrecision {
+	/// Exact conversion without any rounding.
+	Exact,
+	/// Conversion that rounds up to the nearest whole number.
+	RoundUp,
+}
+
 /// Result type of a `bare_code_upload` call.
 pub type CodeUploadResult<Balance> = Result<CodeUploadReturnValue<Balance>, DispatchError>;
 
-- 
GitLab