Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add wind down contracts #1

Closed
wants to merge 18 commits into from

Conversation

0xRaccoon
Copy link
Member

@0xRaccoon 0xRaccoon commented Oct 3, 2024

The purpose is to allow users to claim their balances of eth and ERC20 tokens with a prior snapshot of their balances.

Currently, the assets to be claimed by the users are located in 2 contracts in mainnet:

A snapshot of the users' eth balance of OptimismPortal and snapshot of the users' ERC20 balances of L1StandardBridge will be taken and the Merkle tree, root, and proofs for users will be generated off-chain.

The approach consists of a contract BalanceClaimer that contains the bytes32 merkle root value, all the Merkle verification logic, and claims methods. To achieve this approach, it is be necessary to update L1StandardBridge and the OptimisimPotal contracts and add the following methods:

  • L1StandardBridge: withdrawErc20Balance only called by BalanceClaimer contract after claim verification to send the user token balances.
  • OptimismPortal: withdrawEthBalance only called by BalanceClaimer contract after claim verification to send the user eth balance.

The claim method is permissionless and can be called by any address.

image

@0xRaccoon 0xRaccoon changed the base branch from develop to feat/wind-down October 4, 2024 11:48
@0xRaccoon 0xRaccoon requested a review from agusduha October 9, 2024 18:21
Signed-off-by: 0xRaccoon <[email protected]>
Signed-off-by: 0xRaccoon <[email protected]>
Signed-off-by: 0xRaccoon <[email protected]>
Signed-off-by: 0xRaccoon <[email protected]>
Comment on lines +236 to +239
(bool success,) = _user.call{ value: _ethBalance }("");
if (!success) {
revert IEthBalanceWithdrawer.EthTransferFailed();
}
Copy link
Member

Choose a reason for hiding this comment

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

They have a SafeSend lib that they use for this

address indexed user, uint256 ethBalance, IBalanceWithdrawer.Erc20BalanceClaim[] erc20TokenBalances
);

string public constant version = "1.0.0";
Copy link
Member

Choose a reason for hiding this comment

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

Add natspec here:

    /// @notice Semantic version.
    /// @custom:semver 1.0.0-beta.1

