Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7115c70
Various informational fixes
thedarkjester Feb 8, 2026
4616294
use per pause type expiry
thedarkjester Feb 9, 2026
5ffe75d
add back unchecked
thedarkjester Feb 9, 2026
122d860
allow other pause types to be paused during initial window
thedarkjester Feb 9, 2026
237899d
add docstring on role restriction
thedarkjester Feb 9, 2026
fecf622
add public instead of external for better inheritence
thedarkjester Feb 9, 2026
687268d
emit genesis shnarf and initializer to latest version
thedarkjester Feb 9, 2026
b957cc5
missed saved file
thedarkjester Feb 10, 2026
2a8fe86
allow SC pause extension without unpause
thedarkjester Feb 10, 2026
d9dced5
pause by type doc
thedarkjester Feb 10, 2026
b29b53f
PauseIndefinitely event for SC pausing
thedarkjester Feb 10, 2026
7e87ae4
add state setting for SC
thedarkjester Feb 10, 2026
98a38cc
use correct event for pause indefinitely on YM
thedarkjester Feb 10, 2026
94a063e
Merge branch 'fix/pause-expiry-splitting' into fix/merge-all-audit-fixes
thedarkjester Feb 10, 2026
76e9f87
Merge branch 'fix/initialization-changes' into fix/merge-all-audit-fixes
thedarkjester Feb 10, 2026
7de8192
Merge branch 'fix/diligence-mixed-update' into fix/merge-all-audit-fixes
thedarkjester Feb 10, 2026
e4ef78c
allow SC cooldown reset
thedarkjester Feb 10, 2026
fa878d6
add docstring
thedarkjester Feb 10, 2026
a4b328e
v7.1 ABI
thedarkjester Feb 10, 2026
c374a2c
updated doc
thedarkjester Feb 10, 2026
02e95c9
Merge branch 'fix/pause-expiry-splitting' into fix/merge-all-audit-fixes
thedarkjester Feb 10, 2026
64a46ad
use live values
thedarkjester Feb 11, 2026
63181fb
Merge branch 'fix/initialization-changes' into fix/merge-all-audit-fixes
thedarkjester Feb 11, 2026
8a3c531
match name to version
thedarkjester Feb 11, 2026
75a8807
Merge branch 'fix/initialization-changes' into fix/merge-all-audit-fixes
thedarkjester Feb 11, 2026
67e4d9c
add reentrancy checks and specific transient slot
thedarkjester Feb 12, 2026
b447b83
add testing and correct slot
thedarkjester Feb 12, 2026
2870ce1
Merge branch 'fix/initialization-changes' into fix/merge-all-audit-fixes
thedarkjester Feb 12, 2026
7f1bd60
add extra new deploy check to initialize
thedarkjester Feb 12, 2026
c3f0b55
Merge branch 'fix/initialization-changes' into fix/merge-all-audit-fixes
thedarkjester Feb 12, 2026
7f2cdee
tweaks
thedarkjester Feb 13, 2026
4aac3da
address wrong namespace
thedarkjester Feb 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,851 changes: 2,851 additions & 0 deletions contracts/abi/LineaRollupV7.1.abi

Large diffs are not rendered by default.

96 changes: 96 additions & 0 deletions contracts/docs/pause-by-type-flow.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
pauseByType(_pauseType) Flow
================================

pauseByType(_pauseType)
|
+-----------+-----------+
| Modifier checks |
| - onlyUsedPausedTypes |
| - onlyRole(pauseRole) |
+-----------+-----------+
|
v
senderHasSecurityCouncilRole
= hasRole(SC_ROLE, msg.sender)
|
v
+-------------------------------+
| isPaused && !isSecurityCouncil |
| OR |
| expiry == type(uint256).max |
+-------------------------------+
| |
YES NO
| |
v v
revert IsPaused Is sender Security
Council?
| |
YES NO
| |
v v
+-------------------+ Load cached
| Set expiry | cooldownEnd
| = uint256.max | |
| Set bitmap | v
| Emit | block.timestamp
| PausedIndefinitely| >= cooldownEnd?
| RETURN | | |
+-------------------+ YES NO
| |
v v
+--------------+ cooldownEnd -
| FRESH WINDOW | block.timestamp
| | > COOLDOWN_DURATION?
| expiry = | | |
| now + | YES NO
| PAUSE_DUR | | |
| | v v
| cooldownEnd | +----------+ revert
| = expiry + | | JOIN | PauseUnavailable
| COOLDOWN | | WINDOW | DueToCooldown
+--------------+ | | (cooldownEnd)
| | expiry = |
| | cooldown |
| | End - |
| | COOLDOWN |
| +----------+
| |
v v
+-------------------+
| Set bitmap |
| Emit Paused |
+-------------------+


