Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
298 changes: 149 additions & 149 deletions AllContractsHashes.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions configs/genesis/era/latest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
"minor": 31,
"patch": 0
},
"genesis_root": "0xac5499fd6532a7456a226177bd1e8bd983dc5e20138e934b04b806c53074f991",
"genesis_root": "0xd587b49f995a73535cf8f2ba63ea420cbd34fbda8c26b3b94102f5069b00c52b",
"genesis_rollup_leaf_index": 104,
"genesis_batch_commitment": "0xa11dfd12ee1a863c19ea6782573dc2fadbfe1ef33b965dc50d9b06ecc3d8d5ec",
"genesis_batch_commitment": "0xef771e98edab2758a64c8930512dcb1b80fc08e3e6fec048d7e5d703603c28e4",
"bootloader_hash": "0x0100099b799188da75411d9c2815a792e60e031bc5f89c2938b6deced048ad83",
"default_aa_hash": "0x010005f99a0122b38fe77c713c17106c31fc4ebf0d040038ca9101dfda59983c",
"default_aa_hash": "0x010005f9ffcf2471de535c03a1ac9da1ff92fedd96b40895aaf27a961400d403",
"evm_emulator_hash": "0x01000d8bae37b82f311186426184866498b357f41d7a02ced11f3e3fbfbacd63",
"prover": {
"recursion_scheduler_level_vk_hash": "0x1ffc56111a5cfaf5db387f6a31408ad20217e9bc1f31f2f5c1bd38b0d6d7968b",
Expand Down
6 changes: 3 additions & 3 deletions configs/genesis/era/latest.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
protocol_semantic_version = 133143986176
genesis_root = "0xac5499fd6532a7456a226177bd1e8bd983dc5e20138e934b04b806c53074f991"
genesis_root = "0xd587b49f995a73535cf8f2ba63ea420cbd34fbda8c26b3b94102f5069b00c52b"
genesis_rollup_leaf_index = 104
genesis_batch_commitment = "0xa11dfd12ee1a863c19ea6782573dc2fadbfe1ef33b965dc50d9b06ecc3d8d5ec"
genesis_batch_commitment = "0xef771e98edab2758a64c8930512dcb1b80fc08e3e6fec048d7e5d703603c28e4"
bootloader_hash = "0x0100099b799188da75411d9c2815a792e60e031bc5f89c2938b6deced048ad83"
default_aa_hash = "0x010005f99a0122b38fe77c713c17106c31fc4ebf0d040038ca9101dfda59983c"
default_aa_hash = "0x010005f9ffcf2471de535c03a1ac9da1ff92fedd96b40895aaf27a961400d403"
evm_emulator_hash = "0x01000d8bae37b82f311186426184866498b357f41d7a02ced11f3e3fbfbacd63"

[prover]
Expand Down
4 changes: 2 additions & 2 deletions l1-contracts/contracts/interop/IInteropHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ interface IInteropHandler {

/// @notice Function used to unbundle the bundle. It's present to give more flexibility in cancelling and overall processing of bundles.
/// Can be invoked multiple times until all calls are processed.
/// @param _sourceChainId Originating chain ID of the bundle.
/// @dev This function does not verify the validity of the bundle, as it's assumed it was already checked inside `verifyBundle`.
/// @param _bundle ABI-encoded InteropBundle to unbundle.
/// @param _callStatus Array of desired statuses per call.
function unbundleBundle(uint256 _sourceChainId, bytes memory _bundle, CallStatus[] calldata _callStatus) external;
function unbundleBundle(bytes memory _bundle, CallStatus[] calldata _callStatus) external;

/// @notice The chain ID of L1. This contract can be deployed on multiple layers, but this value is still equal to the
/// L1 that is at the most base layer.
Expand Down
119 changes: 40 additions & 79 deletions l1-contracts/contracts/interop/InteropHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,29 +74,9 @@ contract InteropHandler is IInteropHandler, ReentrancyGuard {
/// @inheritdoc IInteropHandler
function executeBundle(bytes memory _bundle, MessageInclusionProof memory _proof) public {
// Decode the bundle data, calculate its hash and get the current status of the bundle.
(InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus status) = _getBundleData(
_bundle,
_proof.chainId
);

// Verify that the source chainId of the bundle matches the proof's chainId
require(
interopBundle.sourceChainId == _proof.chainId,
WrongSourceChainId(bundleHash, interopBundle.sourceChainId, _proof.chainId)
);
(InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus status) = _getBundleData(_bundle);

// Verify that the destination chainId of the bundle is equal to the chainId where it's trying to get executed
require(
interopBundle.destinationChainId == block.chainid,
WrongDestinationChainId(bundleHash, interopBundle.destinationChainId, block.chainid)
);

// Verify that the destination base token asset ID of the bundle is equal to the base token asset ID of the chain
bytes32 baseTokenAssetId = L2_NATIVE_TOKEN_VAULT.BASE_TOKEN_ASSET_ID();
require(
interopBundle.destinationBaseTokenAssetId == baseTokenAssetId,
WrongDestinationBaseTokenAssetId(bundleHash, baseTokenAssetId, interopBundle.destinationBaseTokenAssetId)
);
_validateBundleDestinationContext(bundleHash, interopBundle, _proof.chainId);

// If the execution address is not specified then the execution is permissionless.
if (interopBundle.bundleAttributes.executionAddress.length != 0) {
Expand Down Expand Up @@ -156,29 +136,9 @@ contract InteropHandler is IInteropHandler, ReentrancyGuard {
/// @inheritdoc IInteropHandler
function verifyBundle(bytes memory _bundle, MessageInclusionProof memory _proof) public {
// Decode the bundle data, calculate its hash and get the current status of the bundle.
(InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus status) = _getBundleData(
_bundle,
_proof.chainId
);

// Verify that the source chainId of the bundle matches the proof's chainId
require(
interopBundle.sourceChainId == _proof.chainId,
WrongSourceChainId(bundleHash, interopBundle.sourceChainId, _proof.chainId)
);

// Verify that the destination chainId of the bundle is equal to the chainId where it's trying to get verified
require(
interopBundle.destinationChainId == block.chainid,
WrongDestinationChainId(bundleHash, interopBundle.destinationChainId, block.chainid)
);
(InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus status) = _getBundleData(_bundle);

// Verify that the destination base token asset ID of the bundle is equal to the base token asset ID of the chain
bytes32 baseTokenAssetId = L2_NATIVE_TOKEN_VAULT.BASE_TOKEN_ASSET_ID();
require(
interopBundle.destinationBaseTokenAssetId == baseTokenAssetId,
WrongDestinationBaseTokenAssetId(bundleHash, baseTokenAssetId, interopBundle.destinationBaseTokenAssetId)
);
_validateBundleDestinationContext(bundleHash, interopBundle, _proof.chainId);

// If the bundle was already fully executed or unbundled, we revert stating that it was processed already.
require(status == BundleStatus.Unreceived, BundleAlreadyProcessed(bundleHash));
Expand All @@ -188,28 +148,9 @@ contract InteropHandler is IInteropHandler, ReentrancyGuard {
}

/// @inheritdoc IInteropHandler
function unbundleBundle(
uint256 _sourceChainId,
bytes memory _bundle,
CallStatus[] calldata _providedCallStatus
) public {
function unbundleBundle(bytes memory _bundle, CallStatus[] calldata _providedCallStatus) public {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep legacy unbundle selector routable

Changing unbundleBundle to unbundleBundle(bytes,uint8[]) changes the function selector (from 0x98483918 to 0x37dd8238 in l1-contracts/selectors), but receiveMessage still dispatches strictly by selector and reverts unknown selectors, so any in-flight message encoded before this upgrade with the old unbundleBundle(uint256,bytes,uint8[]) selector will no longer be executable after deployment. This is a backward-compatibility break for queued cross-chain bundles, so the old selector path should remain supported (with legacy decoding) alongside the new one.

Useful? React with 👍 / 👎.

// Decode the bundle data, calculate its hash and get the current status of the bundle.
(InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus status) = _getBundleData(
_bundle,
_sourceChainId
);

// Verify that the source chainId of the bundle matches the provided source chainId
require(
interopBundle.sourceChainId == _sourceChainId,
WrongSourceChainId(bundleHash, interopBundle.sourceChainId, _sourceChainId)
);

// Verify that the destination chainId of the bundle is equal to the chainId where it's trying to get unbundled
require(
interopBundle.destinationChainId == block.chainid,
WrongDestinationChainId(bundleHash, interopBundle.destinationChainId, block.chainid)
);
(InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus status) = _getBundleData(_bundle);

(uint256 unbundlerChainId, address unbundlerAddress) = InteroperableAddress.parseEvmV1(
interopBundle.bundleAttributes.unbundlerAddress
Expand All @@ -235,7 +176,7 @@ contract InteropHandler is IInteropHandler, ReentrancyGuard {
);

// The bundle status have to be either verified (we know that it's received, but not processed yet), or unbundled.
// Note, that on the first call to unbundle the status of the bundle should be verified.
// Note, that on the first call to unbundle the status of the bundle should be verified, which validates bundle correctness.
require(status == BundleStatus.Verified || status == BundleStatus.Unbundled, CanNotUnbundle(bundleHash));

// Mark the given bundle as unbundled, following CEI pattern.
Expand Down Expand Up @@ -263,7 +204,7 @@ contract InteropHandler is IInteropHandler, ReentrancyGuard {
}

_executeCalls({
_sourceChainId: _sourceChainId,
_sourceChainId: interopBundle.sourceChainId,
_bundleHash: bundleHash,
_interopBundle: interopBundle,
_executeAllCalls: false,
Expand All @@ -280,17 +221,15 @@ contract InteropHandler is IInteropHandler, ReentrancyGuard {

/// @notice Decode an ABI-encoded bundle, compute its hash, and fetch its current status.
/// @param _bundle ABI-encoded InteropBundle.
/// @param _sourceChainId Origin chain ID.
/// @return interopBundle The decoded InteropBundle struct.
/// @return bundleHash Hash corresponding to the bundle that gets decoded.
/// @return currentStatus The current BundleStatus of the bundle that gets decoded.
function _getBundleData(
bytes memory _bundle,
uint256 _sourceChainId
bytes memory _bundle
) internal view returns (InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus currentStatus) {
interopBundle = abi.decode(_bundle, (InteropBundle));
require(interopBundle.version == INTEROP_BUNDLE_VERSION, InvalidInteropBundleVersion());
bundleHash = InteropDataEncoding.encodeInteropBundleHash(_sourceChainId, _bundle);
bundleHash = InteropDataEncoding.encodeInteropBundleHash(interopBundle.sourceChainId, _bundle);
currentStatus = bundleStatus[bundleHash];
}

Expand Down Expand Up @@ -374,7 +313,7 @@ contract InteropHandler is IInteropHandler, ReentrancyGuard {
/// @dev Implements ERC-7786 recipient interface. The payload must be encoded using abi.encodeCall
/// with one of the following function selectors:
/// - executeBundle: payload = abi.encodeCall(InteropHandler.executeBundle, (bundle, proof))
/// - unbundleBundle: payload = abi.encodeCall(InteropHandler.unbundleBundle, (sourceChainId, bundle, providedCallStatus))
/// - unbundleBundle: payload = abi.encodeCall(InteropHandler.unbundleBundle, (bundle, providedCallStatus))
/// The sender must have appropriate permissions (executionAddress or unbundlerAddress) which are
/// validated before calling the respective internal functions. Since this function validates
/// permissions, the called functions (executeBundle/unbundleBundle) will bypass their own
Expand Down Expand Up @@ -422,7 +361,7 @@ contract InteropHandler is IInteropHandler, ReentrancyGuard {
);

// Decode the bundle to get execution permissions
(InteropBundle memory interopBundle, , ) = _getBundleData(bundle, proof.chainId);
(InteropBundle memory interopBundle, , ) = _getBundleData(bundle);

// If the execution address is not specified then the execution is permissionless.
if (interopBundle.bundleAttributes.executionAddress.length != 0) {
Expand Down Expand Up @@ -456,13 +395,10 @@ contract InteropHandler is IInteropHandler, ReentrancyGuard {
address senderAddress,
bytes calldata sender
) internal {
(uint256 sourceChainId, bytes memory bundle, CallStatus[] memory providedCallStatus) = abi.decode(
payload[4:],
(uint256, bytes, CallStatus[])
);
(bytes memory bundle, CallStatus[] memory providedCallStatus) = abi.decode(payload[4:], (bytes, CallStatus[]));

// Decode the bundle to get unbundling permissions
(InteropBundle memory interopBundle, , ) = _getBundleData(bundle, sourceChainId);
(InteropBundle memory interopBundle, , ) = _getBundleData(bundle);

(uint256 unbundlerChainId, address unbundlerAddress) = InteroperableAddress.parseEvmV1(
interopBundle.bundleAttributes.unbundlerAddress
Expand All @@ -474,6 +410,31 @@ contract InteropHandler is IInteropHandler, ReentrancyGuard {
UnbundlingNotAllowed(keccak256(bundle), sender, interopBundle.bundleAttributes.unbundlerAddress)
);

this.unbundleBundle(sourceChainId, bundle, providedCallStatus);
this.unbundleBundle(bundle, providedCallStatus);
}

function _validateBundleDestinationContext(
bytes32 bundleHash,
InteropBundle memory interopBundle,
uint256 proofChainId
) internal view {
// Verify that the source chainId of the bundle matches the proof's chainId
require(
interopBundle.sourceChainId == proofChainId,
WrongSourceChainId(bundleHash, interopBundle.sourceChainId, proofChainId)
);

// Verify that the destination chainId of the bundle is equal to the chainId where it's trying to get executed
require(
interopBundle.destinationChainId == block.chainid,
WrongDestinationChainId(bundleHash, interopBundle.destinationChainId, block.chainid)
);

// Verify that the destination base token asset ID of the bundle is equal to the base token asset ID of the chain
bytes32 baseTokenAssetId = L2_NATIVE_TOKEN_VAULT.BASE_TOKEN_ASSET_ID();
require(
interopBundle.destinationBaseTokenAssetId == baseTokenAssetId,
WrongDestinationBaseTokenAssetId(bundleHash, baseTokenAssetId, interopBundle.destinationBaseTokenAssetId)
);
}
}
4 changes: 2 additions & 2 deletions l1-contracts/selectors
Original file line number Diff line number Diff line change
Expand Up @@ -5316,7 +5316,7 @@ IInteropHandler
|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------|
| Function | initL2(uint256) | 0xfdf736a3 |
|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------|
| Function | unbundleBundle(uint256,bytes,uint8[]) | 0x98483918 |
| Function | unbundleBundle(bytes,uint8[]) | 0x37dd8238 |
|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------|
| Function | verifyBundle(bytes,(uint256,uint256,uint256,(uint16,address,bytes),bytes32[])) | 0x743565a6 |
|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------|
Expand Down Expand Up @@ -7167,7 +7167,7 @@ InteropHandler
|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------|
| Function | receiveMessage(bytes32,bytes,bytes) | 0x2432ef26 |
|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------|
| Function | unbundleBundle(uint256,bytes,uint8[]) | 0x98483918 |
| Function | unbundleBundle(bytes,uint8[]) | 0x37dd8238 |
|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------|
| Function | verifyBundle(bytes,(uint256,uint256,uint256,(uint16,address,bytes),bytes32[])) | 0x743565a6 |
|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ abstract contract L2InteropHandlerTestAbstract is Test, SharedL2ContractDeployer
vm.expectEmit(true, false, false, false);
emit IInteropHandler.BundleUnbundled(bundleHash);
vm.prank(UNBUNDLER_ADDRESS);
IInteropHandler(L2_INTEROP_HANDLER_ADDR).unbundleBundle(proof.chainId, bundle, callStatuses1);
IInteropHandler(L2_INTEROP_HANDLER_ADDR).unbundleBundle(bundle, callStatuses1);
// Check storage changes after first unbundle
assertEq(
uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).callStatus(bundleHash, 0)),
Expand Down Expand Up @@ -258,7 +258,7 @@ abstract contract L2InteropHandlerTestAbstract is Test, SharedL2ContractDeployer
vm.expectEmit(true, false, false, false);
emit IInteropHandler.BundleUnbundled(bundleHash);
vm.prank(UNBUNDLER_ADDRESS);
IInteropHandler(L2_INTEROP_HANDLER_ADDR).unbundleBundle(proof.chainId, bundle, callStatuses2);
IInteropHandler(L2_INTEROP_HANDLER_ADDR).unbundleBundle(bundle, callStatuses2);
// Check storage changes after second unbundle
assertEq(
uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).callStatus(bundleHash, 0)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ abstract contract L2InteropUnbundleTestAbstract is L2InteropTestUtils {
InteropLibrary.sendDirectCall(
destinationChainId,
L2_INTEROP_HANDLER_ADDR,
abi.encodeCall(L2_INTEROP_HANDLER.unbundleBundle, (originalChainId, bundle, callStatuses)),
abi.encodeCall(L2_INTEROP_HANDLER.unbundleBundle, (bundle, callStatuses)),
UNBUNDLER_ADDRESS,
UNBUNDLER_ADDRESS
);
Expand Down
Loading