diff --git a/CHANGELOG.md b/CHANGELOG.md
index 28d74b7bf2..33eabbe4e7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
 
 ## Next release
 
+- feat: actual estimate_fee added, brought back l1 messages and refactored
+  simulate tx
 - dev: impl get_state_updates using get_transaction_re_execution_state_diff
 - feat: support strk as fee token
 - dev: pallet test for estimate_fee that skip validation
diff --git a/Cargo.lock b/Cargo.lock
index 6511ea1ff6..8d48947a64 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -883,7 +883,7 @@ dependencies = [
 [[package]]
 name = "blockifier"
 version = "0.5.0-rc.3"
-source = "git+https://github.com/bidzyyys/blockifier?branch=feature/scale-codec#59950ded347f60bfcbbc31300ff713e5423448e2"
+source = "git+https://github.com/bidzyyys/blockifier?branch=feature/scale-codec#3b2682b949cc691150a682bf26debe6f6e264361"
 dependencies = [
  "anyhow",
  "ark-ec",
@@ -5535,6 +5535,7 @@ dependencies = [
  "mc-db",
  "mc-eth-client",
  "mc-genesis-data-provider",
+ "mc-l1-gas-price",
  "mc-l1-messages",
  "mc-mapping-sync",
  "mc-rpc",
@@ -5543,7 +5544,7 @@ dependencies = [
  "mp-block",
  "mp-digest-log",
  "mp-felt",
- "mp-sequencer-address",
+ "mp-starknet-inherent",
  "num-bigint",
  "pallet-starknet",
  "pallet-starknet-runtime-api",
@@ -5607,6 +5608,7 @@ dependencies = [
  "mp-hashers",
  "mp-program-hash",
  "mp-simulations",
+ "mp-starknet-inherent",
  "pallet-aura",
  "pallet-grandpa",
  "pallet-starknet",
@@ -5748,6 +5750,21 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "mc-l1-gas-price"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "ethers",
+ "futures",
+ "log",
+ "mc-eth-client",
+ "mp-starknet-inherent",
+ "reqwest",
+ "serde",
+ "tokio",
+]
+
 [[package]]
 name = "mc-l1-messages"
 version = "0.1.0"
@@ -6190,17 +6207,6 @@ dependencies = [
  "starknet-ff 0.3.7",
 ]
 
-[[package]]
-name = "mp-sequencer-address"
-version = "0.7.0"
-dependencies = [
- "async-trait",
- "parity-scale-codec",
- "sp-core",
- "sp-inherents",
- "thiserror",
-]
-
 [[package]]
 name = "mp-simulations"
 version = "0.7.0"
@@ -6225,6 +6231,19 @@ dependencies = [
  "starknet_api",
 ]
 
+[[package]]
+name = "mp-starknet-inherent"
+version = "0.7.0"
+dependencies = [
+ "async-trait",
+ "blockifier",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-inherents",
+ "thiserror",
+]
+
 [[package]]
 name = "mp-storage"
 version = "0.7.0"
@@ -6889,8 +6908,8 @@ dependencies = [
  "mp-genesis-config",
  "mp-hashers",
  "mp-program-hash",
- "mp-sequencer-address",
  "mp-simulations",
+ "mp-starknet-inherent",
  "mp-storage",
  "mp-transactions",
  "pallet-timestamp",
@@ -6918,6 +6937,7 @@ dependencies = [
  "blockifier",
  "mp-felt",
  "mp-simulations",
+ "mp-starknet-inherent",
  "parity-scale-codec",
  "scale-info",
  "sp-api",
diff --git a/Cargo.toml b/Cargo.toml
index 857d2aa772..0e60e79d07 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@ members = [
   "crates/primitives/felt",
   "crates/primitives/hashers",
   "crates/primitives/block",
-  "crates/primitives/sequencer-address",
+  "crates/primitives/starknet-inherent",
   "crates/primitives/storage",
   "crates/primitives/chain-id",
   "crates/primitives/messages",
@@ -43,7 +43,7 @@ default-members = [
   "crates/primitives/felt",
   "crates/primitives/hashers",
   "crates/primitives/block",
-  "crates/primitives/sequencer-address",
+  "crates/primitives/starknet-inherent",
   "crates/primitives/storage",
   "crates/primitives/chain-id",
   "crates/primitives/messages",
@@ -164,7 +164,7 @@ mp-block = { path = "crates/primitives/block" }
 mp-fee = { path = "crates/primitives/fee" }
 mp-felt = { path = "crates/primitives/felt" }
 mp-hashers = { path = "crates/primitives/hashers" }
-mp-sequencer-address = { path = "crates/primitives/sequencer-address" }
+mp-starknet-inherent = { path = "crates/primitives/starknet-inherent" }
 mp-snos-output = { path = "crates/primitives/snos-output" }
 mp-storage = { path = "crates/primitives/storage" }
 mp-transactions = { path = "crates/primitives/transactions" }
@@ -185,6 +185,7 @@ mc-rpc = { path = "crates/client/rpc" }
 mc-rpc-core = { path = "crates/client/rpc-core" }
 mc-commitment-state-diff = { path = "crates/client/commitment-state-diff" }
 mc-l1-messages = { path = "crates/client/l1-messages" }
+mc-l1-gas-price = { path = "crates/client/l1-gas-price" }
 mc-eth-client = { path = "crates/client/eth-client" }
 mc-starknet-block-import = { path = "crates/client/starknet-block-import" }
 
@@ -225,15 +226,7 @@ ethers = { git = "https://github.com/gakonst/ethers-rs", rev = "f0e5b194f09c533f
 ethers-solc = { git = "https://github.com/gakonst/ethers-rs", rev = "f0e5b194f09c533feb10d1a686ddb9e5946ec107" }
 
 # Zaun
-ethereum-instance = { git = "https://github.com/keep-starknet-strange/zaun", package = "ethereum-instance", branch = "main" }
-starkgate-manager-client = { git = "https://github.com/keep-starknet-strange/zaun", package = "starkgate-manager-client", branch = "main" }
-starkgate-registry-client = { git = "https://github.com/keep-starknet-strange/zaun", package = "starkgate-registry-client", branch = "main" }
 starknet-core-contract-client = { git = "https://github.com/keep-starknet-strange/zaun", package = "starknet-core-contract-client", branch = "main" }
-starknet-erc20-client = { git = "https://github.com/keep-starknet-strange/zaun", package = "starknet-erc20-client", branch = "main" }
-starknet-eth-bridge-client = { git = "https://github.com/keep-starknet-strange/zaun", package = "starknet-eth-bridge-client", branch = "main" }
-starknet-proxy-client = { git = "https://github.com/keep-starknet-strange/zaun", package = "starknet-proxy-client", branch = "main" }
-starknet-token-bridge-client = { git = "https://github.com/keep-starknet-strange/zaun", package = "starknet-token-bridge-client", branch = "main" }
-zaun-utils = { git = "https://github.com/keep-starknet-strange/zaun", package = "utils", branch = "main" }
 
 
 # Other third party dependencies
diff --git a/configs/genesis-assets/MultiplyNumsContract.casm.json b/configs/genesis-assets/MultiplyNumsContract.casm.json
new file mode 100644
index 0000000000..a433194bc3
--- /dev/null
+++ b/configs/genesis-assets/MultiplyNumsContract.casm.json
@@ -0,0 +1,660 @@
+{
+  "prime": "0x800000000000011000000000000000000000000000000000000000000000001",
+  "compiler_version": "2.5.0",
+  "bytecode": [
+    "0xa0680017fff8000",
+    "0x7",
+    "0x482680017ffa8000",
+    "0x100000000000000000000000000000000",
+    "0x400280007ff97fff",
+    "0x10780017fff7fff",
+    "0xba",
+    "0x4825800180007ffa",
+    "0x0",
+    "0x400280007ff97fff",
+    "0x482680017ff98000",
+    "0x1",
+    "0x48297ffc80007ffd",
+    "0x20680017fff7fff",
+    "0x4",
+    "0x10780017fff7fff",
+    "0xa",
+    "0x482680017ffc8000",
+    "0x1",
+    "0x480a7ffd7fff8000",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480a7ffc7fff8000",
+    "0x10780017fff7fff",
+    "0x8",
+    "0x480a7ffc7fff8000",
+    "0x480a7ffd7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x480680017fff8000",
+    "0x0",
+    "0x20680017fff7ffe",
+    "0x8f",
+    "0x48127ffa7fff8000",
+    "0x480080007ffe8000",
+    "0x1104800180018000",
+    "0x113",
+    "0x20680017fff7ffe",
+    "0x86",
+    "0x48127fee7fff8000",
+    "0x48127fee7fff8000",
+    "0x48307ffe80007fff",
+    "0x20680017fff7fff",
+    "0x4",
+    "0x10780017fff7fff",
+    "0xa",
+    "0x482480017ffd8000",
+    "0x1",
+    "0x48127ffd7fff8000",
+    "0x480680017fff8000",
+    "0x0",
+    "0x48127ffa7fff8000",
+    "0x10780017fff7fff",
+    "0x8",
+    "0x48127ffd7fff8000",
+    "0x48127ffd7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x480680017fff8000",
+    "0x0",
+    "0x20680017fff7ffe",
+    "0x5e",
+    "0x48127ff67fff8000",
+    "0x480080007ffe8000",
+    "0x1104800180018000",
+    "0xf6",
+    "0x20680017fff7ffe",
+    "0x55",
+    "0x48127fee7fff8000",
+    "0x48127fee7fff8000",
+    "0x48307ffe80007fff",
+    "0x20680017fff7fff",
+    "0x4",
+    "0x10780017fff7fff",
+    "0x10",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x480680017fff8000",
+    "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473",
+    "0x400080007ffe7fff",
+    "0x48127ff87fff8000",
+    "0x48127fd07fff8000",
+    "0x480a7ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffa7fff8000",
+    "0x482480017ff98000",
+    "0x1",
+    "0x208b7fff7fff7ffe",
+    "0x1104800180018000",
+    "0x1b7",
+    "0x482480017fff8000",
+    "0x1b6",
+    "0x480080007fff8000",
+    "0xa0680017fff8000",
+    "0x9",
+    "0x4824800180007fce",
+    "0x3d72",
+    "0x482480017fff8000",
+    "0x100000000000000000000000000000000",
+    "0x400080007ff37fff",
+    "0x10780017fff7fff",
+    "0x23",
+    "0x4824800180007fce",
+    "0x3d72",
+    "0x400080007ff47fff",
+    "0x482480017ff48000",
+    "0x1",
+    "0x48127ffe7fff8000",
+    "0x480a7ffb7fff8000",
+    "0x48127fde7fff8000",
+    "0x48127ff27fff8000",
+    "0x1104800180018000",
+    "0xeb",
+    "0x20680017fff7ffd",
+    "0xe",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x400080007fff7ffe",
+    "0x48127ff97fff8000",
+    "0x48127ff97fff8000",
+    "0x48127ff97fff8000",
+    "0x480680017fff8000",
+    "0x0",
+    "0x48127ffb7fff8000",
+    "0x482480017ffa8000",
+    "0x1",
+    "0x208b7fff7fff7ffe",
+    "0x48127ffa7fff8000",
+    "0x48127ffa7fff8000",
+    "0x48127ffa7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffa7fff8000",
+    "0x48127ffa7fff8000",
+    "0x208b7fff7fff7ffe",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x480680017fff8000",
+    "0x4f7574206f6620676173",
+    "0x400080007ffe7fff",
+    "0x482480017ff18000",
+    "0x1",
+    "0x48127fc97fff8000",
+    "0x480a7ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffa7fff8000",
+    "0x482480017ff98000",
+    "0x1",
+    "0x208b7fff7fff7ffe",
+    "0x48127ffd7fff8000",
+    "0x10780017fff7fff",
+    "0x5",
+    "0x40780017fff7fff",
+    "0xe",
+    "0x48127fe87fff8000",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x480680017fff8000",
+    "0x4661696c656420746f20646573657269616c697a6520706172616d202332",
+    "0x400080007ffe7fff",
+    "0x48127ffd7fff8000",
+    "0x48127fd27fff8000",
+    "0x480a7ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffa7fff8000",
+    "0x482480017ff98000",
+    "0x1",
+    "0x208b7fff7fff7ffe",
+    "0x48127ffd7fff8000",
+    "0x10780017fff7fff",
+    "0x5",
+    "0x40780017fff7fff",
+    "0xe",
+    "0x48127fec7fff8000",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x480680017fff8000",
+    "0x4661696c656420746f20646573657269616c697a6520706172616d202331",
+    "0x400080007ffe7fff",
+    "0x48127ffd7fff8000",
+    "0x48127fe77fff8000",
+    "0x480a7ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffa7fff8000",
+    "0x482480017ff98000",
+    "0x1",
+    "0x208b7fff7fff7ffe",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x480680017fff8000",
+    "0x4f7574206f6620676173",
+    "0x400080007ffe7fff",
+    "0x482680017ff98000",
+    "0x1",
+    "0x480a7ffa7fff8000",
+    "0x480a7ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffa7fff8000",
+    "0x482480017ff98000",
+    "0x1",
+    "0x208b7fff7fff7ffe",
+    "0xa0680017fff8000",
+    "0x7",
+    "0x482680017ffa8000",
+    "0x100000000000000000000000000000000",
+    "0x400280007ff97fff",
+    "0x10780017fff7fff",
+    "0x54",
+    "0x4825800180007ffa",
+    "0x0",
+    "0x400280007ff97fff",
+    "0x482680017ff98000",
+    "0x1",
+    "0x48297ffc80007ffd",
+    "0x20680017fff7fff",
+    "0x4",
+    "0x10780017fff7fff",
+    "0x10",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x480680017fff8000",
+    "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473",
+    "0x400080007ffe7fff",
+    "0x48127ffc7fff8000",
+    "0x48127ffa7fff8000",
+    "0x480a7ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffa7fff8000",
+    "0x482480017ff98000",
+    "0x1",
+    "0x208b7fff7fff7ffe",
+    "0x1104800180018000",
+    "0x123",
+    "0x482480017fff8000",
+    "0x122",
+    "0x480080007fff8000",
+    "0xa0680017fff8000",
+    "0x9",
+    "0x4824800180007ff8",
+    "0x1a54",
+    "0x482480017fff8000",
+    "0x100000000000000000000000000000000",
+    "0x400080007ff77fff",
+    "0x10780017fff7fff",
+    "0x1f",
+    "0x4824800180007ff8",
+    "0x1a54",
+    "0x400080007ff87fff",
+    "0x48127fff7fff8000",
+    "0x480a7ffb7fff8000",
+    "0x1104800180018000",
+    "0x84",
+    "0x482480017fd78000",
+    "0x1",
+    "0x20680017fff7ffc",
+    "0xc",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x48127ffe7fff8000",
+    "0x48127ff87fff8000",
+    "0x48127ff87fff8000",
+    "0x480680017fff8000",
+    "0x0",
+    "0x48127ffb7fff8000",
+    "0x48127ffa7fff8000",
+    "0x208b7fff7fff7ffe",
+    "0x48127fff7fff8000",
+    "0x48127ff97fff8000",
+    "0x48127ff97fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ff97fff8000",
+    "0x48127ff97fff8000",
+    "0x208b7fff7fff7ffe",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x480680017fff8000",
+    "0x4f7574206f6620676173",
+    "0x400080007ffe7fff",
+    "0x482480017ff58000",
+    "0x1",
+    "0x48127ff37fff8000",
+    "0x480a7ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffa7fff8000",
+    "0x482480017ff98000",
+    "0x1",
+    "0x208b7fff7fff7ffe",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x480680017fff8000",
+    "0x4f7574206f6620676173",
+    "0x400080007ffe7fff",
+    "0x482680017ff98000",
+    "0x1",
+    "0x480a7ffa7fff8000",
+    "0x480a7ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffa7fff8000",
+    "0x482480017ff98000",
+    "0x1",
+    "0x208b7fff7fff7ffe",
+    "0xa0680017fff8000",
+    "0x12",
+    "0x4825800180007ffd",
+    "0x100000000",
+    "0x4844800180008002",
+    "0x8000000000000110000000000000000",
+    "0x4830800080017ffe",
+    "0x480280007ffc7fff",
+    "0x482480017ffe8000",
+    "0xefffffffffffffde00000000ffffffff",
+    "0x480280017ffc7fff",
+    "0x400280027ffc7ffb",
+    "0x402480017fff7ffb",
+    "0xffffffffffffffffffffffffffffffff",
+    "0x20680017fff7fff",
+    "0x10",
+    "0x402780017fff7fff",
+    "0x1",
+    "0x400380007ffc7ffd",
+    "0x482680017ffd8000",
+    "0xffffffffffffffffffffffff00000000",
+    "0x400280017ffc7fff",
+    "0x40780017fff7fff",
+    "0x5",
+    "0x482680017ffc8000",
+    "0x2",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480a7ffd7fff8000",
+    "0x208b7fff7fff7ffe",
+    "0x482680017ffc8000",
+    "0x3",
+    "0x480680017fff8000",
+    "0x1",
+    "0x480680017fff8000",
+    "0x0",
+    "0x208b7fff7fff7ffe",
+    "0x480a7ff97fff8000",
+    "0x480a7ffc7fff8000",
+    "0x480a7ffd7fff8000",
+    "0x1104800180018000",
+    "0x3e",
+    "0x20680017fff7ffd",
+    "0x1a",
+    "0x480a7ffa7fff8000",
+    "0x480a7ffb7fff8000",
+    "0x48127ffd7fff8000",
+    "0x1104800180018000",
+    "0x52",
+    "0x20680017fff7ffd",
+    "0xb",
+    "0x48127fe47fff8000",
+    "0x48127ffa7fff8000",
+    "0x48127ffa7fff8000",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x0",
+    "0x48127fe27fff8000",
+    "0x208b7fff7fff7ffe",
+    "0x48127fe47fff8000",
+    "0x48127ffa7fff8000",
+    "0x48127ffa7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffa7fff8000",
+    "0x48127ffa7fff8000",
+    "0x208b7fff7fff7ffe",
+    "0x40780017fff7fff",
+    "0x18",
+    "0x48127fe47fff8000",
+    "0x480a7ffa7fff8000",
+    "0x480a7ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127fe27fff8000",
+    "0x48127fe27fff8000",
+    "0x208b7fff7fff7ffe",
+    "0x480a7ffc7fff8000",
+    "0x480a7ffd7fff8000",
+    "0x480680017fff8000",
+    "0x0",
+    "0x1104800180018000",
+    "0x2f",
+    "0x20680017fff7ffd",
+    "0xb",
+    "0x48127ffb7fff8000",
+    "0x48127ffb7fff8000",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x0",
+    "0x208b7fff7fff7ffe",
+    "0x48127ffb7fff8000",
+    "0x48127ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffb7fff8000",
+    "0x48127ffb7fff8000",
+    "0x208b7fff7fff7ffe",
+    "0x480a7ffb7fff8000",
+    "0x484a7ffd7ffc8000",
+    "0x1104800180018000",
+    "0x4d",
+    "0x20680017fff7ffe",
+    "0xb",
+    "0x40780017fff7fff",
+    "0x2",
+    "0x48127ffb7fff8000",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x0",
+    "0x48127ffa7fff8000",
+    "0x208b7fff7fff7ffe",
+    "0x40780017fff7fff",
+    "0x1",
+    "0x480680017fff8000",
+    "0x7533325f6d756c204f766572666c6f77",
+    "0x400080007ffe7fff",
+    "0x48127ffb7fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffc7fff8000",
+    "0x482480017ffb8000",
+    "0x1",
+    "0x208b7fff7fff7ffe",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x2a4a183f82db747ab399ca476ab84cc3def6abe3ac63748d03b4584af38d057",
+    "0x480680017fff8000",
+    "0x53746f726167655772697465",
+    "0x400280007ffc7fff",
+    "0x400380017ffc7ffb",
+    "0x400280027ffc7ffd",
+    "0x400280037ffc7ffe",
+    "0x400380047ffc7ffd",
+    "0x480280067ffc8000",
+    "0x20680017fff7fff",
+    "0xd",
+    "0x480280057ffc8000",
+    "0x482680017ffc8000",
+    "0x7",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x0",
+    "0x10780017fff7fff",
+    "0x9",
+    "0x480280057ffc8000",
+    "0x482680017ffc8000",
+    "0x9",
+    "0x480680017fff8000",
+    "0x1",
+    "0x480280077ffc8000",
+    "0x480280087ffc8000",
+    "0x1104800180018000",
+    "0x2b",
+    "0x20680017fff7ffd",
+    "0xb",
+    "0x48127ff67fff8000",
+    "0x48127ff67fff8000",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x0",
+    "0x208b7fff7fff7ffe",
+    "0x48127ff67fff8000",
+    "0x48127ff67fff8000",
+    "0x480680017fff8000",
+    "0x1",
+    "0x48127ffb7fff8000",
+    "0x48127ffb7fff8000",
+    "0x208b7fff7fff7ffe",
+    "0xa0680017fff8000",
+    "0x7",
+    "0x4825800180007ffd",
+    "0x100000000",
+    "0x400280007ffc7fff",
+    "0x10780017fff7fff",
+    "0xb",
+    "0x482680017ffd8000",
+    "0xffffffffffffffffffffffff00000000",
+    "0x400280007ffc7fff",
+    "0x482680017ffc8000",
+    "0x1",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480a7ffd7fff8000",
+    "0x208b7fff7fff7ffe",
+    "0x482680017ffc8000",
+    "0x1",
+    "0x480680017fff8000",
+    "0x1",
+    "0x480680017fff8000",
+    "0x0",
+    "0x208b7fff7fff7ffe",
+    "0x20780017fff7ffb",
+    "0x9",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x0",
+    "0x480680017fff8000",
+    "0x0",
+    "0x208b7fff7fff7ffe",
+    "0x480680017fff8000",
+    "0x1",
+    "0x480a7ffc7fff8000",
+    "0x480a7ffd7fff8000",
+    "0x208b7fff7fff7ffe"
+  ],
+  "hints": [
+    [
+      0,
+      [
+        {
+          "TestLessThanOrEqual": {
+            "lhs": { "Immediate": "0x0" },
+            "rhs": { "Deref": { "register": "FP", "offset": -6 } },
+            "dst": { "register": "AP", "offset": 0 }
+          }
+        }
+      ]
+    ],
+    [75, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [
+      94,
+      [
+        {
+          "TestLessThanOrEqual": {
+            "lhs": { "Immediate": "0x3d72" },
+            "rhs": { "Deref": { "register": "AP", "offset": -49 } },
+            "dst": { "register": "AP", "offset": 0 }
+          }
+        }
+      ]
+    ],
+    [116, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [136, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [157, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [177, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [191, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [
+      206,
+      [
+        {
+          "TestLessThanOrEqual": {
+            "lhs": { "Immediate": "0x0" },
+            "rhs": { "Deref": { "register": "FP", "offset": -6 } },
+            "dst": { "register": "AP", "offset": 0 }
+          }
+        }
+      ]
+    ],
+    [223, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [
+      242,
+      [
+        {
+          "TestLessThanOrEqual": {
+            "lhs": { "Immediate": "0x1a54" },
+            "rhs": { "Deref": { "register": "AP", "offset": -7 } },
+            "dst": { "register": "AP", "offset": 0 }
+          }
+        }
+      ]
+    ],
+    [262, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [280, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [295, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [
+      310,
+      [
+        {
+          "TestLessThan": {
+            "lhs": { "Deref": { "register": "FP", "offset": -3 } },
+            "rhs": { "Immediate": "0x100000000" },
+            "dst": { "register": "AP", "offset": 0 }
+          }
+        }
+      ]
+    ],
+    [
+      314,
+      [
+        {
+          "LinearSplit": {
+            "value": { "Deref": { "register": "AP", "offset": -1 } },
+            "scalar": { "Immediate": "0x8000000000000110000000000000000" },
+            "max_x": { "Immediate": "0xfffffffffffffffffffffffffffffffe" },
+            "x": { "register": "AP", "offset": 0 },
+            "y": { "register": "AP", "offset": 1 }
+          }
+        }
+      ]
+    ],
+    [427, [{ "AllocSegment": { "dst": { "register": "AP", "offset": 0 } } }]],
+    [
+      450,
+      [
+        {
+          "SystemCall": {
+            "system": { "Deref": { "register": "FP", "offset": -4 } }
+          }
+        }
+      ]
+    ],
+    [
+      491,
+      [
+        {
+          "TestLessThan": {
+            "lhs": { "Deref": { "register": "FP", "offset": -3 } },
+            "rhs": { "Immediate": "0x100000000" },
+            "dst": { "register": "AP", "offset": 0 }
+          }
+        }
+      ]
+    ]
+  ],
+  "entry_points_by_type": {
+    "EXTERNAL": [
+      {
+        "selector": "0x39674cadb16109ec414e371cc8f04eb60a540c52d4880cadb49dfafb8d79797",
+        "offset": 0,
+        "builtins": ["range_check"]
+      }
+    ],
+    "L1_HANDLER": [],
+    "CONSTRUCTOR": [
+      {
+        "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194",
+        "offset": 206,
+        "builtins": ["range_check"]
+      }
+    ]
+  }
+}
diff --git a/configs/genesis-assets/MultiplyNumsContract.sierra.json b/configs/genesis-assets/MultiplyNumsContract.sierra.json
new file mode 100644
index 0000000000..fd388e634c
--- /dev/null
+++ b/configs/genesis-assets/MultiplyNumsContract.sierra.json
@@ -0,0 +1,711 @@
+{
+  "sierra_program": [
+    "0x1",
+    "0x4",
+    "0x0",
+    "0x2",
+    "0x5",
+    "0x0",
+    "0xd9",
+    "0x27",
+    "0x21",
+    "0x52616e6765436865636b",
+    "0x800000000000000100000000000000000000000000000000",
+    "0x537472756374",
+    "0x800000000000000f00000000000000000000000000000001",
+    "0x0",
+    "0x2ee1e2b1b89f8c495f200e4956278a4d47395fe262f27b52e5865c9524c08c3",
+    "0x800000000000000f00000000000000000000000000000002",
+    "0x1",
+    "0x16a4c8d7c05909052238a862d8cc3e7975bf05a07b3a69c6b28951083a6d672",
+    "0x4172726179",
+    "0x800000000000000300000000000000000000000000000001",
+    "0x1d",
+    "0x800000000000000300000000000000000000000000000003",
+    "0x3",
+    "0x4",
+    "0x456e756d",
+    "0xcc5e86243f861d2d64b08c35db21013e773ac5cf10097946fe0011304886d5",
+    "0x2",
+    "0x5",
+    "0x101dc0399934cc08fa0d6f6f2daead4e4a38cabeea1c743e1fc28d2d6e58e99",
+    "0x53746f7261676541646472657373",
+    "0x800000000000000700000000000000000000000000000000",
+    "0x53746f726167654261736541646472657373",
+    "0x753634",
+    "0x105da2b4e27de569d85a3962e8c84e0d75055a91ac1a9cb1cbf3150cfecec8a",
+    "0x800000000000000f00000000000000000000000000000003",
+    "0xb",
+    "0x3561ddf415a895d3c747f8976c09715e6a1840916a4f84f48a35c1e14a810b5",
+    "0xc",
+    "0x753332",
+    "0x800000000000000700000000000000000000000000000002",
+    "0xe",
+    "0x3ab802bcce3a9ca953b0e1f31a5b29eb27a9b727c891e24300e1b5cc57387ba",
+    "0xf",
+    "0x39fe7e2f05475a9afeee1fa9ff3d5beb4311975ef57a7023f6585b4f791d1c",
+    "0x11",
+    "0x1d9568edb93b79ccceefd66fc7325b339819ea8b7338e70425e59e8e35c410c",
+    "0x12",
+    "0x536e617073686f74",
+    "0x800000000000000700000000000000000000000000000001",
+    "0x1baeba72e79e9db2587cf44fedb2f3700b2075a5e8e39a562584862c4b71f62",
+    "0x14",
+    "0x15",
+    "0x800000000000000700000000000000000000000000000003",
+    "0x1afe071b8c7c79454318fcdeb7697f21321f6319e490cbbeab1b56c5ce96390",
+    "0x17",
+    "0x4275696c74696e436f737473",
+    "0x53797374656d",
+    "0x9931c641b913035ae674b400b61a51476d506bbe8bba2ff8a6272790aba9e6",
+    "0x16",
+    "0x19b9ae4ba181a54f9e7af894a81b44a60aea4c9803939708d6cc212759ee94c",
+    "0x66656c74323532",
+    "0x426f78",
+    "0x29d7d57c04a880978e7b3689f6218e507f3be17588744b58dc17762447ad0e7",
+    "0x1e",
+    "0x4761734275696c74696e",
+    "0x6d",
+    "0x7265766f6b655f61705f747261636b696e67",
+    "0x77697468647261775f676173",
+    "0x6272616e63685f616c69676e",
+    "0x7374727563745f6465636f6e737472756374",
+    "0x656e61626c655f61705f747261636b696e67",
+    "0x73746f72655f74656d70",
+    "0x61727261795f736e617073686f745f706f705f66726f6e74",
+    "0x656e756d5f696e6974",
+    "0x1f",
+    "0x6a756d70",
+    "0x7374727563745f636f6e737472756374",
+    "0x656e756d5f6d61746368",
+    "0x756e626f78",
+    "0x72656e616d65",
+    "0x66756e6374696f6e5f63616c6c",
+    "0x1c",
+    "0x64697361626c655f61705f747261636b696e67",
+    "0x64726f70",
+    "0x61727261795f6e6577",
+    "0x66656c743235325f636f6e7374",
+    "0x496e70757420746f6f206c6f6e6720666f7220617267756d656e7473",
+    "0x61727261795f617070656e64",
+    "0x1b",
+    "0x20",
+    "0x1a",
+    "0x6765745f6275696c74696e5f636f737473",
+    "0x19",
+    "0x77697468647261775f6761735f616c6c",
+    "0x18",
+    "0x736e617073686f745f74616b65",
+    "0x7533325f746f5f66656c74323532",
+    "0x4f7574206f6620676173",
+    "0x4661696c656420746f20646573657269616c697a6520706172616d202332",
+    "0x4661696c656420746f20646573657269616c697a6520706172616d202331",
+    "0x13",
+    "0x7533325f7472795f66726f6d5f66656c74323532",
+    "0x10",
+    "0x647570",
+    "0x6",
+    "0xd",
+    "0x7533325f636f6e7374",
+    "0x7533325f776964655f6d756c",
+    "0xa",
+    "0x7",
+    "0x7533325f6d756c204f766572666c6f77",
+    "0x73746f726167655f626173655f616464726573735f636f6e7374",
+    "0x2a4a183f82db747ab399ca476ab84cc3def6abe3ac63748d03b4584af38d057",
+    "0x73746f726167655f616464726573735f66726f6d5f62617365",
+    "0x8",
+    "0x73746f726167655f77726974655f73797363616c6c",
+    "0x646f776e63617374",
+    "0x1b0",
+    "0xffffffffffffffff",
+    "0xaf",
+    "0x9",
+    "0x9e",
+    "0x99",
+    "0x23",
+    "0x28",
+    "0x22",
+    "0x87",
+    "0x24",
+    "0x25",
+    "0x26",
+    "0x27",
+    "0x29",
+    "0x81",
+    "0x2a",
+    "0x2b",
+    "0x2c",
+    "0x2d",
+    "0x2e",
+    "0x47",
+    "0x2f",
+    "0x30",
+    "0x31",
+    "0x32",
+    "0x33",
+    "0x34",
+    "0x35",
+    "0x36",
+    "0x37",
+    "0x38",
+    "0x71",
+    "0x39",
+    "0x3a",
+    "0x3b",
+    "0x3c",
+    "0x3d",
+    "0x3e",
+    "0x3f",
+    "0x40",
+    "0x41",
+    "0x6a",
+    "0x42",
+    "0x43",
+    "0x44",
+    "0x45",
+    "0x46",
+    "0x48",
+    "0x49",
+    "0x4a",
+    "0x4b",
+    "0x4c",
+    "0x4d",
+    "0x4e",
+    "0x4f",
+    "0x50",
+    "0x51",
+    "0x52",
+    "0x53",
+    "0x54",
+    "0x55",
+    "0x56",
+    "0x57",
+    "0x8c",
+    "0x58",
+    "0x59",
+    "0x5a",
+    "0x5b",
+    "0x5c",
+    "0x5d",
+    "0x5e",
+    "0xa2",
+    "0x5f",
+    "0x60",
+    "0x61",
+    "0x62",
+    "0x63",
+    "0x64",
+    "0x65",
+    "0x66",
+    "0x67",
+    "0x68",
+    "0x69",
+    "0x100",
+    "0xd2",
+    "0xf3",
+    "0xec",
+    "0x114",
+    "0x13b",
+    "0x133",
+    "0x155",
+    "0x166",
+    "0x182",
+    "0x187",
+    "0x191",
+    "0x19e",
+    "0x1aa",
+    "0x6b",
+    "0x6c",
+    "0xbd",
+    "0x10e",
+    "0x11a",
+    "0x143",
+    "0x15b",
+    "0x172",
+    "0x198",
+    "0x1a4",
+    "0xff4",
+    "0xd100f080e0806050d030c080b0a0905040308080605070306050403020100",
+    "0x81b0806051a03190504031618161716150f08080814050d10130812081105",
+    "0x1b08230507031308220821050d10200806051f03161e13081d081c050d1008",
+    "0x806051f032a0829051f030f0828271308260825050d100808240806051a03",
+    "0x2c101308320831050d100230162f13082e082d050d102008240806052c032b",
+    "0x83d053c053b053a3902380808370836052c100c0828351634080820083305",
+    "0x8084405434208083f2a08083f0512420812410c0808400508083f053e2b08",
+    "0x49080845120e08480c08083f0c0808470c0808464208084508124208124108",
+    "0x440c08084f4e12084d0c08084c2008084b3708084b2a08084b054a2b080844",
+    "0x5408083f05535008083f5208083f5108083f081250081241130808440e0808",
+    "0x572408084b2e08083d560808450e0e08482008083f240808441b0808440555",
+    "0x5912084d051250081241320808440f08084b0f080857055820080847200808",
+    "0x41055d2608084b5c0808450f0e08482b08084b5b12084d5a12084d0808084b",
+    "0x2408083d2208083d5e080845130e08480812490812414908083f0512490812",
+    "0x415608083f0512560812412e0808441d08083d61080845600e08482008085f",
+    "0x56308125c0812415c08083f05125c08124126080844051208620812560812",
+    "0x125e0812416612084d5e08083f05125e08124122080844650e08486408083f",
+    "0x6508083f051265081241056b6a08083f1b08084b1b08085705696812086708",
+    "0x8083f0512610812411d0808441208083d600808456a0e0848081265081241",
+    "0x6008083f051260081241120808446508084520086408126c08126108124161",
+    "0x80512056560126f130f126e120805120805056e080505056d081260081241",
+    "0x126e126a0860050f086e080f081305056e08050f056a086e080e080e05056e",
+    "0x1d08700561086e0870086a051d086e0864086505056e080512051b081d6470",
+    "0x5e086e0822081d0522086e08051b05056e0805120505240805640520086e08",
+    "0x805120526087124086e122008610520086e085e08700561086e081b086a05",
+    "0x82a085e050f086e080f0813052a086e085c0822055c086e0824082005056e",
+    "0x5056e080512055608722e086e1232082605322b126e082a0f1224052a086e",
+    "0x50126e125208600552086e0852086a0552086e0854080e0554086e0861085c",
+    "0x83708700542086e0850086a0537086e0849086505056e080512050c087349",
+    "0x575086e0800081d0500086e08051b05056e0805120505740805640551086e",
+    "0x6e0805120577087673086e125108610551086e087508700542086e080c086a",
+    "0x6e0879085e052b086e082b08130579086e087808220578086e087308200505",
+    "0x5c05056e080512057d087c7b086e1274082605747a126e08792b1224057908",
+    "0x8180126e127f0860057f086e087f086a057f086e087e080e057e086e084208",
+    "0x2e05056e0881083205056e0880082b05056e08052a05056e08051205830882",
+    "0x885085e0585086e0805540584086e08055605056e082e082e05056e087b08",
+    "0x80c0588086e08868712490587086e0805500586086e08858412520585086e",
+    "0x510512086e081208420513086e08130837057a086e087a08130589086e0888",
+    "0x86e08050005056e0883082b05056e080512058912137a0f0889086e088908",
+    "0x5056e080512058f8e128d8c8b126e128a137a0e73058a086e088a0875058a",
+    "0x837058b086e088b08130591086e089008780590086e08057705056e08052a",
+    "0x7a057b086e087b0879052e086e082e08790512086e08120842058c086e088c",
+    "0x56e0805120598089796086e1295087405959493920f6e087b2e91128c8b60",
+    "0x9c126e089b087e05056e089a087d059b9a126e0896087b0599086e08055605",
+    "0x6e089e991252059e086e089d0880059d086e0882087f05056e089c082e0582",
+    "0x8a2088405a2086e08a1085c05056e08a0088305a1a0126e089f0881059f08",
+    "0x9408420593086e089308370592086e0892081305a4086e08a3088505a3086e",
+    "0x86e0898080c05056e08051205a49493920f08a4086e08a408510594086e08",
+    "0x6e08a508510594086e089408420593086e089308370592086e0892081305a5",
+    "0x2e082e05056e087b082e05056e08052a05056e08051205a59493920f08a508",
+    "0x8a7a6125205a7086e08a7085e05a7086e08058605a6086e08055605056e08",
+    "0x8e081305ab086e08aa080c05aa086e08a8a9124905a9086e08055005a8086e",
+    "0x8e0f08ab086e08ab08510512086e08120842058f086e088f0837058e086e08",
+    "0x5056e082e082e05056e0842082b05056e087d088705056e08051205ab128f",
+    "0x82e082e05056e0877088705056e0805120505ad08056405ac086e087a0813",
+    "0x5ae086e08055605056e08052a05ac086e082b081305056e0842082b05056e",
+    "0x5b1086e08055005b0086e08afae125205af086e08af085e05af086e080588",
+    "0x86e0813083705ac086e08ac081305b3086e08b2080c05b2086e08b0b11249",
+    "0x8705056e08051205b31213ac0f08b3086e08b308510512086e081208420513",
+    "0x6e0805120505b508056405b4086e082b081305056e0861082b05056e085608",
+    "0x5605056e08052a05b4086e080f081305056e0861082b05056e082608870505",
+    "0x5005b8086e08b7b6125205b7086e08b7085e05b7086e08058905b6086e0805",
+    "0x5b4086e08b4081305bb086e08ba080c05ba086e08b8b9124905b9086e0805",
+    "0x1205bb1213b40f08bb086e08bb08510512086e081208420513086e08130837",
+    "0x6e08bd085e05bd086e08058605bc086e08055605056e080e088a05056e0805",
+    "0xc0080c05c0086e08bebf124905bf086e08055005be086e08bdbc125205bd08",
+    "0x8510512086e081208420565086e086508370560086e086008130597086e08",
+    "0x656012c1130f126e120805120805056e08050505971265600f0897086e0897",
+    "0x6470126e126a0860050f086e080f0813056a086e080e080e05056e08051205",
+    "0x51d086e08055605056e0864083205056e0870082b05056e080512051b08c2",
+    "0x522086e0805500520086e08611d12520561086e0861085e0561086e080554",
+    "0x86e08130837050f086e080f08130524086e085e080c055e086e0820221249",
+    "0x2b05056e080512052412130f0f0824086e082408510512086e081208420513",
+    "0x2a5c126e1226130f0e730526086e082608750526086e08050005056e081b08",
+    "0x6e082a08370556086e082e0878052e086e08057705056e08051205322b12c3",
+    "0x55c086e085c0813055052540e6e0856122a0e8b0512086e08120842052a08",
+    "0x537086e08055605056e0849088e05056e080512050c08c449086e1250088c",
+    "0x75086e080008840500086e0851085c05056e08420883055142126e08370881",
+    "0x86e085208420554086e08540837055c086e085c08130573086e0875088505",
+    "0x130577086e080c080c05056e080512057352545c0f0873086e087308510552",
+    "0x877086e087708510552086e085208420554086e08540837055c086e085c08",
+    "0x6e0879085e0579086e0805860578086e08055605056e080512057752545c0f",
+    "0x7b080c057b086e087a7412490574086e080550057a086e0879781252057908",
+    "0x8510512086e081208420532086e08320837052b086e082b0813057d086e08",
+    "0x7e086e08055605056e080e088a05056e080512057d12322b0f087d086e087d",
+    "0x81086e0805500580086e087f7e1252057f086e087f085e057f086e08058605",
+    "0x6e086508370560086e086008130584086e0883080c0583086e088081124905",
+    "0x6e120805128f05841265600f0884086e088408510512086e08120842056508",
+    "0x8910512086e081208130513086e080e089005056e080512050f08c50e1212",
+    "0x565086e086008920560086e08051b05056e080512051312120813086e0813",
+    "0xf08790505086e0805081305650f120865086e08650891050f086e080f0813",
+    "0x6a086e12650894056560126e08130f050e930513086e08130879050f086e08",
+    "0x6e08080837051b086e080e08960564086e086a089505056e080512057008c6",
+    "0x80f99051d086e081d0879051d64126e086408980512086e08120842050808",
+    "0x85e089b05056e080512052408c75e086e1222089a052220610e6e081d1b12",
+    "0x882052b086e08642a129c052a086e0826087805056e085c0887055c26126e",
+    "0x9d0520086e082008420561086e086108370560086e086008130532086e082b",
+    "0x6e0824089e05056e0864082e05056e08051205322061600f0832086e083208",
+    "0x82e089d0520086e082008420561086e086108370560086e08600813052e08",
+    "0x556086e0870089e05056e080e087d05056e080512052e2061600f082e086e",
+    "0x56086e0856089d0512086e081208420508086e080808370560086e08600813",
+    "0x420505086e08050837050f086e08120896050e086e08059f05561208600f08",
+    "0x65089a056560130e6e080e0f08050f99050e086e080e08790508086e080808",
+    "0x1b05056e081b0887051b64126e086a089b05056e080512057008c86a086e12",
+    "0x522086e082008a10520086e081d6112a00561086e08640878051d086e0805",
+    "0x512052260130e0822086e082208a20560086e086008420513086e08130837",
+    "0x5e08a20560086e086008420513086e08130837055e086e087008a305056e08",
+    "0x80e08a50505086e08050813050e086e08120812a4055e60130e085e086e08",
+    "0x5056e080512056508c960086e1213082605130f126e080e0512a6050e086e",
+    "0x70086e087008a9050f086e080f08130570086e086a08a8056a086e086008a7",
+    "0x1b086e0805aa0564086e08055605056e0865088705056e08051205700f1208",
+    "0x6e081d6112490561086e080550051d086e081b641252051b086e081b085e05",
+    "0x5220f120822086e082208a9050f086e080f08130522086e082008ab052008",
+    "0xaf0565086e08059f0560086e080f08ae0513086e080e0880050f086e0805ac",
+    "0x560086e086008b10565086e0865087905056e087008b005706a126e081208",
+    "0x522086e08051b05056e0805120520611d0eca1b64126e12136065080513b2",
+    "0x5c086e085e08b40526086e081b08420524086e08640837055e086e082208b3",
+    "0x8420524086e081d0837052a086e082008b605056e0805120505cb08056405",
+    "0x8cc32086e122b08b8052b086e085c08b7055c086e082a08b40526086e0861",
+    "0x86e085408bb0554086e08566a12ba0556086e083208b905056e080512052e",
+    "0x55226240e0852086e085208bc0526086e082608420524086e082408370552",
+    "0x8420524086e082408370550086e082e08bd05056e086a08b005056e080512",
+    "0xf08cd0e12126e12080512be055026240e0850086e085008bc0526086e0826",
+    "0x813086e081308910512086e081208130513086e080e089005056e08051205",
+    "0x86e080f08130565086e086008920560086e08051b05056e08051205131212",
+    "0x5056e080512051208ce08086e120508bf05650f120865086e08650891050f",
+    "0x6e080512050f08080f086e080f08cf050f086e080e0897050e086e080808c0",
+    "0x6e086508cf0565086e086008d00560086e08121312490513086e0805500505",
+    "0x505251050f2b5251050f050e120805505251050f2b5251050f706508086508",
+    "0xf0e120805565251050f20202452510560d208054905120c0512d10e120805",
+    "0xe201b52510fd51208055e05122020050ed41208055c52510e2452510ed313",
+    "0xd80560086508d70805490512640512d60e120805615251"
+  ],
+  "sierra_program_debug_info": {
+    "type_names": [
+      [0, "RangeCheck"],
+      [1, "Unit"],
+      [2, "Tuple<Unit>"],
+      [3, "core::panics::Panic"],
+      [4, "Array<felt252>"],
+      [5, "Tuple<core::panics::Panic, Array<felt252>>"],
+      [6, "core::panics::PanicResult::<((),)>"],
+      [7, "core::result::Result::<(), core::array::Array::<core::felt252>>"],
+      [8, "StorageAddress"],
+      [9, "StorageBaseAddress"],
+      [10, "u64"],
+      [
+        11,
+        "product::MultiplyNumsContract::__member_module_product::ContractMemberState"
+      ],
+      [
+        12,
+        "Tuple<product::MultiplyNumsContract::__member_module_product::ContractMemberState, Unit>"
+      ],
+      [
+        13,
+        "core::panics::PanicResult::<(product::MultiplyNumsContract::__member_module_product::ContractMemberState, ())>"
+      ],
+      [14, "u32"],
+      [15, "Tuple<u32>"],
+      [16, "core::panics::PanicResult::<(core::integer::u32,)>"],
+      [17, "product::MultiplyNumsContract::ContractState"],
+      [18, "Tuple<product::MultiplyNumsContract::ContractState, Unit>"],
+      [
+        19,
+        "core::panics::PanicResult::<(product::MultiplyNumsContract::ContractState, ())>"
+      ],
+      [20, "Snapshot<Array<felt252>>"],
+      [21, "core::array::Span::<core::felt252>"],
+      [22, "Tuple<core::array::Span::<core::felt252>>"],
+      [23, "Tuple<product::MultiplyNumsContract::ContractState, u32>"],
+      [
+        24,
+        "core::panics::PanicResult::<(product::MultiplyNumsContract::ContractState, core::integer::u32)>"
+      ],
+      [25, "BuiltinCosts"],
+      [26, "System"],
+      [
+        27,
+        "core::panics::PanicResult::<(core::array::Span::<core::felt252>,)>"
+      ],
+      [28, "core::option::Option::<core::integer::u32>"],
+      [29, "felt252"],
+      [30, "Box<felt252>"],
+      [31, "core::option::Option::<core::box::Box::<@core::felt252>>"],
+      [32, "GasBuiltin"]
+    ],
+    "libfunc_names": [
+      [0, "revoke_ap_tracking"],
+      [1, "withdraw_gas"],
+      [2, "branch_align"],
+      [3, "struct_deconstruct<core::array::Span::<core::felt252>>"],
+      [4, "enable_ap_tracking"],
+      [5, "store_temp<RangeCheck>"],
+      [6, "array_snapshot_pop_front<felt252>"],
+      [
+        7,
+        "enum_init<core::option::Option::<core::box::Box::<@core::felt252>>, 0>"
+      ],
+      [8, "store_temp<Snapshot<Array<felt252>>>"],
+      [
+        9,
+        "store_temp<core::option::Option::<core::box::Box::<@core::felt252>>>"
+      ],
+      [10, "jump"],
+      [11, "struct_construct<Unit>"],
+      [
+        12,
+        "enum_init<core::option::Option::<core::box::Box::<@core::felt252>>, 1>"
+      ],
+      [
+        13,
+        "enum_match<core::option::Option::<core::box::Box::<@core::felt252>>>"
+      ],
+      [14, "unbox<felt252>"],
+      [15, "rename<felt252>"],
+      [16, "store_temp<felt252>"],
+      [17, "function_call<user@core::integer::Felt252TryIntoU32::try_into>"],
+      [18, "enum_match<core::option::Option::<core::integer::u32>>"],
+      [19, "struct_construct<core::array::Span::<core::felt252>>"],
+      [20, "disable_ap_tracking"],
+      [21, "drop<Snapshot<Array<felt252>>>"],
+      [22, "drop<Box<felt252>>"],
+      [23, "drop<u32>"],
+      [24, "array_new<felt252>"],
+      [
+        25,
+        "felt252_const<7733229381460288120802334208475838166080759535023995805565484692595>"
+      ],
+      [26, "array_append<felt252>"],
+      [27, "struct_construct<core::panics::Panic>"],
+      [28, "struct_construct<Tuple<core::panics::Panic, Array<felt252>>>"],
+      [
+        29,
+        "enum_init<core::panics::PanicResult::<(core::array::Span::<core::felt252>,)>, 1>"
+      ],
+      [30, "store_temp<GasBuiltin>"],
+      [31, "store_temp<System>"],
+      [
+        32,
+        "store_temp<core::panics::PanicResult::<(core::array::Span::<core::felt252>,)>>"
+      ],
+      [33, "get_builtin_costs"],
+      [34, "store_temp<BuiltinCosts>"],
+      [35, "withdraw_gas_all"],
+      [
+        36,
+        "struct_construct<product::MultiplyNumsContract::__member_module_product::ContractMemberState>"
+      ],
+      [37, "struct_construct<product::MultiplyNumsContract::ContractState>"],
+      [38, "store_temp<u32>"],
+      [
+        39,
+        "function_call<user@product::MultiplyNumsContract::MultiplyNumsContract::multiply>"
+      ],
+      [
+        40,
+        "enum_match<core::panics::PanicResult::<(product::MultiplyNumsContract::ContractState, core::integer::u32)>>"
+      ],
+      [
+        41,
+        "struct_deconstruct<Tuple<product::MultiplyNumsContract::ContractState, u32>>"
+      ],
+      [42, "drop<product::MultiplyNumsContract::ContractState>"],
+      [43, "snapshot_take<u32>"],
+      [44, "rename<u32>"],
+      [45, "u32_to_felt252"],
+      [46, "snapshot_take<Array<felt252>>"],
+      [47, "drop<Array<felt252>>"],
+      [48, "struct_construct<Tuple<core::array::Span::<core::felt252>>>"],
+      [
+        49,
+        "enum_init<core::panics::PanicResult::<(core::array::Span::<core::felt252>,)>, 0>"
+      ],
+      [50, "felt252_const<375233589013918064796019>"],
+      [51, "drop<Unit>"],
+      [
+        52,
+        "felt252_const<485748461484230571791265682659113160264223489397539653310998840191492914>"
+      ],
+      [
+        53,
+        "felt252_const<485748461484230571791265682659113160264223489397539653310998840191492913>"
+      ],
+      [54, "drop<core::array::Span::<core::felt252>>"],
+      [55, "function_call<user@product::MultiplyNumsContract::constructor>"],
+      [
+        56,
+        "enum_match<core::panics::PanicResult::<(product::MultiplyNumsContract::ContractState, ())>>"
+      ],
+      [57, "drop<Tuple<product::MultiplyNumsContract::ContractState, Unit>>"],
+      [58, "u32_try_from_felt252"],
+      [59, "enum_init<core::option::Option::<core::integer::u32>, 0>"],
+      [60, "store_temp<core::option::Option::<core::integer::u32>>"],
+      [61, "enum_init<core::option::Option::<core::integer::u32>, 1>"],
+      [62, "function_call<user@core::integer::U32Mul::mul>"],
+      [63, "enum_match<core::panics::PanicResult::<(core::integer::u32,)>>"],
+      [64, "struct_deconstruct<Tuple<u32>>"],
+      [65, "struct_deconstruct<product::MultiplyNumsContract::ContractState>"],
+      [66, "dup<u32>"],
+      [
+        67,
+        "function_call<user@product::MultiplyNumsContract::__member_module_product::InternalContractMemberStateImpl::write>"
+      ],
+      [
+        68,
+        "enum_match<core::panics::PanicResult::<(product::MultiplyNumsContract::__member_module_product::ContractMemberState, ())>>"
+      ],
+      [
+        69,
+        "struct_deconstruct<Tuple<product::MultiplyNumsContract::__member_module_product::ContractMemberState, Unit>>"
+      ],
+      [
+        70,
+        "struct_construct<Tuple<product::MultiplyNumsContract::ContractState, u32>>"
+      ],
+      [
+        71,
+        "enum_init<core::panics::PanicResult::<(product::MultiplyNumsContract::ContractState, core::integer::u32)>, 0>"
+      ],
+      [
+        72,
+        "store_temp<core::panics::PanicResult::<(product::MultiplyNumsContract::ContractState, core::integer::u32)>>"
+      ],
+      [
+        73,
+        "enum_init<core::panics::PanicResult::<(product::MultiplyNumsContract::ContractState, core::integer::u32)>, 1>"
+      ],
+      [74, "u32_const<0>"],
+      [
+        75,
+        "struct_construct<Tuple<product::MultiplyNumsContract::ContractState, Unit>>"
+      ],
+      [
+        76,
+        "enum_init<core::panics::PanicResult::<(product::MultiplyNumsContract::ContractState, ())>, 0>"
+      ],
+      [
+        77,
+        "store_temp<core::panics::PanicResult::<(product::MultiplyNumsContract::ContractState, ())>>"
+      ],
+      [
+        78,
+        "enum_init<core::panics::PanicResult::<(product::MultiplyNumsContract::ContractState, ())>, 1>"
+      ],
+      [79, "u32_wide_mul"],
+      [80, "store_temp<u64>"],
+      [
+        81,
+        "function_call<user@core::integer::DowncastableIntTryInto::<core::integer::u64, core::integer::u32, core::integer::DowncastableU64, core::integer::DowncastableU32, _>::try_into>"
+      ],
+      [82, "struct_construct<Tuple<u32>>"],
+      [83, "enum_init<core::panics::PanicResult::<(core::integer::u32,)>, 0>"],
+      [84, "store_temp<core::panics::PanicResult::<(core::integer::u32,)>>"],
+      [85, "felt252_const<155785504327651875780457110017927835511>"],
+      [86, "enum_init<core::panics::PanicResult::<(core::integer::u32,)>, 1>"],
+      [
+        87,
+        "storage_base_address_const<1195503354841289263908693606374238119068019599734980372857665784709941612631>"
+      ],
+      [88, "storage_address_from_base"],
+      [
+        89,
+        "snapshot_take<product::MultiplyNumsContract::__member_module_product::ContractMemberState>"
+      ],
+      [
+        90,
+        "drop<product::MultiplyNumsContract::__member_module_product::ContractMemberState>"
+      ],
+      [91, "store_temp<StorageAddress>"],
+      [92, "storage_write_syscall"],
+      [
+        93,
+        "enum_init<core::result::Result::<(), core::array::Array::<core::felt252>>, 0>"
+      ],
+      [
+        94,
+        "store_temp<core::result::Result::<(), core::array::Array::<core::felt252>>>"
+      ],
+      [
+        95,
+        "enum_init<core::result::Result::<(), core::array::Array::<core::felt252>>, 1>"
+      ],
+      [
+        96,
+        "function_call<user@core::starknet::SyscallResultTraitImpl::<()>::unwrap_syscall>"
+      ],
+      [97, "enum_match<core::panics::PanicResult::<((),)>>"],
+      [98, "struct_deconstruct<Tuple<Unit>>"],
+      [
+        99,
+        "struct_construct<Tuple<product::MultiplyNumsContract::__member_module_product::ContractMemberState, Unit>>"
+      ],
+      [
+        100,
+        "enum_init<core::panics::PanicResult::<(product::MultiplyNumsContract::__member_module_product::ContractMemberState, ())>, 0>"
+      ],
+      [
+        101,
+        "store_temp<core::panics::PanicResult::<(product::MultiplyNumsContract::__member_module_product::ContractMemberState, ())>>"
+      ],
+      [
+        102,
+        "enum_init<core::panics::PanicResult::<(product::MultiplyNumsContract::__member_module_product::ContractMemberState, ())>, 1>"
+      ],
+      [103, "downcast<u64, u32>"],
+      [
+        104,
+        "enum_match<core::result::Result::<(), core::array::Array::<core::felt252>>>"
+      ],
+      [105, "struct_construct<Tuple<Unit>>"],
+      [106, "enum_init<core::panics::PanicResult::<((),)>, 0>"],
+      [107, "store_temp<core::panics::PanicResult::<((),)>>"],
+      [108, "enum_init<core::panics::PanicResult::<((),)>, 1>"]
+    ],
+    "user_func_names": [
+      [
+        0,
+        "product::MultiplyNumsContract::__wrapper__MultiplyNumsContract__multiply"
+      ],
+      [1, "product::MultiplyNumsContract::__wrapper__constructor"],
+      [2, "core::integer::Felt252TryIntoU32::try_into"],
+      [3, "product::MultiplyNumsContract::MultiplyNumsContract::multiply"],
+      [4, "product::MultiplyNumsContract::constructor"],
+      [5, "core::integer::U32Mul::mul"],
+      [
+        6,
+        "product::MultiplyNumsContract::__member_module_product::InternalContractMemberStateImpl::write"
+      ],
+      [
+        7,
+        "core::integer::DowncastableIntTryInto::<core::integer::u64, core::integer::u32, core::integer::DowncastableU64, core::integer::DowncastableU32, _>::try_into"
+      ],
+      [8, "core::starknet::SyscallResultTraitImpl::<()>::unwrap_syscall"]
+    ]
+  },
+  "contract_class_version": "0.1.0",
+  "entry_points_by_type": {
+    "EXTERNAL": [
+      {
+        "selector": "0x39674cadb16109ec414e371cc8f04eb60a540c52d4880cadb49dfafb8d79797",
+        "function_idx": 0
+      }
+    ],
+    "L1_HANDLER": [],
+    "CONSTRUCTOR": [
+      {
+        "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194",
+        "function_idx": 1
+      }
+    ]
+  },
+  "abi": [
+    {
+      "type": "impl",
+      "name": "MultiplyNumsContract",
+      "interface_name": "product::IMultiplyNumsContract"
+    },
+    {
+      "type": "interface",
+      "name": "product::IMultiplyNumsContract",
+      "items": [
+        {
+          "type": "function",
+          "name": "multiply",
+          "inputs": [
+            { "name": "first_num", "type": "core::integer::u32" },
+            { "name": "second_num", "type": "core::integer::u32" }
+          ],
+          "outputs": [{ "type": "core::integer::u32" }],
+          "state_mutability": "external"
+        }
+      ]
+    },
+    { "type": "constructor", "name": "constructor", "inputs": [] },
+    {
+      "type": "event",
+      "name": "product::MultiplyNumsContract::Event",
+      "kind": "enum",
+      "variants": []
+    }
+  ]
+}
diff --git a/configs/genesis-assets/genesis.json b/configs/genesis-assets/genesis.json
index e21addbaaa..1323f59002 100644
--- a/configs/genesis-assets/genesis.json
+++ b/configs/genesis-assets/genesis.json
@@ -11,6 +11,10 @@
     [
       "0x04c6d6cf894f8bc96bb9c525e6853e5483177841f7388f74a46cfda6f028c755",
       "0x06910afff92798e29b93649f7627cd34a852e0f9b04b52c51850b438a730224e"
+    ],
+    [
+      "0x015b7c90a4fab33812dc9e2ef525a329e22e591327f006f826b71271099637cd",
+      "0x07155e1b37c5c35dcad0017562066f7d80b610af83dadf925064efcb2ea6b86a"
     ]
   ],
   "contract_classes": [
@@ -83,6 +87,13 @@
         "path": "genesis-assets/OpenZeppelinAccountCairoOne.casm.json",
         "version": 1
       }
+    ],
+    [
+      "0x015b7c90a4fab33812dc9e2ef525a329e22e591327f006f826b71271099637cd",
+      {
+        "path": "genesis-assets/MultiplyNumsContract.casm.json",
+        "version": 1
+      }
     ]
   ],
   "contracts": [
@@ -125,6 +136,10 @@
     [
       "0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf",
       "0x07b3e05f48f0c69e4a65ce5e076a66271a527aff2c34ce1083ec6e1526997a69"
+    ],
+    [
+      "0x123",
+      "0x015b7c90a4fab33812dc9e2ef525a329e22e591327f006f826b71271099637cd"
     ]
   ],
   "predeployed_accounts": [
diff --git a/configs/index.json b/configs/index.json
index f5fd10a6cd..e2d2ed974c 100644
--- a/configs/index.json
+++ b/configs/index.json
@@ -15,7 +15,7 @@
     },
     {
       "name": "genesis.json",
-      "sha3_256": "c35bcc00b70f9d6bfee3416fae0a0ec1e7a1fffe01c3d7fbb660db93a7bed87a"
+      "sha3_256": "bca50369e627d1101e4d693fa6fac9bee6cce2889b324dee3204179a3960ef5e"
     },
     {
       "name": "NoValidateAccount.casm.json",
@@ -52,6 +52,14 @@
     {
       "name": "OpenZeppelinAccountCairoOne.sierra.json",
       "sha3_256": "145fdf2668cf6c36deb295ceea57c6005e43dd7b36be26d020928d1cc3462b5e"
+    },
+    {
+      "name": "MultiplyNumsContract.sierra.json",
+      "sha3_256": "88830cfbad634684d6f18f22b1ade94c9340cffdabd5f3d74bb10ed212389064"
+    },
+    {
+      "name": "MultiplyNumsContract.casm.json",
+      "sha3_256": "113105426f708ab01988f19aa020120c87b82682a94f06b40340ff05c4044f89"
     }
   ]
 }
diff --git a/crates/client/eth-client/src/config.rs b/crates/client/eth-client/src/config.rs
index abb47b5770..3b2aabb1ef 100644
--- a/crates/client/eth-client/src/config.rs
+++ b/crates/client/eth-client/src/config.rs
@@ -66,6 +66,8 @@ pub struct HttpProviderConfig {
     pub rpc_endpoint: String,
     #[serde(default, skip_serializing_if = "Option::is_none")]
     pub tx_poll_interval_ms: Option<u64>,
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub gas_price_poll_ms: Option<u64>,
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -90,7 +92,7 @@ fn default_private_key() -> String {
 
 impl Default for HttpProviderConfig {
     fn default() -> Self {
-        Self { rpc_endpoint: default_rpc_endpoint(), tx_poll_interval_ms: None }
+        Self { rpc_endpoint: default_rpc_endpoint(), tx_poll_interval_ms: None, gas_price_poll_ms: None }
     }
 }
 
@@ -100,6 +102,20 @@ impl Default for EthereumProviderConfig {
     }
 }
 
+impl EthereumProviderConfig {
+    pub fn rpc_endpoint(&self) -> &String {
+        match self {
+            Self::Http(config) => &config.rpc_endpoint,
+        }
+    }
+
+    pub fn gas_price_poll_ms(&self) -> Option<u64> {
+        match self {
+            Self::Http(config) => config.gas_price_poll_ms,
+        }
+    }
+}
+
 impl Default for LocalWalletConfig {
     fn default() -> Self {
         Self { chain_id: default_chain_id(), private_key: default_private_key() }
diff --git a/crates/client/l1-gas-price/Cargo.toml b/crates/client/l1-gas-price/Cargo.toml
new file mode 100644
index 0000000000..5a8daabcf8
--- /dev/null
+++ b/crates/client/l1-gas-price/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "mc-l1-gas-price"
+version = "0.1.0"
+description = "L1 gas price fetching library."
+homepage = "https://github.com/keep-starknet-strange/madara"
+edition = "2021"
+license = "MIT"
+publish = false
+repository = "https://github.com/keep-starknet-strange/madara"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+anyhow = { workspace = true }
+ethers = { workspace = true }
+futures = { workspace = true }
+log = { workspace = true }
+mc-eth-client = { workspace = true }
+mp-starknet-inherent = { workspace = true }
+reqwest = { workspace = true }
+serde = { workspace = true }
+tokio = { workspace = true }
diff --git a/crates/client/l1-gas-price/src/lib.rs b/crates/client/l1-gas-price/src/lib.rs
new file mode 100644
index 0000000000..48466dad9f
--- /dev/null
+++ b/crates/client/l1-gas-price/src/lib.rs
@@ -0,0 +1,2 @@
+mod types;
+pub mod worker;
diff --git a/crates/client/l1-gas-price/src/types.rs b/crates/client/l1-gas-price/src/types.rs
new file mode 100644
index 0000000000..d867acb28d
--- /dev/null
+++ b/crates/client/l1-gas-price/src/types.rs
@@ -0,0 +1,50 @@
+use serde::{Deserialize, Serialize};
+
+// Took this code from alloy-rs and did some modifications. This type can be removed once we've
+// migrated to alloy-rs from ethers-rs.
+// FIXME: 1528
+
+/// Response type for `eth_feeHistory`
+#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct FeeHistory {
+    /// An array of block base fees per gas.
+    /// This includes the next block after the newest of the returned range,
+    /// because this value can be derived from the newest block. Zeroes are
+    /// returned for pre-EIP-1559 blocks.
+    ///
+    /// # Note
+    ///
+    /// Empty list is skipped only for compatibility with Erigon and Geth.
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    pub base_fee_per_gas: Vec<String>,
+    /// An array of block gas used ratios. These are calculated as the ratio
+    /// of `gasUsed` and `gasLimit`.
+    ///
+    /// # Note
+    ///
+    /// The `Option` is only for compatibility with Erigon and Geth.
+    pub gas_used_ratio: Vec<f64>,
+    /// An array of block base fees per blob gas. This includes the next block after the newest
+    /// of  the returned range, because this value can be derived from the newest block. Zeroes
+    /// are returned for pre-EIP-4844 blocks.
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    pub base_fee_per_blob_gas: Vec<u128>,
+    /// An array of block blob gas used ratios. These are calculated as the ratio of gasUsed and
+    /// gasLimit.
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    pub blob_gas_used_ratio: Vec<f64>,
+    /// Lowest number block of the returned range.
+    pub oldest_block: String,
+    /// An (optional) array of effective priority fee per gas data points from a single
+    /// block. All zeroes are returned if the block is empty.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub reward: Option<Vec<Vec<u128>>>,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
+pub struct EthRpcResponse<T> {
+    pub jsonrpc: String,
+    pub id: u64,
+    pub result: T,
+}
diff --git a/crates/client/l1-gas-price/src/worker.rs b/crates/client/l1-gas-price/src/worker.rs
new file mode 100644
index 0000000000..2198c7d639
--- /dev/null
+++ b/crates/client/l1-gas-price/src/worker.rs
@@ -0,0 +1,105 @@
+use std::num::NonZeroU128;
+use std::sync::Arc;
+use std::time::Duration;
+
+use anyhow::{format_err, Result};
+use ethers::utils::__serde_json::json;
+use futures::lock::Mutex;
+use mc_eth_client::config::EthereumClientConfig;
+use mp_starknet_inherent::L1GasPrices;
+use tokio::time::sleep;
+
+use crate::types::{EthRpcResponse, FeeHistory};
+
+const DEFAULT_GAS_PRICE_POLL_MS: u64 = 10_000;
+
+pub async fn run_worker(config: Arc<EthereumClientConfig>, gas_price: Arc<Mutex<L1GasPrices>>, infinite_loop: bool) {
+    let rpc_endpoint = config.provider.rpc_endpoint().clone();
+    let client = reqwest::Client::new();
+    let poll_time = config.provider.gas_price_poll_ms().unwrap_or(DEFAULT_GAS_PRICE_POLL_MS);
+
+    loop {
+        match update_gas_price(rpc_endpoint.clone(), &client, gas_price.clone()).await {
+            Ok(_) => log::trace!("Updated gas prices"),
+            Err(e) => log::error!("Failed to update gas prices: {:?}", e),
+        }
+
+        let gas_price = gas_price.lock().await;
+        let last_update_timestamp = gas_price.last_update_timestamp;
+        drop(gas_price);
+        let current_timestamp = std::time::SystemTime::now()
+            .duration_since(std::time::UNIX_EPOCH)
+            .expect("Failed to get current timestamp")
+            .as_millis();
+
+        if current_timestamp - last_update_timestamp > 10 * poll_time as u128 {
+            panic!(
+                "Gas prices have not been updated for {} ms. Last update was at {}",
+                current_timestamp - last_update_timestamp,
+                last_update_timestamp
+            );
+        }
+
+        if !infinite_loop {
+            break;
+        }
+
+        sleep(Duration::from_millis(poll_time)).await;
+    }
+}
+
+async fn update_gas_price(
+    rpc_endpoint: String,
+    client: &reqwest::Client,
+    gas_price: Arc<Mutex<L1GasPrices>>,
+) -> Result<()> {
+    let fee_history: EthRpcResponse<FeeHistory> = client
+        .post(rpc_endpoint.clone())
+        .json(&json!({
+            "jsonrpc": "2.0",
+            "method": "eth_feeHistory",
+            "params": [300, "latest", []],
+            "id": 83
+        }))
+        .send()
+        .await?
+        .json()
+        .await?;
+
+    // The RPC responds with 301 elements for some reason. It's also just safer to manually
+    // take the last 300. We choose 300 to get average gas caprice for last one hour (300 * 12 sec block
+    // time).
+    let (_, blob_fee_history_one_hour) =
+        fee_history.result.base_fee_per_blob_gas.split_at(fee_history.result.base_fee_per_blob_gas.len() - 300);
+
+    let avg_blob_base_fee = blob_fee_history_one_hour.iter().sum::<u128>() / blob_fee_history_one_hour.len() as u128;
+
+    let eth_gas_price = u128::from_str_radix(
+        fee_history
+            .result
+            .base_fee_per_gas
+            .last()
+            .ok_or(format_err!("Failed to get last element of `base_fee_per_gas`"))?
+            .trim_start_matches("0x"),
+        16,
+    )?;
+
+    // TODO: fetch this from the oracle
+    let eth_strk_price = 2425;
+
+    let mut gas_price = gas_price.lock().await;
+    gas_price.eth_l1_gas_price =
+        NonZeroU128::new(eth_gas_price).ok_or(format_err!("Failed to convert `eth_gas_price` to NonZeroU128"))?;
+    gas_price.eth_l1_data_gas_price = NonZeroU128::new(avg_blob_base_fee)
+        .ok_or(format_err!("Failed to convert `eth_l1_data_gas_price` to NonZeroU128"))?;
+    gas_price.strk_l1_gas_price = NonZeroU128::new(eth_gas_price.saturating_mul(eth_strk_price))
+        .ok_or(format_err!("Failed to convert `strk_l1_gas_price` to NonZeroU128"))?;
+    gas_price.strk_l1_data_gas_price = NonZeroU128::new(avg_blob_base_fee.saturating_mul(eth_strk_price))
+        .ok_or(format_err!("Failed to convert `strk_l1_data_gas_price` to NonZeroU128"))?;
+    gas_price.last_update_timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)?.as_millis();
+    // explicitly dropping gas price here to avoid long waits when fetching the value
+    // on the inherent side which would increase block time
+    drop(gas_price);
+
+    Ok(())
+}
diff --git a/crates/client/l1-messages/src/worker.rs b/crates/client/l1-messages/src/worker.rs
index 938a0192ff..d77c8cf906 100644
--- a/crates/client/l1-messages/src/worker.rs
+++ b/crates/client/l1-messages/src/worker.rs
@@ -17,15 +17,15 @@ use crate::contract::parse_handle_l1_message_transaction;
 use crate::error::L1MessagesWorkerError;
 
 fn create_event_listener(
-    config: EthereumClientConfig,
+    config: Arc<EthereumClientConfig>,
 ) -> Result<StarknetMessagingEvents<Provider<Http>>, mc_eth_client::error::Error> {
     let address = config.contracts.core_contract()?;
-    let provider: Provider<Http> = config.provider.try_into()?;
+    let provider: Provider<Http> = config.provider.clone().try_into()?;
     Ok(StarknetMessagingEvents::new(address, Arc::new(provider)))
 }
 
 pub async fn run_worker<C, P, B>(
-    config: EthereumClientConfig,
+    config: Arc<EthereumClientConfig>,
     client: Arc<C>,
     pool: Arc<P>,
     backend: Arc<mc_db::Backend<B>>,
diff --git a/crates/client/rpc/src/errors.rs b/crates/client/rpc/src/errors.rs
index 9b98272ac8..37da44f656 100644
--- a/crates/client/rpc/src/errors.rs
+++ b/crates/client/rpc/src/errors.rs
@@ -111,6 +111,7 @@ impl From<SimulationError> for StarknetRpcApiError {
             SimulationError::ContractNotFound => StarknetRpcApiError::ContractNotFound,
             SimulationError::TransactionExecutionFailed(e) => StarknetRpcApiError::ContractError(e.into()),
             SimulationError::MissingL1GasUsage | SimulationError::StateDiff => StarknetRpcApiError::InternalServerError,
+            SimulationError::EstimateFeeFailed(_) => StarknetRpcApiError::InternalServerError,
         }
     }
 }
diff --git a/crates/client/rpc/src/lib.rs b/crates/client/rpc/src/lib.rs
index f8427451ba..4065b278a3 100644
--- a/crates/client/rpc/src/lib.rs
+++ b/crates/client/rpc/src/lib.rs
@@ -206,6 +206,18 @@ where
 
         Ok(starknet_block.header().block_number)
     }
+
+    fn get_current_resource_price(&self) -> Result<ResourcePrice, StarknetRpcApiError> {
+        let current_prices =
+            self.client.runtime_api().current_l1_gas_prices(self.client.info().best_hash).map_err(|e| {
+                log::error!("Failed to get current L1 gas prices: {e}");
+                StarknetRpcApiError::InternalServerError
+            })?;
+        Ok(ResourcePrice {
+            price_in_wei: current_prices.eth_l1_gas_price.get().into(),
+            price_in_fri: current_prices.strk_l1_gas_price.get().into(),
+        })
+    }
 }
 
 /// Taken from https://github.com/paritytech/substrate/blob/master/client/rpc/src/author/mod.rs#L78
@@ -843,8 +855,7 @@ where
             new_root: Felt252Wrapper::from(self.backend.temporary_global_state_root_getter()).into(),
             timestamp: starknet_block.header().block_timestamp,
             sequencer_address: Felt252Wrapper::from(starknet_block.header().sequencer_address).into(),
-            // TODO: real value
-            l1_gas_price: ResourcePrice { price_in_fri: Default::default(), price_in_wei: Default::default() },
+            l1_gas_price: self.get_current_resource_price()?,
             starknet_version: starknet_version.to_string(),
         };
 
@@ -942,18 +953,7 @@ where
         let fee_estimates =
             self.estimate_fee(substrate_block_hash, transactions, SimulationFlags::from(simulation_flags))?;
 
-        let estimates = fee_estimates
-            .into_iter()
-			// FIXME: https://github.com/keep-starknet-strange/madara/issues/329
-            .map(|x| FeeEstimate {
-                gas_price: FieldElement::from(10u128),
-                gas_consumed: FieldElement::from(x.1),
-                overall_fee: FieldElement::from(x.0),
-                unit: PriceUnit::Wei,
-            })
-            .collect();
-
-        Ok(estimates)
+        Ok(fee_estimates)
     }
 
     /// Estimate the L2 fee of a message sent on L1
@@ -1000,14 +1000,7 @@ where
 
         let fee_estimate = self.do_estimate_message_fee(substrate_block_hash, transaction)?;
 
-        let estimate = FeeEstimate {
-            gas_price: fee_estimate.0.try_into().map_err(|_| StarknetRpcApiError::InternalServerError)?,
-            gas_consumed: FieldElement::from(fee_estimate.2),
-            overall_fee: FieldElement::from(fee_estimate.1),
-            unit: PriceUnit::Wei,
-        };
-
-        Ok(estimate)
+        Ok(fee_estimate)
     }
 
     /// Get the details of a transaction by a given block id and index.
@@ -1090,8 +1083,7 @@ where
             timestamp: starknet_block.header().block_timestamp,
             sequencer_address: Felt252Wrapper::from(starknet_block.header().sequencer_address).into(),
             transactions,
-            // TODO: fill real prices
-            l1_gas_price: ResourcePrice { price_in_fri: Default::default(), price_in_wei: Default::default() },
+            l1_gas_price: self.get_current_resource_price()?,
             starknet_version: starknet_version.to_string(),
         };
 
@@ -1360,8 +1352,7 @@ where
 
         let pending_block = PendingBlockWithTxHashes {
             transactions: transaction_hashes,
-            // TODO: fill real prices
-            l1_gas_price: ResourcePrice { price_in_fri: Default::default(), price_in_wei: Default::default() },
+            l1_gas_price: self.get_current_resource_price()?,
             parent_hash: latest_block_header.hash().into(),
             sequencer_address: Felt252Wrapper::from(latest_block_header.sequencer_address).into(),
             starknet_version: latest_block_header.protocol_version.to_string(),
@@ -1381,8 +1372,7 @@ where
 
         let pending_block = PendingBlockWithTxs {
             transactions,
-            // TODO: fill real prices
-            l1_gas_price: ResourcePrice { price_in_fri: Default::default(), price_in_wei: Default::default() },
+            l1_gas_price: self.get_current_resource_price()?,
             parent_hash: latest_block_header.hash().into(),
             sequencer_address: Felt252Wrapper::from(latest_block_header.sequencer_address).into(),
             starknet_version: latest_block_header.protocol_version.to_string(),
diff --git a/crates/client/rpc/src/runtime_api.rs b/crates/client/rpc/src/runtime_api.rs
index 69aeac8f95..ca903c170b 100644
--- a/crates/client/rpc/src/runtime_api.rs
+++ b/crates/client/rpc/src/runtime_api.rs
@@ -19,6 +19,7 @@ use sp_blockchain::HeaderBackend;
 use sp_runtime::traits::Block as BlockT;
 use starknet_api::core::{ContractAddress, EntryPointSelector};
 use starknet_api::transaction::{Calldata, Event, TransactionHash};
+use starknet_core::types::FeeEstimate;
 
 use crate::{Starknet, StarknetRpcApiError};
 
@@ -53,11 +54,12 @@ where
         &self,
         block_hash: B::Hash,
         message: L1HandlerTransaction,
-    ) -> RpcApiResult<(u128, u128, u128)> {
-        Ok(self.client.runtime_api().estimate_message_fee(block_hash, message).map_err(|e| {
+    ) -> RpcApiResult<FeeEstimate> {
+        Ok((&self.client.runtime_api().estimate_message_fee(block_hash, message).map_err(|e| {
             error!("Runtime Api error: {e}");
             StarknetRpcApiError::InternalServerError
         })???)
+            .into())
     }
 
     pub fn do_get_tx_execution_outcome(
@@ -104,13 +106,19 @@ where
         block_hash: B::Hash,
         transactions: Vec<AccountTransaction>,
         simulation_flags: SimulationFlags,
-    ) -> RpcApiResult<Vec<(u128, u128)>> {
-        Ok(self.client.runtime_api().estimate_fee(block_hash, transactions, simulation_flags).map_err(
-            |e: ApiError| {
+    ) -> RpcApiResult<Vec<FeeEstimate>> {
+        let fee_estimates = self
+            .client
+            .runtime_api()
+            .estimate_fee(block_hash, transactions, simulation_flags)
+            .map_err(|e: ApiError| {
                 error!("Request parameters error: {e}");
                 StarknetRpcApiError::InternalServerError
-            },
-        )???)
+            })???
+            .iter()
+            .map(|estimate| estimate.into())
+            .collect();
+        Ok(fee_estimates)
     }
 
     pub fn get_best_block_hash(&self) -> B::Hash {
@@ -173,7 +181,8 @@ where
     ) -> RpcApiResult<TransactionExecutionInfo> {
         // Simulate a single User Transaction
         // So the result should have single element in vector (index 0)
-        self.client
+        let simulation = self
+            .client
             .runtime_api()
             .simulate_transactions(block_hash, vec![tx], simulations_flags)
             .map_err(|e| {
@@ -183,13 +192,13 @@ where
             .map_err(|e| {
                 error!("Failed to call function: {:#?}", e);
                 StarknetRpcApiError::from(e)
-            })??
+            })?
             .swap_remove(0)
-            .1
             .map_err(|e| {
                 error!("Failed to simulate User Transaction: {:?}", e);
                 StarknetRpcApiError::InternalServerError
-            })
+            })?;
+        Ok(simulation.execution_info)
     }
 
     fn simulate_l1_tx(
diff --git a/crates/client/rpc/src/trace_api.rs b/crates/client/rpc/src/trace_api.rs
index 86a2a0ca6e..65d1ba24d1 100644
--- a/crates/client/rpc/src/trace_api.rs
+++ b/crates/client/rpc/src/trace_api.rs
@@ -26,8 +26,8 @@ use sp_runtime::traits::Block as BlockT;
 use starknet_api::transaction::TransactionHash;
 use starknet_core::types::{
     BlockId, BroadcastedTransaction, DeclareTransactionTrace, DeployAccountTransactionTrace, ExecuteInvocation,
-    FeeEstimate, InvokeTransactionTrace, L1HandlerTransactionTrace, PriceUnit, RevertedInvocation,
-    SimulatedTransaction, SimulationFlag, StateDiff, TransactionTrace, TransactionTraceWithHash,
+    InvokeTransactionTrace, L1HandlerTransactionTrace, RevertedInvocation, SimulatedTransaction, SimulationFlag,
+    StateDiff, TransactionTrace, TransactionTraceWithHash,
 };
 use starknet_ff::FieldElement;
 
@@ -101,28 +101,18 @@ where
             })?;
 
         let mut simulated_transactions = vec![];
-        for (tx_type, (state_diff, res)) in tx_types.into_iter().zip(res.into_iter().flatten()) {
-            match res {
-                Ok(tx_exec_info) => {
-                    let state_diff = blockifier_to_rpc_state_diff_types(state_diff)
+        for (tx_type, simulation_result) in tx_types.into_iter().zip(res.into_iter()) {
+            match simulation_result {
+                Ok(simulation) => {
+                    let state_diff = blockifier_to_rpc_state_diff_types(simulation.state_diff)
                         .map_err(|_| StarknetRpcApiError::InternalServerError)?;
 
-                    let transaction_trace = tx_execution_infos_to_tx_trace(tx_type, &tx_exec_info, Some(state_diff))?;
-
-                    let gas_consumed =
-                        tx_exec_info.execute_call_info.as_ref().map(|x| x.execution.gas_consumed).unwrap_or_default();
-                    let overall_fee = tx_exec_info.actual_fee.0 as u64;
-                    // TODO: Shouldn't the gas price be taken from the block header instead?
-                    let gas_price = if gas_consumed > 0 { overall_fee / gas_consumed } else { 0 };
+                    let transaction_trace =
+                        tx_execution_infos_to_tx_trace(tx_type, &simulation.execution_info, Some(state_diff))?;
 
                     simulated_transactions.push(SimulatedTransaction {
                         transaction_trace,
-                        fee_estimation: FeeEstimate {
-                            gas_consumed: FieldElement::from(gas_consumed),
-                            gas_price: FieldElement::from(gas_price),
-                            overall_fee: FieldElement::from(overall_fee),
-                            unit: PriceUnit::Wei,
-                        },
+                        fee_estimation: simulation.fee_estimate.into(),
                     });
                 }
                 Err(e) => {
diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml
index c575676022..58948f4c73 100644
--- a/crates/node/Cargo.toml
+++ b/crates/node/Cargo.toml
@@ -80,6 +80,7 @@ madara-runtime = { workspace = true, features = ["std"] }
 mc-commitment-state-diff = { workspace = true }
 mc-db = { workspace = true }
 mc-eth-client = { workspace = true }
+mc-l1-gas-price = { workspace = true }
 mc-l1-messages = { workspace = true }
 mc-mapping-sync = { workspace = true }
 mc-rpc = { workspace = true }
@@ -95,7 +96,7 @@ mc-genesis-data-provider = { workspace = true }
 mp-block = { workspace = true }
 mp-digest-log = { workspace = true }
 mp-felt = { workspace = true }
-mp-sequencer-address = { workspace = true, features = ["client"] }
+mp-starknet-inherent = { workspace = true, features = ["client"] }
 
 # Starknet
 blockifier = { workspace = true }
diff --git a/crates/node/src/commands/run.rs b/crates/node/src/commands/run.rs
index 3de375a100..c5612d2131 100644
--- a/crates/node/src/commands/run.rs
+++ b/crates/node/src/commands/run.rs
@@ -1,3 +1,6 @@
+use std::path::PathBuf;
+
+use clap::ValueHint::FilePath;
 use madara_runtime::SealingMode;
 use sc_cli::{Result, RpcMethods, RunCmd, SubstrateCli};
 use sc_service::BasePath;
@@ -29,6 +32,12 @@ impl From<Sealing> for SealingMode {
     }
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, clap::ValueEnum)]
+pub enum SettlementLayer {
+    /// Use Ethereum core contract
+    Ethereum,
+}
+
 #[derive(Clone, Debug, clap::Args)]
 pub struct ExtendedRunCmd {
     #[clap(flatten)]
@@ -37,6 +46,18 @@ pub struct ExtendedRunCmd {
     /// Choose sealing method.
     #[clap(long, value_enum, ignore_case = true)]
     pub sealing: Option<Sealing>,
+
+    /// Choose a supported settlement layer
+    #[clap(long, ignore_case = true, requires = "settlement_conf")]
+    pub settlement: Option<SettlementLayer>,
+
+    /// Path to a file containing the settlement configuration
+    ///
+    /// If `settlement` is `Some` and `settlement_conf` is `None` we will try to read one at
+    /// `<chain_config_directory>/settlement_conf.json`. If it's not there, an error will be
+    /// returned.
+    #[clap(long, value_hint = FilePath, requires = "settlement")]
+    pub settlement_conf: Option<PathBuf>,
 }
 
 impl ExtendedRunCmd {
@@ -58,9 +79,26 @@ pub fn run_node(mut cli: Cli) -> Result<()> {
     }
     let runner = cli.create_runner(&cli.run.base)?;
 
+    let settlement_config: Option<(SettlementLayer, PathBuf)> = match cli.run.settlement {
+        Some(SettlementLayer::Ethereum) => {
+            let settlement_conf = match cli.run.clone().settlement_conf {
+                Some(settlement_conf) => settlement_conf,
+                None => panic!("Settlement layer Ethereum requires a settlement configuration"),
+            };
+
+            log::info!("Initializing settlement client with layer: {:?}", SettlementLayer::Ethereum);
+            Some((SettlementLayer::Ethereum, settlement_conf))
+        }
+
+        None => {
+            log::info!("Madara initialized w/o settlement layer");
+            None
+        }
+    };
+
     runner.run_node_until_exit(|config| async move {
         let sealing = cli.run.sealing.map(Into::into).unwrap_or_default();
-        service::new_full(config, sealing).map_err(sc_cli::Error::Service)
+        service::new_full(config, sealing, settlement_config).map_err(sc_cli::Error::Service)
     })
 }
 
diff --git a/crates/node/src/genesis_block.rs b/crates/node/src/genesis_block.rs
index ffeb791da1..18de998a88 100644
--- a/crates/node/src/genesis_block.rs
+++ b/crates/node/src/genesis_block.rs
@@ -60,8 +60,10 @@ fn construct_genesis_block<Block: BlockT>(state_root: Block::Hash, state_version
 
     let mut digest = vec![];
     let block = StarknetBlock::try_new(
-        // TODO: Decide what values to put here
-        // This is just filler values for now
+        // The genesis block values don't really matter because when you start a node,
+        // you need to disable fees completely to do the setup process. So we need some blocks
+        // of txs without any fees. And the 1st block will set the correct L1 gas prices through
+        // inherents.
         Header {
             l1_gas_price: unsafe {
                 GasPrices {
diff --git a/crates/node/src/service.rs b/crates/node/src/service.rs
index 423bbaabe8..08a016cce0 100644
--- a/crates/node/src/service.rs
+++ b/crates/node/src/service.rs
@@ -8,14 +8,17 @@ use std::time::Duration;
 use futures::channel::mpsc;
 use futures::future;
 use futures::future::BoxFuture;
+use futures::lock::Mutex;
 use futures::prelude::*;
 use madara_runtime::opaque::Block;
 use madara_runtime::{self, Hash, RuntimeApi, SealingMode, StarknetHasher};
+use mc_eth_client::config::EthereumClientConfig;
 use mc_genesis_data_provider::OnDiskGenesisConfig;
 use mc_mapping_sync::MappingSyncWorker;
 use mc_storage::overrides_handle;
-use mp_sequencer_address::{
-    InherentDataProvider as SeqAddrInherentDataProvider, DEFAULT_SEQUENCER_ADDRESS, SEQ_ADDR_STORAGE_KEY,
+use mp_starknet_inherent::{
+    InherentDataProvider as StarknetInherentDataProvider, InherentError as StarknetInherentError, L1GasPrices,
+    StarknetInherentData, DEFAULT_SEQUENCER_ADDRESS, SEQ_ADDR_STORAGE_KEY,
 };
 use prometheus_endpoint::Registry;
 use sc_basic_authorship::ProposerFactory;
@@ -34,6 +37,7 @@ use sp_api::ConstructRuntimeApi;
 use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
 use sp_offchain::STORAGE_PREFIX;
 
+use crate::commands::SettlementLayer;
 use crate::genesis_block::MadaraGenesisBlockBuilder;
 use crate::import_queue::{
     build_aura_queue_grandpa_pipeline, build_manual_seal_queue_pipeline, BlockImportPipeline,
@@ -174,7 +178,11 @@ where
 /// # Arguments
 ///
 /// - `cache`: whether more information should be cached when storing the block in the database.
-pub fn new_full(config: Configuration, sealing: SealingMode) -> Result<TaskManager, ServiceError> {
+pub fn new_full(
+    config: Configuration,
+    sealing: SealingMode,
+    settlement_config: Option<(SettlementLayer, PathBuf)>,
+) -> Result<TaskManager, ServiceError> {
     let sc_service::PartialComponents {
         client,
         backend,
@@ -316,6 +324,43 @@ pub fn new_full(config: Configuration, sealing: SealingMode) -> Result<TaskManag
     );
 
     if role.is_authority() {
+        let l1_gas_price = Arc::new(Mutex::new(L1GasPrices::default()));
+
+        // initialize settlement workers
+        if let Some((layer_kind, config_path)) = settlement_config {
+            // TODO: make L1 message handling part of the SettlementProvider, support multiple layer options
+            if layer_kind == SettlementLayer::Ethereum {
+                let ethereum_conf = Arc::new(
+                    EthereumClientConfig::from_json_file(&config_path)
+                        .map_err(|e| ServiceError::Other(e.to_string()))?,
+                );
+
+                task_manager.spawn_handle().spawn(
+                    "settlement-worker-sync-l1-messages",
+                    Some(MADARA_TASK_GROUP),
+                    mc_l1_messages::worker::run_worker(
+                        ethereum_conf.clone(),
+                        client.clone(),
+                        transaction_pool.clone(),
+                        madara_backend.clone(),
+                    ),
+                );
+
+                // Ensuring we've fetched the latest price before we start the node
+                futures::executor::block_on(mc_l1_gas_price::worker::run_worker(
+                    ethereum_conf.clone(),
+                    l1_gas_price.clone(),
+                    false,
+                ));
+
+                task_manager.spawn_handle().spawn(
+                    "l1-gas-prices-worker",
+                    Some(MADARA_TASK_GROUP),
+                    mc_l1_gas_price::worker::run_worker(ethereum_conf.clone(), l1_gas_price.clone(), true),
+                );
+            }
+        }
+
         // manual-seal authorship
         if !sealing.is_default() {
             log::info!("{} sealing enabled.", sealing);
@@ -355,6 +400,7 @@ pub fn new_full(config: Configuration, sealing: SealingMode) -> Result<TaskManag
             proposer_factory,
             create_inherent_data_providers: move |_, ()| {
                 let offchain_storage = backend.offchain_storage();
+                let l1_gas_price = l1_gas_price.clone();
                 async move {
                     let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
 
@@ -367,16 +413,22 @@ pub fn new_full(config: Configuration, sealing: SealingMode) -> Result<TaskManag
                     let prefix = &STORAGE_PREFIX;
                     let key = SEQ_ADDR_STORAGE_KEY;
 
-                    let sequencer_address = if let Some(storage) = ocw_storage {
-                        SeqAddrInherentDataProvider::try_from(
-                            storage.get(prefix, key).unwrap_or(DEFAULT_SEQUENCER_ADDRESS.to_vec()),
-                        )
-                        .unwrap_or_default()
+                    let sequencer_address: [u8; 32] = if let Some(storage) = ocw_storage {
+                        storage
+                            .get(prefix, key)
+                            .unwrap_or(DEFAULT_SEQUENCER_ADDRESS.to_vec())
+                            .try_into()
+                            .map_err(|_| StarknetInherentError::WrongAddressFormat)?
                     } else {
-                        SeqAddrInherentDataProvider::default()
+                        DEFAULT_SEQUENCER_ADDRESS
                     };
 
-                    Ok((slot, timestamp, sequencer_address))
+                    let starknet_inherent = StarknetInherentDataProvider::new(StarknetInherentData {
+                        sequencer_address,
+                        l1_gas_price: l1_gas_price.lock().await.clone(),
+                    });
+
+                    Ok((slot, timestamp, starknet_inherent))
                 }
             },
             force_authoring,
diff --git a/crates/pallets/starknet/Cargo.toml b/crates/pallets/starknet/Cargo.toml
index 066b06702b..902e3ff81b 100644
--- a/crates/pallets/starknet/Cargo.toml
+++ b/crates/pallets/starknet/Cargo.toml
@@ -22,11 +22,14 @@ mp-felt = { workspace = true, features = ["parity-scale-codec", "serde"] }
 mp-genesis-config = { workspace = true }
 mp-hashers = { workspace = true }
 mp-program-hash = { workspace = true }
-mp-sequencer-address = { workspace = true, features = ["parity-scale-codec"] }
 mp-simulations = { workspace = true, features = [
   "parity-scale-codec",
   "scale-info",
 ] }
+mp-starknet-inherent = { workspace = true, features = [
+  "parity-scale-codec",
+  "scale-info",
+] }
 mp-storage = { workspace = true, features = ["parity-scale-codec"] }
 mp-transactions = { workspace = true, features = ["scale-info"] }
 
diff --git a/crates/pallets/starknet/runtime_api/Cargo.toml b/crates/pallets/starknet/runtime_api/Cargo.toml
index 9fe6bca8e6..0696932b79 100644
--- a/crates/pallets/starknet/runtime_api/Cargo.toml
+++ b/crates/pallets/starknet/runtime_api/Cargo.toml
@@ -12,6 +12,10 @@ mp-simulations = { workspace = true, features = [
   "parity-scale-codec",
   "scale-info",
 ] }
+mp-starknet-inherent = { workspace = true, features = [
+  "parity-scale-codec",
+  "scale-info",
+] }
 
 # Starknet
 blockifier = { workspace = true }
diff --git a/crates/pallets/starknet/runtime_api/src/lib.rs b/crates/pallets/starknet/runtime_api/src/lib.rs
index 94bcdddeeb..b9af632d59 100644
--- a/crates/pallets/starknet/runtime_api/src/lib.rs
+++ b/crates/pallets/starknet/runtime_api/src/lib.rs
@@ -17,8 +17,10 @@ pub extern crate alloc;
 use alloc::vec::Vec;
 
 use mp_simulations::{
-    InternalSubstrateError, ReExecutionResult, SimulationError, SimulationFlags, TransactionSimulationResult,
+    FeeEstimate, InternalSubstrateError, ReExecutionResult, SimulationError, SimulationFlags,
+    TransactionSimulationResult,
 };
+use mp_starknet_inherent::L1GasPrices;
 use sp_api::BlockT;
 use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, Nonce};
 use starknet_api::hash::StarkFelt;
@@ -44,13 +46,13 @@ sp_api::decl_runtime_apis! {
         /// Returns the fee token address.
         fn fee_token_addresses() -> FeeTokenAddresses;
         /// Returns fee estimate
-        fn estimate_fee(transactions: Vec<AccountTransaction>, simulation_flags: SimulationFlags) -> Result<Result<Vec<(u128, u128)>, SimulationError>, InternalSubstrateError>;
+        fn estimate_fee(transactions: Vec<AccountTransaction>, simulation_flags: SimulationFlags) -> Result<Result<Vec<FeeEstimate>, SimulationError>, InternalSubstrateError>;
         /// Returns message fee estimate
-        fn estimate_message_fee(message: L1HandlerTransaction) -> Result<Result<(u128, u128, u128), SimulationError>, InternalSubstrateError>;
+        fn estimate_message_fee(message: L1HandlerTransaction) -> Result<Result<FeeEstimate, SimulationError>, InternalSubstrateError>;
         /// Simulates single L1 Message and returns its trace
         fn simulate_message(message: L1HandlerTransaction, simulation_flags: SimulationFlags) -> Result<Result<TransactionExecutionInfo, SimulationError>, InternalSubstrateError>;
         /// Simulates transactions and returns their trace
-        fn simulate_transactions(transactions: Vec<AccountTransaction>, simulation_flags: SimulationFlags) -> Result<Result<Vec<(CommitmentStateDiff, TransactionSimulationResult)>, SimulationError>, InternalSubstrateError>;
+        fn simulate_transactions(transactions: Vec<AccountTransaction>, simulation_flags: SimulationFlags) -> Result<Vec<TransactionSimulationResult>, InternalSubstrateError>;
         /// Filters extrinsic transactions to return only Starknet transactions
         ///
         /// To support runtime upgrades, the client must be unaware of the specific extrinsic
@@ -88,6 +90,8 @@ sp_api::decl_runtime_apis! {
         fn get_tx_messages_to_l1(tx_hash: TransactionHash) -> Vec<MessageToL1>;
         /// Check if L1 Message Nonce has not been used
         fn l1_nonce_unused(nonce: Nonce) -> bool;
+        /// Get current L1 gas prices
+        fn current_l1_gas_prices() -> L1GasPrices;
     }
 
     pub trait ConvertTransactionRuntimeApi {
diff --git a/crates/pallets/starknet/src/lib.rs b/crates/pallets/starknet/src/lib.rs
index e30c381720..65295bc386 100644
--- a/crates/pallets/starknet/src/lib.rs
+++ b/crates/pallets/starknet/src/lib.rs
@@ -58,7 +58,7 @@ use std::collections::BTreeSet;
 use std::ops::Deref;
 use std::str::from_utf8_unchecked;
 
-use blockifier::blockifier::block::{BlockInfo, GasPrices};
+use blockifier::blockifier::block::BlockInfo;
 use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionContext};
 use blockifier::execution::call_info::CallInfo;
 use blockifier::execution::contract_class::ContractClass;
@@ -79,7 +79,7 @@ use mp_block::{Block as StarknetBlock, Header as StarknetHeader};
 use mp_chain_id::MADARA_CHAIN_ID;
 use mp_digest_log::MADARA_ENGINE_ID;
 use mp_felt::Felt252Wrapper;
-use mp_sequencer_address::{InherentError, InherentType, DEFAULT_SEQUENCER_ADDRESS, INHERENT_IDENTIFIER};
+use mp_starknet_inherent::{InherentError, InherentType, STARKNET_INHERENT_IDENTIFIER};
 use mp_storage::{StarknetStorageSchemaVersion, PALLET_STARKNET_SCHEMA};
 use mp_transactions::execution::{
     execute_l1_handler_transaction, run_non_revertible_transaction, run_revertible_transaction,
@@ -118,6 +118,7 @@ macro_rules! log {
 
 #[frame_support::pallet]
 pub mod pallet {
+    use mp_starknet_inherent::L1GasPrices;
 
     use super::*;
 
@@ -131,9 +132,6 @@ pub mod pallet {
     pub trait Config: frame_system::Config {
         /// The block time
         type TimestampProvider: Time;
-        /// The gas price
-        #[pallet::constant]
-        type L1GasPrices: Get<GasPrices>;
         /// A configuration for base priority of unsigned transactions.
         ///
         /// This is exposed so that it can be tuned for particular runtime, when
@@ -167,7 +165,7 @@ pub mod pallet {
     impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
         /// The block is being finalized.
         fn on_finalize(_n: BlockNumberFor<T>) {
-            assert!(SeqAddrUpdate::<T>::take(), "Sequencer address must be set for the block");
+            assert!(InherentUpdate::<T>::take(), "Sequencer address must be set for the block");
 
             // Create a new Starknet block and store it.
             <Pallet<T>>::store_block(UniqueSaturatedInto::<u64>::unique_saturated_into(
@@ -300,11 +298,17 @@ pub mod pallet {
     #[pallet::getter(fn sequencer_address)]
     pub type SequencerAddress<T: Config> = StorageValue<_, ContractAddress, ValueQuery>;
 
+    /// Current sequencer address.
+    #[pallet::storage]
+    #[pallet::unbounded]
+    #[pallet::getter(fn current_l1_gas_prices)]
+    pub type CurrentL1GasPrice<T: Config> = StorageValue<_, L1GasPrices, ValueQuery>;
+
     /// Ensure the sequencer address was updated for this block.
     #[pallet::storage]
     #[pallet::unbounded]
-    #[pallet::getter(fn seq_addr_update)]
-    pub type SeqAddrUpdate<T: Config> = StorageValue<_, bool, ValueQuery>;
+    #[pallet::getter(fn inherent_update)]
+    pub type InherentUpdate<T: Config> = StorageValue<_, bool, ValueQuery>;
 
     /// Information about processed L1 Messages
     /// Based on Nonce value.
@@ -413,7 +417,7 @@ pub mod pallet {
                 strk_fee_token_address: self.strk_fee_token_address,
                 eth_fee_token_address: self.eth_fee_token_address,
             });
-            SeqAddrUpdate::<T>::put(true);
+            InherentUpdate::<T>::put(true);
 
             ChainIdStorage::<T>::put(self.chain_id)
         }
@@ -463,20 +467,22 @@ pub mod pallet {
         /// The dispatch origin for this call must be `Inherent`.
         #[pallet::call_index(0)]
         #[pallet::weight((0, DispatchClass::Mandatory))]
-        pub fn set_sequencer_address(origin: OriginFor<T>, addr: [u8; 32]) -> DispatchResult {
+        pub fn set_starknet_inherent_data(origin: OriginFor<T>, data: InherentType) -> DispatchResult {
             ensure_none(origin)?;
-            // The `SeqAddrUpdate` storage item is initialized to `true` in the genesis build. In
+            // The `InherentUpdate` storage item is initialized to `true` in the genesis build. In
             // block 1 we skip the storage update check, and the `on_finalize` hook
             // updates the storage item to `false`. Initializing the storage item with
             // `false` causes the `on_finalize` hook to panic.
             if UniqueSaturatedInto::<u64>::unique_saturated_into(frame_system::Pallet::<T>::block_number()) > 1 {
-                assert!(!SeqAddrUpdate::<T>::exists(), "Sequencer address can be updated only once in the block");
+                assert!(!InherentUpdate::<T>::exists(), "Inherent data can be updated only once in the block");
             }
 
-            let addr = StarkFelt::new(addr).map_err(|_| Error::<T>::SequencerAddressNotValid)?;
+            let addr = StarkFelt::new(data.sequencer_address).map_err(|_| Error::<T>::SequencerAddressNotValid)?;
             let addr = ContractAddress(addr.try_into().map_err(|_| Error::<T>::SequencerAddressNotValid)?);
             SequencerAddress::<T>::put(addr);
-            SeqAddrUpdate::<T>::put(true);
+            CurrentL1GasPrice::<T>::put(data.l1_gas_price);
+
+            InherentUpdate::<T>::put(true);
             Ok(())
         }
 
@@ -699,18 +705,23 @@ pub mod pallet {
     impl<T: Config> ProvideInherent for Pallet<T> {
         type Call = Call<T>;
         type Error = InherentError;
-        const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
+        const INHERENT_IDENTIFIER: InherentIdentifier = STARKNET_INHERENT_IDENTIFIER;
 
         fn create_inherent(data: &InherentData) -> Option<Self::Call> {
             let inherent_data = data
-                .get_data::<InherentType>(&INHERENT_IDENTIFIER)
-                .expect("Sequencer address inherent data not correctly encoded")
-                .unwrap_or(DEFAULT_SEQUENCER_ADDRESS);
-            Some(Call::set_sequencer_address { addr: inherent_data })
+                .get_data::<InherentType>(&STARKNET_INHERENT_IDENTIFIER)
+                .expect("Starknet inherent data not correctly encoded")
+                // if we run in manual sealing, then it goes into the default case
+                // it's usually used in test cases.
+                .unwrap_or_default();
+
+            // TODO: should we have a safety check here that the L1 gas price isn't
+            // very old? We've this check in the l1-gas-prices worker already.
+            Some(Call::set_starknet_inherent_data { data: inherent_data })
         }
 
         fn is_inherent(call: &Self::Call) -> bool {
-            matches!(call, Call::set_sequencer_address { .. })
+            matches!(call, Call::set_starknet_inherent_data { .. })
         }
     }
 
@@ -849,7 +860,7 @@ impl<T: Config> Pallet<T> {
         let sequencer_address = Self::sequencer_address();
 
         let chain_id = ChainId(Self::chain_id_str());
-        let gas_prices = T::L1GasPrices::get();
+        let gas_prices = Self::current_l1_gas_prices().into();
 
         BlockContext::new_unchecked(
             &BlockInfo {
@@ -995,7 +1006,7 @@ impl<T: Config> Pallet<T> {
         let protocol_version = T::ProtocolVersion::get();
         let extra_data = None;
 
-        let l1_gas_price = T::L1GasPrices::get();
+        let l1_gas_price = Self::current_l1_gas_prices().into();
 
         let block = StarknetBlock::try_new(
             StarknetHeader::new(
diff --git a/crates/pallets/starknet/src/simulations.rs b/crates/pallets/starknet/src/simulations.rs
index 3454365d11..99f4ea5cf5 100644
--- a/crates/pallets/starknet/src/simulations.rs
+++ b/crates/pallets/starknet/src/simulations.rs
@@ -1,31 +1,32 @@
+use blockifier::blockifier::block::GasPrices;
 use blockifier::context::BlockContext;
 use blockifier::state::cached_state::{CachedState, CommitmentStateDiff, GlobalContractCache};
 use blockifier::state::state_api::State;
 use blockifier::transaction::account_transaction::AccountTransaction;
 use blockifier::transaction::errors::TransactionExecutionError;
-use blockifier::transaction::objects::TransactionExecutionInfo;
+use blockifier::transaction::objects::{FeeType, GasVector, HasRelatedFeeType, TransactionExecutionInfo};
 use blockifier::transaction::transaction_execution::Transaction;
 use blockifier::transaction::transactions::{ExecutableTransaction, L1HandlerTransaction};
 use frame_support::storage;
 use mp_simulations::{
-    InternalSubstrateError, ReExecutionResult, SimulationError, SimulationFlags, TransactionSimulationResult,
+    FeeEstimate, InternalSubstrateError, ReExecutionResult, SimulationError, SimulationFlags, TransactionSimulation,
+    TransactionSimulationResult,
 };
 use mp_transactions::execution::{
     commit_transactional_state, execute_l1_handler_transaction, run_non_revertible_transaction,
-    run_revertible_transaction, MutRefState, SetArbitraryNonce,
+    run_revertible_transaction, CheckFeeBounds, MutRefState, SetArbitraryNonce,
 };
-use sp_core::Get;
 use sp_runtime::DispatchError;
 use starknet_api::transaction::TransactionVersion;
 
 use crate::blockifier_state_adapter::BlockifierStateAdapter;
-use crate::{log, Config, Error, Pallet};
+use crate::{log, Config, Pallet};
 
 impl<T: Config> Pallet<T> {
     pub fn estimate_fee(
         transactions: Vec<AccountTransaction>,
         simulation_flags: &SimulationFlags,
-    ) -> Result<Result<Vec<(u128, u128)>, SimulationError>, InternalSubstrateError> {
+    ) -> Result<Result<Vec<FeeEstimate>, SimulationError>, InternalSubstrateError> {
         storage::transactional::with_transaction(|| {
             storage::TransactionOutcome::Rollback(Result::<_, DispatchError>::Ok(Self::estimate_fee_inner(
                 transactions,
@@ -41,17 +42,16 @@ impl<T: Config> Pallet<T> {
     fn estimate_fee_inner(
         transactions: Vec<AccountTransaction>,
         simulation_flags: &SimulationFlags,
-    ) -> Result<Vec<(u128, u128)>, SimulationError> {
+    ) -> Result<Vec<FeeEstimate>, SimulationError> {
         let transactions_len = transactions.len();
         let block_context = Self::get_block_context();
         let mut state = BlockifierStateAdapter::<T>::default();
 
-        let fee_res_iterator = transactions
-            .into_iter()
-            .map(|tx| match Self::execute_account_transaction(&tx, &mut state, &block_context, simulation_flags) {
-                Ok(execution_info) => {
+        let fee_res_iterator = transactions.into_iter().map(|tx| {
+            match Self::execute_account_transaction(&tx, &mut state, &block_context, simulation_flags) {
+                Ok(mut execution_info) => {
                     if !execution_info.is_reverted() {
-                        Ok(execution_info)
+                        Self::execution_info_to_fee_estimate(&tx, &mut execution_info, &block_context)
                     } else {
                         log!(
                             debug,
@@ -67,21 +67,12 @@ impl<T: Config> Pallet<T> {
                     log!(debug, "Transaction execution failed during fee estimation: {:?}", e);
                     Err(SimulationError::from(e))
                 }
-            })
-            .map(|exec_info_res| {
-                exec_info_res.map(|exec_info| {
-                    exec_info
-                        .actual_resources
-                        .0
-                        .get("l1_gas_usage")
-                        .ok_or_else(|| DispatchError::from(Error::<T>::MissingL1GasUsage))
-                        .map(|l1_gas_usage| (exec_info.actual_fee.0, *l1_gas_usage))
-                })
-            });
+            }
+        });
 
         let mut fees = Vec::with_capacity(transactions_len);
         for fee_res in fee_res_iterator {
-            let res = fee_res?.map_err(|_| SimulationError::StateDiff)?;
+            let res = fee_res?;
             fees.push(res);
         }
 
@@ -91,8 +82,7 @@ impl<T: Config> Pallet<T> {
     pub fn simulate_transactions(
         transactions: Vec<AccountTransaction>,
         simulation_flags: &SimulationFlags,
-    ) -> Result<Result<Vec<(CommitmentStateDiff, TransactionSimulationResult)>, SimulationError>, InternalSubstrateError>
-    {
+    ) -> Result<Vec<TransactionSimulationResult>, InternalSubstrateError> {
         storage::transactional::with_transaction(|| {
             storage::TransactionOutcome::Rollback(Result::<_, DispatchError>::Ok(Self::simulate_transactions_inner(
                 transactions,
@@ -104,33 +94,53 @@ impl<T: Config> Pallet<T> {
             InternalSubstrateError::FailedToCreateATransactionalStorageExecution
         })
     }
+
     fn simulate_transactions_inner(
         transactions: Vec<AccountTransaction>,
         simulation_flags: &SimulationFlags,
-    ) -> Result<Vec<(CommitmentStateDiff, TransactionSimulationResult)>, SimulationError> {
+    ) -> Vec<TransactionSimulationResult> {
         let block_context = Self::get_block_context();
         let mut state = BlockifierStateAdapter::<T>::default();
 
-        let tx_execution_results: Vec<(CommitmentStateDiff, TransactionSimulationResult)> = transactions
+        let tx_execution_results = transactions
             .into_iter()
             .map(|tx| {
-                let res = Self::execute_account_transaction_with_state_diff(
-                    &tx,
-                    &mut state,
-                    &block_context,
-                    simulation_flags,
-                )?;
-
-                let result = res.0.map_err(|e| {
-                    log::error!("Transaction execution failed during simulation: {e}");
-                    SimulationError::from(e)
-                });
+                // In order to produce a state diff for this specific tx we execute on a transactional state
+                let mut transactional_state =
+                    CachedState::new(MutRefState::new(&mut state), GlobalContractCache::new(1));
+
+                let exec_info =
+                    Self::execute_account_transaction(&tx, &mut transactional_state, &block_context, simulation_flags)
+                        .map_err(|e| {
+                            log!(debug, "Failed to execute transaction: {:?}", e);
+                            SimulationError::from(e)
+                        });
+
+                let mut exec_info = match exec_info {
+                    Ok(exec_info) => exec_info,
+                    Err(e) => return Err(e),
+                };
+
+                let state_diff = transactional_state.to_state_diff();
+                // Once the state diff of this tx is generated, we apply those changes on the original state
+                // so that next txs being simulated are ontop of this one (avoid nonce error)
+                match commit_transactional_state(transactional_state) {
+                    Ok(_) => (),
+                    Err(e) => {
+                        log::error!("Failed to commit state changes: {:?}", e);
+                        return Err(SimulationError::from(e));
+                    }
+                };
 
-                Ok((res.1, result))
+                let fee_estimate = match Self::execution_info_to_fee_estimate(&tx, &mut exec_info, &block_context) {
+                    Ok(fee_estimate) => fee_estimate,
+                    Err(e) => return Err(e),
+                };
+                Ok(TransactionSimulation { fee_estimate, execution_info: exec_info, state_diff })
             })
-            .collect::<Result<Vec<_>, SimulationError>>()?;
+            .collect();
 
-        Ok(tx_execution_results)
+        tx_execution_results
     }
 
     pub fn simulate_message(
@@ -164,7 +174,7 @@ impl<T: Config> Pallet<T> {
 
     pub fn estimate_message_fee(
         message: L1HandlerTransaction,
-    ) -> Result<Result<(u128, u128, u128), SimulationError>, InternalSubstrateError> {
+    ) -> Result<Result<FeeEstimate, SimulationError>, InternalSubstrateError> {
         storage::transactional::with_transaction(|| {
             storage::TransactionOutcome::Rollback(Result::<_, DispatchError>::Ok(Self::estimate_message_fee_inner(
                 message,
@@ -176,10 +186,11 @@ impl<T: Config> Pallet<T> {
         })
     }
 
-    fn estimate_message_fee_inner(message: L1HandlerTransaction) -> Result<(u128, u128, u128), SimulationError> {
+    fn estimate_message_fee_inner(message: L1HandlerTransaction) -> Result<FeeEstimate, SimulationError> {
         let mut cached_state = Self::init_cached_state();
+        let fee_type = message.fee_type();
 
-        let tx_execution_infos = match message.execute(&mut cached_state, &Self::get_block_context(), true, true) {
+        let mut tx_execution_info = match message.execute(&mut cached_state, &Self::get_block_context(), true, true) {
             Ok(execution_info) if !execution_info.is_reverted() => Ok(execution_info),
             Err(e) => {
                 log!(
@@ -201,11 +212,14 @@ impl<T: Config> Pallet<T> {
             }
         }?;
 
-        if let Some(l1_gas_usage) = tx_execution_infos.actual_resources.0.get("l1_gas_usage") {
-            Ok((T::L1GasPrices::get().eth_l1_gas_price.into(), tx_execution_infos.actual_fee.0 as u128, *l1_gas_usage))
-        } else {
-            Err(SimulationError::MissingL1GasUsage)
-        }
+        let current_l1_gas_price: GasPrices = Self::current_l1_gas_prices().into();
+        Self::from_tx_info_and_gas_price(
+            &mut tx_execution_info,
+            &current_l1_gas_price,
+            fee_type,
+            None,
+            &Self::get_block_context(),
+        )
     }
 
     pub fn re_execute_transactions(
@@ -239,21 +253,18 @@ impl<T: Config> Pallet<T> {
             Ok::<(), SimulationError>(())
         })?;
 
+        let simulation_flags =
+            SimulationFlags { charge_fee: !Self::is_transaction_fee_disabled(), ..Default::default() };
         let execution_infos = transactions_to_trace
             .iter()
             .map(|tx| {
                 let mut transactional_state =
                     CachedState::new(MutRefState::new(&mut state), GlobalContractCache::new(1));
-                let res = Self::execute_transaction(
-                    tx,
-                    &mut transactional_state,
-                    &block_context,
-                    &SimulationFlags::default(),
-                )
-                .map_err(|e| {
-                    log::error!("Failed to reexecute a tx: {}", e);
-                    SimulationError::from(e)
-                });
+                let res = Self::execute_transaction(tx, &mut transactional_state, &block_context, &simulation_flags)
+                    .map_err(|e| {
+                        log::error!("Failed to reexecute a tx: {}", e);
+                        SimulationError::from(e)
+                    });
 
                 let res = res
                     .map(|r| if with_state_diff { (r, Some(transactional_state.to_state_diff())) } else { (r, None) });
@@ -373,28 +384,25 @@ impl<T: Config> Pallet<T> {
         }
     }
 
-    fn execute_account_transaction_with_state_diff<S: State + SetArbitraryNonce>(
+    fn execution_info_to_fee_estimate(
         transaction: &AccountTransaction,
-        state: &mut S,
+        execution_info: &mut TransactionExecutionInfo,
         block_context: &BlockContext,
-        simulation_flags: &SimulationFlags,
-    ) -> Result<(Result<TransactionExecutionInfo, TransactionExecutionError>, CommitmentStateDiff), SimulationError>
-    {
-        // In order to produce a state diff for this specific tx we execute on a transactional state
-        let mut transactional_state = CachedState::new(MutRefState::new(state), GlobalContractCache::new(1));
-
-        let result =
-            Self::execute_account_transaction(transaction, &mut transactional_state, block_context, simulation_flags);
-
-        let state_diff = transactional_state.to_state_diff();
-        // Once the state diff of this tx is generated, we apply those changes on the original state
-        // so that next txs being simulated are ontop of this one (avoid nonce error)
-        commit_transactional_state(transactional_state).map_err(|e| {
-            log::error!("Failed to commit state changes: {:?}", e);
-            SimulationError::from(e)
-        })?;
-
-        Ok((result, state_diff))
+    ) -> Result<FeeEstimate, SimulationError> {
+        let tx_context = block_context.to_tx_context(transaction);
+        let gas_vector = match transaction.clone() {
+            AccountTransaction::Declare(tx) => tx.estimate_minimal_gas_vector(&tx_context)?,
+            AccountTransaction::DeployAccount(tx) => tx.estimate_minimal_gas_vector(&tx_context)?,
+            AccountTransaction::Invoke(tx) => tx.estimate_minimal_gas_vector(&tx_context)?,
+        };
+        let current_l1_gas_price: GasPrices = Self::current_l1_gas_prices().into();
+        Self::from_tx_info_and_gas_price(
+            execution_info,
+            &current_l1_gas_price,
+            transaction.fee_type(),
+            Some(gas_vector),
+            block_context,
+        )
     }
 
     fn execute_message<S: State>(
@@ -405,3 +413,53 @@ impl<T: Config> Pallet<T> {
         execute_l1_handler_transaction(transaction, state, block_context)
     }
 }
+
+// Took inspiration from here - https://github.com/eqlabs/pathfinder/blob/4a18125cae2c8fb1284e9e8fd23acf5d5bcfde18/crates/executor/src/types.rs#L41-L41
+impl<T: Config> Pallet<T> {
+    /// Computes fee estimate from the transaction execution information.
+    ///
+    /// `TransactionExecutionInfo` contains two related fields:
+    /// - `TransactionExecutionInfo::actual_fee` is the overall cost of the transaction (in WEI/FRI)
+    /// - `TransactionExecutionInfo::da_gas` is the gas usage for _data availability_.
+    ///
+    /// The problem is that we have to return both `gas_usage` and
+    /// `data_gas_usage` but we don't directly have the value of `gas_usage`
+    /// from the execution info, so we have to calculate that from other
+    /// fields.
+    fn from_tx_info_and_gas_price(
+        tx_info: &mut TransactionExecutionInfo,
+        gas_prices: &GasPrices,
+        fee_type: FeeType,
+        minimal_l1_gas_amount_vector: Option<GasVector>,
+        block_context: &BlockContext,
+    ) -> Result<FeeEstimate, SimulationError> {
+        let gas_price = gas_prices.get_gas_price_by_fee_type(&fee_type).get();
+        let data_gas_price = gas_prices.get_data_gas_price_by_fee_type(&fee_type).get();
+        if tx_info.actual_fee.0 == 0 {
+            // fee is not calculated by default for L1 handler transactions and if max_fee
+            // is zero, we have to do that explicitly
+            tx_info.actual_fee =
+                match blockifier::fee::fee_utils::calculate_tx_fee(&tx_info.actual_resources, block_context, &fee_type)
+                {
+                    Ok(fee) => fee,
+                    Err(e) => {
+                        log!(debug, "Failed to calculate tx fee: {:?}", e);
+                        return Err(SimulationError::from(e));
+                    }
+                };
+        }
+        let data_gas_consumed = tx_info.da_gas.l1_data_gas;
+        let data_gas_fee = data_gas_consumed.saturating_mul(data_gas_price);
+        let gas_consumed = tx_info.actual_fee.0.saturating_sub(data_gas_fee) / gas_price.max(1);
+
+        let (minimal_gas_consumed, minimal_data_gas_consumed) =
+            minimal_l1_gas_amount_vector.map(|v| (v.l1_gas, v.l1_data_gas)).unwrap_or_default();
+
+        let gas_consumed = gas_consumed.max(minimal_gas_consumed);
+        let data_gas_consumed = data_gas_consumed.max(minimal_data_gas_consumed);
+        let overall_fee =
+            gas_consumed.saturating_mul(gas_price).saturating_add(data_gas_consumed.saturating_mul(data_gas_price));
+
+        Ok(FeeEstimate { gas_consumed, gas_price, data_gas_consumed, data_gas_price, overall_fee, fee_type })
+    }
+}
diff --git a/crates/pallets/starknet/src/tests/block.rs b/crates/pallets/starknet/src/tests/block.rs
index c1517a9ecb..a2d40e8889 100644
--- a/crates/pallets/starknet/src/tests/block.rs
+++ b/crates/pallets/starknet/src/tests/block.rs
@@ -5,7 +5,7 @@ use blockifier::blockifier::block::GasPrices;
 use blockifier::transaction::objects::FeeType;
 use frame_support::assert_ok;
 use mp_digest_log::{ensure_log, find_starknet_block};
-use mp_sequencer_address::DEFAULT_SEQUENCER_ADDRESS;
+use mp_starknet_inherent::DEFAULT_SEQUENCER_ADDRESS;
 use starknet_api::block::{BlockNumber, BlockTimestamp};
 use starknet_api::core::{ChainId, ContractAddress, Nonce, PatriciaKey};
 use starknet_api::hash::StarkFelt;
@@ -14,7 +14,7 @@ use super::mock::default_mock::*;
 use super::mock::*;
 use crate::tests::constants::ETH_FEE_TOKEN_ADDRESS;
 use crate::tests::get_invoke_dummy;
-use crate::{SeqAddrUpdate, SequencerAddress};
+use crate::{InherentUpdate, SequencerAddress};
 
 #[test]
 fn store_block_no_pending_transactions_works() {
@@ -52,7 +52,7 @@ fn store_block_with_pending_transactions_works() {
         const BLOCK_NUMBER: u64 = 1;
         System::initialize(&BLOCK_NUMBER, &header.hash(), &Default::default());
 
-        SeqAddrUpdate::<MockRuntime>::put(true);
+        InherentUpdate::<MockRuntime>::put(true);
         let default_addr = ContractAddress(PatriciaKey(StarkFelt::new(DEFAULT_SEQUENCER_ADDRESS).unwrap()));
         SequencerAddress::<MockRuntime>::put(default_addr);
 
@@ -93,7 +93,7 @@ fn get_block_context_works() {
         const BLOCK_NUMBER: u64 = 1;
         System::initialize(&BLOCK_NUMBER, &header.hash(), &Default::default());
 
-        SeqAddrUpdate::<MockRuntime>::put(true);
+        InherentUpdate::<MockRuntime>::put(true);
         let default_addr = ContractAddress(PatriciaKey(StarkFelt::new(DEFAULT_SEQUENCER_ADDRESS).unwrap()));
         SequencerAddress::<MockRuntime>::put(default_addr);
 
diff --git a/crates/pallets/starknet/src/tests/deploy_account_tx.rs b/crates/pallets/starknet/src/tests/deploy_account_tx.rs
index f3c7e96d9e..149d89f881 100644
--- a/crates/pallets/starknet/src/tests/deploy_account_tx.rs
+++ b/crates/pallets/starknet/src/tests/deploy_account_tx.rs
@@ -90,7 +90,7 @@ fn given_contract_run_deploy_account_tx_works() {
                 data: EventData(vec![
                     contract_address.0.0,                   // From
                     StarkFelt::try_from("0xdead").unwrap(), // To
-                    StarkFelt::try_from("0xa17c").unwrap(), // Amount low
+                    StarkFelt::try_from("0x2ee").unwrap(),  // Amount low
                     StarkFelt::from(0u128),                 // Amount high
                 ]),
             },
@@ -98,7 +98,7 @@ fn given_contract_run_deploy_account_tx_works() {
         };
 
         let events = Starknet::tx_events(tx_hash);
-        assert_eq!(expected_fee_transfer_event, events.last().unwrap().clone());
+        pretty_assertions::assert_eq!(expected_fee_transfer_event, events.last().unwrap().clone());
     });
 }
 
diff --git a/crates/pallets/starknet/src/tests/erc20.rs b/crates/pallets/starknet/src/tests/erc20.rs
index 24cff1da01..d05c46b797 100644
--- a/crates/pallets/starknet/src/tests/erc20.rs
+++ b/crates/pallets/starknet/src/tests/erc20.rs
@@ -111,7 +111,7 @@ fn given_erc20_transfer_when_invoke_then_it_works() {
                 data: EventData(vec![
                     sender_address.0 .0, // From
                     StarkFelt::try_from("0xdead").unwrap(), // Sequencer address
-                    StarkFelt::try_from("0x18ab0").unwrap(), // Amount low
+                    StarkFelt::try_from("0x18ba").unwrap(), // Amount low
                     StarkFelt::from(0u128), // Amount high
                 ]),
             },
@@ -207,7 +207,7 @@ fn given_erc20_transfer_when_invoke_then_it_works() {
                 data: EventData(vec![
                     sender_address.0 .0,                    // From
                     StarkFelt::try_from("0xdead").unwrap(), // Sequencer address
-                    StarkFelt::try_from("0x11652").unwrap(), // Amount low
+                    StarkFelt::try_from("0xab4").unwrap(), // Amount low
                     StarkFelt::from(0u128),                 // Amount high
                 ]),
             },
diff --git a/crates/pallets/starknet/src/tests/invoke_tx.rs b/crates/pallets/starknet/src/tests/invoke_tx.rs
index e6a8fb9ab5..baa0292918 100644
--- a/crates/pallets/starknet/src/tests/invoke_tx.rs
+++ b/crates/pallets/starknet/src/tests/invoke_tx.rs
@@ -92,7 +92,7 @@ fn given_hardcoded_contract_run_invoke_tx_then_it_works() {
                     data: EventData(vec![
                         StarkFelt::try_from(BLOCKIFIER_ACCOUNT_ADDRESS).unwrap(),
                         StarkFelt::try_from("0xdead").unwrap(),
-                        StarkFelt::try_from("0xb932").unwrap(),
+                        StarkFelt::try_from("0x2f8").unwrap(),
                         StarkFelt::from(0u128),
                     ]),
                 },
@@ -132,7 +132,7 @@ fn given_hardcoded_contract_run_invoke_tx_then_event_is_emitted() {
                 data: EventData(vec![
                     StarkFelt::try_from("0x01a3339ec92ac1061e3e0f8e704106286c642eaf302e94a582e5f95ef5e6b4d0").unwrap(), // From
                     StarkFelt::try_from("0xdead").unwrap(), // To
-                    StarkFelt::try_from("0xbc84").unwrap(),  // Amount low
+                    StarkFelt::try_from("0x2f8").unwrap(),  // Amount low
                     StarkFelt::from(0u128),                 // Amount high
                 ]),
             },
diff --git a/crates/pallets/starknet/src/tests/mock/setup_mock.rs b/crates/pallets/starknet/src/tests/mock/setup_mock.rs
index 67d06fed50..09455bf65e 100644
--- a/crates/pallets/starknet/src/tests/mock/setup_mock.rs
+++ b/crates/pallets/starknet/src/tests/mock/setup_mock.rs
@@ -12,9 +12,9 @@ macro_rules! mock_runtime {
 			use sp_core::H256;
 			use sp_runtime::traits::{BlakeTwo256, IdentityLookup};
 			use {crate as pallet_starknet, frame_system as system};
-			use crate::{ SeqAddrUpdate, SequencerAddress};
+			use crate::{ InherentUpdate, SequencerAddress};
 			use frame_support::traits::Hooks;
-			use mp_sequencer_address::DEFAULT_SEQUENCER_ADDRESS;
+			use mp_starknet_inherent::DEFAULT_SEQUENCER_ADDRESS;
             use mp_felt::Felt252Wrapper;
 			use starknet_api::core::{PatriciaKey, ContractAddress};
 			use starknet_api::hash::StarkFelt;
@@ -86,18 +86,17 @@ macro_rules! mock_runtime {
                 type DisableNonceValidation = DisableNonceValidation;
 				type ProtocolVersion = ProtocolVersion;
 				type ProgramHash = ProgramHash;
-				type L1GasPrices = L1GasPrices;
 				type ExecutionConstants = ExecutionConstants;
 			}
 
 			/// Run to block n.
-			/// The function will repeatedly create and run blocks until the block number is equal to `n`.
-			/// # Arguments
-			/// * `n` - The block number to run to.
+            /// The function will repeatedly create and run blocks until the block number is equal to `n`.
+            /// # Arguments
+            /// * `n` - The block number to run to.
 			#[allow(unused)]
 			pub(crate) fn run_to_block(n: u64) {
 				for b in System::block_number()..=n {
-					SeqAddrUpdate::<MockRuntime>::put(true);
+					InherentUpdate::<MockRuntime>::put(true);
 					System::set_block_number(b);
 					Timestamp::set_timestamp(System::block_number() * 6_000);
 					Starknet::on_finalize(b);
@@ -107,7 +106,7 @@ macro_rules! mock_runtime {
 			/// Setup initial block and sequencer address for unit tests.
 			#[allow(unused)]
 			pub(crate) fn basic_test_setup(n: u64) {
-				SeqAddrUpdate::<MockRuntime>::put(true);
+				InherentUpdate::<MockRuntime>::put(true);
 				let default_addr = ContractAddress(PatriciaKey(StarkFelt::new(DEFAULT_SEQUENCER_ADDRESS).unwrap()));
 				SequencerAddress::<MockRuntime>::put(default_addr);
 				System::set_block_number(0);
diff --git a/crates/pallets/starknet/src/tests/mod.rs b/crates/pallets/starknet/src/tests/mod.rs
index 0e64d799b6..bc18e7cf0a 100644
--- a/crates/pallets/starknet/src/tests/mod.rs
+++ b/crates/pallets/starknet/src/tests/mod.rs
@@ -39,7 +39,7 @@ mod l1_message;
 mod query_tx;
 mod re_execute_transactions;
 mod send_message;
-mod sequencer_address;
+mod starknet_inherent;
 
 mod block;
 mod constants;
diff --git a/crates/pallets/starknet/src/tests/query_tx.rs b/crates/pallets/starknet/src/tests/query_tx.rs
index 79e4537582..a3c29f1a96 100644
--- a/crates/pallets/starknet/src/tests/query_tx.rs
+++ b/crates/pallets/starknet/src/tests/query_tx.rs
@@ -1,6 +1,7 @@
 use blockifier::transaction::account_transaction::AccountTransaction;
 use frame_support::{assert_err, assert_ok};
 use mp_simulations::SimulationFlags;
+use mp_starknet_inherent::L1GasPrices;
 use mp_transactions::compute_hash::ComputeTransactionHash;
 use starknet_api::core::Nonce;
 use starknet_api::hash::StarkFelt;
@@ -26,14 +27,22 @@ fn estimates_tx_fee_successfully_no_validate() {
         let txs = vec![tx_1, tx_2];
 
         let fees = Starknet::estimate_fee(txs, &Default::default()).expect("estimate should not fail").unwrap();
+        let default_l1_gas_price = L1GasPrices::default();
+
+        let fee_estimate = fees.get(0).unwrap();
+        // fee calculations checks are done in the blockifier
+        assert!(fee_estimate.overall_fee > 0, "actual fee is missing");
+        assert!(
+            fee_estimate.gas_price == default_l1_gas_price.eth_l1_gas_price.get(),
+            "gas price is the default value"
+        );
 
-        let (actual, l1_gas_usage) = fees[0];
-        assert!(actual > 0, "actual fee is missing");
-        assert!(l1_gas_usage == 0, "using blobstream we shouldn't pay l1 fee");
-
-        let (actual, l1_gas_usage) = fees[1];
-        assert!(actual > 0, "actual fee is missing");
-        assert!(l1_gas_usage == 0, "using blobstream we shouldn't pay l1 fee");
+        let fee_estimate = fees.get(1).unwrap();
+        assert!(fee_estimate.overall_fee > 0, "actual fee is missing");
+        assert!(
+            fee_estimate.gas_price == default_l1_gas_price.eth_l1_gas_price.get(),
+            "gas price is the default value"
+        );
     });
 }
 
diff --git a/crates/pallets/starknet/src/tests/sequencer_address.rs b/crates/pallets/starknet/src/tests/sequencer_address.rs
deleted file mode 100644
index 48dd006c39..0000000000
--- a/crates/pallets/starknet/src/tests/sequencer_address.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use frame_support::assert_ok;
-use frame_support::traits::Hooks;
-use mp_sequencer_address::{DEFAULT_SEQUENCER_ADDRESS, SEQ_ADDR_STORAGE_KEY};
-use starknet_api::core::{ContractAddress, PatriciaKey};
-use starknet_api::hash::StarkFelt;
-
-use super::mock::default_mock::*;
-use super::mock::*;
-
-pub const GOOD_SEQUENCER_ADDRESS: [u8; 32] =
-    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 173];
-
-pub const BAD_SEQUENCER_ADDRESS: [u8; 24] =
-    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 173];
-
-#[test]
-fn sequencer_address_is_set_to_default_when_not_provided() {
-    let mut ext = new_test_ext::<MockRuntime>();
-    ext.execute_with(|| {
-        basic_test_setup(0);
-        assert_eq!(
-            Starknet::sequencer_address(),
-            ContractAddress(PatriciaKey(StarkFelt::new(GOOD_SEQUENCER_ADDRESS).unwrap()))
-        );
-    });
-}
-
-#[test]
-fn sequencer_address_is_set_to_default_when_provided_in_bad_format() {
-    let mut ext = new_test_ext::<MockRuntime>();
-    ext.execute_with(|| {
-        basic_test_setup(0);
-        sp_io::offchain_index::set(SEQ_ADDR_STORAGE_KEY, &BAD_SEQUENCER_ADDRESS);
-        assert_eq!(
-            Starknet::sequencer_address(),
-            ContractAddress(PatriciaKey(StarkFelt::new(DEFAULT_SEQUENCER_ADDRESS).unwrap()))
-        );
-    });
-}
-
-#[test]
-fn sequencer_address_is_set_correctly() {
-    let mut ext = new_test_ext::<MockRuntime>();
-    ext.execute_with(|| {
-        basic_test_setup(0);
-        sp_io::offchain_index::set(SEQ_ADDR_STORAGE_KEY, &GOOD_SEQUENCER_ADDRESS);
-        assert_eq!(
-            Starknet::sequencer_address(),
-            ContractAddress(PatriciaKey(StarkFelt::new(GOOD_SEQUENCER_ADDRESS).unwrap()))
-        );
-    });
-    ext.persist_offchain_overlay();
-    let offchain_db = ext.offchain_db();
-    assert_eq!(offchain_db.get(SEQ_ADDR_STORAGE_KEY), Some(GOOD_SEQUENCER_ADDRESS.to_vec()));
-}
-
-#[test]
-fn sequencer_address_is_set_only_once_per_block() {
-    let mut ext = new_test_ext::<MockRuntime>();
-    ext.execute_with(|| {
-        basic_test_setup(0);
-        assert!(!Starknet::seq_addr_update());
-        sp_io::offchain_index::set(SEQ_ADDR_STORAGE_KEY, &GOOD_SEQUENCER_ADDRESS);
-        assert_eq!(
-            Starknet::sequencer_address(),
-            ContractAddress(PatriciaKey(StarkFelt::new(GOOD_SEQUENCER_ADDRESS).unwrap())),
-        );
-        sp_io::offchain_index::set(SEQ_ADDR_STORAGE_KEY, &DEFAULT_SEQUENCER_ADDRESS);
-        assert_eq!(
-            Starknet::sequencer_address(),
-            ContractAddress(PatriciaKey(StarkFelt::new(GOOD_SEQUENCER_ADDRESS).unwrap())),
-        );
-    });
-    ext.persist_offchain_overlay();
-    let offchain_db = ext.offchain_db();
-    assert_eq!(offchain_db.get(SEQ_ADDR_STORAGE_KEY), Some(DEFAULT_SEQUENCER_ADDRESS.to_vec()));
-}
-
-#[test]
-fn sequencer_address_has_not_been_updated() {
-    let mut ext = new_test_ext::<MockRuntime>();
-    ext.execute_with(|| {
-        basic_test_setup(0);
-        sp_io::offchain_index::set(SEQ_ADDR_STORAGE_KEY, &GOOD_SEQUENCER_ADDRESS);
-        assert_eq!(
-            Starknet::sequencer_address(),
-            ContractAddress(PatriciaKey(StarkFelt::new(GOOD_SEQUENCER_ADDRESS).unwrap())),
-        );
-        run_to_block(1);
-        assert!(!Starknet::seq_addr_update());
-    });
-}
-
-#[test]
-fn on_finalize_hook_takes_storage_update() {
-    let mut ext = new_test_ext::<MockRuntime>();
-    ext.execute_with(|| {
-        System::set_block_number(1);
-        assert!(Starknet::seq_addr_update());
-        Starknet::on_finalize(1);
-        assert!(!Starknet::seq_addr_update());
-    });
-}
-
-#[test]
-fn inherent_updates_storage() {
-    let mut ext = new_test_ext::<MockRuntime>();
-    ext.execute_with(|| {
-        let none_origin = RuntimeOrigin::none();
-
-        System::set_block_number(0);
-        assert!(Starknet::seq_addr_update());
-        Starknet::on_finalize(0);
-        assert!(!Starknet::seq_addr_update());
-
-        System::set_block_number(1);
-        assert_ok!(Starknet::set_sequencer_address(none_origin, DEFAULT_SEQUENCER_ADDRESS));
-        assert!(Starknet::seq_addr_update());
-    });
-}
diff --git a/crates/pallets/starknet/src/tests/starknet_inherent.rs b/crates/pallets/starknet/src/tests/starknet_inherent.rs
new file mode 100644
index 0000000000..4f479dc5e8
--- /dev/null
+++ b/crates/pallets/starknet/src/tests/starknet_inherent.rs
@@ -0,0 +1,98 @@
+use std::num::NonZeroU128;
+
+use frame_support::assert_ok;
+use frame_support::traits::Hooks;
+use mp_starknet_inherent::{L1GasPrices, StarknetInherentData, DEFAULT_SEQUENCER_ADDRESS};
+use starknet_api::core::{ContractAddress, PatriciaKey};
+use starknet_api::hash::StarkFelt;
+
+use super::mock::default_mock::*;
+use super::mock::*;
+
+pub const GOOD_SEQUENCER_ADDRESS: [u8; 32] =
+    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 175];
+
+fn get_dummy_l1_gas_price() -> L1GasPrices {
+    unsafe {
+        L1GasPrices {
+            eth_l1_gas_price: NonZeroU128::new_unchecked(123),
+            eth_l1_data_gas_price: NonZeroU128::new_unchecked(123),
+            strk_l1_gas_price: NonZeroU128::new_unchecked(123),
+            strk_l1_data_gas_price: NonZeroU128::new_unchecked(123),
+            last_update_timestamp: 2,
+        }
+    }
+}
+
+#[test]
+fn inherent_updates_storage() {
+    let mut ext = new_test_ext::<MockRuntime>();
+    ext.execute_with(|| {
+        let none_origin = RuntimeOrigin::none();
+
+        System::set_block_number(0);
+        assert!(Starknet::inherent_update());
+        Starknet::on_finalize(0);
+        assert!(!Starknet::inherent_update());
+
+        System::set_block_number(1);
+        let l1_gas_price = get_dummy_l1_gas_price();
+        assert_ok!(Starknet::set_starknet_inherent_data(
+            none_origin,
+            StarknetInherentData { sequencer_address: GOOD_SEQUENCER_ADDRESS, l1_gas_price: l1_gas_price.clone() }
+        ));
+        assert!(Starknet::inherent_update());
+        assert_eq!(
+            Starknet::sequencer_address(),
+            ContractAddress(PatriciaKey(StarkFelt::new(GOOD_SEQUENCER_ADDRESS).unwrap()))
+        );
+        assert_eq!(Starknet::current_l1_gas_prices(), l1_gas_price);
+    });
+}
+
+#[test]
+fn on_finalize_hook_takes_storage_update() {
+    let mut ext = new_test_ext::<MockRuntime>();
+    ext.execute_with(|| {
+        System::set_block_number(1);
+        assert!(Starknet::inherent_update());
+        Starknet::on_finalize(1);
+        assert!(!Starknet::inherent_update());
+    });
+}
+
+#[test]
+#[should_panic]
+fn inherent_updates_only_once_per_block() {
+    let mut ext = new_test_ext::<MockRuntime>();
+    ext.execute_with(|| {
+        let none_origin = RuntimeOrigin::none();
+
+        System::set_block_number(1);
+        assert!(Starknet::inherent_update());
+        Starknet::on_finalize(1);
+        assert!(!Starknet::inherent_update());
+
+        // setting block number to 2 as we ignore "already updated" check
+        // for genesis blocks
+        System::set_block_number(2);
+        let l1_gas_price = get_dummy_l1_gas_price();
+
+        // setting it first time works
+        assert_ok!(Starknet::set_starknet_inherent_data(
+            none_origin.clone(),
+            StarknetInherentData { sequencer_address: DEFAULT_SEQUENCER_ADDRESS, l1_gas_price: l1_gas_price.clone() }
+        ));
+        assert_eq!(Starknet::current_l1_gas_prices(), l1_gas_price);
+
+        let l1_gas_price_new = L1GasPrices { last_update_timestamp: 999, ..l1_gas_price };
+        // setting it second time causes it to panic
+        let _ = Starknet::set_starknet_inherent_data(
+            none_origin,
+            StarknetInherentData {
+                sequencer_address: DEFAULT_SEQUENCER_ADDRESS,
+                l1_gas_price: l1_gas_price_new.clone(),
+            },
+        );
+    });
+}
diff --git a/crates/primitives/sequencer-address/src/lib.rs b/crates/primitives/sequencer-address/src/lib.rs
deleted file mode 100644
index 68296f7ddb..0000000000
--- a/crates/primitives/sequencer-address/src/lib.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-//! The address of the account receiving the network fee
-use sp_inherents::{InherentData, InherentIdentifier, IsFatalError};
-use thiserror::Error;
-
-/// The identifier for the `sequencer_address` inherent.
-pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"seqaddr0";
-
-/// Default value in case the sequencer address is not set.
-pub const DEFAULT_SEQUENCER_ADDRESS: [u8; 32] =
-    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 173];
-
-/// The storage key for the sequencer address value.
-pub const SEQ_ADDR_STORAGE_KEY: &[u8] = b"starknet::seq_addr";
-
-/// The inherent type for the sequencer address.
-pub type InherentType = [u8; 32];
-
-#[derive(Error, sp_core::RuntimeDebug)]
-#[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))]
-/// Error types when working with the sequencer address.
-pub enum InherentError {
-    /// Submitted address must be `[u8; 32]`.
-    #[error("Inherent decoding error")]
-    WrongAddressFormat,
-}
-
-impl IsFatalError for InherentError {
-    fn is_fatal_error(&self) -> bool {
-        match self {
-            InherentError::WrongAddressFormat => true,
-        }
-    }
-}
-
-/// Auxiliary trait to extract sequencer address inherent data.
-pub trait SequencerAddressInherentData {
-    /// Get sequencer address inherent data.
-    fn sequencer_address_inherent_data(&self) -> Result<Option<InherentType>, sp_inherents::Error>;
-}
-
-impl SequencerAddressInherentData for InherentData {
-    fn sequencer_address_inherent_data(&self) -> Result<Option<InherentType>, sp_inherents::Error> {
-        self.get_data(&INHERENT_IDENTIFIER)
-    }
-}
-
-#[cfg(feature = "client")]
-mod reexport_for_client_only {
-    use std::array::TryFromSliceError;
-    use std::boxed::Box;
-
-    use parity_scale_codec::{Decode, Encode};
-
-    use super::*;
-    /// Helper function to convert storage value.
-    fn slice_to_arr(slice: &[u8]) -> Result<[u8; 32], TryFromSliceError> {
-        slice.try_into()
-    }
-
-    impl InherentError {
-        /// Try to create an instance ouf of the given identifier and data.
-        // TODO: Bad name. This let think that it uses the trait TryFrom
-        pub fn try_from(id: &InherentIdentifier, mut data: &[u8]) -> Option<Self> {
-            if id == &INHERENT_IDENTIFIER { <InherentError as Decode>::decode(&mut data).ok() } else { None }
-        }
-    }
-
-    #[derive(Copy, Clone, Decode, Encode, sp_core::RuntimeDebug)]
-    /// The inherent data provider for sequencer address.
-    pub struct InherentDataProvider {
-        /// The sequencer address field.
-        pub sequencer_address: InherentType,
-    }
-
-    impl InherentDataProvider {
-        /// Create `Self` using the given `addr`.
-        pub fn new(addr: InherentType) -> Self {
-            Self { sequencer_address: addr }
-        }
-
-        /// Returns the sequencer address of this inherent data provider.
-        pub fn sequencer_address(&self) -> InherentType {
-            self.sequencer_address
-        }
-    }
-
-    impl Default for InherentDataProvider {
-        fn default() -> InherentDataProvider {
-            InherentDataProvider { sequencer_address: DEFAULT_SEQUENCER_ADDRESS }
-        }
-    }
-
-    impl TryFrom<Vec<u8>> for InherentDataProvider {
-        type Error = InherentError;
-        fn try_from(storage_val: Vec<u8>) -> Result<Self, InherentError> {
-            match slice_to_arr(&storage_val) {
-                Ok(addr) => Ok(InherentDataProvider { sequencer_address: addr }),
-                Err(_) => Err(InherentError::WrongAddressFormat),
-            }
-        }
-    }
-
-    #[async_trait::async_trait]
-    impl sp_inherents::InherentDataProvider for InherentDataProvider {
-        async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), sp_inherents::Error> {
-            inherent_data.put_data(INHERENT_IDENTIFIER, &self.sequencer_address)
-        }
-
-        async fn try_handle_error(
-            &self,
-            identifier: &InherentIdentifier,
-            error: &[u8],
-        ) -> Option<Result<(), sp_inherents::Error>> {
-            Some(Err(sp_inherents::Error::Application(Box::from(InherentError::try_from(identifier, error)?))))
-        }
-    }
-}
-
-#[cfg(feature = "client")]
-pub use reexport_for_client_only::*;
diff --git a/crates/primitives/simulations/Cargo.toml b/crates/primitives/simulations/Cargo.toml
index c547f6475d..310c370632 100644
--- a/crates/primitives/simulations/Cargo.toml
+++ b/crates/primitives/simulations/Cargo.toml
@@ -21,4 +21,4 @@ scale-info = { workspace = true, optional = true }
 
 [features]
 parity-scale-codec = ["dep:parity-scale-codec"]
-scale-info = ["dep:scale-info"]
+scale-info = ["dep:scale-info", "blockifier/scale-info"]
diff --git a/crates/primitives/simulations/src/lib.rs b/crates/primitives/simulations/src/lib.rs
index bdf482e52c..8436a7649c 100644
--- a/crates/primitives/simulations/src/lib.rs
+++ b/crates/primitives/simulations/src/lib.rs
@@ -1,8 +1,8 @@
 use blockifier::state::cached_state::CommitmentStateDiff;
 use blockifier::state::errors::StateError;
-use blockifier::transaction::errors::TransactionExecutionError;
-use blockifier::transaction::objects::TransactionExecutionInfo;
-use starknet_core::types::{SimulationFlag, SimulationFlagForEstimateFee};
+use blockifier::transaction::errors::{TransactionExecutionError, TransactionFeeError};
+use blockifier::transaction::objects::{FeeType, TransactionExecutionInfo};
+use starknet_core::types::{PriceUnit, SimulationFlag, SimulationFlagForEstimateFee};
 
 #[derive(Debug, Clone)]
 #[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))]
@@ -12,6 +12,7 @@ pub enum SimulationError {
     TransactionExecutionFailed(String),
     MissingL1GasUsage,
     StateDiff,
+    EstimateFeeFailed(String),
 }
 
 #[derive(Debug, Clone)]
@@ -27,14 +28,29 @@ impl From<TransactionExecutionError> for SimulationError {
     }
 }
 
+impl From<TransactionFeeError> for SimulationError {
+    fn from(e: TransactionFeeError) -> SimulationError {
+        SimulationError::EstimateFeeFailed(e.to_string())
+    }
+}
+
 impl From<StateError> for SimulationError {
     fn from(_e: StateError) -> SimulationError {
         SimulationError::StateDiff
     }
 }
 
+#[derive(Debug)]
+#[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))]
+#[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))]
+pub struct TransactionSimulation {
+    pub execution_info: TransactionExecutionInfo,
+    pub state_diff: CommitmentStateDiff,
+    pub fee_estimate: FeeEstimate,
+}
+
+pub type TransactionSimulationResult = Result<TransactionSimulation, SimulationError>;
 pub type ReExecutionResult = Result<Vec<(TransactionExecutionInfo, Option<CommitmentStateDiff>)>, SimulationError>;
-pub type TransactionSimulationResult = Result<TransactionExecutionInfo, SimulationError>;
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))]
@@ -87,3 +103,38 @@ impl core::default::Default for SimulationFlags {
         Self { validate: true, charge_fee: true }
     }
 }
+
+// We can use `FeeEstimate` from starknet-rs once we upgrade to 0.13.1
+#[derive(Debug)]
+#[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))]
+#[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))]
+pub struct FeeEstimate {
+    pub gas_consumed: u128,
+    pub gas_price: u128,
+    pub data_gas_consumed: u128,
+    pub data_gas_price: u128,
+    pub overall_fee: u128,
+    pub fee_type: FeeType,
+}
+
+impl From<&FeeEstimate> for starknet_core::types::FeeEstimate {
+    fn from(fee_estimate: &FeeEstimate) -> Self {
+        Self {
+            gas_price: fee_estimate.gas_price.into(),
+            // this is a rough estimate because in reality the gas is split into data gas
+            // and execution gas. however, since we're not on 0.13.1 yet, we're using this
+            gas_consumed: fee_estimate.overall_fee.saturating_div(fee_estimate.gas_price).into(),
+            overall_fee: fee_estimate.overall_fee.into(),
+            unit: match fee_estimate.fee_type {
+                FeeType::Strk => PriceUnit::Fri,
+                FeeType::Eth => PriceUnit::Wei,
+            },
+        }
+    }
+}
+
+impl From<FeeEstimate> for starknet_core::types::FeeEstimate {
+    fn from(fee_estimate: FeeEstimate) -> Self {
+        Self::from(&fee_estimate)
+    }
+}
diff --git a/crates/primitives/sequencer-address/Cargo.toml b/crates/primitives/starknet-inherent/Cargo.toml
similarity index 81%
rename from crates/primitives/sequencer-address/Cargo.toml
rename to crates/primitives/starknet-inherent/Cargo.toml
index 9bc659229a..be82c5bb8d 100644
--- a/crates/primitives/sequencer-address/Cargo.toml
+++ b/crates/primitives/starknet-inherent/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "mp-sequencer-address"
+name = "mp-starknet-inherent"
 version.workspace = true
 edition.workspace = true
 license = "MIT"
@@ -11,6 +11,7 @@ repository = { workspace = true }
 targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
+blockifier = { workspace = true }
 sp-core = { workspace = true }
 sp-inherents = { workspace = true }
 thiserror = { workspace = true }
@@ -20,7 +21,9 @@ async-trait = { workspace = true, optional = true }
 parity-scale-codec = { workspace = true, features = [
   "derive",
 ], optional = true }
+scale-info = { workspace = true, optional = true }
 
 [features]
 parity-scale-codec = ["dep:parity-scale-codec"]
+scale-info = ["dep:scale-info"]
 client = ["parity-scale-codec", "dep:async-trait"]
diff --git a/crates/primitives/starknet-inherent/src/lib.rs b/crates/primitives/starknet-inherent/src/lib.rs
new file mode 100644
index 0000000000..443fb64d04
--- /dev/null
+++ b/crates/primitives/starknet-inherent/src/lib.rs
@@ -0,0 +1,147 @@
+//! The address of the account receiving the network fee
+use std::num::NonZeroU128;
+
+use blockifier::blockifier::block::GasPrices;
+use sp_inherents::{InherentData, InherentIdentifier, IsFatalError};
+use thiserror::Error;
+
+/// The identifier for the `sequencer_address` inherent.
+pub const STARKNET_INHERENT_IDENTIFIER: InherentIdentifier = *b"starknet";
+
+/// Default value in case the sequencer address is not set.
+pub const DEFAULT_SEQUENCER_ADDRESS: [u8; 32] =
+    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 173];
+
+/// The storage key for the sequencer address value.
+pub const SEQ_ADDR_STORAGE_KEY: &[u8] = b"starknet::seq_addr";
+
+#[derive(Clone, sp_core::RuntimeDebug, PartialEq, Eq)]
+#[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))]
+#[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))]
+pub struct L1GasPrices {
+    pub eth_l1_gas_price: NonZeroU128,       // In wei.
+    pub strk_l1_gas_price: NonZeroU128,      // In fri.
+    pub eth_l1_data_gas_price: NonZeroU128,  // In wei.
+    pub strk_l1_data_gas_price: NonZeroU128, // In fri.
+    pub last_update_timestamp: u128,
+}
+
+impl Default for L1GasPrices {
+    fn default() -> Self {
+        L1GasPrices {
+            eth_l1_gas_price: NonZeroU128::new(10).unwrap(),
+            strk_l1_gas_price: NonZeroU128::new(10).unwrap(),
+            eth_l1_data_gas_price: NonZeroU128::new(10).unwrap(),
+            strk_l1_data_gas_price: NonZeroU128::new(10).unwrap(),
+            last_update_timestamp: Default::default(),
+        }
+    }
+}
+
+#[derive(Error, sp_core::RuntimeDebug)]
+pub enum L1GasPriceError {
+    #[error("Failed to convert {0} with value {1}  to NonZeroU128")]
+    GasPriceCoversionError(String, u128),
+}
+
+impl From<L1GasPrices> for GasPrices {
+    fn from(l1_gas_prices: L1GasPrices) -> Self {
+        GasPrices {
+            eth_l1_gas_price: l1_gas_prices.eth_l1_gas_price,
+            strk_l1_gas_price: l1_gas_prices.strk_l1_gas_price,
+            eth_l1_data_gas_price: l1_gas_prices.eth_l1_data_gas_price,
+            strk_l1_data_gas_price: l1_gas_prices.strk_l1_data_gas_price,
+        }
+    }
+}
+
+/// Struct to hold all data for the Starknet inherent
+#[derive(Clone, sp_core::RuntimeDebug, PartialEq, Eq)]
+#[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))]
+#[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))]
+pub struct StarknetInherentData {
+    /// The sequencer address field.
+    pub sequencer_address: [u8; 32],
+    /// The L1 gas price
+    pub l1_gas_price: L1GasPrices,
+}
+
+impl Default for StarknetInherentData {
+    fn default() -> Self {
+        StarknetInherentData { sequencer_address: DEFAULT_SEQUENCER_ADDRESS, l1_gas_price: Default::default() }
+    }
+}
+
+/// The inherent type for the sequencer address.
+pub type InherentType = StarknetInherentData;
+
+#[derive(Error, sp_core::RuntimeDebug)]
+#[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))]
+/// Error types when working with the sequencer address.
+pub enum InherentError {
+    /// Submitted address must be `[u8; 32]`.
+    #[error("Inherent decoding error")]
+    WrongAddressFormat,
+}
+
+impl IsFatalError for InherentError {
+    fn is_fatal_error(&self) -> bool {
+        match self {
+            InherentError::WrongAddressFormat => true,
+        }
+    }
+}
+
+#[cfg(feature = "client")]
+mod reexport_for_client_only {
+
+    use std::boxed::Box;
+
+    use parity_scale_codec::{Decode, Encode};
+
+    use super::*;
+
+    impl InherentError {
+        /// Try to create an instance ouf of the given identifier and data.
+        // TODO: Bad name. This let think that it uses the trait TryFrom
+        pub fn try_from(id: &InherentIdentifier, mut data: &[u8]) -> Option<Self> {
+            if id == &STARKNET_INHERENT_IDENTIFIER { <InherentError as Decode>::decode(&mut data).ok() } else { None }
+        }
+    }
+
+    #[derive(Clone, Decode, Encode, sp_core::RuntimeDebug)]
+    /// The inherent data provider for sequencer address.
+    pub struct InherentDataProvider {
+        pub starknet_inherent_data: InherentType,
+    }
+
+    impl InherentDataProvider {
+        /// Create `Self` using the given `addr`.
+        pub fn new(data: InherentType) -> Self {
+            Self { starknet_inherent_data: data }
+        }
+
+        /// Returns the sequencer address of this inherent data provider.
+        pub fn starknet_inherent_data(&self) -> &InherentType {
+            &self.starknet_inherent_data
+        }
+    }
+
+    #[async_trait::async_trait]
+    impl sp_inherents::InherentDataProvider for InherentDataProvider {
+        async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), sp_inherents::Error> {
+            inherent_data.put_data(STARKNET_INHERENT_IDENTIFIER, &self.starknet_inherent_data)
+        }
+
+        async fn try_handle_error(
+            &self,
+            identifier: &InherentIdentifier,
+            error: &[u8],
+        ) -> Option<Result<(), sp_inherents::Error>> {
+            Some(Err(sp_inherents::Error::Application(Box::from(InherentError::try_from(identifier, error)?))))
+        }
+    }
+}
+
+#[cfg(feature = "client")]
+pub use reexport_for_client_only::*;
diff --git a/crates/primitives/transactions/src/execution.rs b/crates/primitives/transactions/src/execution.rs
index d1530ea738..74a2fbab27 100644
--- a/crates/primitives/transactions/src/execution.rs
+++ b/crates/primitives/transactions/src/execution.rs
@@ -197,28 +197,7 @@ pub trait CheckFeeBounds: GetCalldataLen + GetTxType {
     fn state_changes() -> StateChangesCount;
 
     fn check_fee_bounds(&self, tx_context: &TransactionContext) -> TransactionExecutionResult<()> {
-        let minimal_l1_gas_amount_vector = {
-            let block_info = tx_context.block_context.block_info();
-            let versioned_constants = tx_context.block_context.versioned_constants();
-
-            let state_changes = Self::state_changes();
-
-            let GasVector { l1_gas: gas_cost, l1_data_gas: blob_gas_cost } =
-                blockifier::fee::gas_usage::get_da_gas_cost(&state_changes, block_info.use_kzg_da);
-
-            let data_segment_length = blockifier::fee::gas_usage::get_onchain_data_segment_length(&state_changes);
-            let os_steps_for_type =
-                versioned_constants.os_resources_for_tx_type(&Self::tx_type(), self.get_calldata_len()).n_steps
-                    + versioned_constants.os_kzg_da_resources(data_segment_length).n_steps;
-
-            let resources = ResourcesMapping(IndexMap::from([
-                (blockifier::abi::constants::L1_GAS_USAGE.to_string(), gas_cost),
-                (blockifier::abi::constants::BLOB_GAS_USAGE.to_string(), blob_gas_cost),
-                (blockifier::abi::constants::N_STEPS_RESOURCE.to_string(), os_steps_for_type as u128),
-            ]));
-
-            blockifier::fee::fee_utils::calculate_tx_gas_vector(&resources, versioned_constants)?
-        };
+        let minimal_l1_gas_amount_vector = self.estimate_minimal_gas_vector(tx_context)?;
 
         // TODO(Aner, 30/01/24): modify once data gas limit is enforced.
         let minimal_l1_gas_amount = blockifier::fee::gas_usage::compute_discounted_gas_from_gas_vector(
@@ -270,6 +249,29 @@ pub trait CheckFeeBounds: GetCalldataLen + GetTxType {
 
         Ok(())
     }
+
+    fn estimate_minimal_gas_vector(&self, tx_context: &TransactionContext) -> TransactionExecutionResult<GasVector> {
+        let block_info = tx_context.block_context.block_info();
+        let versioned_constants = tx_context.block_context.versioned_constants();
+
+        let state_changes = Self::state_changes();
+
+        let GasVector { l1_gas: gas_cost, l1_data_gas: blob_gas_cost } =
+            blockifier::fee::gas_usage::get_da_gas_cost(&state_changes, block_info.use_kzg_da);
+
+        let data_segment_length = blockifier::fee::gas_usage::get_onchain_data_segment_length(&state_changes);
+        let os_steps_for_type =
+            versioned_constants.os_resources_for_tx_type(&Self::tx_type(), self.get_calldata_len()).n_steps
+                + versioned_constants.os_kzg_da_resources(data_segment_length).n_steps;
+
+        let resources = ResourcesMapping(IndexMap::from([
+            (blockifier::abi::constants::L1_GAS_USAGE.to_string(), gas_cost),
+            (blockifier::abi::constants::BLOB_GAS_USAGE.to_string(), blob_gas_cost),
+            (blockifier::abi::constants::N_STEPS_RESOURCE.to_string(), os_steps_for_type as u128),
+        ]));
+
+        Ok(blockifier::fee::fee_utils::calculate_tx_gas_vector(&resources, versioned_constants)?)
+    }
 }
 
 impl CheckFeeBounds for DeclareTransaction {
diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml
index 873445ed52..0cd21cf64e 100644
--- a/crates/runtime/Cargo.toml
+++ b/crates/runtime/Cargo.toml
@@ -59,6 +59,7 @@ mp-felt = { workspace = true }
 mp-hashers = { workspace = true }
 mp-program-hash = { workspace = true }
 mp-simulations = { workspace = true }
+mp-starknet-inherent = { workspace = true }
 pallet-starknet = { workspace = true }
 pallet-starknet-runtime-api = { workspace = true }
 # Starknet dependencies
diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs
index 81eba9ef77..cdb7f76d2c 100644
--- a/crates/runtime/src/lib.rs
+++ b/crates/runtime/src/lib.rs
@@ -34,8 +34,10 @@ pub use frame_support::{construct_runtime, parameter_types, StorageValue};
 pub use frame_system::Call as SystemCall;
 use mp_felt::Felt252Wrapper;
 use mp_simulations::{
-    InternalSubstrateError, ReExecutionResult, SimulationError, SimulationFlags, TransactionSimulationResult,
+    FeeEstimate, InternalSubstrateError, ReExecutionResult, SimulationError, SimulationFlags,
+    TransactionSimulationResult,
 };
+use mp_starknet_inherent::L1GasPrices;
 use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
 /// Import the Starknet pallet.
 pub use pallet_starknet;
@@ -277,7 +279,7 @@ impl_runtime_apis! {
             Starknet::is_transaction_fee_disabled()
         }
 
-        fn estimate_fee(transactions: Vec<AccountTransaction>, simulation_flags: SimulationFlags) -> Result<Result<Vec<(u128, u128)>, SimulationError>, InternalSubstrateError> {
+        fn estimate_fee(transactions: Vec<AccountTransaction>, simulation_flags: SimulationFlags) -> Result<Result<Vec<FeeEstimate>, SimulationError>, InternalSubstrateError> {
             Starknet::estimate_fee(transactions, &simulation_flags)
         }
 
@@ -285,15 +287,15 @@ impl_runtime_apis! {
             Starknet::re_execute_transactions(transactions_before, transactions_to_trace, with_state_diff)
         }
 
-        fn get_transaction_re_execution_state_diff( transactions_before: Vec<Transaction>, transactions_to_trace: Vec<Transaction>) -> Result<Result<CommitmentStateDiff, SimulationError>, InternalSubstrateError> {
-            Starknet::get_transaction_re_execution_state_diff(transactions_before, transactions_to_trace)
+        fn estimate_message_fee(message: L1HandlerTransaction) -> Result<Result<FeeEstimate, SimulationError>, InternalSubstrateError> {
+            Starknet::estimate_message_fee(message)
         }
 
-        fn estimate_message_fee(message: L1HandlerTransaction) -> Result<Result<(u128, u128, u128), SimulationError>, InternalSubstrateError> {
-            Starknet::estimate_message_fee(message)
+        fn get_transaction_re_execution_state_diff( transactions_before: Vec<Transaction>, transactions_to_trace: Vec<Transaction>) -> Result<Result<CommitmentStateDiff, SimulationError>, InternalSubstrateError> {
+            Starknet::get_transaction_re_execution_state_diff(transactions_before, transactions_to_trace)
         }
 
-        fn simulate_transactions(transactions: Vec<AccountTransaction>, simulation_flags: SimulationFlags) -> Result<Result<Vec<(CommitmentStateDiff, TransactionSimulationResult)>, SimulationError>, InternalSubstrateError> {
+        fn simulate_transactions(transactions: Vec<AccountTransaction>, simulation_flags: SimulationFlags) -> Result<Vec<TransactionSimulationResult>, InternalSubstrateError> {
             Starknet::simulate_transactions(transactions, &simulation_flags)
         }
 
@@ -355,6 +357,10 @@ impl_runtime_apis! {
         fn l1_nonce_unused(nonce: Nonce) -> bool {
             Starknet::ensure_l1_message_not_executed(&nonce).is_ok()
         }
+
+        fn current_l1_gas_prices() -> L1GasPrices {
+            Starknet::current_l1_gas_prices()
+        }
     }
 
     impl pallet_starknet_runtime_api::ConvertTransactionRuntimeApi<Block> for Runtime {
diff --git a/crates/runtime/src/pallets.rs b/crates/runtime/src/pallets.rs
index f0a5bf8e36..e6b22473cc 100644
--- a/crates/runtime/src/pallets.rs
+++ b/crates/runtime/src/pallets.rs
@@ -3,13 +3,11 @@
 //! This file is used to generate the `construct_runtime!` macro.
 #[cfg(all(debug_assertions, feature = "dev"))]
 use std::env::VarError;
-use std::num::NonZeroU128;
 use std::ops::Deref;
 #[cfg(all(debug_assertions, feature = "dev"))]
 use std::path::Path;
 use std::sync::Arc;
 
-use blockifier::blockifier::block::GasPrices;
 use blockifier::versioned_constants::VersionedConstants;
 pub use frame_support::traits::{
     ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, OnTimestampSet, Randomness, StorageInfo,
@@ -76,7 +74,6 @@ impl pallet_starknet::Config for Runtime {
     type DisableNonceValidation = ConstBool<false>;
     type ProtocolVersion = ProtocolVersion;
     type ProgramHash = ProgramHash;
-    type L1GasPrices = L1GasPrices;
     type ExecutionConstants = ExecutionConstants;
 }
 
@@ -192,7 +189,6 @@ parameter_types! {
     pub const TransactionLongevity: u64 = u64::MAX;
     pub const ProtocolVersion: u8 = 0;
     pub const ProgramHash: Felt252Wrapper = SN_OS_PROGRAM_HASH;
-    pub const L1GasPrices: GasPrices = GasPrices { eth_l1_gas_price: unsafe { NonZeroU128::new_unchecked(10) }, strk_l1_gas_price: unsafe { NonZeroU128::new_unchecked(10) }, eth_l1_data_gas_price: unsafe { NonZeroU128::new_unchecked(10) }, strk_l1_data_gas_price: unsafe { NonZeroU128::new_unchecked(10) } };
     pub ExecutionConstants: Arc<VersionedConstants> = get_execution_constants();
 }
 
diff --git a/docs/genesis.md b/docs/genesis.md
index 6445aa7081..47cc36f983 100644
--- a/docs/genesis.md
+++ b/docs/genesis.md
@@ -44,6 +44,7 @@ The below defines all hardcoded values set in the geneses:
 | 0x04569ffd48c2a3d455437c16dc843801fb896b1af845bc8bc7ba83ebc4358b7f | Universal deployer class hash                  |
 | 0x01a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003 | Argent Cairo 1 Account                         |
 | 0x04c6d6cf894f8bc96bb9c525e6853e5483177841f7388f74a46cfda6f028c755 | OpenZepplin Cairo 1 Account                    |
+| 0x015b7c90a4fab33812dc9e2ef525a329e22e591327f006f826b71271099637cd | Multiply 2 numbers test contract               |
 
 <!-- markdownlint-disable MD013 -->
 
@@ -61,7 +62,7 @@ The below defines all hardcoded values set in the geneses:
 where `pk` is the following vector of `u8`:
 
 ```rust
-[48,120,48,48,99,49,99,102,49,52,57,48,100,101,49,51,53,50,56,54,53,51,48,49,98,98,56,55,48,53,49,52,51,102,51,101,102,57,51,56,102,57,55,102,100,102,56,57,50,102,49,48,57,48,100,99,98,53,97,99,55,98,99,100,49,100]
+[48, 120, 48, 48, 99,49, 99, 102, 49, 52,57, 48, 100, 101, 49,51, 53, 50, 56, 54,53, 51, 48, 49, 98,98, 56, 55, 48, 53,49, 52, 51, 102, 51,101, 102, 57, 51, 56,102, 57, 55, 102, 100,102, 56, 57, 50, 102,49, 48, 57, 48, 100,99, 98, 53, 97, 99,55, 98, 99, 100, 49,100]
 ```
 
 <!-- markdownlint-disable MD013 -->
@@ -82,6 +83,7 @@ where `pk` is the following vector of `u8`:
 | 0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7  | 0x0372ee6669dc86563007245ed7343d5180b96221ce28f44408cff2898038dbd4 |
 | 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d  | 0x0372ee6669dc86563007245ed7343d5180b96221ce28f44408cff2898038dbd4 |
 | 0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf | 0x07b3e05f48f0c69e4a65ce5e076a66271a527aff2c34ce1083ec6e1526997a69 |
+| 0x123                                                              | 0x015b7c90a4fab33812dc9e2ef525a329e22e591327f006f826b71271099637cd |
 
 <!-- markdownlint-disable MD013 -->
 
diff --git a/examples/messaging/eth-config.json b/examples/messaging/eth-config.json
new file mode 100644
index 0000000000..5657dfa26a
--- /dev/null
+++ b/examples/messaging/eth-config.json
@@ -0,0 +1,9 @@
+{
+  "provider": {
+    "rpc_endpoint": "https://eth.merkle.io",
+    "gas_price_poll_ms": 10000
+  },
+  "contracts": {
+    "core_contract": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512"
+  }
+}
diff --git a/examples/messaging/l1-messaging-config.json b/examples/messaging/l1-messaging-config.json
deleted file mode 100644
index e14106a7ce..0000000000
--- a/examples/messaging/l1-messaging-config.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "httpProvider": "http://127.0.0.1:8545",
-  "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512"
-}
diff --git a/starknet-rpc-test/estimate_fee.rs b/starknet-rpc-test/estimate_fee.rs
index c657197dab..58daf41657 100644
--- a/starknet-rpc-test/estimate_fee.rs
+++ b/starknet-rpc-test/estimate_fee.rs
@@ -1,16 +1,17 @@
+use anyhow::Error;
 use assert_matches::assert_matches;
 use rstest::rstest;
 use starknet_core::types::{
     BlockId, BlockTag, BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, BroadcastedTransaction,
-    StarknetError,
+    FeeEstimate, MaybePendingTransactionReceipt, StarknetError, TransactionReceipt,
 };
 use starknet_core::utils::get_selector_from_name;
 use starknet_ff::FieldElement;
 use starknet_providers::Provider;
 use starknet_providers::ProviderError::StarknetError as StarknetProviderError;
-use starknet_rpc_test::constants::{ACCOUNT_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS};
+use starknet_rpc_test::constants::{ACCOUNT_CONTRACT_ADDRESS, MULTIPLY_TEST_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS};
 use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient};
-use starknet_rpc_test::utils::is_good_error_code;
+use starknet_rpc_test::utils::{get_transaction_receipt, is_good_error_code};
 
 #[rstest]
 #[tokio::test]
@@ -84,16 +85,20 @@ async fn fail_if_one_txn_cannot_be_executed(madara: &ThreadSafeMadaraClient) ->
 async fn works_ok(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> {
     let rpc = madara.get_starknet_client().await;
 
-    let tx = BroadcastedInvokeTransactionV1 {
-        max_fee: FieldElement::ZERO,
+    let sender_address = FieldElement::from_hex_be(ACCOUNT_CONTRACT_ADDRESS).unwrap();
+    let nonce = rpc.get_nonce(BlockId::Tag(BlockTag::Latest), sender_address).await.unwrap();
+
+    let mut tx = BroadcastedInvokeTransactionV1 {
+        max_fee: FieldElement::from_hex_be("0xfffffffffff").unwrap(),
         signature: vec![],
-        nonce: FieldElement::ZERO,
-        sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT_ADDRESS).unwrap(),
+        nonce,
+        sender_address,
         calldata: vec![
-            FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(),
-            get_selector_from_name("sqrt").unwrap(),
-            FieldElement::from_hex_be("1").unwrap(),
-            FieldElement::from(81u8),
+            FieldElement::from_hex_be(MULTIPLY_TEST_CONTRACT_ADDRESS).unwrap(),
+            get_selector_from_name("multiply").unwrap(),
+            FieldElement::TWO,
+            FieldElement::from_hex_be("2").unwrap(),
+            FieldElement::from_hex_be("5").unwrap(),
         ],
         is_query: true,
     };
@@ -102,22 +107,68 @@ async fn works_ok(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error>
 
     let invoke_transaction_2 =
         BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 {
-            nonce: FieldElement::ONE,
-            ..tx
+            nonce: nonce + FieldElement::ONE,
+            calldata: vec![
+                FieldElement::from_hex_be(MULTIPLY_TEST_CONTRACT_ADDRESS).unwrap(),
+                get_selector_from_name("multiply").unwrap(),
+                FieldElement::TWO,
+                FieldElement::from_hex_be("3").unwrap(),
+                FieldElement::from_hex_be("5").unwrap(),
+            ],
+            ..tx.clone()
         }));
 
     let estimates = rpc
         .estimate_fee(&vec![invoke_transaction, invoke_transaction_2], vec![], BlockId::Tag(BlockTag::Latest))
         .await?;
 
-    // TODO: instead execute the tx and check that the actual fee are the same as the estimated ones
     assert_eq!(estimates.len(), 2);
-    // TODO: use correct values when we implement estimate fee correctly
-    // assert_eq!(estimates[0].overall_fee, FieldElement::from(210u128));
-    // assert_eq!(estimates[1].overall_fee, FieldElement::from(210u128));
-    // https://starkscan.co/block/5
-    // assert_eq!(estimates[0].gas_consumed, FieldElement::ZERO);
-    // assert_eq!(estimates[1].gas_consumed, FieldElement::ZERO);
+    assert_eq!(estimates[0].overall_fee, FieldElement::from(2060u128));
+    // less gas as the second transaction doesn't cause a storage change
+    assert_eq!(estimates[1].overall_fee, FieldElement::from(2060u128));
+    // It's 271 gas on sepolia as well (15 gas and 256 data gas). The difference in gas costs
+    // can be due to different accounts. Also, gas calculation tests are done in the blockifier
+    assert_eq!(estimates[0].gas_consumed, FieldElement::from_hex_be("0xce").unwrap());
+    assert_eq!(estimates[1].gas_consumed, FieldElement::from_hex_be("0xce").unwrap());
+
+    tx.is_query = false;
+    let invoke_transaction = BroadcastedInvokeTransaction::V1(tx.clone());
+    let invoke_transaction_2 = BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 {
+        nonce: FieldElement::ONE,
+        calldata: vec![
+            FieldElement::from_hex_be(MULTIPLY_TEST_CONTRACT_ADDRESS).unwrap(),
+            get_selector_from_name("multiply").unwrap(),
+            FieldElement::TWO,
+            FieldElement::from_hex_be("3").unwrap(),
+            FieldElement::from_hex_be("5").unwrap(),
+        ],
+        ..tx.clone()
+    });
+    let executed_tx_1 = rpc.add_invoke_transaction(invoke_transaction).await?;
+    let executed_tx_2 = rpc.add_invoke_transaction(invoke_transaction_2).await?;
+
+    madara.write().await.create_block_with_pending_txs().await?;
+
+    let receipt_1 = get_transaction_receipt(&rpc, executed_tx_1.transaction_hash).await?;
+    let receipt_2 = get_transaction_receipt(&rpc, executed_tx_2.transaction_hash).await?;
+
+    let match_estimate_and_receipt = |estimate: FeeEstimate,
+                                      receipt: MaybePendingTransactionReceipt|
+     -> Result<(), anyhow::Error> {
+        match receipt {
+            MaybePendingTransactionReceipt::PendingReceipt(_) => Err(Error::msg("Transaction should not be pending")),
+            MaybePendingTransactionReceipt::Receipt(receipt) => match receipt {
+                TransactionReceipt::Invoke(receipt) => {
+                    assert_eq!(estimate.overall_fee, receipt.actual_fee.amount);
+                    Ok(())
+                }
+                _ => Err(Error::msg("Transaction should be an invoke transaction")),
+            },
+        }
+    };
+
+    match_estimate_and_receipt(estimates[0].clone(), receipt_1)?;
+    match_estimate_and_receipt(estimates[1].clone(), receipt_2)?;
 
     Ok(())
 }
diff --git a/starknet-rpc-test/get_state_update.rs b/starknet-rpc-test/get_state_update.rs
index 437b9659de..a3cf755132 100644
--- a/starknet-rpc-test/get_state_update.rs
+++ b/starknet-rpc-test/get_state_update.rs
@@ -41,12 +41,13 @@ async fn returns_correct_state_diff_transfer(madara: &ThreadSafeMadaraClient) ->
     let account_bob = build_single_owner_account(&rpc, SIGNER_PRIVATE, OZ_CONTRACT_ADDRESS, true);
 
     let nonce = account_alice.get_nonce().await?.try_into()?;
+    let receiver = FieldElement::ONE;
     {
         let mut madara_write_lock = madara.write().await;
         let txs = madara_write_lock
             .create_block_with_txs(vec![
-                Transaction::Execution(account_alice.transfer_tokens(recipient, FieldElement::ONE, Some(nonce))),
-                Transaction::Execution(account_bob.transfer_tokens(recipient, FieldElement::ONE, None)),
+                Transaction::Execution(account_alice.transfer_tokens(recipient, receiver, Some(nonce))),
+                Transaction::Execution(account_bob.transfer_tokens(recipient, receiver, None)),
             ])
             .await?;
         txs.iter().for_each(|tx| assert!(tx.is_ok()));
@@ -72,13 +73,17 @@ async fn returns_correct_state_diff_transfer(madara: &ThreadSafeMadaraClient) ->
             .map(|item| (&item.key, &item.value))
             .collect::<Vec<(&FieldElement, &FieldElement)>>(),
     );
-    for account_address in
-        [account_alice.address(), account_bob.address(), FieldElement::from_hex_be(SEQUENCER_CONTRACT_ADDRESS).unwrap()]
-    {
+    for account_address in [
+        account_alice.address(),
+        account_bob.address(),
+        FieldElement::from_hex_be(SEQUENCER_CONTRACT_ADDRESS).unwrap(),
+        receiver,
+    ] {
         let balance = read_erc20_balance(&rpc, fee_token_address, account_address).await[0]; // omit the second part since it probably won't change
         let key = get_storage_var_address("ERC20_balances", &[account_address]).unwrap();
         assert_eq!(storage_diff_map.remove(&key).unwrap(), &balance);
     }
+    println!("this is storage_diff_map {:#?}", storage_diff_map);
     assert!(storage_diff_map.is_empty());
     assert_eq!(state_update.state_diff.nonces.len(), 2);
     let mut nonce_map: HashMap<&FieldElement, &FieldElement> = HashMap::from_iter(
diff --git a/starknet-rpc-test/get_transaction_receipt.rs b/starknet-rpc-test/get_transaction_receipt.rs
index 41a0b9486c..283e8b2690 100644
--- a/starknet-rpc-test/get_transaction_receipt.rs
+++ b/starknet-rpc-test/get_transaction_receipt.rs
@@ -53,7 +53,7 @@ async fn work_with_invoke_transaction(madara: &ThreadSafeMadaraClient) -> Result
     };
 
     let invoke_tx_receipt = get_transaction_receipt(&rpc, rpc_response.transaction_hash).await;
-    let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0x1219c").unwrap(), unit: PriceUnit::Wei };
+    let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0x5c8").unwrap(), unit: PriceUnit::Wei };
 
     match invoke_tx_receipt {
         Ok(MaybePendingTransactionReceipt::Receipt(TransactionReceipt::Invoke(receipt))) => {
@@ -191,7 +191,7 @@ async fn work_with_declare_transaction(madara: &ThreadSafeMadaraClient) -> Resul
     };
 
     let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap();
-    let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0x40a2e").unwrap(), unit: PriceUnit::Wei };
+    let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0x38216").unwrap(), unit: PriceUnit::Wei };
     let expected_events = vec![Event {
         from_address: fee_token_address,
         keys: vec![get_selector_from_name("Transfer").unwrap()],
@@ -298,7 +298,7 @@ async fn work_with_deploy_account_transaction(madara: &ThreadSafeMadaraClient) -
 
     let account_deployment_tx_receipt = get_transaction_receipt(&rpc, rpc_response.transaction_hash).await;
     let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap();
-    let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0xac76").unwrap(), unit: PriceUnit::Wei };
+    let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0x2ee").unwrap(), unit: PriceUnit::Wei };
 
     match account_deployment_tx_receipt {
         Ok(MaybePendingTransactionReceipt::Receipt(TransactionReceipt::DeployAccount(receipt))) => {
@@ -408,7 +408,7 @@ async fn ensure_transfer_fee_event_not_messed_up_with_similar_transfer(
     };
     let tx_receipt = get_transaction_receipt(&rpc, rpc_response.transaction_hash).await;
     let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap();
-    let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0x12188").unwrap(), unit: PriceUnit::Wei };
+    let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0x5c8").unwrap(), unit: PriceUnit::Wei };
 
     match tx_receipt {
         Ok(MaybePendingTransactionReceipt::Receipt(TransactionReceipt::Invoke(mut receipt))) => {
diff --git a/starknet-rpc-test/simulate_transaction.rs b/starknet-rpc-test/simulate_transaction.rs
index 5e7fe45b1f..c303bc209b 100644
--- a/starknet-rpc-test/simulate_transaction.rs
+++ b/starknet-rpc-test/simulate_transaction.rs
@@ -19,12 +19,15 @@ use starknet_rpc_test::utils::{build_single_owner_account, is_good_error_code, A
 async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> {
     let rpc = madara.get_starknet_client().await;
 
+    let sender_address = FieldElement::from_hex_be(ACCOUNT_CONTRACT_ADDRESS).unwrap();
+    let nonce = rpc.get_nonce(BlockId::Tag(BlockTag::Latest), sender_address).await.unwrap();
+
     let ok_invoke_transaction =
         BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 {
             max_fee: FieldElement::ZERO,
             signature: vec![],
-            nonce: FieldElement::ZERO,
-            sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT_ADDRESS).unwrap(),
+            nonce,
+            sender_address,
             calldata: vec![
                 FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(),
                 get_selector_from_name("sqrt").unwrap(),
@@ -46,12 +49,15 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(),
 async fn fail_max_fee_too_big(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> {
     let rpc = madara.get_starknet_client().await;
 
+    let sender_address = FieldElement::from_hex_be(ACCOUNT_CONTRACT_ADDRESS).unwrap();
+    let nonce = rpc.get_nonce(BlockId::Tag(BlockTag::Latest), sender_address).await.unwrap();
+
     let ok_invoke_transaction =
         BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 {
             max_fee: FieldElement::from_hex_be("0x100000000000000000000000000000000").unwrap(), // u128::MAX + 1
             signature: vec![],
-            nonce: FieldElement::ZERO,
-            sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT_ADDRESS).unwrap(),
+            nonce,
+            sender_address,
             calldata: vec![
                 FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(),
                 get_selector_from_name("sqrt").unwrap(),
@@ -83,12 +89,15 @@ async fn fail_if_one_txn_cannot_be_executed(madara: &ThreadSafeMadaraClient) ->
             is_query: false,
         }));
 
+    let sender_address = FieldElement::from_hex_be(ACCOUNT_CONTRACT_ADDRESS).unwrap();
+    let nonce = rpc.get_nonce(BlockId::Tag(BlockTag::Latest), sender_address).await.unwrap();
+
     let ok_invoke_transaction =
         BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 {
             max_fee: FieldElement::ZERO,
             signature: vec![],
-            nonce: FieldElement::ZERO,
-            sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT_ADDRESS).unwrap(),
+            nonce,
+            sender_address,
             calldata: vec![
                 FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(),
                 get_selector_from_name("sqrt").unwrap(),
@@ -113,6 +122,7 @@ async fn works_ok_on_no_validate(madara: &ThreadSafeMadaraClient) {
     let rpc = madara.get_starknet_client().await;
 
     let sender_address = FieldElement::from_hex_be(ACCOUNT_CONTRACT_ADDRESS).unwrap();
+    let nonce = rpc.get_nonce(BlockId::Tag(BlockTag::Latest), sender_address).await.unwrap();
 
     let mut madara_write_lock = madara.write().await;
     let _ = madara_write_lock.create_empty_block().await;
@@ -127,7 +137,7 @@ async fn works_ok_on_no_validate(madara: &ThreadSafeMadaraClient) {
         ],
         max_fee: FieldElement::from(100_000u128),
         signature: vec![],
-        nonce: FieldElement::ZERO,
+        nonce,
         is_query: false,
     };
 
@@ -135,7 +145,7 @@ async fn works_ok_on_no_validate(madara: &ThreadSafeMadaraClient) {
 
     let invoke_transaction_2 =
         BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 {
-            nonce: FieldElement::ONE,
+            nonce: nonce + FieldElement::ONE,
             ..tx
         }));
 
@@ -146,9 +156,9 @@ async fn works_ok_on_no_validate(madara: &ThreadSafeMadaraClient) {
 
     assert_eq!(simulations.len(), 2);
     // TODO: check again when implemented correctly
-    // assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::ZERO);
-    // assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(210u128));
-    // assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::ZERO);
+    assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::from_hex_be("0x8c").unwrap());
+    assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(1400u128));
+    assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::from_hex_be("0xa").unwrap());
 }
 
 #[rstest]
@@ -172,9 +182,9 @@ async fn works_ok_on_validate_with_signature(madara: &ThreadSafeMadaraClient) ->
 
     assert_eq!(simulations.len(), 1);
     // TODO: check again when implemented correctly
-    // assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::ZERO);
-    // assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(240u128));
-    // assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::ZERO);
+    assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::from_hex_be("0x8f").unwrap());
+    assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(1430u128));
+    assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::from_hex_be("0xa").unwrap());
 
     Ok(())
 }
@@ -204,9 +214,9 @@ async fn works_ok_on_validate_without_signature_with_skip_validate(
 
     assert_eq!(simulations.len(), 1);
     // TODO: check again when implemented correctly
-    // assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::ZERO);
-    // assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(220u128));
-    // assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::ZERO);
+    assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::from_hex_be("0x8e").unwrap());
+    assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(1420u128));
+    assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::from_hex_be("0xa").unwrap());
 
     Ok(())
 }
@@ -217,11 +227,12 @@ async fn works_ok_without_max_fee_with_skip_fee_charge(madara: &ThreadSafeMadara
     let rpc = madara.get_starknet_client().await;
 
     let sender_address = FieldElement::from_hex_be(ACCOUNT_CONTRACT_ADDRESS).unwrap();
+    let nonce = rpc.get_nonce(BlockId::Tag(BlockTag::Latest), sender_address).await.unwrap();
 
     let tx = BroadcastedInvokeTransactionV1 {
         max_fee: FieldElement::from(0u8),
         signature: vec![],
-        nonce: FieldElement::ZERO,
+        nonce,
         sender_address,
         calldata: vec![
             FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(),
@@ -236,7 +247,7 @@ async fn works_ok_without_max_fee_with_skip_fee_charge(madara: &ThreadSafeMadara
 
     let invoke_transaction_2 =
         BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 {
-            nonce: FieldElement::ONE,
+            nonce: nonce + FieldElement::ONE,
             ..tx
         }));
 
@@ -250,9 +261,9 @@ async fn works_ok_without_max_fee_with_skip_fee_charge(madara: &ThreadSafeMadara
 
     assert_eq!(simulations.len(), 2);
     // TODO: check again when implemented correctly
-    // assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::ZERO);
-    // assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(210u128));
-    // assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::ZERO);
+    assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::from_hex_be("0x8c").unwrap());
+    assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(1400u128));
+    assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::from_hex_be("0xa").unwrap());
 
     Ok(())
 }
diff --git a/starknet-rpc-test/src/constants.rs b/starknet-rpc-test/src/constants.rs
index 3653e28f09..59d53259ab 100644
--- a/starknet-rpc-test/src/constants.rs
+++ b/starknet-rpc-test/src/constants.rs
@@ -26,11 +26,10 @@ pub const ARGENT_CONTRACT_ADDRESS: &str = "0x2";
 pub const OZ_CONTRACT_ADDRESS: &str = "0x3";
 pub const CAIRO_1_ACCOUNT_CONTRACT_ADDRESS: &str = "0x4";
 pub const TEST_CONTRACT_ADDRESS: &str = "0x1111";
+pub const MULTIPLY_TEST_CONTRACT_ADDRESS: &str = "0x123";
 pub const L1_CONTRACT_ADDRESS: &str = "0xae0ee0a63a2ce6baeeffe56e7714fb4efe48d419";
 pub const UDC_CONTRACT_ADDRESS: &str = "0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf";
 
 // Need to use `from_mont` because this needs to be a constant function call
 pub const MADARA_CHAIN_ID: FieldElement =
     FieldElement::from_mont([18444025906882525153, 18446744073709551615, 18446744073709551615, 530251916243973616]);
-
-pub const SPEC_VERSION: &str = "0.4.0";
diff --git a/starknet-test-utils/src/constants.rs b/starknet-test-utils/src/constants.rs
index 64a6d86fd6..ee92dec856 100644
--- a/starknet-test-utils/src/constants.rs
+++ b/starknet-test-utils/src/constants.rs
@@ -31,7 +31,7 @@ pub const OZ_CONTRACT_ADDRESS: &str = "0x3";
 pub const L1_CONTRACT_ADDRESS: &str = "0xae0ee0a63a2ce6baeeffe56e7714fb4efe48d419";
 
 pub const MAX_U256: &str = "0xffffffffffffffffffffffffffffffff";
-pub const MAX_FEE_OVERRIDE: &str = "0x1000000";
+pub const MAX_FEE_OVERRIDE: &str = "0xfffffffffffff";
 
 // Need to use `from_mont` because this needs to be a constant function call
 pub const MADARA_CHAIN_ID: FieldElement =