diff --git a/.github/workflows/large_vote_ci.yml b/.github/workflows/large_vote_ci.yml index 69d69eb6..f1c3e1ff 100644 --- a/.github/workflows/large_vote_ci.yml +++ b/.github/workflows/large_vote_ci.yml @@ -15,7 +15,7 @@ jobs: run-tests-large: name: Brownie fork LARGE tests runs-on: [protocol-heavy-runners] - timeout-minutes: 100 + timeout-minutes: 150 steps: - uses: actions/checkout@v3 - name: Main action diff --git a/archive/scripts/fallback_2024_10_08_enable_deposits.py b/archive/scripts/fallback_2024_10_08_enable_deposits.py new file mode 100644 index 00000000..27128c97 --- /dev/null +++ b/archive/scripts/fallback_2024_10_08_enable_deposits.py @@ -0,0 +1,64 @@ +""" +Fallback voting xx/xx/2024. + +1. Enable deposits on Optimism L1 Token Bridge + +""" +import time +from brownie import interface +from typing import Dict +from brownie.network.transaction import TransactionReceipt +from utils.voting import bake_vote_items, confirm_vote_script, create_vote +from utils.ipfs import upload_vote_ipfs_description, calculate_vote_ipfs_description +from utils.agent import agent_forward +from utils.config import ( + get_deployer_account, + get_is_live, + get_priority_fee, + L1_OPTIMISM_TOKENS_BRIDGE, +) + +description = """ +Fallback voting xx/xx/2024. + +Enable deposits on Optimism L1 Token Bridge + +""" + + +def start_vote(tx_params: Dict[str, str], silent: bool) -> bool | list[int | TransactionReceipt | None]: + """Prepare and run voting.""" + + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + + call_script_items = [ + # 1. Enable deposits on Optimism L1 Token Bridge + agent_forward([(l1_token_bridge.address, l1_token_bridge.enableDeposits.encode_input())]), + ] + + vote_desc_items = [ + "1) Enable deposits on Optimism L1 Token Bridge", + ] + + vote_items = bake_vote_items(list(vote_desc_items), list(call_script_items)) + + if silent: + desc_ipfs = calculate_vote_ipfs_description(description) + else: + desc_ipfs = upload_vote_ipfs_description(description) + + return confirm_vote_script(vote_items, silent, desc_ipfs) and list( + create_vote(vote_items, tx_params, desc_ipfs=desc_ipfs) + ) + + +def main(): + tx_params = {"from": get_deployer_account()} + if get_is_live(): + tx_params["priority_fee"] = get_priority_fee() + + vote_id, _ = start_vote(tx_params=tx_params, silent=False) + + vote_id >= 0 and print(f"Vote created: {vote_id}.") + + time.sleep(5) # hack for waiting thread #2. diff --git a/archive/scripts/fallback_2024_10_08_rollback_l1.py b/archive/scripts/fallback_2024_10_08_rollback_l1.py new file mode 100644 index 00000000..dda2f9a5 --- /dev/null +++ b/archive/scripts/fallback_2024_10_08_rollback_l1.py @@ -0,0 +1,101 @@ +""" +Rollback voting if L2 part of the upgrade failed. + +TODO + +""" + +import time +import eth_abi +from brownie import interface, web3 +from typing import Dict +from brownie.network.transaction import TransactionReceipt +from utils.voting import bake_vote_items, confirm_vote_script, create_vote +from utils.ipfs import upload_vote_ipfs_description, calculate_vote_ipfs_description +from utils.agent import agent_forward +from utils.config import ( + get_deployer_account, + get_is_live, + get_priority_fee, + L1_OPTIMISM_CROSS_DOMAIN_MESSENGER, + L1_EMERGENCY_BRAKES_MULTISIG, + LIDO_LOCATOR, + LIDO_LOCATOR_IMPL, + L1_OPTIMISM_TOKENS_BRIDGE, + L1_OPTIMISM_TOKENS_BRIDGE_IMPL, +) + + +DESCRIPTION = """ + +Upgrade back L1Bridge, LidoLocator and revokeRole for deposit pause on L1Bridge + +""" + +DEPOSITS_ENABLER_ROLE = "0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a" + +def start_vote(tx_params: Dict[str, str], silent: bool) -> bool | list[int | TransactionReceipt | None]: + """Prepare and run voting.""" + + l1_token_bridge_as_proxy = interface.OssifiableProxy(L1_OPTIMISM_TOKENS_BRIDGE) + lido_locator_as_proxy = interface.OssifiableProxy(LIDO_LOCATOR) + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + + call_script_items = [ + # 1. L1 TokenBridge upgrade proxy + agent_forward( + [ + ( + l1_token_bridge_as_proxy.address, + l1_token_bridge_as_proxy.proxy__upgradeTo.encode_input(L1_OPTIMISM_TOKENS_BRIDGE_IMPL), + ) + ] + ), + # 2. Rollback L1 LidoLocator implementation + agent_forward( + [ + ( + lido_locator_as_proxy.address, + lido_locator_as_proxy.proxy__upgradeTo.encode_input(LIDO_LOCATOR_IMPL), + ) + ] + ), + # 3. Revoke DEPOSITS_ENABLER_ROLE for Emergency Brakes Committee multisig + agent_forward( + [ + ( + l1_token_bridge.address, + l1_token_bridge.revokeRole.encode_input(DEPOSITS_ENABLER_ROLE, L1_EMERGENCY_BRAKES_MULTISIG), + ) + ] + ), + ] + + vote_desc_items = [ + "1) Rollback Optimism L1 Bridge implementation", + "2) Upgrade LidoLocator implementation", + "3) Revoke DEPOSITS_ENABLER_ROLE from Emergency Brakes Committee multisig", + ] + + vote_items = bake_vote_items(list(vote_desc_items), list(call_script_items)) + + if silent: + desc_ipfs = calculate_vote_ipfs_description(DESCRIPTION) + else: + desc_ipfs = upload_vote_ipfs_description(DESCRIPTION) + + return confirm_vote_script(vote_items, silent, desc_ipfs) and list( + create_vote(vote_items, tx_params, desc_ipfs=desc_ipfs) + ) + + +def main(): + tx_params = {"from": get_deployer_account()} + if get_is_live(): + tx_params["priority_fee"] = get_priority_fee() + + vote_id, _ = start_vote(tx_params=tx_params, silent=False) + + vote_id >= 0 and print(f"Vote created: {vote_id}.") + + time.sleep(5) # hack for waiting thread #2. diff --git a/archive/scripts/fork_utils_2024_10_08.py b/archive/scripts/fork_utils_2024_10_08.py new file mode 100644 index 00000000..53654442 --- /dev/null +++ b/archive/scripts/fork_utils_2024_10_08.py @@ -0,0 +1,85 @@ +import time +import os +from scripts.upgrade_2024_10_08 import start_vote +from brownie import interface, accounts, network +from tests.conftest import Helpers +from utils.config import ( + contracts, + get_deployer_account, + get_is_live, + get_priority_fee, + network_name, + L1_OPTIMISM_TOKENS_BRIDGE, + AGENT +) + +ENV_OMNIBUS_VOTE_IDS = "OMNIBUS_VOTE_IDS" + +def pause_deposits(): + if not network_name() in ("mainnet-fork",): + return + + network.gas_price("2 gwei") + + accounts[0].transfer(AGENT, "2 ethers") + + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + agent = accounts.at(AGENT, force=True) + l1_token_bridge.disableDeposits({"from": agent}) + assert not l1_token_bridge.isDepositsEnabled() + +def resume_deposits(): + if not network_name() in ("mainnet-fork",): + return + + network.gas_price("2 gwei") + + accounts[0].transfer(AGENT, "2 ethers") + + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + agent = accounts.at(AGENT, force=True) + l1_token_bridge.enableDeposits({"from": agent}) + assert l1_token_bridge.isDepositsEnabled() + +def start_and_execute_for_fork_upgrade(): + if not network_name() in ("mainnet-fork",): + return + + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + if l1_token_bridge.isDepositsEnabled(): + pause_deposits() + + deployerAccount = get_deployer_account() + + # Top up accounts + accounts[0].transfer(AGENT, "2 ethers") + accounts[0].transfer(deployerAccount.address, "2 ethers") + + tx_params = {"from": deployerAccount} + if get_is_live(): + tx_params["priority_fee"] = get_priority_fee() + + if len(vote_ids_from_env()) > 0: + vote_id = vote_ids_from_env()[0] + else: + vote_id, _ = start_vote(tx_params=tx_params, silent=True) + + vote_tx = Helpers.execute_vote(accounts, vote_id, contracts.voting) + + print(f"voteId = {vote_id}, gasUsed = {vote_tx.gas_used}") + + vote_id >= 0 and print(f"Vote created: {vote_id}.") + + time.sleep(5) # hack for waiting thread #2. + +def vote_ids_from_env() -> [int]: + if os.getenv(ENV_OMNIBUS_VOTE_IDS): + try: + vote_ids_str = os.getenv(ENV_OMNIBUS_VOTE_IDS) + vote_ids = [int(s) for s in vote_ids_str.split(",")] + print(f"OMNIBUS_VOTE_IDS env var is set, using existing votes {vote_ids}") + return vote_ids + except: + pass + + return [] diff --git a/archive/scripts/upgrade_2024_10_08.py b/archive/scripts/upgrade_2024_10_08.py new file mode 100644 index 00000000..86df3b33 --- /dev/null +++ b/archive/scripts/upgrade_2024_10_08.py @@ -0,0 +1,206 @@ +""" +Voting 08/10/2024. + +Ia. Upgrade Ethereum Contracts +1. Upgrade L1ERC20TokenBridge contract to implementation 0x168Cfea1Ad879d7032B3936eF3b0E90790b6B6D4 +2. Call L1ERC20TokenBridge's finalizeUpgrade_v2() to update internal version counter +3. Upgrade Lido Locator contract to implementation 0x39aFE23cE59e8Ef196b81F0DCb165E9aD38b9463 +4. Grant permission DEPOSITS_ENABLER_ROLE to Ethereum Emergency Brakes Multisig 0x73b047fe6337183A454c5217241D780a932777bD + +Ib. Upgrade Optimism Contracts +5. Send Optimism upgrade call: + (a) Upgrade L2ERC20TokenBridge contract to implementation 0x2734602C0CEbbA68662552CacD5553370B283E2E + (b) Call L2ERC20TokenBridge's finalizeUpgrade_v2() to update internal version counter + (c) Upgrade WstETH ERC20Bridged contract to implementation 0xFe57042De76c8D6B1DF0E9E2047329fd3e2B7334 + (d) Call WstETH ERC20Bridged's finalizeUpgrade_v2() to update internal version counter and set the name and version for EIP5267 + +II. Add Easy Track setup for funding Lido Alliance Operational Multisig +6. Add Alliance Ops stablecoins top up EVM script factory 0xe5656eEe7eeD02bdE009d77C88247BC8271e26Eb (AllowedRecipientsRegistry 0x3B525F4c059F246Ca4aa995D21087204F30c9E2F) + +Vote passed & executed on Oct-11-2024 04:21:11 PM +UTC, block #20943533. +""" + +import time +import eth_abi + +from brownie import interface, web3, accounts +from typing import Dict +from brownie.network.transaction import TransactionReceipt +from utils.voting import bake_vote_items, confirm_vote_script, create_vote +from utils.ipfs import upload_vote_ipfs_description, calculate_vote_ipfs_description +from utils.agent import agent_forward +from utils.config import ( + AGENT, + network_name, + get_deployer_account, + get_is_live, + get_priority_fee, + contracts, + L1_EMERGENCY_BRAKES_MULTISIG, + L1_OPTIMISM_CROSS_DOMAIN_MESSENGER, + LIDO_LOCATOR, + LIDO_LOCATOR_IMPL_NEW, + L1_OPTIMISM_TOKENS_BRIDGE, + L1_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW, + L2_OPTIMISM_GOVERNANCE_EXECUTOR, + L2_OPTIMISM_TOKENS_BRIDGE, + L2_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW, + L2_OPTIMISM_WSTETH_TOKEN, + L2_OPTIMISM_WSTETH_TOKEN_IMPL_NEW, +) +from utils.easy_track import add_evmscript_factory, create_permissions + + +DESCRIPTION = """ +1. Upgrade **wstETH on Optimism bridge endpoints** to enable **rebasable stETH** on Optimism alongside wstETH. Following [Snapshot vote](https://snapshot.org/#/lido-snapshot.eth/proposal/0xb1a3c33a4911712770c351504bac0499611ceb0faff248eacb1e96354f8e21e8) and proposed [action plan](https://research.lido.fi/t/steth-on-optimism-upgrade-announcement-and-action-plan/8474). +Solution audited by [MixBytes](https://github.com/lidofinance/audits/blob/main/L2/stETH-on-Optimism-2024-06-MixBytes-Audit-Report.pdf) and [Ackee Blockchain](https://github.com/lidofinance/audits/blob/main/L2/stETH-on-Optimism-2024-06-Ackee-Blockchain-Audit-report.pdf). Items 1-5. + +2. Add **Easy Track setup** for funding the [Lido Alliance Operational Multisig](https://app.safe.global/transactions/queue?safe=eth:0x606f77BF3dd6Ed9790D9771C7003f269a385D942) following the [Lido DAO Snapshot decision](https://snapshot.org/#/lido-snapshot.eth/proposal/0xa478fa5518769096eda2b7403a1d4104ca47de3102e8a9abab8640ef1b50650c). Item 6. +""" + +DEPOSITS_ENABLER_ROLE = "0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a" + +def encode_l2_upgrade_call(l2_token_bridge_proxy: str, l2_token_bridge_new_impl: str, l2_wst_token_proxy: str, l2_wst_token_new_impl: str): + queue_definition = f"queue(address[],uint256[],string[],bytes[],bool[])" + queue_selector = web3.keccak(text=queue_definition).hex()[:10] + + args_bytes = eth_abi.encode( + ["address[]", "uint256[]", "string[]", "bytes[]", "bool[]"], + [ + [l2_token_bridge_proxy, l2_token_bridge_proxy, l2_wst_token_proxy, l2_wst_token_proxy], + [0, 0, 0, 0], + [ + "proxy__upgradeTo(address)", + "finalizeUpgrade_v2()", + "proxy__upgradeTo(address)", + "finalizeUpgrade_v2(string,string)", + ], + [ + eth_abi.encode(["address"], [l2_token_bridge_new_impl]), + eth_abi.encode([], []), + eth_abi.encode(["address"], [l2_wst_token_new_impl]), + eth_abi.encode(["string", "string"], ["Wrapped liquid staked Ether 2.0", "2"]), + ], + [False, False, False, False], + ], + ).hex() + assert args_bytes[1] != "x" # just convenient debug check + calldata = f"{queue_selector}{args_bytes}" + return calldata + +def encode_l1_l2_sendMessage(to: str, calldata: str): + l1_l2_msg_service = interface.OpCrossDomainMessenger(L1_OPTIMISM_CROSS_DOMAIN_MESSENGER) + min_gas_limit = 1_000_000 + return l1_l2_msg_service.sendMessage.encode_input(to, calldata, min_gas_limit) + +def start_vote(tx_params: Dict[str, str], silent: bool) -> bool | list[int | TransactionReceipt | None]: + """Prepare and run voting.""" + + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + lido_locator_as_proxy = interface.OssifiableProxy(LIDO_LOCATOR) + l1_token_bridge_as_proxy = interface.OssifiableProxy(L1_OPTIMISM_TOKENS_BRIDGE) + + alliance_ops_registry = interface.AllowedRecipientRegistry("0x3B525F4c059F246Ca4aa995D21087204F30c9E2F") + alliance_ops_topup_factory = interface.TopUpAllowedRecipients("0xe5656eEe7eeD02bdE009d77C88247BC8271e26Eb") + + if network_name() in ("mainnet-fork",) and l1_token_bridge.isDepositsEnabled(): + agent = accounts.at(AGENT, force=True) + l1_token_bridge.disableDeposits({"from": agent}) + + vote_desc_items, call_script_items = zip( + # Ia. Upgrade Ethereum Contracts + ( + "1) Upgrade L1ERC20TokenBridge contract to implementation 0x168Cfea1Ad879d7032B3936eF3b0E90790b6B6D4", + agent_forward( + [ + ( + l1_token_bridge_as_proxy.address, + l1_token_bridge_as_proxy.proxy__upgradeTo.encode_input(L1_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW), + ) + ] + ), + ), + ( + "2) Call L1ERC20TokenBridge's finalizeUpgrade_v2() to update internal version counter", + agent_forward([(l1_token_bridge.address, l1_token_bridge.finalizeUpgrade_v2.encode_input())]), + ), + ( + "3) Upgrade Lido Locator contract to implementation 0x39aFE23cE59e8Ef196b81F0DCb165E9aD38b9463", + agent_forward( + [ + ( + lido_locator_as_proxy.address, + lido_locator_as_proxy.proxy__upgradeTo.encode_input(LIDO_LOCATOR_IMPL_NEW), + ) + ] + ), + ), + ( + "4) Grant permission DEPOSITS_ENABLER_ROLE to Ethereum Emergency Brakes Multisig 0x73b047fe6337183A454c5217241D780a932777bD", + agent_forward( + [ + ( + l1_token_bridge.address, + l1_token_bridge.grantRole.encode_input(DEPOSITS_ENABLER_ROLE, L1_EMERGENCY_BRAKES_MULTISIG), + ) + ] + ), + ), + # Ib. Upgrade Optimism Contracts + ( + "5) Send Optimism upgrade call:" + + " (a) Upgrade L2ERC20TokenBridge contract to implementation 0x2734602C0CEbbA68662552CacD5553370B283E2E;" + + " (b) Call L2ERC20TokenBridge's finalizeUpgrade_v2() to update internal version counter;" + + " (c) Upgrade WstETH ERC20Bridged contract to implementation 0xFe57042De76c8D6B1DF0E9E2047329fd3e2B7334;" + + " (d) Call WstETH ERC20Bridged's finalizeUpgrade_v2() to update internal version counter and set the name and version for EIP5267;", + agent_forward( + [ + ( + L1_OPTIMISM_CROSS_DOMAIN_MESSENGER, + encode_l1_l2_sendMessage( + L2_OPTIMISM_GOVERNANCE_EXECUTOR, + encode_l2_upgrade_call( + L2_OPTIMISM_TOKENS_BRIDGE, + L2_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW, + L2_OPTIMISM_WSTETH_TOKEN, + L2_OPTIMISM_WSTETH_TOKEN_IMPL_NEW, + ), + ), + ) + ] + ), + ), + # + # II. Add Easy Track setup for funding Lido Alliance Operational Multisig + # + ( + "6) Add Alliance Ops stablecoins top up EVM script factory 0xe5656eEe7eeD02bdE009d77C88247BC8271e26Eb (AllowedRecipientsRegistry 0x3B525F4c059F246Ca4aa995D21087204F30c9E2F)", + add_evmscript_factory( + factory=alliance_ops_topup_factory, + permissions=create_permissions(contracts.finance, "newImmediatePayment") + + create_permissions(alliance_ops_registry, "updateSpentAmount")[2:], + ) + ) + ) + + vote_items = bake_vote_items(list(vote_desc_items), list(call_script_items)) + + if silent: + desc_ipfs = calculate_vote_ipfs_description(DESCRIPTION) + else: + desc_ipfs = upload_vote_ipfs_description(DESCRIPTION) + + return confirm_vote_script(vote_items, silent, desc_ipfs) and list( + create_vote(vote_items, tx_params, desc_ipfs=desc_ipfs) + ) + +def main(): + tx_params = {"from": get_deployer_account()} + if get_is_live(): + tx_params["priority_fee"] = get_priority_fee() + + vote_id, _ = start_vote(tx_params=tx_params, silent=False) + + vote_id >= 0 and print(f"Vote created: {vote_id}.") + + time.sleep(5) # hack for waiting thread #2. diff --git a/archive/scripts/vote_2024_08_02_sepolia.py b/archive/scripts/vote_2024_08_02_sepolia.py new file mode 100644 index 00000000..b38dd4e1 --- /dev/null +++ b/archive/scripts/vote_2024_08_02_sepolia.py @@ -0,0 +1,201 @@ +""" +Voting 02/08/2024. + +1. Upgrade L1 Bridge implementation +2. Finalize L1 Bridge upgrade +3. Upgrade L1 LidoLocator implementation +4. Grant DEPOSITS_ENABLER_ROLE to Emergency Brakes Committee multisig +5. Send L2 upgrade call: + (a) upgrade L2TokenBridge; + (b) finalize L2TokenBridge upgrade; + (c) upgrade wstETH on L2; + (d) finalize wstETH upgrade"; + +""" + +import time +import eth_abi +from brownie import interface, accounts +from typing import Dict +from brownie.network.transaction import TransactionReceipt +from utils.voting import bake_vote_items, confirm_vote_script, create_vote +from utils.ipfs import upload_vote_ipfs_description, calculate_vote_ipfs_description +from utils.agent import agent_forward +from tests.conftest import Helpers +from utils.config import ( + contracts, + get_deployer_account, + get_is_live, + get_priority_fee, + network_name, +) +from configs.config_sepolia import ( + L1_TOKENS_BRIDGE_PROXY, + L1_TOKENS_BRIDGE_NEW_IMPL, + LIDO_LOCATOR, + LIDO_LOCATOR_IMPL_UPGRADE, + L1_EMERGENCY_BRAKES_MULTISIG, + L2_TOKENS_BRIDGE_PROXY, + L2_TOKENS_BRIDGE_NEW_IMPL, + L2_OPTIMISM_BRIDGE_EXECUTOR, + L2_OPTIMISM_WSTETH_TOKEN, + L2_OPTIMISM_WSTETH_TOKEN_NEW_IMPL, + L1_OPTIMISM_CROSS_DOMAIN_MESSENGER, + AGENT +) + +description = """ +Voting 02/08/2024. + +Upgrade L1Bridge, L2Bridge, L2 wstETH + +""" + +DEPOSITS_ENABLER_ROLE = "0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a" + +def encode_l2_upgrade_call(proxy1: str, new_impl1: str, proxy2: str, new_impl2: str): + govBridgeExecutor = interface.OpBridgeExecutor(L2_OPTIMISM_BRIDGE_EXECUTOR) + + return govBridgeExecutor.queue.encode_input( + [proxy1, proxy1, proxy2, proxy2], + [0, 0, 0, 0], + [ + "proxy__upgradeTo(address)", + "finalizeUpgrade_v2()", + "proxy__upgradeTo(address)", + "finalizeUpgrade_v2(string,string)" + ], + [ + eth_abi.encode(["address"], [new_impl1]), + eth_abi.encode([],[]), + eth_abi.encode(["address"], [new_impl2]), + eth_abi.encode(["string", "string"], ["Wrapped liquid staked Ether 2.0","wstETH"]), + ], + [False, False, False, False], + ) + + +def encode_l1_l2_sendMessage(to: str, calldata: str): + l1_l2_msg_service = interface.OpCrossDomainMessenger(L1_OPTIMISM_CROSS_DOMAIN_MESSENGER) + min_gas_limit = 1_000_000 + return l1_l2_msg_service.sendMessage.encode_input(to, calldata, min_gas_limit) + + +def start_vote(tx_params: Dict[str, str], silent: bool) -> bool | list[int | TransactionReceipt | None]: + """Prepare and run voting.""" + + if not network_name() in ("sepolia", "sepolia-fork"): + return + + lido_locator_as_proxy = interface.OssifiableProxy(LIDO_LOCATOR) + l1_token_bridge_as_proxy = interface.OssifiableProxy(L1_TOKENS_BRIDGE_PROXY) + l1_token_bridge = interface.L1LidoTokensBridge(L1_TOKENS_BRIDGE_PROXY) + + call_script_items = [ + # 1. L1 TokenBridge upgrade proxy + agent_forward( + [ + ( + l1_token_bridge_as_proxy.address, + l1_token_bridge_as_proxy.proxy__upgradeTo.encode_input(L1_TOKENS_BRIDGE_NEW_IMPL), + ) + ] + ), + # 2. L1 TokenBridge finalize upgrade + agent_forward( + [ + ( + l1_token_bridge.address, + l1_token_bridge.finalizeUpgrade_v2.encode_input() + ) + ] + ), + # 3. Upgrade L1 LidoLocator implementation + agent_forward( + [ + ( + lido_locator_as_proxy.address, + lido_locator_as_proxy.proxy__upgradeTo.encode_input(LIDO_LOCATOR_IMPL_UPGRADE), + ) + ] + ), + # 4. Grant DEPOSITS_ENABLER_ROLE to Emergency Brakes Committee multisig + agent_forward( + [ + ( + l1_token_bridge.address, + l1_token_bridge.grantRole.encode_input(DEPOSITS_ENABLER_ROLE, L1_EMERGENCY_BRAKES_MULTISIG), + ) + ] + ), + # 5. L2 TokenBridge + agent_forward( + [ + ( + L1_OPTIMISM_CROSS_DOMAIN_MESSENGER, + encode_l1_l2_sendMessage( + L2_OPTIMISM_BRIDGE_EXECUTOR, + encode_l2_upgrade_call( + L2_TOKENS_BRIDGE_PROXY, + L2_TOKENS_BRIDGE_NEW_IMPL, + L2_OPTIMISM_WSTETH_TOKEN, + L2_OPTIMISM_WSTETH_TOKEN_NEW_IMPL, + ), + ), + ) + ] + ), + ] + + vote_desc_items = [ + "1) Upgrade L1 Bridge implementation", + "2) Finalize L1 Bridge upgrade", + "3) Upgrade L1 LidoLocator implementation", + "4) Grant DEPOSITS_ENABLER_ROLE to Emergency Brakes Committee multisig", + "5) Send L2 upgrade call: (a) upgrade L2TokenBridge; (b) finalize L2TokenBridge upgrade; (c) upgrade wstETH on L2; (d) finalize wstETH upgrade", + ] + + vote_items = bake_vote_items(list(vote_desc_items), list(call_script_items)) + + if silent: + desc_ipfs = calculate_vote_ipfs_description(description) + else: + desc_ipfs = upload_vote_ipfs_description(description) + + return confirm_vote_script(vote_items, silent, desc_ipfs) and list( + create_vote(vote_items, tx_params, desc_ipfs=desc_ipfs) + ) + + +def main(): + tx_params = {"from": get_deployer_account()} + if get_is_live(): + tx_params["priority_fee"] = get_priority_fee() + + vote_id, _ = start_vote(tx_params=tx_params, silent=False) + + vote_id >= 0 and print(f"Vote created: {vote_id}.") + + time.sleep(5) # hack for waiting thread #2. + +def startAndExecuteForForkUpgrade(): + ACCOUNT_WITH_MONEY = "0x4200000000000000000000000000000000000023" + deployerAccount = get_deployer_account() + + # Top up accounts + accountWithEth = accounts.at(ACCOUNT_WITH_MONEY, force=True) + accountWithEth.transfer(deployerAccount.address, "2 ethers") + accountWithEth.transfer(AGENT, "2 ethers") + + tx_params = {"from": deployerAccount} + if get_is_live(): + tx_params["priority_fee"] = get_priority_fee() + + vote_id, _ = start_vote(tx_params=tx_params, silent=True) + vote_tx = Helpers.execute_vote(accounts, vote_id, contracts.voting) + + print(f"voteId = {vote_id}, gasUsed = {vote_tx.gas_used}") + + vote_id >= 0 and print(f"Vote created: {vote_id}.") + + time.sleep(5) # hack for waiting thread #2. diff --git a/archive/tests/_test_fallback_2024_10_08_enable_deposits.py b/archive/tests/_test_fallback_2024_10_08_enable_deposits.py new file mode 100644 index 00000000..80687185 --- /dev/null +++ b/archive/tests/_test_fallback_2024_10_08_enable_deposits.py @@ -0,0 +1,45 @@ +""" +Tests for fallback enable deposits voting xx/xx/2024 +""" +from scripts.fallback_enable_deposits import start_vote +from brownie import interface +from utils.test.tx_tracing_helpers import * +from utils.config import ( + contracts, + AGENT, + L1_OPTIMISM_TOKENS_BRIDGE, +) + +L1_TOKEN_BRIDGE_OLD_IMPL: str = "0x29C5c51A031165CE62F964966A6399b81165EFA4" + + +def test_vote(helpers, accounts, vote_ids_from_env, ldo_holder): + l1_token_bridge_proxy = interface.OssifiableProxy(L1_OPTIMISM_TOKENS_BRIDGE) + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + + # Prepare required state for the voting + if l1_token_bridge.isDepositsEnabled(): + agent = accounts.at(AGENT, force=True) + l1_token_bridge.disableDeposits({"from": agent}) + + # Disabled deposits is the starting condition for the vote + assert not l1_token_bridge.isDepositsEnabled() + + # L1 Bridge hasn't been upgraded (just in case check) + assert l1_token_bridge_proxy.proxy__getImplementation() == L1_TOKEN_BRIDGE_OLD_IMPL + + # START VOTE + if len(vote_ids_from_env) > 0: + (vote_id,) = vote_ids_from_env + else: + vote_id, _ = start_vote({"from": ldo_holder}, silent=True) + + vote_tx = helpers.execute_vote(accounts, vote_id, contracts.voting) + + print(f"voteId = {vote_id}, gasUsed = {vote_tx.gas_used}") + + # validate vote events + assert count_vote_items_by_events(vote_tx, contracts.voting) == 1, "Incorrect voting items count" + + # Check the deposits are indeed enabled + assert l1_token_bridge.isDepositsEnabled() diff --git a/archive/tests/_test_fallback_2024_10_08_rollback_l1.py b/archive/tests/_test_fallback_2024_10_08_rollback_l1.py new file mode 100644 index 00000000..2daec120 --- /dev/null +++ b/archive/tests/_test_fallback_2024_10_08_rollback_l1.py @@ -0,0 +1,54 @@ +""" +Tests for voting xx/xx/2024 +""" +from scripts.upgrade_2024_10_08 import start_vote +from test_2024_10_08 import check_pre_upgrade_state, check_post_upgrade_state +from scripts.fallback_rollback_l1 import start_vote as start_vote_fallback +from brownie import interface +from utils.test.tx_tracing_helpers import * +from utils.config import ( + contracts, + AGENT, + L1_OPTIMISM_TOKENS_BRIDGE +) + +def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env): + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + + # Prepare required state for the voting + if l1_token_bridge.isDepositsEnabled(): + agent = accounts.at(AGENT, force=True) + l1_token_bridge.disableDeposits({"from": agent}) + + check_pre_upgrade_state() + wsteth_bridge_balance_before = contracts.wsteth.balanceOf(L1_OPTIMISM_TOKENS_BRIDGE) + + # START VOTE + if len(vote_ids_from_env) > 0: + (vote_id,) = vote_ids_from_env + else: + vote_id, _ = start_vote({"from": ldo_holder}, silent=True) + + vote_tx = helpers.execute_vote(accounts, vote_id, contracts.voting) + + print(f"voteId = {vote_id}, gasUsed = {vote_tx.gas_used}") + + # validate vote events + assert count_vote_items_by_events(vote_tx, contracts.voting) == 5, "Incorrect voting items count" + + evs = group_voting_events(vote_tx) + check_post_upgrade_state(evs) + assert wsteth_bridge_balance_before == contracts.wsteth.balanceOf(L1_OPTIMISM_TOKENS_BRIDGE) + + # START FALLBACK VOTE + if len(vote_ids_from_env) > 0: + (vote_id,) = vote_ids_from_env + else: + vote_id, _ = start_vote_fallback({"from": ldo_holder}, silent=True) + + vote_tx = helpers.execute_vote(accounts, vote_id, contracts.voting) + + # validate vote events + assert count_vote_items_by_events(vote_tx, contracts.voting) == 3, "Incorrect voting items count" + + check_pre_upgrade_state() diff --git a/archive/tests/test_2024_08_02_sepolia.py b/archive/tests/test_2024_08_02_sepolia.py new file mode 100644 index 00000000..20ad863b --- /dev/null +++ b/archive/tests/test_2024_08_02_sepolia.py @@ -0,0 +1,133 @@ +""" +Tests for voting xx/xx/2024 +""" +import eth_abi +from scripts.vote_2024_xx_xx_upgrade_optimism_bridge import start_vote +from brownie import interface, reverts +from utils.test.tx_tracing_helpers import * +from utils.config import ( + contracts, + LDO_HOLDER_ADDRESS_FOR_TESTS, + network_name, + get_deployer_account, + AGENT +) + +L1_TOKEN_BRIDGE_PROXY: str = "0x4Abf633d9c0F4aEebB4C2E3213c7aa1b8505D332" +L1_TOKEN_BRIDGE_OLD_IMPL: str = "0x02825dbCaFbBfda57511dBD73d22c2787B653814" +L1_TOKEN_BRIDGE_NEW_IMPL: str = "0x8375029773953d91CaCfa452b7D24556b9F318AA" + +LIDO_LOCATOR_PROXY: str = "0x8f6254332f69557A72b0DA2D5F0Bc07d4CA991E7" +LIDO_LOCATOR_OLD_IMPL: str = "0x604dc1776eEbe7ddCf4cf5429226Ad20a5a294eE" +LIDO_LOCATOR_NEW_IMPL: str = "0x314Ab8D774c0580942E832f971Bbc7A27B1c2552" + +DEPOSITS_ENABLER_ROLE = "0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a" +L1_EMERGENCY_BRAKES_MULTISIG = "0xa5F1d7D49F581136Cf6e58B32cBE9a2039C48bA1" + +L2_OPTIMISM_BRIDGE_EXECUTOR = "0xf695357C66bA514150Da95b189acb37b46DDe602" +L2_TOKENS_BRIDGE_PROXY = "0xdBA2760246f315203F8B716b3a7590F0FFdc704a" +L2_TOKENS_BRIDGE_NEW_IMPL = "0xD48c69358193a34aC035ea7dfB70daDea1600112" +L2_OPTIMISM_WSTETH_TOKEN = "0x24B47cd3A74f1799b32B2de11073764Cb1bb318B" +L2_OPTIMISM_WSTETH_TOKEN_NEW_IMPL = "0x298953B9426eba4F35a137a4754278a16d97A063" + +WST_ETH = "0xB82381A3fBD3FaFA77B3a7bE693342618240067b" + + +def test_vote(helpers, accounts, vote_ids_from_env): + if not network_name() in ("sepolia", "sepolia-fork"): + return + + deployerAccount = get_deployer_account() + + # Top up accounts + accountWithEth = accounts.at('0x4200000000000000000000000000000000000023', force=True) + accountWithEth.transfer(deployerAccount.address, "2 ethers") + accountWithEth.transfer(AGENT, "2 ethers") + + l1_token_bridge_proxy = interface.OssifiableProxy(L1_TOKEN_BRIDGE_PROXY); + l1_token_bridge = interface.L1LidoTokensBridge(L1_TOKEN_BRIDGE_PROXY); + + # L1 Bridge has old implementation + l1_token_bridge_implementation_address_before = l1_token_bridge_proxy.proxy__getImplementation() + assert l1_token_bridge_implementation_address_before == L1_TOKEN_BRIDGE_OLD_IMPL, "Old address is incorrect" + + # L1 Bridge doesn't have version before update + with reverts(): + l1_token_bridge.getContractVersion() + + # Upgrade LidoLocator implementation + lido_locator_proxy = interface.OssifiableProxy(LIDO_LOCATOR_PROXY); + lido_locator_implementation_address_before = lido_locator_proxy.proxy__getImplementation() + assert lido_locator_implementation_address_before == LIDO_LOCATOR_OLD_IMPL, "Old address is incorrect" + + # Multisig hasn't been assigned as deposit enabler + assert l1_token_bridge.hasRole(DEPOSITS_ENABLER_ROLE, L1_EMERGENCY_BRAKES_MULTISIG) is False + + wst_eth = interface.WstETH(WST_ETH) + wst_eth_bridge_balance_before = wst_eth.balanceOf(L1_TOKEN_BRIDGE_PROXY) + + # START VOTE + if len(vote_ids_from_env) > 0: + (vote_id,) = vote_ids_from_env + else: + tx_params = {"from": LDO_HOLDER_ADDRESS_FOR_TESTS} + vote_id, _ = start_vote(tx_params, silent=True) + + vote_tx = helpers.execute_vote(accounts, vote_id, contracts.voting) + + print(f"voteId = {vote_id}, gasUsed = {vote_tx.gas_used}") + + # validate vote events + if not network_name() in ("sepolia", "sepolia-fork"): + assert count_vote_items_by_events(vote_tx, contracts.voting) == 5, "Incorrect voting items count" + + # L1 Bridge has new implementation + l1_token_bridge_implementation_address_after = l1_token_bridge_proxy.proxy__getImplementation() + assert l1_token_bridge_implementation_address_before != l1_token_bridge_implementation_address_after, "Implementation is not changed" + assert l1_token_bridge_implementation_address_after == L1_TOKEN_BRIDGE_NEW_IMPL, "New address is incorrect" + + # update L1 Bridge to 2 version + assert l1_token_bridge.getContractVersion() == 2 + + # LidoLocator has new implementation + lido_locator_implementation_address_after = lido_locator_proxy.proxy__getImplementation() + assert lido_locator_implementation_address_before != lido_locator_implementation_address_after, "Implementation is not changed" + assert lido_locator_implementation_address_after == LIDO_LOCATOR_NEW_IMPL, "New address is incorrect" + + # Multisig has been assigned as deposit enabler + assert l1_token_bridge.hasRole(DEPOSITS_ENABLER_ROLE, L1_EMERGENCY_BRAKES_MULTISIG) is True + + # Check bytecode that was send to messenger to update L2 bridge and wstETH token + sentMessage = vote_tx.events['SentMessage']['message'] + encoded_l2_upgrade_call = encode_l2_upgrade_call( + L2_TOKENS_BRIDGE_PROXY, + L2_TOKENS_BRIDGE_NEW_IMPL, + L2_OPTIMISM_WSTETH_TOKEN, + L2_OPTIMISM_WSTETH_TOKEN_NEW_IMPL, + ) + assert sentMessage == encoded_l2_upgrade_call + + wst_eth_bridge_balance_after = wst_eth.balanceOf(L1_TOKEN_BRIDGE_PROXY) + assert wst_eth_bridge_balance_before == wst_eth_bridge_balance_after + + +def encode_l2_upgrade_call(proxy1: str, new_impl1: str, proxy2: str, new_impl2: str): + govBridgeExecutor = interface.OpBridgeExecutor(L2_OPTIMISM_BRIDGE_EXECUTOR) + + return govBridgeExecutor.queue.encode_input( + [proxy1, proxy1, proxy2, proxy2], + [0, 0, 0, 0], + [ + "proxy__upgradeTo(address)", + "finalizeUpgrade_v2()", + "proxy__upgradeTo(address)", + "finalizeUpgrade_v2(string,string)" + ], + [ + eth_abi.encode(["address"], [new_impl1]), + eth_abi.encode([],[]), + eth_abi.encode(["address"], [new_impl2]), + eth_abi.encode(["string", "string"], ["Wrapped liquid staked Ether 2.0","wstETH"]), + ], + [False, False, False, False], + ) diff --git a/archive/tests/test_2024_10_08.py b/archive/tests/test_2024_10_08.py new file mode 100644 index 00000000..c8ba5a77 --- /dev/null +++ b/archive/tests/test_2024_10_08.py @@ -0,0 +1,321 @@ +""" +Tests for voting 08/10/2024 +""" + +import eth_abi +from scripts.upgrade_2024_10_08 import start_vote, encode_l2_upgrade_call +from brownie import interface, reverts, web3 +from brownie.exceptions import VirtualMachineError +from utils.test.event_validators.common import validate_events_chain +from utils.test.event_validators.permission import validate_grant_role_event +from utils.test.tx_tracing_helpers import * +from utils.voting import find_metadata_by_vote_id +from utils.ipfs import get_lido_vote_cid_from_str +from utils.config import contracts +from utils.easy_track import create_permissions +from utils.test.easy_track_helpers import create_and_enact_payment_motion, check_add_and_remove_recipient_with_voting +from utils.test.event_validators.easy_track import ( + validate_evmscript_factory_added_event, + EVMScriptFactoryAdded, +) + +AGENT = "0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c" + +LIDO_LOCATOR = "0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb" +LIDO_LOCATOR_IMPL = "0x1D920cc5bACf7eE506a271a5259f2417CaDeCE1d" +LIDO_LOCATOR_IMPL_NEW = "0x39aFE23cE59e8Ef196b81F0DCb165E9aD38b9463" + +DEPOSITS_ENABLER_ROLE = "0x4b43b36766bde12c5e9cbbc37d15f8d1f769f08f54720ab370faeb4ce893753a" +L1_EMERGENCY_BRAKES_MULTISIG = "0x73b047fe6337183A454c5217241D780a932777bD" +L2_OPTIMISM_GOVERNANCE_EXECUTOR = "0xefa0db536d2c8089685630fafe88cf7805966fc3" +L1_OPTIMISM_PORTAL_2 = "0xbEb5Fc579115071764c7423A4f12eDde41f106Ed" + +L1_OPTIMISM_TOKENS_BRIDGE = "0x76943C0D61395d8F2edF9060e1533529cAe05dE6" +L1_OPTIMISM_TOKENS_BRIDGE_IMPL = "0x29C5c51A031165CE62F964966A6399b81165EFA4" +L1_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW = "0x168Cfea1Ad879d7032B3936eF3b0E90790b6B6D4" + +L2_OPTIMISM_TOKENS_BRIDGE = "0x8E01013243a96601a86eb3153F0d9Fa4fbFb6957" +L2_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW = "0x2734602C0CEbbA68662552CacD5553370B283E2E" +L2_OPTIMISM_WSTETH_TOKEN = "0x1F32b1c2345538c0c6f582fCB022739c4A194Ebb" +L2_OPTIMISM_WSTETH_TOKEN_IMPL_NEW = "0xFe57042De76c8D6B1DF0E9E2047329fd3e2B7334" + +DAI_TOKEN = "0x6b175474e89094c44da98b954eedeac495271d0f" +USDT_TOKEN = "0xdac17f958d2ee523a2206206994597c13d831ec7" +USDC_TOKEN = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + +def test_vote(helpers, accounts, vote_ids_from_env, stranger, ldo_holder): + # 1-5. Prepare required state for the voting + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + if l1_token_bridge.isDepositsEnabled(): + agent = accounts.at(AGENT, force=True) + l1_token_bridge.disableDeposits({"from": agent}) + + # 6. Prepare data before the voting + steth = interface.StETH("0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84") + alliance_ops_top_up_evm_script_factory_new = interface.TopUpAllowedRecipients( + "0xe5656eEe7eeD02bdE009d77C88247BC8271e26Eb" + ) + alliance_ops_allowed_recipients_registry = interface.AllowedRecipientRegistry( + "0x3B525F4c059F246Ca4aa995D21087204F30c9E2F" + ) + alliance_ops_top_up_evm_script_factory_new = interface.TopUpAllowedRecipients( + "0xe5656eEe7eeD02bdE009d77C88247BC8271e26Eb" + ) + alliance_multisig_acc = accounts.at("0x606f77BF3dd6Ed9790D9771C7003f269a385D942", force=True) + alliance_trusted_caller_acc = alliance_multisig_acc + + check_pre_upgrade_state() + wsteth_bridge_balance_before = contracts.wsteth.balanceOf(L1_OPTIMISM_TOKENS_BRIDGE) + + evm_script_factories_before = contracts.easy_track.getEVMScriptFactories() + assert alliance_ops_top_up_evm_script_factory_new not in evm_script_factories_before + + dai_token = interface.Dai(DAI_TOKEN) + dai_balance_before = dai_token.balanceOf(alliance_multisig_acc) + dai_transfer_amount = 1_000 * 10**18 + usdc_token = interface.Usdc(USDC_TOKEN) + usdc_balance_before = usdc_token.balanceOf(alliance_multisig_acc) + usdc_transfer_amount = 1_000 * 10**6 + usdt_token = interface.Usdt(USDT_TOKEN) + usdt_balance_before = usdt_token.balanceOf(alliance_multisig_acc) + usdt_transfer_amount = 1_000 * 10**6 + + # START VOTE + if len(vote_ids_from_env) > 0: + (vote_id,) = vote_ids_from_env + else: + vote_id, _ = start_vote({"from": ldo_holder}, silent=True) + + vote_tx = helpers.execute_vote(accounts, vote_id, contracts.voting) + + print(f"voteId = {vote_id}, gasUsed = {vote_tx.gas_used}") + display_voting_events(vote_tx) + evs = group_voting_events(vote_tx) + + # validate vote metadata + metadata = find_metadata_by_vote_id(vote_id) + assert get_lido_vote_cid_from_str(metadata) == "bafkreiacfthtkgooaeqvfwrlh5rz4betlgvwie7mp6besbhtsev75vyy2y" + + # validate vote events + assert count_vote_items_by_events(vote_tx, contracts.voting) == 6, "Incorrect voting items count" + + # 1-5 validation + check_post_upgrade_state(evs) + assert wsteth_bridge_balance_before == contracts.wsteth.balanceOf(L1_OPTIMISM_TOKENS_BRIDGE) + + # 6 validation + evm_script_factories_after = contracts.easy_track.getEVMScriptFactories() + assert alliance_ops_top_up_evm_script_factory_new in evm_script_factories_after + + check_add_and_remove_recipient_with_voting( + registry=alliance_ops_allowed_recipients_registry, + helpers=helpers, + ldo_holder=ldo_holder, + dao_voting=contracts.voting, + ) + + validate_evmscript_factory_added_event( + evs[5], + EVMScriptFactoryAdded( + factory_addr=alliance_ops_top_up_evm_script_factory_new, + permissions=create_permissions(contracts.finance, "newImmediatePayment") + + create_permissions(alliance_ops_allowed_recipients_registry, "updateSpentAmount")[2:], + ), + ) + + # transfer dai, usdc, usdt to alliance multisig and check that it was successful + create_and_enact_payment_motion( + contracts.easy_track, + trusted_caller=alliance_trusted_caller_acc, + factory=alliance_ops_top_up_evm_script_factory_new, + token=dai_token, + recievers=[alliance_multisig_acc], + transfer_amounts=[dai_transfer_amount], + stranger=stranger, + ) + + assert dai_token.balanceOf(alliance_multisig_acc) == dai_balance_before + dai_transfer_amount + + create_and_enact_payment_motion( + contracts.easy_track, + trusted_caller=alliance_trusted_caller_acc, + factory=alliance_ops_top_up_evm_script_factory_new, + token=usdc_token, + recievers=[alliance_multisig_acc], + transfer_amounts=[usdc_transfer_amount], + stranger=stranger, + ) + + assert usdc_token.balanceOf(alliance_multisig_acc) == usdc_balance_before + usdc_transfer_amount + + create_and_enact_payment_motion( + contracts.easy_track, + trusted_caller=alliance_trusted_caller_acc, + factory=alliance_ops_top_up_evm_script_factory_new, + token=usdt_token, + recievers=[alliance_multisig_acc], + transfer_amounts=[usdt_transfer_amount], + stranger=stranger, + ) + + assert usdt_token.balanceOf(alliance_multisig_acc) == usdt_balance_before + usdt_transfer_amount + + # check that transfer of steth is not allowed + with reverts("TOKEN_NOT_ALLOWED"): + create_and_enact_payment_motion( + contracts.easy_track, + trusted_caller=alliance_trusted_caller_acc, + factory=alliance_ops_top_up_evm_script_factory_new, + token=steth, + recievers=[alliance_multisig_acc], + transfer_amounts=[1], + stranger=stranger, + ) + + +def check_pre_upgrade_state(): + l1_token_bridge_proxy = interface.OssifiableProxy(L1_OPTIMISM_TOKENS_BRIDGE) + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + lido_locator_proxy = interface.OssifiableProxy(LIDO_LOCATOR) + + # Disabled deposits is the starting condition for the vote + assert not l1_token_bridge.isDepositsEnabled() + + # L1 Bridge has old implementation + assert ( + l1_token_bridge_proxy.proxy__getImplementation() == L1_OPTIMISM_TOKENS_BRIDGE_IMPL + ), "Old L1ERC20TokenBridge's implementation address is incorrect" + + # L1 Bridge doesn't have version before update + try: + l1_token_bridge.getContractVersion() + except VirtualMachineError: + pass + + # Upgrade LidoLocator implementation + assert ( + lido_locator_proxy.proxy__getImplementation() == LIDO_LOCATOR_IMPL + ), "Old LidoLocator's implementation address is incorrect" + + # Multisig hasn't been assigned as deposit enabler + assert not l1_token_bridge.hasRole(DEPOSITS_ENABLER_ROLE, L1_EMERGENCY_BRAKES_MULTISIG) + + +def check_post_upgrade_state(evs: List[EventDict]): + l1_token_bridge_proxy = interface.OssifiableProxy(L1_OPTIMISM_TOKENS_BRIDGE) + l1_token_bridge = interface.L1LidoTokensBridge(L1_OPTIMISM_TOKENS_BRIDGE) + lido_locator_proxy = interface.OssifiableProxy(LIDO_LOCATOR) + + # L1 Bridge has new implementation + assert ( + l1_token_bridge_proxy.proxy__getImplementation() == L1_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW + ), "New L1ERC20TokenBridge's implementation address is incorrect" + + # update L1 Bridge to 2 version + assert l1_token_bridge.getContractVersion() == 2 + + # check deposits are still paused + assert not l1_token_bridge.isDepositsEnabled() + + # LidoLocator has new implementation + assert ( + lido_locator_proxy.proxy__getImplementation() == LIDO_LOCATOR_IMPL_NEW + ), "New LidoLocator's implementation address is incorrect" + + # Multisig has been assigned as deposit enabler + assert l1_token_bridge.hasRole(DEPOSITS_ENABLER_ROLE, L1_EMERGENCY_BRAKES_MULTISIG) + + interface.OptimismPortal2(L1_OPTIMISM_PORTAL_2) # load OptimismPortal2 contract ABI to see events + + validate_contract_upgrade(evs[0], L1_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW) + validate_contract_finalization(evs[1], 2) + validate_contract_upgrade(evs[2], LIDO_LOCATOR_IMPL_NEW) + validate_grant_role_event(evs[3], DEPOSITS_ENABLER_ROLE, L1_EMERGENCY_BRAKES_MULTISIG, AGENT) + validate_optimism_upgrade_call( + evs[4], + L2_OPTIMISM_GOVERNANCE_EXECUTOR, + AGENT, + L2_OPTIMISM_TOKENS_BRIDGE, + L2_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW, + L2_OPTIMISM_WSTETH_TOKEN, + L2_OPTIMISM_WSTETH_TOKEN_IMPL_NEW, + ) + + +def validate_contract_upgrade(events: EventDict, implementation: str): + _events_chain = ["LogScriptCall", "LogScriptCall", "Upgraded", "ScriptResult"] + validate_events_chain([e.name for e in events], _events_chain) + assert events.count("Upgraded") == 1 + assert events["Upgraded"]["implementation"] == implementation, "Wrong implementation" + + +def validate_contract_finalization(events: EventDict, version: int): + _events_chain = ["LogScriptCall", "LogScriptCall", "ContractVersionSet", "ScriptResult"] + validate_events_chain([e.name for e in events], _events_chain) + assert events.count("ContractVersionSet") == 1 + assert events["ContractVersionSet"]["version"] == version + + +def validate_optimism_upgrade_call( + events: EventDict, + target: str, + sender: str, + l2_bridge_proxy: str, + l2_bridge_impl: str, + l2_wst_proxy: str, + l2_wst_impl: str, +): + _events_chain = [ + "LogScriptCall", + "LogScriptCall", + "TransactionDeposited", + "SentMessage", + "SentMessageExtension1", + "ScriptResult", + ] + validate_events_chain([e.name for e in events], _events_chain) + assert events.count("SentMessage") == 1 + + assert events["SentMessage"]["target"] == target + assert events["SentMessage"]["sender"] == sender + + # Check bytecode that was sent to messenger to update L2 bridge and wstETH token + encoded_l2_upgrade_call = encode_l2_upgrade_call(l2_bridge_proxy, l2_bridge_impl, l2_wst_proxy, l2_wst_impl) + assert events["SentMessage"]["message"] == encoded_l2_upgrade_call + + # Unparse and check l2 params + decoded_msg = decode_l2_message(events["SentMessage"]["message"].hex()) + + addresses = decoded_msg[0] + assert addresses[0] == L2_OPTIMISM_TOKENS_BRIDGE.lower() + assert addresses[1] == L2_OPTIMISM_TOKENS_BRIDGE.lower() + assert addresses[2] == L2_OPTIMISM_WSTETH_TOKEN.lower() + assert addresses[3] == L2_OPTIMISM_WSTETH_TOKEN.lower() + + values = decoded_msg[1] + assert values[0] == values[1] == values[2] == values[3] == 0 + + signatures = decoded_msg[2] + assert signatures[0] == "proxy__upgradeTo(address)" + assert signatures[1] == "finalizeUpgrade_v2()" + assert signatures[2] == "proxy__upgradeTo(address)" + assert signatures[3] == "finalizeUpgrade_v2(string,string)" + + calldatas = decoded_msg[3] + assert eth_abi.decode(["address"], calldatas[0])[0] == L2_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW.lower() + assert len(eth_abi.decode([], calldatas[1])) == 0 + assert eth_abi.decode(["address"], calldatas[2])[0] == L2_OPTIMISM_WSTETH_TOKEN_IMPL_NEW.lower() + assert eth_abi.decode(["string", "string"], calldatas[3])[0] == "Wrapped liquid staked Ether 2.0" + assert eth_abi.decode(["string", "string"], calldatas[3])[1] == "2" + + with_delegatecalls = decoded_msg[4] + assert with_delegatecalls[0] == with_delegatecalls[1] == with_delegatecalls[2] == with_delegatecalls[3] == False + + +def decode_l2_message(message: str): + queue_definition = f"queue(address[],uint256[],string[],bytes[],bool[])" + queue_selector = web3.keccak(text=queue_definition).hex()[2:10] + assert message.startswith(queue_selector) == True + message_without_queue_selector = message.removeprefix(queue_selector) + encoded_msg = eth_abi.decode(["address[]", "uint256[]", "string[]", "bytes[]", "bool[]"], bytes.fromhex(message_without_queue_selector)) + return encoded_msg diff --git a/configs/config_mainnet.py b/configs/config_mainnet.py index 9de530a4..43ba475e 100644 --- a/configs/config_mainnet.py +++ b/configs/config_mainnet.py @@ -71,6 +71,7 @@ # Multisigs FINANCE_MULTISIG = "0x48F300bD3C52c7dA6aAbDE4B683dEB27d38B9ABb" +L1_EMERGENCY_BRAKES_MULTISIG = "0x73b047fe6337183A454c5217241D780a932777bD" # Other INSURANCE_FUND = "0x8B3f33234ABD88493c0Cd28De33D583B70beDe35" @@ -79,7 +80,7 @@ BALANCER_REWARDS_MANAGER = "0x1dD909cDdF3dbe61aC08112dC0Fdf2Ab949f79D8" # Auxiliary addresses -LDO_HOLDER_ADDRESS_FOR_TESTS = "0x820fb25352bb0c5e03e07afc1d86252ffd2f0a18" +LDO_HOLDER_ADDRESS_FOR_TESTS = "0xAD4f7415407B83a081A0Bee22D05A8FDC18B42da" LDO_VOTE_EXECUTORS_FOR_TESTS = [ "0x3e40d73eb977dc6a537af587d48316fee66e9c8c", "0xb8d83908aab38a159f3da47a59d84db8e1838712", @@ -99,6 +100,7 @@ # LidoLocator LIDO_LOCATOR = "0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb" LIDO_LOCATOR_IMPL = "0x1D920cc5bACf7eE506a271a5259f2417CaDeCE1d" +LIDO_LOCATOR_IMPL_NEW = "0x39aFE23cE59e8Ef196b81F0DCb165E9aD38b9463" # Other upgrade addresses LIDO_V2_UPGRADE_TEMPLATE = "0xa818fF9EC93122Bf9401ab4340C42De638CD600a" @@ -302,6 +304,26 @@ OBOL_LIDO_SPLIT_FACTORY = "0xA9d94139A310150Ca1163b5E23f3E1dbb7D9E2A6" OBOL_LIDO_SPLIT_IMPL = "0x2fB59065F049e0D0E3180C6312FA0FeB5Bbf0FE3" +# Ethereum Part for Optimism bridge +L1_TOKEN_RATE_NOTIFIER = "0xe6793B9e4FbA7DE0ee833F9D02bba7DB5EB27823" +L1_OPTIMISM_TOKEN_RATE_PUSHER = "0xd54c1c6413caac3477AC14b2a80D5398E3c32FfE" +L1_OPTIMISM_TOKENS_BRIDGE = "0x76943C0D61395d8F2edF9060e1533529cAe05dE6" +L1_OPTIMISM_TOKENS_BRIDGE_IMPL = "0x29C5c51A031165CE62F964966A6399b81165EFA4" +L1_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW = "0x168Cfea1Ad879d7032B3936eF3b0E90790b6B6D4" +L1_OPTIMISM_CROSS_DOMAIN_MESSENGER = "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1" + +## Optimism Part of Optimism bridge +L2_OPTIMISM_GOVERNANCE_EXECUTOR = "0xefa0db536d2c8089685630fafe88cf7805966fc3" +L2_OPTIMISM_TOKENS_BRIDGE = "0x8E01013243a96601a86eb3153F0d9Fa4fbFb6957" +L2_OPTIMISM_TOKENS_BRIDGE_IMPL = "0x23B96aDD54c479C6784Dd504670B5376B808f4C7" +L2_OPTIMISM_TOKENS_BRIDGE_IMPL_NEW = "0x2734602C0CEbbA68662552CacD5553370B283E2E" +L2_OPTIMISM_TOKEN_RATE_ORACLE = "0x294ED1f214F4e0ecAE31C3Eae4F04EBB3b36C9d0" +L2_OPTIMISM_STETH_TOKEN = "0x76A50b8c7349cCDDb7578c6627e79b5d99D24138" +L2_OPTIMISM_STETH_TOKEN_IMPL = "0xe9b65dA5DcBe92f1b397991C464FF568Dc98D761" +L2_OPTIMISM_WSTETH_TOKEN = "0x1F32b1c2345538c0c6f582fCB022739c4A194Ebb" +L2_OPTIMISM_WSTETH_TOKEN_IMPL = "0x92834c37dF982A13bb0f8C3F6608E26F0546538e" +L2_OPTIMISM_WSTETH_TOKEN_IMPL_NEW = "0xFe57042De76c8D6B1DF0E9E2047329fd3e2B7334" + # TRP TRP_VESTING_ESCROW_FACTORY = "0xDA1DF6442aFD2EC36aBEa91029794B9b2156ADD0" TRP_FACTORY_DEPLOY_BLOCK_NUMBER = 16540381 diff --git a/configs/config_sepolia.py b/configs/config_sepolia.py index 45f6ce7f..0766ab89 100644 --- a/configs/config_sepolia.py +++ b/configs/config_sepolia.py @@ -55,3 +55,143 @@ WSTETH_TOKEN = "0xB82381A3fBD3FaFA77B3a7bE693342618240067b" CHAIN_DEPOSIT_CONTRACT = "0x7f02C3E3c98b133055B8B348B2Ac625669Ed295D" + +EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER = "" +EASYTRACK_SIMPLE_DVT_ADD_NODE_OPERATORS_FACTORY = "" +EASYTRACK_SIMPLE_DVT_SET_VETTED_VALIDATORS_LIMITS_FACTORY = "" + +ACCOUNTING_ORACLE_IMPL = None +TOTAL_NON_COVER_SHARES_BURNT = None +DEPOSIT_SECURITY_MODULE = None +GATE_SEAL_EXPIRY_TIMESTAMP = None +LEGACY_ORACLE = None +LIDO_IMPL = None +LIDO_LOCATOR_IMPL = None +NODE_OPERATORS_REGISTRY = None +NORMALIZED_CL_REWARD_PER_EPOCH = None +CHURN_VALIDATORS_PER_DAY_LIMIT = None +SIMPLE_DVT = None +STAKING_ROUTER_IMPL = None +VALIDATORS_EXIT_BUS_ORACLE = None +VALIDATORS_EXIT_BUS_ORACLE_IMPL = None +WITHDRAWAL_QUEUE = "0x1583C7b3f4C3B008720E6BcE5726336b0aB25fdd" +WITHDRAWAL_VAULT_IMPL = None +MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT = None +EASYTRACK_INCREASE_NOP_STAKING_LIMIT_FACTORY = None +WETH_TOKEN = None +EASYTRACK_EVMSCRIPT_EXECUTOR = None +AO_EPOCHS_PER_FRAME = None +TOTAL_COVER_SHARES_BURNT = None +DSM_MAX_DEPOSITS_PER_BLOCK = None +GATE_SEAL_PAUSE_DURATION = None +LEGACY_ORACLE_IMPL = None +INITIAL_DEAD_TOKEN_HOLDER = None +NODE_OPERATORS_REGISTRY_IMPL = None +NORMALIZED_CL_REWARD_MISTAKE_RATE_BP = None +ONE_OFF_CL_BALANCE_DECREASE_BP_LIMIT = None +SIMPLE_DVT_IMPL = None +SR_MODULES_FEE_BP = None +CHAIN_SLOTS_PER_EPOCH = None +WITHDRAWAL_QUEUE_IMPL = None +MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT = None +EASYTRACK_SIMPLE_DVT_ACTIVATE_NODE_OPERATORS_FACTORY = None +ARAGON_EVMSCRIPT_REGISTRY = None +AO_FAST_LANE_LENGTH_SLOTS = None +DSM_MIN_DEPOSIT_BLOCK_DISTANCE = None +GATE_SEAL_COMMITTEE = None +ORACLE_ARAGON_APP_ID = None +LIDO_ARAGON_APP_ID = None +NODE_OPERATORS_REGISTRY_ARAGON_APP_ID = None +REBASE_CHECK_NEAREST_EPOCH_DISTANCE = None +ANNUAL_BALANCE_INCREASE_BP_LIMIT = None +SIMPLE_DVT_ARAGON_APP_ID = None +SR_TREASURY_FEE_BP = None +CHAIN_SECONDS_PER_SLOT = None +WQ_ERC721_TOKEN_NAME = None +EASYTRACK_SIMPLE_DVT_DEACTIVATE_NODE_OPERATORS_FACTORY = None +ACL_DEPLOY_BLOCK_NUMBER = None +CHAIN_GENESIS_TIME = None +DSM_PAUSE_INTENT_VALIDITY_PERIOD_BLOCKS = None +LIDO_MAX_STAKE_LIMIT_ETH = None +CURATED_STAKING_MODULE_STUCK_PENALTY_DELAY = None +REBASE_CHECK_DISTANT_EPOCH_DISTANCE = None +SIMULATED_SHARE_RATE_DEVIATION_BP_LIMIT = None +SIMPLE_DVT_MODULE_STUCK_PENALTY_DELAY = None +SR_MODULES_FEE_E20 = None +WQ_ERC721_TOKEN_SYMBOL = None +EASYTRACK_SIMPLE_DVT_SET_NODE_OPERATOR_NAMES_FACTORY = None +DAI_TOKEN = None +MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT = None +ORACLE_QUORUM = None +DSM_GUARDIAN_QUORUM = None +CURATED_STAKING_MODULE_OPERATORS_COUNT = None +VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS = None +REQUEST_TIMESTAMP_MARGIN = None +SIMPLE_DVT_MODULE_TYPE = None +SR_TREASURY_FEE_E20 = None +VEBO_EPOCHS_PER_FRAME = None +WQ_ERC721_TOKEN_BASE_URI = None +EASYTRACK_SIMPLE_DVT_SET_NODE_OPERATOR_REWARD_ADDRESSES_FACTORY = None +REQUEST_TIMESTAMP_MARGIN = None +AO_CONSENSUS_VERSION = None +CURATED_STAKING_MODULE_OPERATORS_ACTIVE_COUNT = None +VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS = None +MAX_POSITIVE_TOKEN_REBASE = None +EASYTRACK_SIMPLE_DVT_UPDATE_TARGET_VALIDATOR_LIMITS_FACTORY = None +SR_BASE_PRECISION_E20 = None +VEBO_FAST_LANE_LENGTH_SLOTS = None +CURATED_STAKING_MODULE_TYPE = None +PREDICTION_DURATION_IN_SLOTS = None +EASYTRACK_SIMPLE_DVT_CHANGE_NODE_OPERATOR_MANAGERS_FACTORY = None +CURATED_STAKING_MODULE_NAME = None +CURATED_STAKING_MODULE_ID = None +CURATED_STAKING_MODULE_TARGET_SHARE_BP = None +CURATED_STAKING_MODULE_MODULE_FEE_BP = None +CURATED_STAKING_MODULE_TREASURY_FEE_BP = None +NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP = None +FINALIZATION_MAX_NEGATIVE_REBASE_EPOCH_SHIFT = None +VEBO_CONSENSUS_VERSION = None +EASYTRACK_SIMPLE_DVT_CHANGE_NODE_OPERATOR_MANAGERS_FACTORY = None +WITHDRAWAL_CREDENTIALS = None + +# NodeOperatorsRegistry clone aka SimpleDVT +SIMPLE_DVT_IMPL = "0x8538930c385C0438A357d2c25CB3eAD95Ab6D8ed" +## see SimpleDVT's proxy appId() +SIMPLE_DVT_ARAGON_APP_NAME = "simple-dvt" +SIMPLE_DVT_ARAGON_APP_ID = "0xe1635b63b5f7b5e545f2a637558a4029dea7905361a2f0fc28c66e9136cf86a4" +SIMPLE_DVT_MODULE_STUCK_PENALTY_DELAY = 432000 +SIMPLE_DVT_MODULE_TARGET_SHARE_BP = 50 +SIMPLE_DVT_MODULE_MODULE_FEE_BP = 800 +SIMPLE_DVT_MODULE_TREASURY_FEE_BP = 200 +SIMPLE_DVT_MODULE_ID = 2 +SIMPLE_DVT_MODULE_NAME = "SimpleDVT" +SIMPLE_DVT_MODULE_TYPE = ( + # bytes32("curated-onchain-v1") + "0x637572617465642d6f6e636861696e2d76310000000000000000000000000000" +) + + +# stETH on optimism +## L1 +L1_OPTIMISM_TOKENS_BRIDGE = "0x4Abf633d9c0F4aEebB4C2E3213c7aa1b8505D332" +L1_OPTIMISM_CROSS_DOMAIN_MESSENGER = "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef" +L1_OP_STACK_TOKEN_RATE_PUSHER = "0xa72AE76Ba8Bd44b734FdCbB1A173aec069FDbb5C" +L1_TOKEN_RATE_NOTIFIER_PROXY = "0x3B0db4a2004b02F62e48BAF9dA706b7F789b0258" +L1_EMERGENCY_BRAKES_MULTISIG = "0xa5F1d7D49F581136Cf6e58B32cBE9a2039C48bA1" +## L2 +L2_TOKENS_BRIDGE_PROXY = "0xdBA2760246f315203F8B716b3a7590F0FFdc704a" +L2_OPTIMISM_BRIDGE_EXECUTOR = "0xf695357C66bA514150Da95b189acb37b46DDe602" +L2_STETH_TOKEN_PROXY = "0xdF6FAF146E7508317df7d23b89B02D6d4ADFE8C1" +L2_TOKEN_RATE_ORACLE_PROXY = "0x3E86Ed02EDeF6f9B398493B58a09380bb661d81" +L2_OPTIMISM_WSTETH_TOKEN = "0x24B47cd3A74f1799b32B2de11073764Cb1bb318B" + +# stETH on optimism - only for upgrade +## L1 +LIDO_LOCATOR_IMPL_UPGRADE = "0x314Ab8D774c0580942E832f971Bbc7A27B1c2552" +L1_TOKENS_BRIDGE_NEW_IMPL = "0x8375029773953d91CaCfa452b7D24556b9F318AA" +L1_TOKEN_RATE_NOTIFIER_IMPL = "0x2EC2a213cc8086c42856630841CcACb7Bdd29ADf" +## L2 Optimism +L2_STETH_TOKEN_IMPL = "0x2De0D0bA2475a1D5F7813acdCdeba0c7C4d24ff6" +L2_TOKENS_BRIDGE_NEW_IMPL = "0xD48c69358193a34aC035ea7dfB70daDea1600112" +L2_OPTIMISM_WSTETH_TOKEN_NEW_IMPL = "0x298953B9426eba4F35a137a4754278a16d97A063" +L2_TOKEN_RATE_ORACLE_IMPL = "0x4EB53FaF5B1cf1fCa0339D5E54Cba1C0Af49B97B" diff --git a/contracts/OpStackTokenRatePusherWithSomeErrorStub.sol b/contracts/OpStackTokenRatePusherWithSomeErrorStub.sol new file mode 100644 index 00000000..fb91cc71 --- /dev/null +++ b/contracts/OpStackTokenRatePusherWithSomeErrorStub.sol @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2024 Lido +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity 0.8.10; + +interface ITokenRatePusher { + function pushTokenRate() external; +} + +interface IERC165 { + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +abstract contract ERC165 is IERC165 { + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + +/// @dev For testing purposes. +contract OpStackTokenRatePusherWithSomeErrorStub is ERC165, ITokenRatePusher { + + error SomeError(); + + function pushTokenRate() pure external { + revert SomeError(); + } + + /// @inheritdoc ERC165 + function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) { + return ( + _interfaceId == type(ITokenRatePusher).interfaceId + || super.supportsInterface(_interfaceId) + ); + } +} diff --git a/interfaces/ERC20BridgedPermit.json b/interfaces/ERC20BridgedPermit.json new file mode 100644 index 00000000..d9769779 --- /dev/null +++ b/interfaces/ERC20BridgedPermit.json @@ -0,0 +1,608 @@ +[ + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + }, + { + "internalType": "string", + "name": "version_", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + }, + { + "internalType": "address", + "name": "bridge_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrorAccountIsZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorDeadlineExpired", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorInvalidSignature", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorMetadataIsAlreadyInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorMetadataIsNotInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorNameIsEmpty", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorNotBridge", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorNotEnoughAllowance", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorNotEnoughBalance", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorSymbolIsEmpty", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressBridge", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroDecimals", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidContractVersionIncrement", + "type": "error" + }, + { + "inputs": [], + "name": "NonZeroContractVersionOnInit", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "UnexpectedContractVersion", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "version", + "type": "uint256" + } + ], + "name": "ContractVersionSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bridge", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "name": "bridgeBurn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "name": "bridgeMint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "eip712Domain", + "outputs": [ + { + "internalType": "bytes1", + "name": "fields", + "type": "bytes1" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "verifyingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "extensions", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "version_", + "type": "string" + } + ], + "name": "finalizeUpgrade_v2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getContractVersion", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + }, + { + "internalType": "string", + "name": "version_", + "type": "string" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + }, + { + "internalType": "address", + "name": "spender_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline_", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signature_", + "type": "bytes" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + }, + { + "internalType": "address", + "name": "spender_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline_", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v_", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r_", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s_", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from_", + "type": "address" + }, + { + "internalType": "address", + "name": "to_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] diff --git a/interfaces/ITokenRateUpdatable.json b/interfaces/ITokenRateUpdatable.json new file mode 100644 index 00000000..8414ddfb --- /dev/null +++ b/interfaces/ITokenRateUpdatable.json @@ -0,0 +1,20 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenRate_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rateUpdatedL1Timestamp_", + "type": "uint256" + } + ], + "name": "updateRate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/interfaces/L1LidoTokensBridge.json b/interfaces/L1LidoTokensBridge.json new file mode 100644 index 00000000..3162c641 --- /dev/null +++ b/interfaces/L1LidoTokensBridge.json @@ -0,0 +1,963 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "messenger_", + "type": "address" + }, + { + "internalType": "address", + "name": "l2TokenBridge_", + "type": "address" + }, + { + "internalType": "address", + "name": "l1TokenNonRebasable_", + "type": "address" + }, + { + "internalType": "address", + "name": "l1TokenRebasable_", + "type": "address" + }, + { + "internalType": "address", + "name": "l2TokenNonRebasable_", + "type": "address" + }, + { + "internalType": "address", + "name": "l2TokenRebasable_", + "type": "address" + }, + { + "internalType": "address", + "name": "accountingOracle_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrorAccountIsZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorAlreadyInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorBridgingManagerIsNotInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorDepositsDisabled", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorDepositsEnabled", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorSenderNotEOA", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorUnauthorizedMessenger", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "l1Token", + "type": "address" + }, + { + "internalType": "address", + "name": "l2Token", + "type": "address" + } + ], + "name": "ErrorUnsupportedL1L2TokensPair", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "l2Token", + "type": "address" + } + ], + "name": "ErrorUnsupportedL2Token", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorWithdrawalsDisabled", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorWithdrawalsEnabled", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorWrongCrossDomainSender", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressAccountingOracle", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressAdmin", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressL1TokenNonRebasable", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressL1TokenRebasable", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressL2Bridge", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressL2TokenNonRebasable", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressL2TokenRebasable", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressMessenger", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressWstETH", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidContractVersionIncrement", + "type": "error" + }, + { + "inputs": [], + "name": "NonZeroContractVersionOnInit", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "UnexpectedContractVersion", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "version", + "type": "uint256" + } + ], + "name": "ContractVersionSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "disabler", + "type": "address" + } + ], + "name": "DepositsDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "enabler", + "type": "address" + } + ], + "name": "DepositsEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_l1Token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_l2Token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "ERC20DepositInitiated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_l1Token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_l2Token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "ERC20WithdrawalFinalized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "admin", + "type": "address" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "disabler", + "type": "address" + } + ], + "name": "WithdrawalsDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "enabler", + "type": "address" + } + ], + "name": "WithdrawalsEnabled", + "type": "event" + }, + { + "inputs": [], + "name": "ACCOUNTING_ORACLE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEPOSITS_DISABLER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEPOSITS_ENABLER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GENESIS_TIME", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L1_TOKEN_NON_REBASABLE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L1_TOKEN_REBASABLE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L2_TOKEN_NON_REBASABLE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L2_TOKEN_REBASABLE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MESSENGER", + "outputs": [ + { + "internalType": "contract ICrossDomainMessenger", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SECONDS_PER_SLOT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TOKEN_RATE_DECIMALS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WITHDRAWALS_DISABLER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WITHDRAWALS_ENABLER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WSTETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "l1Token_", + "type": "address" + }, + { + "internalType": "address", + "name": "l2Token_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "l2Gas_", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "data_", + "type": "bytes" + } + ], + "name": "depositERC20", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "l1Token_", + "type": "address" + }, + { + "internalType": "address", + "name": "l2Token_", + "type": "address" + }, + { + "internalType": "address", + "name": "to_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "l2Gas_", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "data_", + "type": "bytes" + } + ], + "name": "depositERC20To", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disableDeposits", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disableWithdrawals", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "enableDeposits", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "enableWithdrawals", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "l1Token_", + "type": "address" + }, + { + "internalType": "address", + "name": "l2Token_", + "type": "address" + }, + { + "internalType": "address", + "name": "from_", + "type": "address" + }, + { + "internalType": "address", + "name": "to_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data_", + "type": "bytes" + } + ], + "name": "finalizeERC20Withdrawal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeUpgrade_v2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getContractVersion", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "admin_", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isDepositsEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isWithdrawalsEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l2TokenBridge", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ] diff --git a/interfaces/L2ERC20ExtendedTokensBridge.json b/interfaces/L2ERC20ExtendedTokensBridge.json new file mode 100644 index 00000000..81bf4e23 --- /dev/null +++ b/interfaces/L2ERC20ExtendedTokensBridge.json @@ -0,0 +1,883 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "messenger_", + "type": "address" + }, + { + "internalType": "address", + "name": "l1TokenBridge_", + "type": "address" + }, + { + "internalType": "address", + "name": "l1TokenNonRebasable_", + "type": "address" + }, + { + "internalType": "address", + "name": "l1TokenRebasable_", + "type": "address" + }, + { + "internalType": "address", + "name": "l2TokenNonRebasable_", + "type": "address" + }, + { + "internalType": "address", + "name": "l2TokenRebasable_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrorAccountIsZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorAlreadyInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorBridgingManagerIsNotInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorDepositDataLength", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorDepositsDisabled", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorDepositsEnabled", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorSenderNotEOA", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorTransferToL1TokenContract", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorUnauthorizedMessenger", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "l1Token", + "type": "address" + }, + { + "internalType": "address", + "name": "l2Token", + "type": "address" + } + ], + "name": "ErrorUnsupportedL1L2TokensPair", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "l2Token", + "type": "address" + } + ], + "name": "ErrorUnsupportedL2Token", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorWithdrawalsDisabled", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorWithdrawalsEnabled", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorWrongCrossDomainSender", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressAdmin", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressL1Bridge", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressL1TokenNonRebasable", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressL1TokenRebasable", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressL2TokenNonRebasable", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressL2TokenRebasable", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressMessenger", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidContractVersionIncrement", + "type": "error" + }, + { + "inputs": [], + "name": "NonZeroContractVersionOnInit", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "received", + "type": "uint256" + } + ], + "name": "UnexpectedContractVersion", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "version", + "type": "uint256" + } + ], + "name": "ContractVersionSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_l1Token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_l2Token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "DepositFinalized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "disabler", + "type": "address" + } + ], + "name": "DepositsDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "enabler", + "type": "address" + } + ], + "name": "DepositsEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "admin", + "type": "address" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_l1Token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_l2Token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "WithdrawalInitiated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "disabler", + "type": "address" + } + ], + "name": "WithdrawalsDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "enabler", + "type": "address" + } + ], + "name": "WithdrawalsEnabled", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEPOSITS_DISABLER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEPOSITS_ENABLER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L1_TOKEN_NON_REBASABLE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L1_TOKEN_REBASABLE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L2_TOKEN_NON_REBASABLE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L2_TOKEN_REBASABLE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MESSENGER", + "outputs": [ + { + "internalType": "contract ICrossDomainMessenger", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WITHDRAWALS_DISABLER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WITHDRAWALS_ENABLER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "disableDeposits", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disableWithdrawals", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "enableDeposits", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "enableWithdrawals", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "l1Token_", + "type": "address" + }, + { + "internalType": "address", + "name": "l2Token_", + "type": "address" + }, + { + "internalType": "address", + "name": "from_", + "type": "address" + }, + { + "internalType": "address", + "name": "to_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data_", + "type": "bytes" + } + ], + "name": "finalizeDeposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "finalizeUpgrade_v2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getContractVersion", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "admin_", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isDepositsEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isWithdrawalsEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1TokenBridge", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "l2Token_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "l1Gas_", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "data_", + "type": "bytes" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "l2Token_", + "type": "address" + }, + { + "internalType": "address", + "name": "to_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "l1Gas_", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "data_", + "type": "bytes" + } + ], + "name": "withdrawTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] diff --git a/interfaces/OpBridgeExecutor.json b/interfaces/OpBridgeExecutor.json new file mode 100644 index 00000000..f3f080da --- /dev/null +++ b/interfaces/OpBridgeExecutor.json @@ -0,0 +1,705 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "l2ScrollMessenger", + "type": "address" + }, + { + "internalType": "address", + "name": "ethereumGovernanceExecutor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "delay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gracePeriod", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumDelay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maximumDelay", + "type": "uint256" + }, + { + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "DelayLongerThanMax", + "type": "error" + }, + { + "inputs": [], + "name": "DelayShorterThanMin", + "type": "error" + }, + { + "inputs": [], + "name": "DuplicateAction", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyTargets", + "type": "error" + }, + { + "inputs": [], + "name": "FailedActionExecution", + "type": "error" + }, + { + "inputs": [], + "name": "GracePeriodTooShort", + "type": "error" + }, + { + "inputs": [], + "name": "InconsistentParamsLength", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidActionsSetId", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitParams", + "type": "error" + }, + { + "inputs": [], + "name": "MaximumDelayTooShort", + "type": "error" + }, + { + "inputs": [], + "name": "MinimumDelayTooLong", + "type": "error" + }, + { + "inputs": [], + "name": "NotGuardian", + "type": "error" + }, + { + "inputs": [], + "name": "OnlyCallableByThis", + "type": "error" + }, + { + "inputs": [], + "name": "OnlyQueuedActions", + "type": "error" + }, + { + "inputs": [], + "name": "TimelockNotFinished", + "type": "error" + }, + { + "inputs": [], + "name": "UnauthorizedEthereumExecutor", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "ActionsSetCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "initiatorExecution", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes[]", + "name": "returnedData", + "type": "bytes[]" + } + ], + "name": "ActionsSetExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "indexed": false, + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "indexed": false, + "internalType": "bool[]", + "name": "withDelegatecalls", + "type": "bool[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "executionTime", + "type": "uint256" + } + ], + "name": "ActionsSetQueued", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldDelay", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newDelay", + "type": "uint256" + } + ], + "name": "DelayUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldEthereumGovernanceExecutor", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newEthereumGovernanceExecutor", + "type": "address" + } + ], + "name": "EthereumGovernanceExecutorUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldGracePeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newGracePeriod", + "type": "uint256" + } + ], + "name": "GracePeriodUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldGuardian", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newGuardian", + "type": "address" + } + ], + "name": "GuardianUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldMaximumDelay", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMaximumDelay", + "type": "uint256" + } + ], + "name": "MaximumDelayUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldMinimumDelay", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMinimumDelay", + "type": "uint256" + } + ], + "name": "MinimumDelayUpdate", + "type": "event" + }, + { + "inputs": [], + "name": "L2_SCROLL_MESSENGER", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actionsSetId", + "type": "uint256" + } + ], + "name": "cancel", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actionsSetId", + "type": "uint256" + } + ], + "name": "execute", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "executeDelegateCall", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actionsSetId", + "type": "uint256" + } + ], + "name": "getActionsSetById", + "outputs": [ + { + "components": [ + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "bool[]", + "name": "withDelegatecalls", + "type": "bool[]" + }, + { + "internalType": "uint256", + "name": "executionTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "executed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "canceled", + "type": "bool" + } + ], + "internalType": "struct IExecutorBase.ActionsSet", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getActionsSetCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actionsSetId", + "type": "uint256" + } + ], + "name": "getCurrentState", + "outputs": [ + { + "internalType": "enum IExecutorBase.ActionsSetState", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDelay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEthereumGovernanceExecutor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getGracePeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getGuardian", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMaximumDelay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMinimumDelay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "actionHash", + "type": "bytes32" + } + ], + "name": "isActionQueued", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "bool[]", + "name": "withDelegatecalls", + "type": "bool[]" + } + ], + "name": "queue", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "receiveFunds", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "delay", + "type": "uint256" + } + ], + "name": "updateDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "ethereumGovernanceExecutor", + "type": "address" + } + ], + "name": "updateEthereumGovernanceExecutor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "gracePeriod", + "type": "uint256" + } + ], + "name": "updateGracePeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "updateGuardian", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "maximumDelay", + "type": "uint256" + } + ], + "name": "updateMaximumDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "minimumDelay", + "type": "uint256" + } + ], + "name": "updateMinimumDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/interfaces/OpCrossDomainMessenger.json b/interfaces/OpCrossDomainMessenger.json new file mode 100644 index 00000000..2aeb3547 --- /dev/null +++ b/interfaces/OpCrossDomainMessenger.json @@ -0,0 +1,464 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + } + ], + "name": "FailedRelayedMessage", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + } + ], + "name": "RelayedMessage", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "message", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "messageNonce", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "gasLimit", + "type": "uint256" + } + ], + "name": "SentMessage", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SentMessageExtension1", + "type": "event" + }, + { + "inputs": [], + "name": "MESSAGE_VERSION", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_GAS_CALLDATA_OVERHEAD", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OTHER_MESSENGER", + "outputs": [ + { + "internalType": "contract CrossDomainMessenger", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PORTAL", + "outputs": [ + { + "internalType": "contract OptimismPortal", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RELAY_CALL_OVERHEAD", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RELAY_CONSTANT_OVERHEAD", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RELAY_GAS_CHECK_BUFFER", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RELAY_RESERVED_GAS", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_message", + "type": "bytes" + }, + { + "internalType": "uint32", + "name": "_minGasLimit", + "type": "uint32" + } + ], + "name": "baseGas", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "failedMessages", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract SuperchainConfig", + "name": "_superchainConfig", + "type": "address" + }, + { + "internalType": "contract OptimismPortal", + "name": "_portal", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "messageNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "otherMessenger", + "outputs": [ + { + "internalType": "contract CrossDomainMessenger", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "portal", + "outputs": [ + { + "internalType": "contract OptimismPortal", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_nonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_sender", + "type": "address" + }, + { + "internalType": "address", + "name": "_target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_minGasLimit", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_message", + "type": "bytes" + } + ], + "name": "relayMessage", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_message", + "type": "bytes" + }, + { + "internalType": "uint32", + "name": "_minGasLimit", + "type": "uint32" + } + ], + "name": "sendMessage", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "successfulMessages", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "superchainConfig", + "outputs": [ + { + "internalType": "contract SuperchainConfig", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "xDomainMessageSender", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/interfaces/OptimismPortal2.json b/interfaces/OptimismPortal2.json new file mode 100644 index 00000000..eae9bdc1 --- /dev/null +++ b/interfaces/OptimismPortal2.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint256","name":"_proofMaturityDelaySeconds","type":"uint256"},{"internalType":"uint256","name":"_disputeGameFinalityDelaySeconds","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadTarget","type":"error"},{"inputs":[],"name":"CallPaused","type":"error"},{"inputs":[],"name":"ContentLengthMismatch","type":"error"},{"inputs":[],"name":"EmptyItem","type":"error"},{"inputs":[],"name":"GasEstimation","type":"error"},{"inputs":[],"name":"InvalidDataRemainder","type":"error"},{"inputs":[],"name":"InvalidHeader","type":"error"},{"inputs":[],"name":"LargeCalldata","type":"error"},{"inputs":[],"name":"OutOfGas","type":"error"},{"inputs":[],"name":"SmallGasLimit","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnexpectedList","type":"error"},{"inputs":[],"name":"UnexpectedString","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IDisputeGame","name":"disputeGame","type":"address"}],"name":"DisputeGameBlacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"GameType","name":"newGameType","type":"uint32"},{"indexed":true,"internalType":"Timestamp","name":"updatedAt","type":"uint64"}],"name":"RespectedGameTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"version","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"opaqueData","type":"bytes"}],"name":"TransactionDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"withdrawalHash","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"}],"name":"WithdrawalFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"withdrawalHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"WithdrawalProven","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"withdrawalHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"proofSubmitter","type":"address"}],"name":"WithdrawalProvenExtension1","type":"event"},{"inputs":[{"internalType":"contract IDisputeGame","name":"_disputeGame","type":"address"}],"name":"blacklistDisputeGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalHash","type":"bytes32"},{"internalType":"address","name":"_proofSubmitter","type":"address"}],"name":"checkWithdrawal","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint64","name":"_gasLimit","type":"uint64"},{"internalType":"bool","name":"_isCreation","type":"bool"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"depositTransaction","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDisputeGame","name":"","type":"address"}],"name":"disputeGameBlacklist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disputeGameFactory","outputs":[{"internalType":"contract DisputeGameFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disputeGameFinalityDelaySeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"donateETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Types.WithdrawalTransaction","name":"_tx","type":"tuple"}],"name":"finalizeWithdrawalTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Types.WithdrawalTransaction","name":"_tx","type":"tuple"},{"internalType":"address","name":"_proofSubmitter","type":"address"}],"name":"finalizeWithdrawalTransactionExternalProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"finalizedWithdrawals","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract DisputeGameFactory","name":"_disputeGameFactory","type":"address"},{"internalType":"contract SystemConfig","name":"_systemConfig","type":"address"},{"internalType":"contract SuperchainConfig","name":"_superchainConfig","type":"address"},{"internalType":"GameType","name":"_initialRespectedGameType","type":"uint32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"l2Sender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_byteCount","type":"uint64"}],"name":"minimumGasLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalHash","type":"bytes32"}],"name":"numProofSubmitters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"params","outputs":[{"internalType":"uint128","name":"prevBaseFee","type":"uint128"},{"internalType":"uint64","name":"prevBoughtGas","type":"uint64"},{"internalType":"uint64","name":"prevBlockNum","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proofMaturityDelaySeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"proofSubmitters","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Types.WithdrawalTransaction","name":"_tx","type":"tuple"},{"internalType":"uint256","name":"_disputeGameIndex","type":"uint256"},{"components":[{"internalType":"bytes32","name":"version","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"internalType":"bytes32","name":"messagePasserStorageRoot","type":"bytes32"},{"internalType":"bytes32","name":"latestBlockhash","type":"bytes32"}],"internalType":"struct Types.OutputRootProof","name":"_outputRootProof","type":"tuple"},{"internalType":"bytes[]","name":"_withdrawalProof","type":"bytes[]"}],"name":"proveWithdrawalTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"provenWithdrawals","outputs":[{"internalType":"contract IDisputeGame","name":"disputeGameProxy","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"respectedGameType","outputs":[{"internalType":"GameType","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"respectedGameTypeUpdatedAt","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"GameType","name":"_gameType","type":"uint32"}],"name":"setRespectedGameType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"superchainConfig","outputs":[{"internalType":"contract SuperchainConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"systemConfig","outputs":[{"internalType":"contract SystemConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}] diff --git a/interfaces/TokenRateNotifier.json b/interfaces/TokenRateNotifier.json new file mode 100644 index 00000000..c9545906 --- /dev/null +++ b/interfaces/TokenRateNotifier.json @@ -0,0 +1,313 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "initialOwner_", + "type": "address" + }, + { + "internalType": "address", + "name": "lido_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrorAddExistedObserver", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorBadObserverInterface", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorMaxObserversCountExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorNoObserverToRemove", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorNotAuthorizedRebaseCaller", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorTokenRateNotifierRevertedWithNoData", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressLido", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressObserver", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorZeroAddressOwner", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "observer", + "type": "address" + } + ], + "name": "ObserverAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "observer", + "type": "address" + } + ], + "name": "ObserverRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "observer", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "lowLevelRevertData", + "type": "bytes" + } + ], + "name": "PushTokenRateFailed", + "type": "event" + }, + { + "inputs": [], + "name": "INDEX_NOT_FOUND", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "LIDO", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_OBSERVERS_COUNT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "REQUIRED_INTERFACE", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "observer_", + "type": "address" + } + ], + "name": "addObserver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "handlePostTokenRebase", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "observers", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "observersLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "observer_", + "type": "address" + } + ], + "name": "removeObserver", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/network-config.yaml b/network-config.yaml index 179fb0ad..0bfe78a6 100644 --- a/network-config.yaml +++ b/network-config.yaml @@ -10,8 +10,8 @@ live: multicall2: "0xcA11bde05977b3631167028862bE2a173976CA11" name: Holesky (Infura) provider: infura -development: +development: - cmd: ./ganache.sh cmd_settings: accounts: 10 @@ -19,6 +19,7 @@ development: gas_limit: 30000000 mnemonic: brownie port: 8545 + evm_version: london host: http://127.0.0.1 id: mainnet-fork name: Ganache-CLI (Mainnet Fork) diff --git a/tests/acceptance/test_accounting_oracle.py b/tests/acceptance/test_accounting_oracle.py index 3be6bc2f..94364f92 100644 --- a/tests/acceptance/test_accounting_oracle.py +++ b/tests/acceptance/test_accounting_oracle.py @@ -17,7 +17,6 @@ ) from utils.evm_script import encode_error - @pytest.fixture(scope="module") def contract() -> interface.AccountingOracle: return interface.AccountingOracle(ACCOUNTING_ORACLE) diff --git a/tests/acceptance/test_legacy_oracle.py b/tests/acceptance/test_legacy_oracle.py index beb4c617..7e8046fc 100644 --- a/tests/acceptance/test_legacy_oracle.py +++ b/tests/acceptance/test_legacy_oracle.py @@ -17,7 +17,6 @@ lastSeenTotalPooledEther = 5879742251110033487920093 - @pytest.fixture(scope="module") def contract() -> interface.LegacyOracle: return interface.LegacyOracle(LEGACY_ORACLE) diff --git a/tests/acceptance/test_lido.py b/tests/acceptance/test_lido.py index 001d7e35..00627a94 100644 --- a/tests/acceptance/test_lido.py +++ b/tests/acceptance/test_lido.py @@ -15,7 +15,6 @@ last_seen_total_rewards_collected = 50327973200740183385860 last_seen_beacon_validators = 175906 - @pytest.fixture(scope="module") def contract() -> interface.Lido: return interface.Lido(LIDO) diff --git a/tests/acceptance/test_locator.py b/tests/acceptance/test_locator.py index f0649390..5213461b 100644 --- a/tests/acceptance/test_locator.py +++ b/tests/acceptance/test_locator.py @@ -1,7 +1,7 @@ import pytest from brownie import interface # type: ignore -from utils.config import contracts, LIDO_LOCATOR, LIDO_LOCATOR_IMPL +from utils.config import contracts, LIDO_LOCATOR, LIDO_LOCATOR_IMPL_NEW @pytest.fixture(scope="module") @@ -11,7 +11,7 @@ def contract() -> interface.LidoLocator: def test_proxy(contract): proxy = interface.OssifiableProxy(contract) - assert proxy.proxy__getImplementation() == LIDO_LOCATOR_IMPL + assert proxy.proxy__getImplementation() == LIDO_LOCATOR_IMPL_NEW assert proxy.proxy__getAdmin() == contracts.agent.address @@ -22,7 +22,7 @@ def test_addresses(contract): assert contract.legacyOracle() == contracts.legacy_oracle assert contract.lido() == contracts.lido assert contract.oracleReportSanityChecker() == contracts.oracle_report_sanity_checker - assert contract.postTokenRebaseReceiver() == contracts.legacy_oracle + assert contract.postTokenRebaseReceiver() == contracts.token_rate_notifier assert contract.burner() == contracts.burner assert contract.stakingRouter() == contracts.staking_router assert contract.treasury() == contracts.agent @@ -47,5 +47,5 @@ def test_addresses(contract): contracts.burner, contracts.withdrawal_queue, contracts.withdrawal_vault, - contracts.legacy_oracle, + contracts.token_rate_notifier, ) diff --git a/tests/acceptance/test_simple_dvt_module.py b/tests/acceptance/test_simple_dvt_module.py index fc36a72d..524a46e9 100644 --- a/tests/acceptance/test_simple_dvt_module.py +++ b/tests/acceptance/test_simple_dvt_module.py @@ -20,6 +20,7 @@ EASYTRACK_SIMPLE_DVT_CHANGE_NODE_OPERATOR_MANAGERS_FACTORY, ) + REQUEST_BURN_SHARES_ROLE = "0x4be29e0e4eb91f98f709d98803cba271592782e293b84a625e025cbb40197ba8" STAKING_ROUTER_ROLE = "0xbb75b874360e0bfd87f964eadd8276d8efb7c942134fc329b513032d0803e0c6" MANAGE_NODE_OPERATOR_ROLE = "0x78523850fdd761612f46e844cf5a16bda6b3151d6ae961fd7e8e7b92bfbca7f8" diff --git a/tests/acceptance/test_withdrawal_queue.py b/tests/acceptance/test_withdrawal_queue.py index b79834c4..f41bf852 100644 --- a/tests/acceptance/test_withdrawal_queue.py +++ b/tests/acceptance/test_withdrawal_queue.py @@ -11,7 +11,6 @@ ) from utils.evm_script import encode_error - @pytest.fixture(scope="module") def contract() -> interface.WithdrawalQueueERC721: return interface.WithdrawalQueueERC721(WITHDRAWAL_QUEUE) diff --git a/tests/acceptance/test_withdrawals_negative.py b/tests/acceptance/test_withdrawals_negative.py index 11cce371..6d5e368f 100644 --- a/tests/acceptance/test_withdrawals_negative.py +++ b/tests/acceptance/test_withdrawals_negative.py @@ -10,7 +10,6 @@ MAX_STETH_WITHDRAWAL_AMOUNT = Wei(1000 * 10**18) UINT256_MAX = 2**256 - 1 - def test_request_withdrawals_steth(wq: Contract, steth_whale: Account): too_small_amount = MIN_STETH_WITHDRAWAL_AMOUNT - 10 too_large_amount = MAX_STETH_WITHDRAWAL_AMOUNT + 10 diff --git a/tests/conftest.py b/tests/conftest.py index b495c516..8f34f5af 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,7 +4,7 @@ import brownie.exceptions import pytest -from brownie import chain, interface, web3 +from brownie import chain, interface, web3, network from brownie.network import state from brownie.network.contract import Contract @@ -15,6 +15,8 @@ from utils.config import * from utils.txs.deploy import deploy_from_prepared_tx from utils.test.helpers import ETH +from utils.balance import set_balance +from functools import wraps ENV_OMNIBUS_BYPASS_EVENTS_DECODING = "OMNIBUS_BYPASS_EVENTS_DECODING" ENV_PARSE_EVENTS_FROM_LOCAL_ABI = "PARSE_EVENTS_FROM_LOCAL_ABI" @@ -25,6 +27,9 @@ def shared_setup(fn_isolation): pass +@pytest.fixture(scope="session", autouse=True) +def network_gas_price(): + network.gas_price("2 gwei") @pytest.fixture(scope="function") def deployer(): @@ -80,7 +85,6 @@ def trp_recipient(accounts): assert trp_recipient.balance() == ETH(100000) return trp_recipient - @pytest.fixture(scope="module") def eth_whale(accounts): if network_name() in ("goerli", "goerli-fork"): @@ -118,7 +122,7 @@ def assert_event_not_emitted(evt_name, tx): raise AssertionError(f"Event {evt_name} was fired") @staticmethod - def execute_vote(accounts, vote_id, dao_voting, topup="0.1 ether", skip_time=MAINNET_VOTE_DURATION): + def execute_vote(accounts, vote_id, dao_voting, topup="1 ether", skip_time=MAINNET_VOTE_DURATION): (tx,) = Helpers.execute_votes(accounts, [vote_id], dao_voting, topup, skip_time) return tx @@ -265,3 +269,25 @@ def parse_events_from_local_abi(): # See https://eth-brownie.readthedocs.io/en/stable/api-network.html?highlight=_add_contract#brownie.network.state._add_contract # Added contract will resolve from address during state._find_contract without a request to Etherscan state._add_contract(contract) + +@pytest.fixture(scope="session", autouse=True) +def add_balance_check_middleware(): + web3.middleware_onion.add(balance_check_middleware, name='balance_check') + +# TODO: Such implicit manipulation of the balances may lead to hard-debugging errors in the future. +# Better to return back balance after request is done. +def ensure_balance(address): + if web3.eth.get_balance(address) < ETH(1): + set_balance(address, 1000000) + +def balance_check_middleware(make_request, web3): + @wraps(make_request) + def middleware(method, params): + if method in ["eth_sendTransaction", "eth_sendRawTransaction"]: + transaction = params[0] + from_address = transaction.get('from') + if from_address: + ensure_balance(from_address) + + return make_request(method, params) + return middleware diff --git a/tests/regression/test_accounting.py b/tests/regression/test_accounting.py index f9b96b91..723790eb 100644 --- a/tests/regression/test_accounting.py +++ b/tests/regression/test_accounting.py @@ -11,6 +11,7 @@ from utils.config import contracts from utils.test.helpers import ETH, GWEI, ZERO_ADDRESS, almostEqWithDiff, eth_balance from utils.test.oracle_report_helpers import ONE_DAY, SHARE_RATE_PRECISION, oracle_report +from utils.balance import set_balance LIMITER_PRECISION_BASE = 10**9 MAX_BASIS_POINTS = 10_000 @@ -106,12 +107,6 @@ def test_accounting_no_cl_rebase(accounting_oracle: Contract, lido: Contract, he shares_rate_before, shares_rate_after = _shares_rate_from_event(tx) assert shares_rate_before <= shares_rate_after, "Shares rate lowered" - post_ttl_shares_event = _first_event(tx, PostTotalShares) - assert ( - post_ttl_shares_event["preTotalPooledEther"] - == post_ttl_shares_event["postTotalPooledEther"] + withdrawals_finalized["amountOfETHLocked"] - ), "PostTotalShares preTotalPooledEther <> postTotalPooledEther" - assert ( eth_balance(lido.address, block_before_report) == eth_balance(lido.address, block_after_report) + withdrawals_finalized["amountOfETHLocked"] @@ -166,12 +161,6 @@ def test_accounting_negative_cl_rebase(accounting_oracle: Contract, lido: Contra eth_distributed_event["preCLBalance"] + rebase_amount == eth_distributed_event["postCLBalance"] ), "ETHDistributed: CL balance differs from expected" - post_ttl_shares_event = _first_event(tx, PostTotalShares) - assert ( - post_ttl_shares_event["preTotalPooledEther"] + rebase_amount - == post_ttl_shares_event["postTotalPooledEther"] + withdrawals_finalized["amountOfETHLocked"] - ), "PostTotalShares: TotalPooledEther differs from expected" - def test_accounting_cl_rebase_at_limits(accounting_oracle: Contract, lido: Contract): """Check Lido rebase after accounting report with positive CL rebase close to the limits""" @@ -281,11 +270,6 @@ def test_accounting_cl_rebase_at_limits(accounting_oracle: Contract, lido: Contr eth_distributed_event["preCLBalance"] + rebase_amount == eth_distributed_event["postCLBalance"] ), "ETHDistributed: CL balance has not increased" - post_ttl_shares_event = _first_event(tx, PostTotalShares) - assert ( - post_ttl_shares_event["preTotalPooledEther"] + rebase_amount == post_ttl_shares_event["postTotalPooledEther"] - ) + withdrawals_finalized["amountOfETHLocked"], "PostTotalShares: TotalPooledEther has not increased" - def test_accounting_cl_rebase_above_limits(): """Check that report reverts on sanity checks""" @@ -1129,11 +1113,7 @@ def _round_to_gwei(amount: int) -> int: def _drain_eth(address: str): """Drain ETH from address""" - accounts.at(address, force=True).transfer( - Account(ZERO_ADDRESS), - eth_balance(address), - silent=True, - ) + set_balance(address, 0) assert eth_balance(address) == 0, f"Expected account {address} to be empty" diff --git a/tests/regression/test_accounting_oracle_extra_data_full_items.py b/tests/regression/test_accounting_oracle_extra_data_full_items.py index 7775fb45..8078baa2 100644 --- a/tests/regression/test_accounting_oracle_extra_data_full_items.py +++ b/tests/regression/test_accounting_oracle_extra_data_full_items.py @@ -74,7 +74,7 @@ def test_extra_data_full_items( new_keys_per_operator, nor_stuck_items, nor_exited_items, - max_node_operators_per_item, + max_node_operators_per_item ) # Fill SimpleDVT with new operators and keys @@ -85,7 +85,7 @@ def test_extra_data_full_items( new_keys_per_operator, sdvt_stuck_items, sdvt_exited_items, - max_node_operators_per_item, + max_node_operators_per_item ) # Deposit for new added keys from buffer @@ -173,7 +173,7 @@ def test_extra_data_full_items( assert almostEqWithDiff( shares_after - sdvt_balance_shares_before[i], rewards_after // 2, - 1, + 2, ) penalty_shares += rewards_after // 2 @@ -211,13 +211,13 @@ def add_nor_operators_with_keys(nor, voting_eoa: Account, evm_script_executor_eo def fill_nor_with_old_and_new_operators( - nor, voting_eoa, evm_script_executor_eoa, new_keys_per_operator, nor_stuck_items, nor_exited_items, max_node_operators_per_item, + nor, voting_eoa, evm_script_executor_eoa, new_keys_per_operator, nor_stuck_items, nor_exited_items, max_node_operators_per_item ) -> tuple[int, int]: contracts.acl.grantPermission( contracts.voting, nor.address, convert.to_uint(Web3.keccak(text="MANAGE_NODE_OPERATOR_ROLE")), - {"from": contracts.voting}, + {"from": contracts.voting} ) # Calculate new operators count diff --git a/tests/regression/test_all_round_happy_path.py b/tests/regression/test_all_round_happy_path.py index a692d895..74294fd9 100644 --- a/tests/regression/test_all_round_happy_path.py +++ b/tests/regression/test_all_round_happy_path.py @@ -5,6 +5,7 @@ from utils.test.helpers import ETH, almostEqEth from utils.config import contracts from utils.test.simple_dvt_helpers import fill_simple_dvt_ops_vetted_keys +from utils.balance import set_balance def test_all_round_happy_path(accounts, stranger, steth_holder, eth_whale): @@ -29,14 +30,16 @@ def test_all_round_happy_path(accounts, stranger, steth_holder, eth_whale): contracts.lido.approve(contracts.withdrawal_queue.address, 1000, {"from": steth_holder}) contracts.withdrawal_queue.requestWithdrawals([1000], steth_holder, {"from": steth_holder}) + # ensure SimpleDVT has some keys to deposit + fill_simple_dvt_ops_vetted_keys(stranger, 3, 5) + set_balance(stranger.address, 1000000) + print(stranger, stranger.balance()) steth_balance_before_submit = contracts.lido.balanceOf(stranger) eth_balance_before_submit = stranger.balance() assert steth_balance_before_submit == 0 - # ensure SimpleDVT has some keys to deposit - fill_simple_dvt_ops_vetted_keys(stranger, 3, 5) # Submitting ETH stakeLimitInfo = contracts.lido.getStakeLimitFullInfo() @@ -65,7 +68,7 @@ def test_all_round_happy_path(accounts, stranger, steth_holder, eth_whale): print("block after view: ", chain.height) assert almostEqEth(steth_balance_after_submit, steth_balance_before_submit + amount) - assert eth_balance_before_submit == stranger.balance() + amount + assert eth_balance_before_submit == stranger.balance() + amount + submit_tx.gas_used * submit_tx.gas_price shares_to_be_minted = contracts.lido.getSharesByPooledEth(amount) @@ -316,7 +319,7 @@ def test_all_round_happy_path(accounts, stranger, steth_holder, eth_whale): assert transfer_event["to"] == ZERO_ADDRESS assert transfer_event["tokenId"] == request_ids[0] - assert eth_balance_before_withdrawal == stranger.balance() - amount_with_rewards + assert eth_balance_before_withdrawal == stranger.balance() - amount_with_rewards + claim_tx.gas_used * claim_tx.gas_price assert ( locked_ether_amount_after_finalization == contracts.withdrawal_queue.getLockedEtherAmount() + amount_with_rewards diff --git a/tests/regression/test_el_rewards.py b/tests/regression/test_el_rewards.py index 25982023..080c128e 100644 --- a/tests/regression/test_el_rewards.py +++ b/tests/regression/test_el_rewards.py @@ -53,7 +53,7 @@ def test_receive_el_rewards_permissions(stranger): assert_el_rewards_received_log(log=tx.logs[0], amount=reward_amount) assert contracts.lido.getTotalELRewardsCollected() - lido_el_rewards_collected_before == reward_amount - assert contracts.execution_layer_rewards_vault.balance() == (el_balance_after - reward_amount) + assert contracts.execution_layer_rewards_vault.balance() == (el_balance_after - reward_amount) - tx.gas_used * tx.gas_price assert contracts.lido.balance() == lido_eth_balance_before + reward_amount diff --git a/tests/regression/test_node_operators_flow.py b/tests/regression/test_node_operators_flow.py index 76995f28..6e9135f8 100644 --- a/tests/regression/test_node_operators_flow.py +++ b/tests/regression/test_node_operators_flow.py @@ -50,7 +50,8 @@ def voting_eoa(accounts): @pytest.fixture(scope="module") def evm_script_executor_eoa(accounts): - return accounts.at(contracts.easy_track.evmScriptExecutor(), force=True) + evmScriptExecutor = contracts.easy_track.evmScriptExecutor() + return accounts.at(evmScriptExecutor, force=True) @pytest.fixture(scope="module") diff --git a/tests/regression/test_oracle_report_with_notifier.py b/tests/regression/test_oracle_report_with_notifier.py new file mode 100644 index 00000000..95347d69 --- /dev/null +++ b/tests/regression/test_oracle_report_with_notifier.py @@ -0,0 +1,187 @@ +import pytest +from brownie import Contract, accounts, chain, interface, OpStackTokenRatePusherWithSomeErrorStub, web3, reverts +from utils.test.oracle_report_helpers import oracle_report +from utils.config import contracts, get_deployer_account, network_name +from utils.test.helpers import ZERO_ADDRESS, eth_balance +from utils.evm_script import encode_error +from typing import TypedDict, TypeVar, Any + +WST_ETH = "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0" +ACCOUNTING_ORACLE = "0x852deD011285fe67063a08005c71a85690503Cee" +L1_TOKEN_RATE_NOTIFIER = "0xe6793B9e4FbA7DE0ee833F9D02bba7DB5EB27823" +L1_CROSS_DOMAIN_MESSENGER = "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1" +L2_TOKEN_RATE_ORACLE = "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0" + + +@pytest.fixture(scope="module") +def accounting_oracle() -> Contract: + return contracts.accounting_oracle + + +@pytest.fixture(scope="module") +def lido() -> Contract: + return contracts.lido + + +@pytest.fixture(scope="module") +def el_vault() -> Contract: + return contracts.execution_layer_rewards_vault + + +@pytest.fixture(scope="module") +def withdrawal_queue() -> Contract: + return contracts.withdrawal_queue + + +def test_oracle_report_revert(): + """Test oracle report reverts when messenger is empty""" + interface.TokenRateNotifier(L1_TOKEN_RATE_NOTIFIER) # load TokenRateNotifier contract ABI to catch correct error + + web3.provider.make_request("hardhat_setCode", [L1_CROSS_DOMAIN_MESSENGER, "0x"]) + web3.provider.make_request("evm_setAccountCode", [L1_CROSS_DOMAIN_MESSENGER, "0x"]) + + with reverts(encode_error("ErrorTokenRateNotifierRevertedWithNoData()")): + oracle_report(cl_diff=0, report_el_vault=True, report_withdrawals_vault=False) + + +def test_oracle_report_pushes_rate(): + """Test oracle report emits cross domain messenger event""" + + tx, _ = oracle_report( + cl_diff=0, + report_el_vault=True, + report_withdrawals_vault=False, + ) + + tokenRateOracle = interface.ITokenRateUpdatable(L2_TOKEN_RATE_ORACLE) + + wstETH = interface.WstETH(WST_ETH) + accountingOracle = interface.AccountingOracle(ACCOUNTING_ORACLE) + + tokenRate = wstETH.getStETHByWstETH(10**27) + + genesisTime = accountingOracle.GENESIS_TIME() + secondsPerSlot = accountingOracle.SECONDS_PER_SLOT() + lastProcessingRefSlot = accountingOracle.getLastProcessingRefSlot() + updateTimestamp = genesisTime + secondsPerSlot * lastProcessingRefSlot + + updateRateCalldata = tokenRateOracle.updateRate.encode_input(tokenRate, updateTimestamp) + + assert updateRateCalldata == tx.events["SentMessage"]["message"] + + +def test_oracle_report_success_when_observer_reverts(accounting_oracle: Contract, lido: Contract, el_vault: Contract): + """Test oracle report works when token rate observer reverts""" + + opStackTokenRatePusher = OpStackTokenRatePusherWithSomeErrorStub.deploy({"from": get_deployer_account()}) + + tokenRateNotifier = interface.TokenRateNotifier(L1_TOKEN_RATE_NOTIFIER) + tokenRateNotifierOwner = tokenRateNotifier.owner() + tokenRateNotifier.addObserver(opStackTokenRatePusher, {"from": tokenRateNotifierOwner}) + + accounts[0].transfer(el_vault.address, 10**18) + block_before_report = chain.height + + el_rewards = eth_balance(el_vault.address, block_before_report) + assert el_rewards > 0, "Expected EL vault to be non-empty" + + tx, _ = oracle_report( + cl_diff=0, + report_el_vault=True, + report_withdrawals_vault=False, + ) + + block_after_report = chain.height + + withdrawals_finalized = _try_get_withdrawals_finalized(tx) + shares_burnt = _try_get_shares_burnt(tx) + + assert accounting_oracle.getLastProcessingRefSlot( + block_identifier=block_before_report + ) < accounting_oracle.getLastProcessingRefSlot( + block_identifier=block_after_report, + ), "LastProcessingRefSlot should be updated" + + assert lido.getTotalELRewardsCollected( + block_identifier=block_before_report + ) + el_rewards == lido.getTotalELRewardsCollected( + block_identifier=block_after_report + ), "TotalELRewardsCollected change mismatch" + + assert ( + lido.getTotalPooledEther(block_identifier=block_before_report) + el_rewards + == lido.getTotalPooledEther( + block_identifier=block_after_report, + ) + + withdrawals_finalized["amountOfETHLocked"] + ), "TotalPooledEther change mismatch" + + assert ( + lido.getTotalShares(block_identifier=block_before_report) + == lido.getTotalShares( + block_identifier=block_after_report, + ) + + shares_burnt["sharesAmount"] + ), "TotalShares has changed" + + assert ( + eth_balance(lido.address, block_before_report) + el_rewards + == eth_balance(lido.address, block_after_report) + withdrawals_finalized["amountOfETHLocked"] + ), "Lido ETH balance change mismatch" + + assert eth_balance(el_vault.address, block_after_report) == 0, "Expected EL vault to be empty" + + assert tx.events["PushTokenRateFailed"]["observer"] == opStackTokenRatePusher + assert tx.events["PushTokenRateFailed"]["lowLevelRevertData"] == "0x332e27d2" + + +T = TypeVar("T") + +WithdrawalsFinalized = TypedDict( + "WithdrawalsFinalized", + {"from": str, "to": str, "amountOfETHLocked": int, "sharesToBurn": int, "timestamp": int}, +) + + +class ELRewardsReceived(TypedDict): + """ELRewardsReceived event definition""" + + amount: int + + +class SharesBurnt(TypedDict): + """SharesBurnt event definition""" + + account: str + preRebaseTokenAmount: int + postRebaseTokenAmount: int + sharesAmount: int + + +def _get_events(tx, event: type[T]) -> list[T]: + """Get event of type T from transaction""" + + assert event.__name__ in tx.events, f"Event {event.__name__} was not found in the transaction" + return tx.events[event.__name__] + + +def _first_event(tx, event: type[T]) -> T: + """Get first event of type T from transaction""" + + events = _get_events(tx, event) + assert len(events) == 1, f"Event {event.__name__} was found more than once in the transaction" + return events[0] + + +def _try_get_withdrawals_finalized(tx: Any) -> WithdrawalsFinalized: + if WithdrawalsFinalized.__name__ in tx.events: + return _first_event(tx, WithdrawalsFinalized) + else: + return {"from": ZERO_ADDRESS, "to": ZERO_ADDRESS, "amountOfETHLocked": 0, "sharesToBurn": 0, "timestamp": 0} + + +def _try_get_shares_burnt(tx: Any) -> SharesBurnt: + if SharesBurnt.__name__ in tx.events: + return _first_event(tx, SharesBurnt) + else: + return SharesBurnt(account=ZERO_ADDRESS, preRebaseTokenAmount=0, postRebaseTokenAmount=0, sharesAmount=0) diff --git a/tests/regression/test_pause_role_tests.py b/tests/regression/test_pause_role_tests.py index 2040ff70..2a2c4e8a 100644 --- a/tests/regression/test_pause_role_tests.py +++ b/tests/regression/test_pause_role_tests.py @@ -7,7 +7,6 @@ from utils.config import contracts - @pytest.fixture(scope="function") def stop_lido(): if not contracts.lido.isStopped(): diff --git a/tests/regression/test_sanity_checks.py b/tests/regression/test_sanity_checks.py index aa99fdcd..c83eeb88 100644 --- a/tests/regression/test_sanity_checks.py +++ b/tests/regression/test_sanity_checks.py @@ -12,6 +12,7 @@ from utils.evm_script import encode_error from utils.test.helpers import ETH, eth_balance + from utils.config import ( contracts, CHURN_VALIDATORS_PER_DAY_LIMIT, @@ -264,16 +265,15 @@ def test_veb_oracle_too_much_extra_data(): def fake_deposited_validators_increase(cl_validators_diff): (deposited, _, _) = contracts.lido.getBeaconStat() - voting = accounts.at(contracts.voting.address, force=True) contracts.acl.createPermission( - voting, + contracts.voting, contracts.lido, web3.keccak(text="UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE"), - voting, - {"from": voting}, + contracts.voting, + {"from": contracts.voting}, ) - contracts.lido.unsafeChangeDepositedValidators(deposited + cl_validators_diff, {"from": voting}) + contracts.lido.unsafeChangeDepositedValidators(deposited + cl_validators_diff, {"from": contracts.voting}) def create_withdrawal_request(steth_holder): diff --git a/tests/regression/test_staking_module_happy_path.py b/tests/regression/test_staking_module_happy_path.py index e708fe45..4a278213 100644 --- a/tests/regression/test_staking_module_happy_path.py +++ b/tests/regression/test_staking_module_happy_path.py @@ -19,7 +19,6 @@ STAKING_MODULE_MANAGE_ROLE = Web3.keccak(text="STAKING_MODULE_MANAGE_ROLE") SET_NODE_OPERATOR_LIMIT_ROLE = Web3.keccak(text="SET_NODE_OPERATOR_LIMIT_ROLE") - @pytest.fixture(scope="function") def impersonated_voting(accounts): return accounts.at(contracts.voting.address, force=True) diff --git a/tests/snapshot/test_dsm.py b/tests/snapshot/test_dsm.py index a30c0f02..ea784a8f 100644 --- a/tests/snapshot/test_dsm.py +++ b/tests/snapshot/test_dsm.py @@ -136,7 +136,6 @@ def _snap(dsm): block = chain.height with brownie.multicall(block_identifier=block): return { - "block_number": chain.height, "chain_time": web3.eth.get_block(chain.height)["timestamp"], "DEPOSIT_CONTRACT": dsm.DEPOSIT_CONTRACT(), "LIDO": dsm.LIDO(), diff --git a/tests/snapshot/test_first_slots.py b/tests/snapshot/test_first_slots.py index eea8e50d..0383b59d 100644 --- a/tests/snapshot/test_first_slots.py +++ b/tests/snapshot/test_first_slots.py @@ -35,8 +35,7 @@ class SandwichFn(Protocol): def __call__( snapshot_fn: SnapshotFn = ..., snapshot_block: int = ..., - ) -> tuple[Stack, Stack]: - ... + ) -> tuple[Stack, Stack]: ... def test_first_slots(sandwich_upgrade: SandwichFn): diff --git a/tests/snapshot/test_lido_snapshot.py b/tests/snapshot/test_lido_snapshot.py index 4f3615ac..548c445a 100644 --- a/tests/snapshot/test_lido_snapshot.py +++ b/tests/snapshot/test_lido_snapshot.py @@ -364,8 +364,9 @@ def far_block() -> int: @pytest.fixture(scope="module") def some_contract(accounts) -> Account: + some_contract_addr = "0xcA11bde05977b3631167028862bE2a173976CA11" # Multicall3 contract deployed almost on the every network on the same address - return accounts.at("0xcA11bde05977b3631167028862bE2a173976CA11", force=True) + return accounts.at(some_contract_addr, force=True) @pytest.fixture(scope="function") diff --git a/utils/balance.py b/utils/balance.py new file mode 100644 index 00000000..f0ab0036 --- /dev/null +++ b/utils/balance.py @@ -0,0 +1,21 @@ +from brownie import accounts, web3 +from utils.test.helpers import ETH + + +def set_balance_in_wei(address, balance): + account = accounts.at(address, force=True) + + if account.balance() != balance: + # set balance for Ganache node + web3.provider.make_request("evm_setAccountBalance", [address, hex(balance)]) + # set balance for Anvil and Hardhat nodes (https://book.getfoundry.sh/reference/anvil/#custom-methods) + web3.provider.make_request("hardhat_setBalance", [address, hex(balance)]) + + assert account.balance() == balance + return account + + +def set_balance(address, balanceInEth): + balance = ETH(balanceInEth) + + return set_balance_in_wei(address, balance) diff --git a/utils/config.py b/utils/config.py index 6832e483..c8f13896 100644 --- a/utils/config.py +++ b/utils/config.py @@ -59,14 +59,12 @@ def get_priority_fee() -> str: else: return "2 gwei" - def get_max_fee() -> str: if "OMNIBUS_MAX_FEE" in os.environ: return os.environ["OMNIBUS_MAX_FEE"] else: return "300 gwei" - def local_deployer() -> LocalAccount: """ Local deployer can ONLY be used for the local run. @@ -190,6 +188,10 @@ def simple_dvt(self) -> interface.SimpleDVT: def legacy_oracle(self) -> interface.LegacyOracle: return interface.LegacyOracle(LEGACY_ORACLE) + @property + def token_rate_notifier(self) -> interface.TokenRateNotifier: + return interface.LegacyOracle(L1_TOKEN_RATE_NOTIFIER) + @property def deposit_security_module_v1(self) -> interface.DepositSecurityModule: return interface.DepositSecurityModuleV1(DEPOSIT_SECURITY_MODULE_V1) @@ -334,6 +336,9 @@ def split_main(self) -> interface.SplitMain: def trp_escrow_factory(self) -> interface.VestingEscrowFactory: return interface.VestingEscrowFactory(TRP_VESTING_ESCROW_FACTORY) + @property + def token_rate_notifier(self) -> interface.TokenRateNotifier: + return interface.TokenRateNotifier(L1_TOKEN_RATE_NOTIFIER) def __getattr__(name: str) -> Any: if name == "contracts": diff --git a/utils/import_current_votes.py b/utils/import_current_votes.py index 2a1657b4..4f42038e 100644 --- a/utils/import_current_votes.py +++ b/utils/import_current_votes.py @@ -5,7 +5,7 @@ from brownie import accounts from brownie.network.transaction import TransactionReceipt -from utils.config import LDO_HOLDER_ADDRESS_FOR_TESTS, LIDO_V2_UPGRADE_TEMPLATE, get_is_live, contracts +from utils.config import LDO_HOLDER_ADDRESS_FOR_TESTS def get_vote_scripts_dir() -> str: @@ -20,6 +20,7 @@ def get_vote_script_files() -> List[str]: vote_files = glob.glob(os.path.join(dir_path, "vote_*.py")) return vote_files + def get_upgrade_script_files() -> List[str]: """Return List of abs paths to vote scripts""" dir_path = get_vote_scripts_dir() @@ -58,7 +59,7 @@ def start_and_execute_votes(dao_voting, helpers) -> tuple[List[str], List[Transa start_vote = locals()[start_vote_name] vote_id, _ = start_vote({"from": LDO_HOLDER_ADDRESS_FOR_TESTS}, silent=True) - (tx,) = helpers.execute_votes(accounts, [vote_id], dao_voting, topup="0.5 ether") + (tx,) = helpers.execute_votes(accounts, [vote_id], dao_voting, topup="1 ether") vote_ids.append(vote_id) vote_transactions.append(tx) return vote_ids, vote_transactions