diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L1ETHGateway.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L1ETHGateway.sol index 8039a895fe5a..1080e5691895 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L1ETHGateway.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L1ETHGateway.sol @@ -174,4 +174,25 @@ contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_Addr (bool success, ) = _to.call{value: _value}(new bytes(0)); require(success, 'TransferHelper::safeTransferETH: ETH transfer failed'); } + + /***************************** + * Temporary - Migrating ETH * + *****************************/ + + /** + * @dev Migrates entire ETH balance to another gateway + * @param _to Gateway Proxy address to migrate ETH to + */ + function migrateEth(address payable _to) external { + address owner = Lib_AddressManager(libAddressManager).owner(); + require(msg.sender == owner, "Only the owner can migrate ETH"); + uint256 balance = address(this).balance; + OVM_L1ETHGateway(_to).donateETH{value:balance}(); + } + + /** + * @dev Adds ETH balance to the account. This is meant to allow for ETH + * to be migrated from an old gateway to a new gateway + */ + function donateETH() external payable {} } diff --git a/packages/contracts/test/contracts/OVM/bridge/assets/OVM_L1ETHGateway.spec.ts b/packages/contracts/test/contracts/OVM/bridge/assets/OVM_L1ETHGateway.spec.ts index f76f55e9b693..98d64620cfad 100644 --- a/packages/contracts/test/contracts/OVM/bridge/assets/OVM_L1ETHGateway.spec.ts +++ b/packages/contracts/test/contracts/OVM/bridge/assets/OVM_L1ETHGateway.spec.ts @@ -8,7 +8,7 @@ import { smockit, MockContract } from '@eth-optimism/smock' /* Internal Imports */ import { NON_ZERO_ADDRESS, makeAddressManager } from '../../../../helpers' -const L1_ETH_GATEWAY_NAME = 'Proxy__OVM_L1CrossDomainMessenger' +const L1_MESSENGER_NAME = 'Proxy__OVM_L1CrossDomainMessenger' const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenticated' const ERR_INVALID_X_DOMAIN_MSG_SENDER = @@ -82,7 +82,7 @@ describe('OVM_L1ETHGateway', () => { it('onlyFromCrossDomainAccount: should revert on calls from the right crossDomainMessenger, but wrong xDomainMessageSender (ie. not the L2ETHGateway)', async () => { await AddressManager.setAddress( - L1_ETH_GATEWAY_NAME, + L1_MESSENGER_NAME, Mock__OVM_L1CrossDomainMessenger.address ) @@ -163,7 +163,7 @@ describe('OVM_L1ETHGateway', () => { await ethers.getContractFactory('OVM_L1CrossDomainMessenger') ) await AddressManager.setAddress( - L1_ETH_GATEWAY_NAME, + L1_MESSENGER_NAME, Mock__OVM_L1CrossDomainMessenger.address ) @@ -256,4 +256,41 @@ describe('OVM_L1ETHGateway', () => { expect(depositCallToMessenger._gasLimit).to.equal(finalizeDepositGasLimit) }) }) + describe('migrating ETH', () => { + const migrateAmount = 1_000 + + beforeEach(async () => { + await OVM_L1ETHGateway.donateETH({ value: migrateAmount }) + const gatewayBalance = await ethers.provider.getBalance( + OVM_L1ETHGateway.address + ) + expect(gatewayBalance).to.equal(migrateAmount) + }) + it('should successfully migrate ETH to new gateway', async () => { + const New_OVM_L1ETHGateway = await ( + await ethers.getContractFactory('OVM_L1ETHGateway') + ).deploy() + await New_OVM_L1ETHGateway.initialize( + AddressManager.address, + Mock__OVM_L2DepositedERC20.address + ) + await OVM_L1ETHGateway.migrateEth(New_OVM_L1ETHGateway.address) + const newGatewayBalance = await ethers.provider.getBalance( + New_OVM_L1ETHGateway.address + ) + expect(newGatewayBalance).to.equal(migrateAmount) + }) + it('should not allow migrating ETH from non-owner', async () => { + const New_OVM_L1ETHGateway = await ( + await ethers.getContractFactory('OVM_L1ETHGateway') + ).deploy() + await New_OVM_L1ETHGateway.initialize( + AddressManager.address, + Mock__OVM_L2DepositedERC20.address + ) + await expect( + OVM_L1ETHGateway.connect(bob).migrateEth(New_OVM_L1ETHGateway.address) + ).to.be.revertedWith('Only the owner can migrate ETH') + }) + }) })