feat(contracts-bedrock): add compliance module for cross-chain transaction screening#19321
feat(contracts-bedrock): add compliance module for cross-chain transaction screening#19321
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #19321 +/- ##
===========================================
+ Coverage 75.8% 79.4% +3.5%
===========================================
Files 683 142 -541
Lines 72644 6938 -65706
===========================================
- Hits 55092 5509 -49583
+ Misses 17408 1429 -15979
+ Partials 144 0 -144
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
| address proxyAdmin = Storage.getAddress(Constants.PROXY_OWNER_ADDRESS); | ||
| if (msg.sender != proxyAdmin && msg.sender != IProxyAdmin(proxyAdmin).owner()) { |
There was a problem hiding this comment.
You can import ProxyAdminOwned here. It was recently moved into src/L2.
| } | ||
| } | ||
|
|
||
| /// @notice Sets the compliance module address. Only callable by the proxy admin or its owner. |
There was a problem hiding this comment.
We need to put some thought into which account to use here. Should it be the chain operator?
Making it the PAO will be onerous process wise.
There was a problem hiding this comment.
I believe the PAO is required here to ensure that stage 1 status can be maintained. You lower the amount of collusion required to censor. Perhaps we can set this in genesis if the feature is on, which should handle most cases, then the option still exists to enable it later or disable it later for chains that want it
There was a problem hiding this comment.
OK, I agree that enabling in genesis as the primary mechanism makes the most sense.
|
|
||
| /// @notice Adds a compliance rule to the set. Reverts if already present. | ||
| /// @param _rule The address of the rule contract. | ||
| function addRule(address _rule) external onlyOwner { |
There was a problem hiding this comment.
rather than using Ownable in this contract, would it make sense to put this value into L1Block?
There was a problem hiding this comment.
This contract lives on both L1 and L2, so I do not think it makes sense to enshrine logic in L1Block, unless you also suggest that it is enshrined in SystemConfig as well for symmetry
There was a problem hiding this comment.
I see, I did not consider that properly.
I do think it would be nice to have a symmetry like that, as I generally dislike having roles configure via Ownable within a contract, as it is usually harder to inspect and manage. This is especially case when you have a situation where the owner is always meant to be the same as as some other pre-existing entity, for example DelayedWeth used to be OwnableUpgradable, but the owner was just meant to the ProxyAdminOwner (fixed in this PR).
But before we make any changes, I think the first thing to do is figure out who actually should have this power. If stage 1 still matters, then it seems to me that it should be the proxy admin owner based on my understanding of the potential power of a rule.
b7afcfe to
0bd9e40
Compare
…ction screening Add a compliance screening layer for cross-chain transactions (deposits and withdrawals). When enabled, transactions pass through configurable rules before execution. Flagged transactions are held pending; compliant transactions proceed without delay. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d version bumps Expand ICompliance and IL2ToL1MessagePasserCGT interfaces to include Solady Ownable, ProxyAdminOwnedBase, and ReinitializableBase inherited events/errors/functions. Apply forge fmt formatting across compliance contracts and tests. Bump OPContractsManager to 6.0.4 and OPContractsManagerV2 to 7.0.9. Regenerate ABI and storage layout snapshots for all affected contracts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…s and interfaces Exclude IOwnable from the interface checker since Solady's Ownable has a different ABI than the minimal IOwnable interface. Rename compliance test contracts and functions to conform to the project's naming conventions: contract names must map to source contract functions, and test function names must have 3 or 4 underscore-separated parts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…le test Compliance contracts are not deployed as part of the standard deployment script, so they need to be excluded from the reinitialization test. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…n is enabled Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…pliance module Resolve conflicts from rebase on develop: bump COMPLIANCE dev feature bit to avoid collision with SUPER_ROOT_GAMES_MIGRATION, fix Predeploys address checksum, fix Compliance.sol import path, and regenerate snapshots. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…Passer Replace hand-rolled proxy admin ownership check in setCompliance() with ProxyAdminOwnedBase inheritance, aligning with the pattern used by all other L2 predeploys (FeeVault, L2StandardBridge, L2CrossDomainMessenger, etc.). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Patch-bump semver for contracts with changed initCodeHash due to transitive dependency changes from the compliance module - Fix spacer check to exclude .dispute.json artifacts for legacy spacer contracts - Regenerate nut-bundle and snapshots Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…deHash change The initCodeHash changed due to a transitive dependency update but the version was not bumped, causing the semver-diff check to fail. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OptimismPortalInterop was missing the compliance module integration that was added to OptimismPortal2. This caused L1Compliance tests to fail when the OPTIMISM_PORTAL_INTEROP feature flag was enabled. Adds compliance storage variable, approved() callback, and compliance check in depositTransaction() to OptimismPortalInterop, matching the OptimismPortal2 implementation. Updates the initialize() signature to accept _compliance parameter and updates all call sites. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…eployments and guard L2_FORK_RPC_URL Increase deployment gas limits for L2ToL1MessagePasser and L2ToL1MessagePasserCGT after compliance feature addition, and add an early exit guard for missing L2_FORK_RPC_URL in prepare-l2-upgrade-env. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| bool allowed = ICompliance(compliance).check{ value: msg.value }( | ||
| msg.sender, _to, _value, _gasLimit, _isCreation, _data, 0 | ||
| ); |
There was a problem hiding this comment.
I think it causes two identical deposit transactions to conflict, since they are gonna generate the same id and they are going to be overwritten. Should we add a nonce for deposits? or add a require(_status[id] == 0
| if (!SafeCall.send(_from, _mint)) revert ICompliance.Compliance_TransferFailed(); | ||
| } | ||
| } | ||
| // If still Pending, do nothing — leave it for later settlement. |
There was a problem hiding this comment.
Wondering if a timeout here would make sense, for cases where the owner never acts for any reason, so that pending deposits can get the rejected status and refund. Something like flagTime + T <= block.timestamp check and settle() could auto-resolve to Rejected.
Summary
Design doc: ethereum-optimism/design-docs#367
OptimismPortal2(L1 deposits) andL2ToL1MessagePasser(L2 withdrawals)Complianceabstract contract with configurable rules, pending/approved/rejected status tracking, and ETH escrow for flagged transactionsL1ComplianceandL2Complianceimplementations override_executeApprovedto call the correct bridgeapproved()anddonateETH()callbacks onOptimismPortal2andL2ToL1MessagePasserfor compliance settlementICompliance,IL2ToL1MessagePasserCGT, andIOptimismPortal2interfacesOPContractsManagerto 6.0.4 andOPContractsManagerV2to 7.0.9🤖 Generated with Claude Code