Skip to content

[WIP] feat: new lockbox#192

Merged
agusduha merged 13 commits intosc-feat/add-shared-lockboxfrom
feat/new-lockbox
Jan 16, 2025
Merged

[WIP] feat: new lockbox#192
agusduha merged 13 commits intosc-feat/add-shared-lockboxfrom
feat/new-lockbox

Conversation

@agusduha
Copy link
Copy Markdown
Member

@agusduha agusduha commented Jan 9, 2025

No description provided.

@agusduha agusduha self-assigned this Jan 9, 2025
@@ -28,9 +28,6 @@ contract SharedLockbox is ISemver {
/// @notice The address of the SuperchainConfig contract.
ISuperchainConfig public immutable SUPERCHAIN_CONFIG;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We should not leak the fact that this is immutable into the abi, could we add a superchainConfig()(address) getter and make internal immutable SUPERCHAIN_CONFIG ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This contract address should never change, the SharedLockbox should always have the same SuperchaingConfig contract address, or were you thinking of something else?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We can make it immutable but no leak the camel case to the abi, then we leak implementation details into the abi

/// @notice
contract UpgradeHandler {
function addDependency(address _supechainConfig, uint256 _chainId, address _systemConfig) external {
if (msg.sender != Constants.DEPOSITOR_ACCOUNT) revert Unauthorized(); // TODO: check if this is safe enough
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is safe enough because only the derivation pipeline can mock this identity

/// @title UpgradeHandler
/// @notice
contract UpgradeHandler {
function addDependency(address _supechainConfig, uint256 _chainId, address _systemConfig) external {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: typo _superchainConfig


IL2ToL1MessagePasser(payable(Predeploys.L2_TO_L1_MESSAGE_PASSER)).initiateWithdrawal(
_supechainConfig,
400_000, // TODO: find an arbitrary value that is enough
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We need to remove the gas limit on withdrawals, its the source of so much pain


event ETHMigrated(uint256 amount);

function migrateLiquidity() external {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Do you think its better to move away from the intermediate upgrade contract?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This approach does simplify multisig operations which is nice

Copy link
Copy Markdown
Member Author

@agusduha agusduha Jan 10, 2025

Choose a reason for hiding this comment

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

Yes! Also you can be sure that the ETH liquidity migration is done at the same time as the portal is authorized to withdraw from the lockbox. The other way it has to be manually done and checked before processing the addDependency withdrawal tx .

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ok i am on board with this


// Check the Identifier.
_checkIdentifier(_id);
if (!IDependencySet(Predeploys.L1_BLOCK_ATTRIBUTES).isInDependencySet(_id.chainId)) revert InvalidChainId();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If we have this, then we will need the first block to set the dependency set, which makes testing a bit more complicated. The real benefit that I see is on outgoing messages from the L2 to L2 xdm

Copy link
Copy Markdown

@tynes tynes Jan 10, 2025

Choose a reason for hiding this comment

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

We need to make sure that we do not have unprovable logs. Its most simple to assume that you cannot consume logs before the interop start. We would need to move that logic offchain in the block builder, proof and fork choice rule if its not onchain. I think we can get away with keeping everything that was in _checkIdentifier offchain, it will save a bit of gas over time

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ok perfect, we will remove the check from here but leave it in the L2toL2CDM

@@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Curious if you have an opinion on the dependency set living in this contract vs the L1Block contract. The tradeoff is with it being in the L1Block contract, it expands the ABI, which causes more gas cost for every single system transaction doing 4byte selector matching. Its likely a minimal amount of gas but it adds up every block. Historically we just always added things to L1Block but this consideration exists

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I like this approach, as we talked, we can have a DependencyManager predeploy handling this

@tynes
Copy link
Copy Markdown

tynes commented Jan 10, 2025

These changes generally look good to me

// TODO: check if this function makes sense
/// @notice Initializes the first portal of the cluster.
/// @param _initialPortal The address of the initial portal.
function initializePortal(address _initialPortal) external {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We agreed that for the first version, we would make the auth be "withdrawal OR multisig" and add a new role to superchain config that represents the multisig. This solves the bootstrapping problem and lets us handle the first upgrade to interop in a simple way. In the future, we can integrate more tightly into OPCM where when deploying a cluster, the first portal is auth'd by op-deployer/opcm. cc @maurelian for visibility

"type": "bool"
},
{
"bytes": "20",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We may want to move this storage slot away from being managed by solc, its putting it on the same slot as _initialized which is annoying to deal with

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We are going to change everything to use unstructured storage

string public constant version = "1.1.1-beta.5";

/// @notice The Shared Lockbox contract
ISharedLockbox public sharedLockbox;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I would recommend that we either use a spacer to move this away from being in the same slot as initialized or we use a custom setter/getter + a hash to define the slot

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

slight preference for custom storage

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agree! We are moving to unstructured storage to avoid this problems and future upgrades


if (_dependencySet.length() == type(uint8).max) revert DependencySetTooLarge();
if (_chainId == block.chainid) revert InvalidChainID();
if (_chainId == block.chainid) revert InvalidChainID(); // TODO: is this check really necessary?
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This check is good for preventing footguns altho i don't think its that useful in practice. If we mess up the config for the dep set then we are going to have a bad time regardless of this check. I would be down to remove this to reduce test maintenance


/// @notice Stores the Identifier in transient storage.
/// @param _id Identifier to store.
function _storeIdentifier(Identifier calldata _id) internal {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We chatted about this out of band, but we can remove the whole _storeIdentifier function and the getters for the context variables given the only entrypoint now is the validateMessage function

// Initiate a withdrawal tx to update the dependency set on L1.
IL2ToL1MessagePasser(payable(Predeploys.L2_TO_L1_MESSAGE_PASSER)).initiateWithdrawal(
_superchainConfig,
400_000, // TODO: find an arbitrary value that is enough
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

In the future, I want to make a new "type" of withdrawal message that doesn't have a gas limit for the call and there is a require on the success of the call. This would simplify so much. For now we have to deal with this whole gaslimit thing and be careful of the footgun

// Set the migrator as an authorized portal so it can lock the ETH while migrating
vm.prank(address(superchainConfig));
sharedLockbox.authorizePortal(address(liquidityMigrator));
// sharedLockbox.authorizePortal(address(liquidityMigrator));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: dead code

import { IL2ToL1MessagePasser } from "interfaces/L2/IL2ToL1MessagePasser.sol";
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";

/// @custom:proxied true
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

TODO: backport spec ethereum-optimism/specs#495

@tynes
Copy link
Copy Markdown

tynes commented Jan 13, 2025

This is good to merge into the feature branch once the comments have been ack'd

@@ -1,37 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think that we still need this contract for the multisig path

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Now the new CLUSTER_MANAGER role can directly call addDependency following the same flow as withdrawals

/// One-time use logic upgraded over OptimismPortalProxy address and then deprecated by another approval.
function migrateETH() external {
uint256 balance = address(this).balance;
SHARED_LOCKBOX.lockETH{ value: balance }();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This contract could be generic if the abi on the shared lockbox was just fallback rather than a function

@@ -1,16 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
pragma solidity 0.8.25;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

In favor of making new contracts 0.8.25

if (_destination == block.chainid) revert MessageDestinationSameChain();
if (_target == Predeploys.CROSS_L2_INBOX) revert MessageTargetCrossL2Inbox();
if (_target == Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) revert MessageTargetL2ToL2CrossDomainMessenger();
if (!IDependencySet(Predeploys.L1_BLOCK_ATTRIBUTES).isInDependencySet(_destination)) revert InvalidChainId();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think we need to update the address being called here

Copy link
Copy Markdown
Member Author

@agusduha agusduha Jan 14, 2025

Choose a reason for hiding this comment

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

Fixing, also changing L2ToL2CDM tests to be integrated with the setup so this can be catch

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The Setup can't be integrated rn because of how the tests are being handled for transient storage testing. Maybe we can do it once the CommonTest and Setup are migrated to 0.8.25.

@agusduha agusduha merged commit 18bd71e into sc-feat/add-shared-lockbox Jan 16, 2025
@agusduha agusduha deleted the feat/new-lockbox branch January 16, 2025 16:38
agusduha added a commit that referenced this pull request Feb 7, 2025
* feat: add shared lockbox (#126)

* feat: create shared lockbox contract with its interface and unit tests

* chore: polish tests and interfaces

* chore: run pre-pr

* chore: improve natspec

* chore: run pre-pr

* chore: update compiler version

* feat: integrate portal to lockbox (#139)

* feat: integrate portal to lockbox

* fix: pr fixes

* test: refactor assert

* feat: add liquidity migrator contract with its unit test and interface (#128)

* feat: create shared lockbox contract with its interface and unit tests

* chore: polish tests and interfaces

* chore: run pre-pr

* chore: improve natspec

* chore: run pre-pr

* feat: add liqudity migrator contract with its unit test and interface

* chore: remove underscore on stack var

* chore: add todo

* chore: run pre-pr

* chore: add contract title natspec and proxied

* refactor: integrate testing suite with common test

* chore: pre-pr

* chore: add spec test

* feat: integrate system config with superchain config (#140)

* feat: integrate portal to lockbox

* fix: pr fixes

* test: refactor assert

* feat: integrate system config with superchain config

* fix: remove OPCM interop

* test: add dependency counter test

* feat: manage dependency set on superchain config (#138)

* chore: add zero dependencies check (#142)

* fix: pre pr

* feat: Add pause check (#145)

* feat: Add pause check

Co-authored-by: 0xParticle <particle@defi.sucks>
Co-authored-by: gotzenx <78360669+gotzenx@users.noreply.github.com>
Co-authored-by: Joxess <joxes@defi.sucks>

* test: add tests natspecs

---------

Co-authored-by: 0xParticle <particle@defi.sucks>
Co-authored-by: gotzenx <78360669+gotzenx@users.noreply.github.com>
Co-authored-by: Joxess <joxes@defi.sucks>

* fix: pre pr and interfaces imports

* feat: add upgrader role to superchain config (#163)

* feat: use superchain config lockbox in portal (#164)

* feat: use superchain config lockbox in portal

* test: add new sharedlockbox test

* fix: pre pr

* feat: liquidity migrator deployment (#166)

* feat: liquidity migrator deployment

* test: fix comment

* test: fix internal variables names

* feat: dependency set refactor (#170)

* feat: dependency set refactor

* fix: deploy script variable name

* fix: pr

* fix: pr

* fix: pre pr

* fix: semgrep

* fix: merge conflict

* [WIP] feat: new lockbox (#192)

* chore: partial implementation comments

* feat: new lockbox

* feat: introduce dependency manager predeploy

* feat: remove timestamp check from CrossL2Inbox

* feat: introduce cluster manager role and remove immutables

* fix: remove unnecessary code, fix tests and setup

* feat: use unstructured storage and OZ v5

* fix: L2ToL2CDM dependency set check

* fix: dependency manager gas limit

* feat: refactor interop feature contracts (#200)

* feat: refactor interop feature contracts

* fix: add noops comment

* feat: adds OptimismPortal migrated flag

* test: add missing tests

* fix: portal interop storage naming

---------

Co-authored-by: Skeletor Spaceman <skeletorspaceman@gmail.com>

* fix: pre pr, setup and tests

* fix: remove system config interop and add interop portal target check (#205)

* fix: remove system config interop and add interop portal check

* fix: interop portal target check order

* fix: remove wrong comment

* fix: refactor portal noops function (#206)

* test: add dependency manager and portal interop tests (#209)

* feat: initialize shared lockbox in interop portal (#211)

* feat: initialize shared lockbox in interop portal

* fix: refactor shared lockbox storage getter

* fix: lockbox pr fixes (#214)

* fix: pre pr

* fix: semver lock

* fix: semver lock

* feat: descope dependency manager (#242)

* feat: descope dependency manager

* test: fix tests

* test: fix tests

* chore: improve eth liquidity test (#248)

* fix: internal review fixes (#243)

* fix: I-0

* fix: I-1

* fix: I-2

* fix: I-3

* fix: I-6

* fix: I-7

* fix: I-9

* fix: pre pr

* fix: pre pr

* fix: portal withdrawal checks (#255)

* fix: portal withdrawal checks

* fix: include current withdrawal check

* fix: remove unused interop contracts (#256)

* test: fix flake tests (#257)

* fix: adjust op-deployer interop scripts (#262)

* fix: pre pr

* fix op-deployer tests

* remove dependency code

* fix lint

* use Bob account

---------

Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com>
Co-authored-by: AgusDuha <81362284+agusduha@users.noreply.github.com>
Co-authored-by: agusduha <agusnduha@gmail.com>
Co-authored-by: 0xParticle <particle@defi.sucks>
Co-authored-by: gotzenx <78360669+gotzenx@users.noreply.github.com>
Co-authored-by: Joxess <joxes@defi.sucks>
Co-authored-by: Skeletor Spaceman <skeletorspaceman@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants