diff --git a/packages/protocol/contracts/libs/LibBlockHeader.sol b/packages/protocol/contracts/libs/LibBlockHeader.sol
index cc5269dc59c..4525b8cb5fa 100644
--- a/packages/protocol/contracts/libs/LibBlockHeader.sol
+++ b/packages/protocol/contracts/libs/LibBlockHeader.sol
@@ -25,6 +25,7 @@ struct BlockHeader {
     bytes32 mixHash;
     uint64 nonce;
     uint256 baseFeePerGas;
+    bytes32 withdrawalsRoot;
 }
 
 library LibBlockHeader {
@@ -44,12 +45,15 @@ library LibBlockHeader {
         BlockHeader memory header,
         uint256 extraCapacity
     ) internal pure returns (bytes[] memory list) {
-        if (header.baseFeePerGas == 0) {
-            // non-EIP11559 transaction
-            list = new bytes[](15 + extraCapacity);
-        } else {
-            // EIP1159 transaction
+        if (header.withdrawalsRoot != 0) {
+            // EIP-4895 transaction
+            list = new bytes[](17 + extraCapacity);
+        } else if (header.baseFeePerGas != 0) {
+            // EIP-1559 transaction
             list = new bytes[](16 + extraCapacity);
+        } else {
+            // non-EIP-1559 transaction
+            list = new bytes[](15 + extraCapacity);
         }
         list[0] = LibRLPWriter.writeHash(header.parentHash);
         list[1] = LibRLPWriter.writeHash(header.ommersHash);
@@ -69,9 +73,13 @@ library LibBlockHeader {
         // as [8]byte when hashing the block.
         list[14] = LibRLPWriter.writeBytes(abi.encodePacked(header.nonce));
         if (header.baseFeePerGas != 0) {
-            // non-EIP11559 transaction
+            // EIP-1559 transaction
             list[15] = LibRLPWriter.writeUint(header.baseFeePerGas);
         }
+        if (header.withdrawalsRoot != 0) {
+            // EIP-4895 transaction
+            list[16] = LibRLPWriter.writeHash(header.withdrawalsRoot);
+        }
     }
 
     function isPartiallyValidForTaiko(
diff --git a/packages/protocol/test/libs/LibBlockHeader.test.ts b/packages/protocol/test/libs/LibBlockHeader.test.ts
index 7959d0752d3..ba37b402a56 100644
--- a/packages/protocol/test/libs/LibBlockHeader.test.ts
+++ b/packages/protocol/test/libs/LibBlockHeader.test.ts
@@ -46,6 +46,7 @@ describe("LibBlockHeader tests", function () {
                 "0xf5ba25df1e92e89a09e0b32063b81795f631100801158f5fa733f2ba26843bd0",
             nonce: EBN.from("0x738b7e38476abe98"),
             baseFeePerGas: 0,
+            withdrawalsRoot: ethers.constants.HashZero,
         };
 
         const headerComputed = await libBlockHeader.hashBlockHeader(
@@ -87,6 +88,7 @@ describe("LibBlockHeader tests", function () {
             mixHash: ethers.constants.HashZero,
             nonce: EBN.from("0x0"),
             baseFeePerGas: 0,
+            withdrawalsRoot: ethers.constants.HashZero,
         };
 
         const headerComputed = await libBlockHeader.hashBlockHeader(
@@ -96,7 +98,7 @@ describe("LibBlockHeader tests", function () {
         expect(headerComputed).to.equal(blockHash);
     });
 
-    it("can calculate EIP1159", async function () {
+    it("can calculate EIP-1559", async function () {
         const blockHash =
             "0xb39b05b327d23ca29286fa7e2331d8269cd257cf10a8310b40ebaddf411f191e";
         // block 0xb39b05b327d23ca29286fa7e2331d8269cd257cf10a8310b40ebaddf411f191e on our L1 testnet
@@ -130,6 +132,52 @@ describe("LibBlockHeader tests", function () {
                 "0x0000000000000000000000000000000000000000000000000000000000000000",
             nonce: "0x0",
             baseFeePerGas: EBN.from("0x37"),
+            withdrawalsRoot: ethers.constants.HashZero,
+        };
+
+        const headerComputed = await libBlockHeader.hashBlockHeader(
+            l2BlockHeader
+        );
+        log.debug("headerComputed:", headerComputed);
+
+        expect(headerComputed).to.equal(blockHash);
+    });
+
+    it("can hash post Shanghai fork blocks", async function () {
+        const blockHash =
+            "0x0fb703aea6875ca7e78a73552064cf96a0985879c3b1fa27c846d41b1aa4e98e";
+        // block 0x0fb703aea6875ca7e78a73552064cf96a0985879c3b1fa27c846d41b1aa4e98e on Sepolia.
+
+        const parentHash =
+            "0xe122a2cc28199703e3ed6bee61875dc1703aa97c3187d8df507f1f789e363977";
+
+        const l2BlockHeader: any = {
+            parentHash: parentHash,
+            ommersHash:
+                "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+            beneficiary: "0x3826539cbd8d68dcf119e80b994557b4278cec9f",
+            stateRoot:
+                "0x2525478f8cd349640e6d1780334e63c56fa0bfb44d89fbd75cb3fcf82d38521c",
+            transactionsRoot:
+                "0x97ea65e77b43073c372976694916209b916caa0caef1445d53e9757b9824bdef",
+            receiptsRoot:
+                "0xa8b034a217a5d4d4615ee0ed28c4d5275b93888c01c65a98fcdd1aeda6903e1c",
+            logsBloom:
+                "00000004000000000000000000100000000100000010001000000000000000000000880000000000000400001100000000000000000000000000000010300000000000000000000000000008000000000000200000000000000000008080000000002000020040000200000400000900000000000000000010000014000000000020024008000000000800000000900000211001000040002000000000000810021000000040400000102000000000040400002000000000000008000000001000008002300000000000000020000008004000000001000110000001000028000014440800010000000000000000000004210000000000400000000000000000"
+                    .match(/.{1,64}/g)!
+                    .map((s) => "0x" + s),
+            difficulty: EBN.from("0x0"),
+            height: EBN.from("0x2e93c3"),
+            gasLimit: EBN.from("0x1c9c380"),
+            gasUsed: EBN.from("0x44dd61"),
+            timestamp: EBN.from("0x64097a78"),
+            extraData: "0x",
+            mixHash:
+                "0xa3fedc5083947ffb01157d6a89aa00f0592e14b94da8768ac0e6ded0aa490eb8",
+            nonce: "0x0000000000000000",
+            baseFeePerGas: EBN.from("0x7"),
+            withdrawalsRoot:
+                "0x0975bba9482fab7591735f9dc8c344078d27abac007086d5dd62ee3a21e3ed29",
         };
 
         const headerComputed = await libBlockHeader.hashBlockHeader(
diff --git a/packages/protocol/test/thirdparty/LibBlockHeaderDecoder.test.ts b/packages/protocol/test/thirdparty/LibBlockHeaderDecoder.test.ts
index 3c2edc94315..865dd00a96d 100644
--- a/packages/protocol/test/thirdparty/LibBlockHeaderDecoder.test.ts
+++ b/packages/protocol/test/thirdparty/LibBlockHeaderDecoder.test.ts
@@ -59,6 +59,7 @@ describe("LibBlockHeaderDecoder", async function () {
                 "0xf5ba25df1e92e89a09e0b32063b81795f631100801158f5fa733f2ba26843bd0",
             nonce: EBN.from("0x738b7e38476abe98"),
             baseFeePerGas: 0,
+            withdrawalsRoot: ethers.constants.HashZero,
         };
 
         const encodedBlockHeader = await hashBlockHeader.rlpBlockHeader(
@@ -103,6 +104,7 @@ describe("LibBlockHeaderDecoder", async function () {
             mixHash: block.mixHash,
             nonce: block.nonce,
             baseFeePerGas: 0,
+            withdrawalsRoot: ethers.constants.HashZero,
         };
         const encodedBlockHeader = await hashBlockHeader.rlpBlockHeader(
             blockHeader
@@ -146,6 +148,7 @@ describe("LibBlockHeaderDecoder", async function () {
             mixHash: block.mixHash,
             nonce: block.nonce,
             baseFeePerGas: 0,
+            withdrawalsRoot: ethers.constants.HashZero,
         };
         const encodedBlockHeader = await hashBlockHeader.rlpBlockHeader(
             blockHeader
diff --git a/packages/protocol/test/utils/rpc.ts b/packages/protocol/test/utils/rpc.ts
index a72ee514925..cdac87a5e6c 100644
--- a/packages/protocol/test/utils/rpc.ts
+++ b/packages/protocol/test/utils/rpc.ts
@@ -37,6 +37,7 @@ type Block = {
     uncles: string[];
     baseFeePerGas?: string;
     mixHash: string;
+    withdrawalsRoot: string;
 };
 
 type BlockHeader = {
@@ -56,6 +57,7 @@ type BlockHeader = {
     mixHash: string;
     nonce: number;
     baseFeePerGas: number;
+    withdrawalsRoot: string;
 };
 
 async function getBlockHeader(
@@ -90,6 +92,8 @@ async function getBlockHeader(
         mixHash: block.mixHash,
         nonce: block.nonce,
         baseFeePerGas: block.baseFeePerGas ? parseInt(block.baseFeePerGas) : 0,
+        // set to zero for pre-shanghai L1 blocks used in the integration test node
+        withdrawalsRoot: ethers.constants.HashZero,
     };
 
     return { block, blockHeader };
diff --git a/packages/protocol/test/utils/signal.ts b/packages/protocol/test/utils/signal.ts
index b535ee1b2c8..e6ce33179ad 100644
--- a/packages/protocol/test/utils/signal.ts
+++ b/packages/protocol/test/utils/signal.ts
@@ -61,7 +61,7 @@ async function getSignalProof(
     // encode the SignalProof struct from LibBridgeSignal
     const signalProof = ethers.utils.defaultAbiCoder.encode(
         [
-            "tuple(tuple(bytes32 parentHash, bytes32 ommersHash, address beneficiary, bytes32 stateRoot, bytes32 transactionsRoot, bytes32 receiptsRoot, bytes32[8] logsBloom, uint256 difficulty, uint128 height, uint64 gasLimit, uint64 gasUsed, uint64 timestamp, bytes extraData, bytes32 mixHash, uint64 nonce, uint256 baseFeePerGas) header, bytes proof)",
+            "tuple(tuple(bytes32 parentHash, bytes32 ommersHash, address beneficiary, bytes32 stateRoot, bytes32 transactionsRoot, bytes32 receiptsRoot, bytes32[8] logsBloom, uint256 difficulty, uint128 height, uint64 gasLimit, uint64 gasUsed, uint64 timestamp, bytes extraData, bytes32 mixHash, uint64 nonce, uint256 baseFeePerGas, bytes32 withdrawalsRoot) header, bytes proof)",
         ],
         [{ header: blockHeader, proof: encodedProof }]
     );