Skip to content
Closed
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
10 changes: 10 additions & 0 deletions packages/contracts-bedrock/interfaces/L1/IL1Compliance.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { ICompliance } from "interfaces/universal/ICompliance.sol";

/// @title IL1Compliance
/// @notice Interface for the L1Compliance contract.
interface IL1Compliance is ICompliance {
function __constructor__() external;
}
15 changes: 14 additions & 1 deletion packages/contracts-bedrock/interfaces/L1/IOptimismPortal2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ interface IOptimismPortal2 is IProxyAdminOwnedBase {
error OptimismPortal_ProofNotOldEnough();
error OptimismPortal_Unproven();
error OptimismPortal_InvalidLockboxState();
error OptimismPortal_OnlyCompliance();
error OutOfGas();
error UnexpectedList();
error UnexpectedString();
Expand All @@ -47,6 +48,18 @@ interface IOptimismPortal2 is IProxyAdminOwnedBase {
receive() external payable;

function anchorStateRegistry() external view returns (IAnchorStateRegistry);
function approved(
address _from,
address _to,
uint256 _value,
uint256 _mint,
uint64 _gasLimit,
bool _isCreation,
bytes calldata _data
)
external
payable;
function compliance() external view returns (address);
function ethLockbox() external view returns (IETHLockbox);
function checkWithdrawal(bytes32 _withdrawalHash, address _proofSubmitter) external view;
function depositTransaction(
Expand All @@ -71,7 +84,7 @@ interface IOptimismPortal2 is IProxyAdminOwnedBase {
external;
function finalizedWithdrawals(bytes32) external view returns (bool);
function guardian() external view returns (address);
function initialize(ISystemConfig _systemConfig, IAnchorStateRegistry _anchorStateRegistry) external;
function initialize(ISystemConfig _systemConfig, IAnchorStateRegistry _anchorStateRegistry, address _compliance) external;
function initVersion() external view returns (uint8);
function l2Sender() external view returns (address);
function minimumGasLimit(uint64 _byteCount) external pure returns (uint64);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ interface IOptimismPortalInterop is IProxyAdminOwnedBase {
error OptimismPortal_ProofNotOldEnough();
error OptimismPortal_Unproven();
error OptimismPortal_MigratingToSameRegistry();
error OptimismPortal_OnlyCompliance();
error OutOfGas();
error UnexpectedList();
error UnexpectedString();
Expand All @@ -48,6 +49,18 @@ interface IOptimismPortalInterop is IProxyAdminOwnedBase {
receive() external payable;

function anchorStateRegistry() external view returns (IAnchorStateRegistry);
function approved(
address _from,
address _to,
uint256 _value,
uint256 _mint,
uint64 _gasLimit,
bool _isCreation,
bytes calldata _data
)
external
payable;
function compliance() external view returns (address);
function ethLockbox() external view returns (IETHLockbox);
function checkWithdrawal(bytes32 _withdrawalHash, address _proofSubmitter) external view;
function depositTransaction(
Expand Down Expand Up @@ -76,7 +89,8 @@ interface IOptimismPortalInterop is IProxyAdminOwnedBase {
function initialize(
ISystemConfig _systemConfig,
IAnchorStateRegistry _anchorStateRegistry,
IETHLockbox _ethLockbox
IETHLockbox _ethLockbox,
address _compliance
)
external;
function initVersion() external view returns (uint8);
Expand Down
10 changes: 10 additions & 0 deletions packages/contracts-bedrock/interfaces/L2/IL2Compliance.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { ICompliance } from "interfaces/universal/ICompliance.sol";

/// @title IL2Compliance
/// @notice Interface for the L2Compliance contract.
interface IL2Compliance is ICompliance {
function __constructor__() external;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IL2ToL1MessagePasser {
import { IProxyAdminOwnedBase } from "interfaces/universal/IProxyAdminOwnedBase.sol";

interface IL2ToL1MessagePasser is IProxyAdminOwnedBase {
event MessagePassed(
uint256 indexed nonce,
address indexed sender,
Expand All @@ -13,13 +15,27 @@ interface IL2ToL1MessagePasser {
);
event WithdrawerBalanceBurnt(uint256 indexed amount);

error L2ToL1MessagePasser_OnlyCompliance();
receive() external payable;

function MESSAGE_VERSION() external view returns (uint16);
function approved(
address _from,
address _target,
uint256 _value,
uint64 _gasLimit,
bytes calldata _data,
uint256 _nonce
)
external
payable;
function burn() external;
function compliance() external view returns (address);
function donateETH() external payable;
function initiateWithdrawal(address _target, uint256 _gasLimit, bytes memory _data) external payable;
function messageNonce() external view returns (uint256);
function sentMessages(bytes32) external view returns (bool);
function setCompliance(address _compliance) external;
function version() external view returns (string memory);

function __constructor__() external;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IL2ToL1MessagePasserCGT {
import { IProxyAdminOwnedBase } from "interfaces/universal/IProxyAdminOwnedBase.sol";

interface IL2ToL1MessagePasserCGT is IProxyAdminOwnedBase {
error L2ToL1MessagePasserCGT_NotAllowedOnCGTMode();
error L2ToL1MessagePasser_OnlyCompliance();

event MessagePassed(
uint256 indexed nonce,
Expand All @@ -18,10 +21,14 @@ interface IL2ToL1MessagePasserCGT {
receive() external payable;

function MESSAGE_VERSION() external view returns (uint16);
function approved(address _from, address _target, uint256 _value, uint64 _gasLimit, bytes memory _data, uint256 _nonce) external payable;
function burn() external;
function compliance() external view returns (address);
function donateETH() external payable;
function initiateWithdrawal(address _target, uint256 _gasLimit, bytes memory _data) external payable;
function messageNonce() external view returns (uint256);
function sentMessages(bytes32) external view returns (bool);
function setCompliance(address _compliance) external;
function version() external view returns (string memory);

function __constructor__() external;
Expand Down
156 changes: 156 additions & 0 deletions packages/contracts-bedrock/interfaces/universal/ICompliance.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";

/// @title ICompliance
/// @notice Interface for the Compliance contract that provides optional compliance screening
/// for cross-chain transactions on OptimismPortal2 (deposits) and L2ToL1MessagePasser
/// (withdrawals).
interface ICompliance {
/// @notice The status of a transaction in the compliance system.
enum Status {
Approved,
Pending,
Rejected,
Refunded
}

/// @notice Emitted when a transaction is flagged as pending by compliance rules.
event Pending(
bytes32 indexed id,
address indexed from,
address indexed to,
uint256 value,
uint256 mint,
uint64 gasLimit,
uint256 nonce,
bytes data
);

/// @notice Emitted when a transaction is rejected — either automatically during check()
/// or when the owner calls reject().
event Rejected(bytes32 indexed id);

/// @notice Emitted when a transaction is approved (either automatically or by the owner).
event Approved(bytes32 indexed id);

/// @notice Emitted when a rejected transaction's ETH is refunded to the sender.
event Refunded(bytes32 indexed id);

// Solady Ownable events
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
event OwnershipHandoverRequested(address indexed pendingOwner);
event OwnershipHandoverCanceled(address indexed pendingOwner);

// ReinitializableBase event
event Initialized(uint8 version);

/// @notice Thrown when the caller is not the bridge contract.
error Compliance_OnlyBridge();

/// @notice Thrown when attempting to settle a transaction that is not pending.
error Compliance_NotPending();

/// @notice Thrown when an ETH transfer fails.
error Compliance_TransferFailed();

/// @notice Thrown when attempting to add a rule that already exists.
error Compliance_DuplicateRule();

/// @notice Thrown when attempting to remove a rule that does not exist.
error Compliance_RuleNotFound();

/// @notice Thrown when a rule returns an invalid status (Refunded).
error Compliance_InvalidRuleStatus();

// Solady Ownable errors
error Unauthorized();
error NewOwnerIsZeroAddress();
error NoHandoverRequest();
error AlreadyInitialized();
error Reentrancy();

// ProxyAdminOwnedBase errors
error ProxyAdminOwnedBase_NotSharedProxyAdminOwner();
error ProxyAdminOwnedBase_NotProxyAdminOwner();
error ProxyAdminOwnedBase_NotProxyAdmin();
error ProxyAdminOwnedBase_NotProxyAdminOrProxyAdminOwner();
error ProxyAdminOwnedBase_ProxyAdminNotFound();
error ProxyAdminOwnedBase_NotResolvedDelegateProxy();

// ReinitializableBase errors
error ReinitializableBase_ZeroInitVersion();

/// @notice Checks a transaction against all configured compliance rules.
function check(
address _from,
address _to,
uint256 _value,
uint64 _gasLimit,
bool _isCreation,
bytes calldata _data,
uint256 _nonce
)
external
payable
returns (bool allowed_);

/// @notice Returns the Status of a cross chain message and whether it is final.
function status(bytes32 _id) external view returns (bool isFinal_, Status status_);

/// @notice Owner approves a pending transaction.
function approve(bytes32 _id) external;

/// @notice Owner rejects a pending transaction.
function reject(bytes32 _id) external;

/// @notice Settles a pending transaction.
function settle(
address _from,
address _to,
uint256 _value,
uint256 _mint,
uint64 _gasLimit,
bool _isCreation,
bytes calldata _data,
uint256 _nonce
)
external;

/// @notice Adds a new compliance rule to the set.
function addRule(address _rule) external;

/// @notice Removes a compliance rule from the set.
function removeRule(address _rule) external;

/// @notice Returns the bridge contract address.
function bridge() external view returns (address payable);

/// @notice Returns all rule addresses.
function rules() external view returns (address[] memory);

/// @notice Returns whether the given address is a registered rule.
function hasRule(address _rule) external view returns (bool);

/// @notice Initializes the compliance contract.
function initialize(address _bridge, address _owner) external;

function version() external pure returns (string memory);

// Solady Ownable functions
function owner() external view returns (address result);
function transferOwnership(address newOwner) external payable;
function renounceOwnership() external payable;
function requestOwnershipHandover() external payable;
function cancelOwnershipHandover() external payable;
function completeOwnershipHandover(address pendingOwner) external payable;
function ownershipHandoverExpiresAt(address pendingOwner) external view returns (uint256 result);

// ProxyAdminOwnedBase functions
function proxyAdmin() external view returns (IProxyAdmin);
function proxyAdminOwner() external view returns (address);

// ReinitializableBase functions
function initVersion() external view returns (uint8);
}
12 changes: 12 additions & 0 deletions packages/contracts-bedrock/interfaces/universal/IDonatable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title IDonatable
/// @notice Interface for contracts that accept ETH donations without triggering
/// side effects (deposits on L1, withdrawals on L2). Used by the Compliance
/// module to return ETH to the bridge when a transaction passes all rules
/// during check().
interface IDonatable {
/// @notice Accepts ETH value without triggering a deposit or withdrawal.
function donateETH() external payable;
}
30 changes: 30 additions & 0 deletions packages/contracts-bedrock/interfaces/universal/IRule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { ICompliance } from "interfaces/universal/ICompliance.sol";

/// @title IRule
/// @notice Interface for compliance rule contracts. Rules are evaluated by the Compliance
/// contract to determine whether a cross-chain transaction should be allowed.
interface IRule {
/// @notice Checks a transaction against this rule.
/// @param _from The sender of the transaction.
/// @param _to The recipient of the transaction.
/// @param _value The ETH value of the transaction.
/// @param _gasLimit The gas limit for execution.
/// @param _isCreation Whether the transaction creates a contract.
/// @param _data The calldata of the transaction.
/// @param _nonce The nonce of the transaction.
/// @return The compliance status result of this rule's evaluation.
function check(
address _from,
address _to,
uint256 _value,
uint64 _gasLimit,
bool _isCreation,
bytes calldata _data,
uint256 _nonce
)
external
returns (ICompliance.Status);
}
5 changes: 5 additions & 0 deletions packages/contracts-bedrock/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ coverage-lcov-all *ARGS:
prepare-l2-upgrade-env *ARGS:
#!/bin/bash
set -euo pipefail
if [ -z "${L2_FORK_RPC_URL:-}" ]; then
echo "Error: L2_FORK_RPC_URL must be set to an L2 RPC URL."
echo "Usage: L2_FORK_RPC_URL=<url> just test-l2-fork-upgrade"
exit 1
fi
export L2_FORK_TEST=true
export DEV_FEATURE__L2CM=true
export FOUNDRY_FORK_RETRIES=10
Expand Down
8 changes: 8 additions & 0 deletions packages/contracts-bedrock/scripts/L2Genesis.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ contract L2Genesis is Script {
setConditionalDeployer(); // 2C
setL2DevFeatureFlags(_input); // 2D
}
if (DevFeatures.isDevFeatureEnabled(_input.devFeatureBitmap, DevFeatures.COMPLIANCE)) {
setL2Compliance(); // 2E
}
}

function setInteropPredeployProxies() internal { }
Expand Down Expand Up @@ -619,6 +622,11 @@ contract L2Genesis is Script {
IL2DevFeatureFlags(Predeploys.L2_DEV_FEATURE_FLAGS).setDevFeatureBitmap(_input.devFeatureBitmap);
}

/// @notice This predeploy is following the safety invariant #1.
function setL2Compliance() internal {
_setImplementationCode(Predeploys.L2_COMPLIANCE);
}

/// @notice Sets all the preinstalls.
function setPreinstalls() internal {
address tmpSetPreinstalls = address(uint160(uint256(keccak256("SetPreinstalls"))));
Expand Down
Loading
Loading