function initialize(
IL2OutputOracle _l2Oracle,
ISystemConfig _systemConfig,
ISuperchainConfig _superchainConfig
ISuperchainConfig _superchainConfig,
address _balanceClaimer
Copy link
Member

Choose a reason for hiding this comment

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

What about using IBalanceClaimer directly?

Copy link
Collaborator

Choose a reason for hiding this comment

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

+1

@@ -24,6 +24,8 @@ import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol";
import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol";
import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol";
import { IL1Block } from "src/L2/interfaces/IL1Block.sol";
import { IEthBalanceWithdrawer } from "src/L1/interfaces/winddown/IEthBalanceWithdrawer.sol";
Copy link
Member

Choose a reason for hiding this comment

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

This interface can be inherited here, the only thing to take into account is that it also has to be added to its interface also.

@@ -24,6 +28,8 @@ import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol";
/// of some token types that may not be properly supported by this contract include, but are
/// not limited to: tokens with transfer fees, rebasing tokens, and tokens with blocklists.
contract L1StandardBridge is StandardBridge, ISemver {
Copy link
Member

@agusduha agusduha Oct 10, 2024

Choose a reason for hiding this comment

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

IBalanceWithdrawer should be inherit here and in IL1StandardBridge


/// @title BalanceClaimer
/// @notice Contract that allows users to claim and withdraw their balances
contract BalanceClaimer is Initializable, ISemver {
Copy link
Member

Choose a reason for hiding this comment

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

Is it going to be proxied like the others contracts? Missing the natspec

/// @custom:proxied true

Copy link

@0xDiscotech 0xDiscotech left a comment

Choose a reason for hiding this comment

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

Looking good so far sir! Well done

I put the focus mainly on the contracts logic, left suggestions mostly related to styling and some NITs.

The tests need to follow their tests naming standard, you can find it here https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/STYLE_GUIDE.md#tests :)

uint256 _ethBalance,
IBalanceWithdrawer.Erc20BalanceClaim[] calldata _erc20TokenBalances
)
internal

Choose a reason for hiding this comment

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

Why not just doing it public and removing the external one?

Suggested change
internal
public

Copy link
Collaborator

Choose a reason for hiding this comment

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

second this

@@ -0,0 +1,118 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

Choose a reason for hiding this comment

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

New contracts are being created under 0.8.25, is there any specific requirement for it to be 0.8.15?

Copy link
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 update this from a very old commit, I preferred to use the same version than the L1StandardBridge and OptmismPortal contracts for consistency.

IErc20BalanceWithdrawer public erc20BalanceWithdrawer;

/// @notice The mapping of users who have claimed their balances
mapping(address => bool) public claimed;

Choose a reason for hiding this comment

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

If updating the compiler version, the mapping could have named args

Suggested change
mapping(address => bool) public claimed;
mapping(address _user => bool _claimed) public claimed;

Copy link
Member Author

Choose a reason for hiding this comment

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

since we prefer to deploy using solidity 0.8.15 this naming is not supported in this version

Comment on lines +66 to +67
if (!_canClaim(_proof, _user, _ethBalance, _erc20TokenBalances)) {
revert IBalanceClaimer.NoBalanceToClaim();

Choose a reason for hiding this comment

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

Just a NIT, but I'm very much in favor of inlined if's, wdyt?

contract BalanceClaimer is Initializable, ISemver {
/// @notice Emitted when a user claims their balance
event BalanceClaimed(
address indexed user, uint256 ethBalance, IBalanceWithdrawer.Erc20BalanceClaim[] erc20TokenBalances

Choose a reason for hiding this comment

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

Missng args natspec

}

/// @dev Test that the claim function reverts when the user is invalid
function test_claim_invalid_user_reverts() external {

Choose a reason for hiding this comment

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

Suggested change
function test_claim_invalid_user_reverts() external {
function test_claim_reverts_invalidUser() external {

}

/// @dev Test that the claim function reverts when the proof is invalid
function test_claim_invalid_proof_reverts() external {

Choose a reason for hiding this comment

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

Suggested change
function test_claim_invalid_proof_reverts() external {
function test_claim_reverts_invalidProof() external {

}

/// @dev Test that the claim function reverts when the eth balance is invalid
function test_claim_invalid_eth_balance_reverts() external {

Choose a reason for hiding this comment

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

Suggested change
function test_claim_invalid_eth_balance_reverts() external {
function test_claim_reverts_invalidEthBalance() external {

}

/// @dev Test that the claim function reverts when the erc20 balance is invalid
function test_claim_invalid_erc20_balance_reverts() external {

Choose a reason for hiding this comment

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

Suggested change
function test_claim_invalid_erc20_balance_reverts() external {
function test_claim_reverts_erc20BalanceReverts() external {


/// @notice Address of the SuperchainConfig contract.
ISuperchainConfig public superchainConfig;

/// @notice Address of the SystemConfig contract.
ISystemConfig public systemConfig;

address public balanceClaimer;
Copy link

@0xDiscotech 0xDiscotech Oct 10, 2024

Choose a reason for hiding this comment

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

Missing natspec

Copy link
Collaborator

@0xmoebius 0xmoebius Oct 15, 2024

Choose a reason for hiding this comment

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

also storing it casted to IBalanceWithdrawer for neatness :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

+1 to IBalanceWithdrawer

@turtlemoji turtlemoji self-requested a review October 14, 2024 16:28
@0xRaccoon 0xRaccoon requested a review from 0xmoebius October 14, 2024 16:35
bytes32[] calldata _proof,
address _user,
uint256 _ethBalance,
IBalanceWithdrawer.Erc20BalanceClaim[] calldata _erc20TokenBalances
Copy link
Collaborator

Choose a reason for hiding this comment

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

as mentioned by @0xDiscotech on L1StandardBridge, i'd rename this argument to _erc20TokenClaim

Comment on lines +114 to +117
if (claimed[_user]) return false;
bytes32 _leaf = keccak256(bytes.concat(keccak256(abi.encode(_user, _ethBalance, _erc20TokenBalances))));
_canClaimTokens = MerkleProof.verify(_proof, root, _leaf);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

is there a chance someone may need two claims to fully withdraw their balances? if so, the claimed check wouldn't allow a second claim.

Copy link
Member Author

Choose a reason for hiding this comment

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

no, the claim should be just one per account, the merkle tree should include all the tokens and eth information for the user to claim

Comment on lines +15 to +16

function balanceClaimer() external view returns (address);
Copy link
Collaborator

Choose a reason for hiding this comment

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

missing natspec

Copy link
Member Author

Choose a reason for hiding this comment

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

will add the natspec in the contract since it seems to be the practice used in this repo

@@ -33,6 +33,7 @@ import { IL1CrossDomainMessenger } from "src/L1/interfaces/IL1CrossDomainMesseng
import { IL1ERC721Bridge } from "src/L1/interfaces/IL1ERC721Bridge.sol";
import { IL1StandardBridge } from "src/L1/interfaces/IL1StandardBridge.sol";
import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol";
import { IBalanceClaimer } from "src/L1/interfaces/winddown/IBalanceClaimer.sol";
Copy link
Collaborator

Choose a reason for hiding this comment

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

the BalanceClaimer and BalanceWithdrawer interfaces are really confusing

Comment on lines +112 to +113
address public balanceClaimer;

Copy link
Collaborator

Choose a reason for hiding this comment

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

  • missing natspec
  • i'd store the address casted to an interface like the rest of contracts for neatness

Copy link
Collaborator

Choose a reason for hiding this comment

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

+1

returns (bool _canClaimTokens)
{
if (claimed[_user]) return false;
bytes32 _leaf = keccak256(bytes.concat(keccak256(abi.encode(_user, _ethBalance, _erc20TokenBalances))));
Copy link
Collaborator

Choose a reason for hiding this comment

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

do we have an example merkle tree / data created via the offchain script to test?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes we tested with an example, the plan is to test all the leaves with a script

@0xRaccoon
Copy link
Member Author

PR moved to: #3

@0xRaccoon 0xRaccoon closed this Oct 21, 2024
@0xRaccoon 0xRaccoon deleted the feat/add-wind-down-contracts branch October 22, 2024 11:05
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.

5 participants