Timeline for non-SC pauses:

EP pause Pause expires Cooldown ends
| | |
v v v
|---- PAUSE_DURATION --|----- COOLDOWN_DUR ---|
| (48 hours) | (48 hours) |
| | |
| Pause active. | Pause expired. | Fresh pause
| Additional types | No new EP pauses | window allowed.
| can join this window. | allowed (cooldown). |
| | |
| SC can extend to | SC can still pause. |
| indefinite at any | |
| point by re-pausing. | SC can call |
| | resetNonSecurity- |
| | CouncilCooldownEnd |
| | to unlock EP early. |


Events:
Paused(sender, pauseType) — emitted by EP pauses
PausedIndefinitely(sender, pauseType) — emitted by SC pauses
UnPaused(sender, pauseType) — emitted by unPauseByType
UnPausedDueToExpiry(pauseType) — emitted by unPauseByExpiredType
NonSecurityCouncilCooldownEndReset() — emitted by resetNonSecurityCouncilCooldownEnd

Legend:
SC = SECURITY_COUNCIL_ROLE holder
EP = Emergency Pauser (non-SC role holder, e.g. PAUSE_ALL_ROLE)
now = block.timestamp
12 changes: 12 additions & 0 deletions contracts/src/_testing/unit/rollup/TestLineaRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ contract TestLineaRollup is LineaRollup, CalldataBlobAcceptor {
super.renounceRole(_role, _account);
}

function setSlotValue(uint256 _slot, uint256 _value) external {
assembly {
sstore(_slot, _value)
}
}

function getSlotValue(uint256 _slot) external view returns (uint256 slotValue) {
assembly {
slotValue := sload(_slot)
}
}

function addL2MerkleRoots(bytes32[] calldata _newRoot, uint256 _treeDepth) external onlyRole(DEFAULT_ADMIN_ROLE) {
_addL2MerkleRoots(_newRoot, _treeDepth);
}
Expand Down
21 changes: 11 additions & 10 deletions contracts/src/bridging/token/TokenBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
pragma solidity 0.8.33;

import { TokenBridgeBase } from "./TokenBridgeBase.sol";
import { InitializationVersionCheck } from "../../common/InitializationVersionCheck.sol";

/**
* @title Linea Canonical Token Bridge
* @notice Contract to manage cross-chain ERC-20 bridging.
* @author ConsenSys Software Inc.
* @custom:security-contact security-report@linea.build
*/
contract TokenBridge is TokenBridgeBase {
contract TokenBridge is InitializationVersionCheck, TokenBridgeBase {
/// @dev Disable constructor for safety
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
Expand All @@ -29,22 +30,22 @@ contract TokenBridge is TokenBridgeBase {
nonZeroAddress(_initializationData.tokenBeacon)
nonZeroChainId(_initializationData.sourceChainId)
nonZeroChainId(_initializationData.targetChainId)
initializer
onlyInitializedVersion(0)
reinitializer(3)
{
__TokenBridge_init(_initializationData);
}

/**
* @notice Reinitializes TokenBridge and clears the old reentry slot value.
*/
function reinitializeV2() external reinitializer(2) {
address proxyAdmin;
assembly {
proxyAdmin := sload(PROXY_ADMIN_SLOT)
}
require(msg.sender == proxyAdmin, CallerNotProxyAdmin());

assembly {
function reinitializeV3() external reinitializer(3) {
uint256 oldReentrancyGuardEntered = 2;
assembly ("memory-safe") {
if eq(sload(1), oldReentrancyGuardEntered) {
mstore(0x00, 0x37ed32e8) //ReentrantCall.selector;
revert(0x1c, 0x04)
}
sstore(1, 0)
}
}
Expand Down
12 changes: 2 additions & 10 deletions contracts/src/bridging/token/TokenBridgeBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,8 @@ abstract contract TokenBridgeBase is
PermissionsManager,
StorageFiller39
{
using EfficientLeftRightKeccak for *;
using SafeERC20Upgradeable for IERC20Upgradeable;

/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* used to validate on the proxy admin can reinitialize the contract.
*/
bytes32 internal constant PROXY_ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

/// @notice Role used for setting the message service address.
bytes32 public constant SET_MESSAGE_SERVICE_ROLE = keccak256("SET_MESSAGE_SERVICE_ROLE");

Expand Down Expand Up @@ -187,7 +179,7 @@ abstract contract TokenBridgeBase is
* @notice Returns the ABI version and not the reinitialize version.
* @return contractVersion The contract ABI version.
*/
function CONTRACT_VERSION() external view virtual returns (string memory contractVersion) {
function CONTRACT_VERSION() public view virtual returns (string memory contractVersion) {
contractVersion = _CONTRACT_VERSION;
}

Expand Down Expand Up @@ -338,7 +330,7 @@ abstract contract TokenBridgeBase is
uint256 _chainId,
bytes calldata _tokenMetadata
)
external
public
virtual
nonReentrant
onlyMessagingService
Expand Down
7 changes: 0 additions & 7 deletions contracts/src/bridging/token/interfaces/ITokenBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,6 @@ interface ITokenBridge {
*/
event NewTokenDeployed(address indexed bridgedToken, address indexed nativeToken);

/**
* @notice Emitted when the remote token bridge is set.
* @param remoteTokenBridge The indexed remote token bridge address.
* @param setBy The indexed address that set the remote token bridge.
*/
event RemoteTokenBridgeSet(address indexed remoteTokenBridge, address indexed setBy);

/**
* @notice Emitted when the token is set as deployed.
* @dev This can be triggered by anyone calling confirmDeployment on the alternate chain.
Expand Down
23 changes: 23 additions & 0 deletions contracts/src/common/InitializationVersionCheck.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.33;

import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { IGenericErrors } from "../interfaces/IGenericErrors.sol";

/**
* @title Modifier to guard initialize functions against re-initialization.
* @author ConsenSys Software Inc.
* @custom:security-contact security-report@linea.build
*/
abstract contract InitializationVersionCheck is Initializable, IGenericErrors {
/**
* @dev Reverts if the contract's initialized version does not match the expected version.
* @param _expectedVersion The exact initialized version required.
*/
modifier onlyInitializedVersion(uint8 _expectedVersion) {
if (_getInitializedVersion() != _expectedVersion) {
revert InitializedVersionWrong(_expectedVersion, _getInitializedVersion());
}
_;
}
}
6 changes: 4 additions & 2 deletions contracts/src/interfaces/IGenericErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ interface IGenericErrors {
error NoEthSent();

/**
* @dev Thrown when the caller is not the ProxyAdmin.
* @dev Thrown when an initialize function is called on an already initialized contract with the wrong version.
* @param expected The expected initialized version.
* @param actual The actual initialized version.
*/
error CallerNotProxyAdmin();
error InitializedVersionWrong(uint256 expected, uint256 actual);
}
1 change: 0 additions & 1 deletion contracts/src/messaging/l1/L1MessageManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { EfficientLeftRightKeccak } from "../../libraries/EfficientLeftRightKecc
*/
abstract contract L1MessageManager is L1MessageManagerV1, IL1MessageManager {
using BitMaps for BitMaps.BitMap;
using EfficientLeftRightKeccak for *;

/// @notice Contains the L1 to L2 messaging rolling hashes mapped to message number computed on L1.
mapping(uint256 messageNumber => bytes32 rollingHash) public rollingHashes;
Expand Down
7 changes: 2 additions & 5 deletions contracts/src/messaging/l1/L1MessageService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ abstract contract L1MessageService is
IL1MessageService,
IGenericErrors
{
using SparseMerkleTreeVerifier for *;
using MessageHashing for *;

/// @dev This is currently not in use, but is reserved for future upgrades.
uint256 public systemMigrationBlock;

Expand Down Expand Up @@ -94,7 +91,7 @@ abstract contract L1MessageService is
*/
function claimMessageWithProof(
ClaimMessageWithProofParams calldata _params
) external virtual nonReentrant distributeFees(_params.fee, _params.to, _params.data, _params.feeRecipient) {
) public virtual nonReentrant distributeFees(_params.fee, _params.to, _params.data, _params.feeRecipient) {
_claimMessageWithProof(_params);
}

Expand Down Expand Up @@ -201,7 +198,7 @@ abstract contract L1MessageService is
* @dev The message sender address is set temporarily in the transient storage when claiming.
* @return originalSender The message sender address that is stored temporarily in the transient storage when claiming.
*/
function sender() external view virtual returns (address originalSender) {
function sender() public view virtual returns (address originalSender) {
originalSender = TRANSIENT_MESSAGE_SENDER;
}
}
10 changes: 4 additions & 6 deletions contracts/src/messaging/l1/L1MessageServiceBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { RateLimiter } from "../../security/limiting/RateLimiter.sol";
import { L1MessageManagerV1 } from "./v1/L1MessageManagerV1.sol";
import { TransientStorageReentrancyGuardUpgradeable } from "../../security/reentrancy/TransientStorageReentrancyGuardUpgradeable.sol";
import { IMessageService } from "../interfaces/IMessageService.sol";
import { MessageHashing } from "../libraries/MessageHashing.sol";

/**
* @title Contract to manage cross-chain messaging on L1.
Expand All @@ -20,14 +19,13 @@ abstract contract L1MessageServiceBase is
LineaRollupPauseManager,
IMessageService
{
using MessageHashing for *;

address transient TRANSIENT_MESSAGE_SENDER;
/// @dev This is the transient message sender address.
address internal transient TRANSIENT_MESSAGE_SENDER;

// @dev This is initialised to save user cost with existing slot.
uint256 public nextMessageNumber;

/// @dev DEPRECATED in favor of new transient storage with `MESSAGE_SENDER_TRANSIENT_KEY` key.
/// @dev DEPRECATED in favor of new transient storage with `TRANSIENT_MESSAGE_SENDER` key.
address private _messageSender_DEPRECATED;

/// @dev Total contract storage is 52 slots including the gap below.
Expand All @@ -37,7 +35,7 @@ abstract contract L1MessageServiceBase is
/// @dev adding these should not affect storage as they are constants and are stored in bytecode.
uint256 internal constant REFUND_OVERHEAD_IN_GAS = 48252;

/// @notice The default value for the message sender reset to post claiming using the MESSAGE_SENDER_TRANSIENT_KEY.
/// @notice The default value for the message sender reset to post claiming using the `TRANSIENT_MESSAGE_SENDER`.
address internal constant DEFAULT_MESSAGE_SENDER_TRANSIENT_VALUE = address(0);

/**
Expand Down
6 changes: 2 additions & 4 deletions contracts/src/messaging/l1/v1/ClaimMessageV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.33;

import { L1MessageServiceBase } from "../L1MessageServiceBase.sol";
import { IClaimMessageV1 } from "../../interfaces/IClaimMessageV1.sol";
import { IClaimMessageV1 } from "../../l1/v1/interfaces/IClaimMessageV1.sol";
import { MessageHashing } from "../../libraries/MessageHashing.sol";

/**
Expand All @@ -11,8 +11,6 @@ import { MessageHashing } from "../../libraries/MessageHashing.sol";
* @custom:security-contact security-report@linea.build
*/
abstract contract ClaimMessageV1 is IClaimMessageV1, L1MessageServiceBase {
using MessageHashing for *;

/**
* @notice Claims and delivers a cross-chain message.
* @dev _feeRecipient can be set to address(0) to receive as msg.sender.
Expand All @@ -34,7 +32,7 @@ abstract contract ClaimMessageV1 is IClaimMessageV1, L1MessageServiceBase {
address payable _feeRecipient,
bytes calldata _calldata,
uint256 _nonce
) external nonReentrant distributeFees(_fee, _to, _calldata, _feeRecipient) {
) public virtual nonReentrant distributeFees(_fee, _to, _calldata, _feeRecipient) {
_requireTypeAndGeneralNotPaused(PauseType.L2_L1);

/// @dev This is placed earlier to fix the stack issue by using these two earlier on.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ interface IClaimMessageV1 {
* @notice Is called by the Postman, dApp or end user.
* @param _from The msg.sender calling the origin message service.
* @param _to The destination address on the destination chain.
* @param _value The value to be transferred to the destination address.
* @param _fee The message service fee on the origin chain.
* @param _value The value to be transferred to the destination address.
* @param _feeRecipient Address that will receive the fees.
* @param _calldata The calldata used by the destination message service to call/forward to the destination contract.
* @param _nonce Unique message number.
Expand Down
2 changes: 0 additions & 2 deletions contracts/src/messaging/l2/L2MessageManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import { EfficientLeftRightKeccak } from "../../libraries/EfficientLeftRightKecc
* @custom:security-contact security-report@linea.build
*/
abstract contract L2MessageManager is AccessControlUpgradeable, IL2MessageManager, L2MessageManagerV1 {
using EfficientLeftRightKeccak for *;

/// @notice The role required to anchor L1 to L2 message hashes.
bytes32 public constant L1_L2_MESSAGE_SETTER_ROLE = keccak256("L1_L2_MESSAGE_SETTER_ROLE");

Expand Down
Loading
Loading