From 7387bffc6ed47146f98fc550caa75e7419192927 Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Thu, 15 Apr 2021 15:42:13 -0700 Subject: [PATCH 1/8] feat: Have predeploys use OVM solc only --- l2geth/core/vm/evm.go | 2 - .../OVM/accounts/OVM_ECDSAContractAccount.sol | 71 ++-- .../OVM/accounts/OVM_ProxyEOA.sol | 39 +- .../messaging/OVM_L2CrossDomainMessenger.sol | 6 +- .../OVM/chain/OVM_StateCommitmentChain.sol | 2 +- .../OVM/predeploys/OVM_DeployerWhitelist.sol | 99 +---- .../OVM/predeploys/OVM_L1MessageSender.sol | 43 -- .../OVM_ProxySequencerEntrypoint.sol | 116 ------ .../predeploys/OVM_SequencerEntrypoint.sol | 49 ++- .../predeploys/iOVM_DeployerWhitelist.sol | 1 - .../iOVM/predeploys/iOVM_L1MessageSender.sol | 14 - .../libraries/codec/Lib_OVMCodec.sol | 7 +- .../wrappers/Lib_ExecutionManagerWrapper.sol | 148 +++++++ .../Lib_SafeExecutionManagerWrapper.sol | 376 ------------------ .../wrappers/Lib_SafeMathWrapper.sol | 168 -------- .../accounts/mockOVM_ECDSAContractAccount.sol | 95 ----- .../test-libraries/codec/TestLib_OVMCodec.sol | 8 +- .../src/contract-deployment/config.ts | 10 - packages/contracts/src/contract-dumps.ts | 5 +- packages/contracts/src/predeploys.ts | 1 - .../accounts/OVM_ECDSAContractAccount.spec.ts | 292 -------------- .../OVM/accounts/OVM_ProxyEOA.spec.ts | 149 ------- .../base/OVM_L2CrossDomainMessenger.spec.ts | 201 ---------- .../precompiles/OVM_L1MessageSender.spec.ts | 67 ---- .../OVM_ProxySequencerEntrypoint.spec.ts | 164 -------- .../libraries/codec/Lib_OVMCodec.test.json | 3 +- packages/hardhat-ovm/src/index.ts | 3 + 27 files changed, 270 insertions(+), 1869 deletions(-) delete mode 100644 packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_L1MessageSender.sol delete mode 100644 packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_ProxySequencerEntrypoint.sol delete mode 100644 packages/contracts/contracts/optimistic-ethereum/iOVM/predeploys/iOVM_L1MessageSender.sol create mode 100644 packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_ExecutionManagerWrapper.sol delete mode 100644 packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol delete mode 100644 packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeMathWrapper.sol delete mode 100644 packages/contracts/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol delete mode 100644 packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts delete mode 100644 packages/contracts/test/contracts/OVM/accounts/OVM_ProxyEOA.spec.ts delete mode 100644 packages/contracts/test/contracts/OVM/bridge/base/OVM_L2CrossDomainMessenger.spec.ts delete mode 100644 packages/contracts/test/contracts/OVM/precompiles/OVM_L1MessageSender.spec.ts delete mode 100644 packages/contracts/test/contracts/OVM/precompiles/OVM_ProxySequencerEntrypoint.spec.ts diff --git a/l2geth/core/vm/evm.go b/l2geth/core/vm/evm.go index d6fbecc802453..d7811e6b660ca 100644 --- a/l2geth/core/vm/evm.go +++ b/l2geth/core/vm/evm.go @@ -139,7 +139,6 @@ type Context struct { OriginalTargetReached bool OvmExecutionManager dump.OvmDumpAccount OvmStateManager dump.OvmDumpAccount - OvmMockAccount dump.OvmDumpAccount OvmSafetyChecker dump.OvmDumpAccount } @@ -190,7 +189,6 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon if chainConfig != nil && chainConfig.StateDump != nil { ctx.OvmExecutionManager = chainConfig.StateDump.Accounts["OVM_ExecutionManager"] ctx.OvmStateManager = chainConfig.StateDump.Accounts["OVM_StateManager"] - ctx.OvmMockAccount = chainConfig.StateDump.Accounts["mockOVM_ECDSAContractAccount"] ctx.OvmSafetyChecker = chainConfig.StateDump.Accounts["OVM_SafetyChecker"] } diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol index ee013f1e69345..90565026dfe04 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol @@ -1,15 +1,19 @@ // SPDX-License-Identifier: MIT +// @unsupported: evm pragma solidity >0.5.0 <0.8.0; pragma experimental ABIEncoderV2; /* Interface Imports */ +import { iOVM_ERC20 } from "../../iOVM/predeploys/iOVM_ERC20.sol"; import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContractAccount.sol"; /* Library Imports */ import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; import { Lib_ECDSAUtils } from "../../libraries/utils/Lib_ECDSAUtils.sol"; -import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol"; -import { Lib_SafeMathWrapper } from "../../libraries/wrappers/Lib_SafeMathWrapper.sol"; +import { Lib_ExecutionManagerWrapper } from "../../libraries/wrappers/Lib_ExecutionManagerWrapper.sol"; + +/* External Imports */ +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; /** * @title OVM_ECDSAContractAccount @@ -17,7 +21,7 @@ import { Lib_SafeMathWrapper } from "../../libraries/wrappers/Lib_SafeMathWrappe * ovmCREATEEOA operation. It enables backwards compatibility with Ethereum's Layer 1, by * providing eth_sign and EIP155 formatted transaction encodings. * - * Compiler used: solc + * Compiler used: optimistic-solc * Runtime target: OVM */ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { @@ -29,7 +33,7 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { // TODO: should be the amount sufficient to cover the gas costs of all of the transactions up // to and including the CALL/CREATE which forms the entrypoint of the transaction. uint256 constant EXECUTION_VALIDATION_GAS_OVERHEAD = 25000; - address constant ETH_ERC20_ADDRESS = 0x4200000000000000000000000000000000000006; + iOVM_ERC20 constant ETH_ERC20 = iOVM_ERC20(0x4200000000000000000000000000000000000006); /******************** @@ -66,75 +70,76 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { // recovered address of the user who signed this message. This is how we manage to shim // account abstraction even though the user isn't a contract. // Need to make sure that the transaction nonce is right and bump it if so. - Lib_SafeExecutionManagerWrapper.safeREQUIRE( + require( Lib_ECDSAUtils.recover( _transaction, isEthSign, _v, _r, _s - ) == Lib_SafeExecutionManagerWrapper.safeADDRESS(), + ) == address(this), "Signature provided for EOA transaction execution is invalid." ); Lib_OVMCodec.EIP155Transaction memory decodedTx = Lib_OVMCodec.decodeEIP155Transaction(_transaction, isEthSign); // Need to make sure that the transaction chainId is correct. - Lib_SafeExecutionManagerWrapper.safeREQUIRE( - decodedTx.chainId == Lib_SafeExecutionManagerWrapper.safeCHAINID(), + require( + decodedTx.chainId == Lib_ExecutionManagerWrapper.ovmCHAINID(), "Transaction chainId does not match expected OVM chainId." ); // Need to make sure that the transaction nonce is right. - Lib_SafeExecutionManagerWrapper.safeREQUIRE( - decodedTx.nonce == Lib_SafeExecutionManagerWrapper.safeGETNONCE(), + require( + decodedTx.nonce == Lib_ExecutionManagerWrapper.ovmGETNONCE(), "Transaction nonce does not match the expected nonce." ); // TEMPORARY: Disable gas checks for mainnet. // // Need to make sure that the gas is sufficient to execute the transaction. - // Lib_SafeExecutionManagerWrapper.safeREQUIRE( - // gasleft() >= Lib_SafeMathWrapper.add(decodedTx.gasLimit, EXECUTION_VALIDATION_GAS_OVERHEAD), + // Lib_ExecutionManagerWrapper.safeREQUIRE( + // gasleft() >= SafeMath.add(decodedTx.gasLimit, EXECUTION_VALIDATION_GAS_OVERHEAD), // "Gas is not sufficient to execute the transaction." // ); // Transfer fee to relayer. - address relayer = Lib_SafeExecutionManagerWrapper.safeCALLER(); - uint256 fee = Lib_SafeMathWrapper.mul(decodedTx.gasLimit, decodedTx.gasPrice); - (bool success, ) = Lib_SafeExecutionManagerWrapper.safeCALL( - gasleft(), - ETH_ERC20_ADDRESS, - abi.encodeWithSignature("transfer(address,uint256)", relayer, fee) - ); - Lib_SafeExecutionManagerWrapper.safeREQUIRE( - success == true, + require( + ETH_ERC20.transfer( + msg.sender, + SafeMath.mul(decodedTx.gasLimit, decodedTx.gasPrice) + ), "Fee was not transferred to relayer." ); // Contract creations are signalled by sending a transaction to the zero address. if (decodedTx.to == address(0)) { - (address created, bytes memory revertData) = Lib_SafeExecutionManagerWrapper.safeCREATE( - gasleft(), - decodedTx.data - ); + address created; + bytes memory code = decodedTx.data; + bytes memory revertdata; + assembly { + created := create(0, add(code, 0x20), mload(code)) + if iszero(created) { + let size := returndatasize() + revertdata := mload(0x40) + mstore(0x40, add(add(revertdata, 0x20), size)) + mstore(revertdata, size) + returndatacopy(add(revertdata, 0x20), 0x0, size) + } + } - // Return true if the contract creation succeeded, false w/ revertData otherwise. + // Return true if the contract creation succeeded, false w/ revertdata otherwise. if (created != address(0)) { return (true, abi.encode(created)); } else { - return (false, revertData); + return (false, revertdata); } } else { // We only want to bump the nonce for `ovmCALL` because `ovmCREATE` automatically bumps // the nonce of the calling account. Normally an EOA would bump the nonce for both // cases, but since this is a contract we'd end up bumping the nonce twice. - Lib_SafeExecutionManagerWrapper.safeINCREMENTNONCE(); + Lib_ExecutionManagerWrapper.ovmINCREMENTNONCE(); - return Lib_SafeExecutionManagerWrapper.safeCALL( - gasleft(), - decodedTx.to, - decodedTx.data - ); + return decodedTx.to.call(decodedTx.data); } } } diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol index 0f376f821fee0..2d1477aa109b3 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol @@ -3,9 +3,6 @@ pragma solidity >0.5.0 <0.8.0; /* Library Imports */ import { Lib_Bytes32Utils } from "../../libraries/utils/Lib_Bytes32Utils.sol"; -import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; -import { Lib_ECDSAUtils } from "../../libraries/utils/Lib_ECDSAUtils.sol"; -import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol"; /** * @title OVM_ProxyEOA @@ -13,7 +10,7 @@ import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_Sa * In combination with the logic implemented in the ECDSA Contract Account, this enables a form of upgradable * 'account abstraction' on layer 2. * - * Compiler used: solc + * Compiler used: optimistic-solc * Runtime target: OVM */ contract OVM_ProxyEOA { @@ -47,20 +44,16 @@ contract OVM_ProxyEOA { fallback() external { - (bool success, bytes memory returndata) = Lib_SafeExecutionManagerWrapper.safeDELEGATECALL( - gasleft(), - getImplementation(), - msg.data - ); + (bool success, bytes memory returndata) = getImplementation().call(msg.data); if (success) { assembly { return(add(returndata, 0x20), mload(returndata)) } } else { - Lib_SafeExecutionManagerWrapper.safeREVERT( - string(returndata) - ); + assembly { + revert(add(returndata, 0x20), mload(returndata)) + } } } @@ -78,8 +71,8 @@ contract OVM_ProxyEOA { ) external { - Lib_SafeExecutionManagerWrapper.safeREQUIRE( - Lib_SafeExecutionManagerWrapper.safeADDRESS() == Lib_SafeExecutionManagerWrapper.safeCALLER(), + require( + msg.sender == address(this), "EOAs can only upgrade their own EOA implementation" ); @@ -96,11 +89,11 @@ contract OVM_ProxyEOA { address ) { - return Lib_Bytes32Utils.toAddress( - Lib_SafeExecutionManagerWrapper.safeSLOAD( - IMPLEMENTATION_KEY - ) - ); + bytes32 addr32; + assembly { + addr32 := sload(IMPLEMENTATION_KEY) + } + return Lib_Bytes32Utils.toAddress(addr32); } @@ -113,9 +106,9 @@ contract OVM_ProxyEOA { ) internal { - Lib_SafeExecutionManagerWrapper.safeSSTORE( - IMPLEMENTATION_KEY, - Lib_Bytes32Utils.fromAddress(_implementation) - ); + bytes32 addr32 = Lib_Bytes32Utils.fromAddress(_implementation); + assembly { + sstore(IMPLEMENTATION_KEY, addr32) + } } } diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L2CrossDomainMessenger.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L2CrossDomainMessenger.sol index cddb14559c78c..d5f0f04207ef2 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L2CrossDomainMessenger.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L2CrossDomainMessenger.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: MIT +// @unsupported: evm pragma solidity >0.5.0 <0.8.0; pragma experimental ABIEncoderV2; /* Library Imports */ import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol"; import { Lib_ReentrancyGuard } from "../../../libraries/utils/Lib_ReentrancyGuard.sol"; +import { Lib_ExecutionManagerWrapper } from "../../../libraries/wrappers/Lib_ExecutionManagerWrapper.sol"; /* Interface Imports */ import { iOVM_L2CrossDomainMessenger } from "../../../iOVM/bridge/messaging/iOVM_L2CrossDomainMessenger.sol"; -import { iOVM_L1MessageSender } from "../../../iOVM/predeploys/iOVM_L1MessageSender.sol"; import { iOVM_L2ToL1MessagePasser } from "../../../iOVM/predeploys/iOVM_L2ToL1MessagePasser.sol"; /* Contract Imports */ @@ -117,14 +118,13 @@ contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, Abs_BaseCros * @return _valid Whether or not the message is valid. */ function _verifyXDomainMessage() - view internal returns ( bool _valid ) { return ( - iOVM_L1MessageSender(resolve("OVM_L1MessageSender")).getL1MessageSender() == resolve("OVM_L1CrossDomainMessenger") + Lib_ExecutionManagerWrapper.ovmL1TXORIGIN() == resolve("OVM_L1CrossDomainMessenger") ); } diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/chain/OVM_StateCommitmentChain.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/chain/OVM_StateCommitmentChain.sol index a860b7236f06f..646251be09192 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/chain/OVM_StateCommitmentChain.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/chain/OVM_StateCommitmentChain.sol @@ -15,7 +15,7 @@ import { iOVM_BondManager } from "../../iOVM/verification/iOVM_BondManager.sol"; import { iOVM_ChainStorageContainer } from "../../iOVM/chain/iOVM_ChainStorageContainer.sol"; /* External Imports */ -import '@openzeppelin/contracts/math/SafeMath.sol'; +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; /** * @title OVM_StateCommitmentChain diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol index 8b5189cfdaf2d..08de2e7f32b21 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol @@ -6,7 +6,6 @@ import { Lib_Bytes32Utils } from "../../libraries/utils/Lib_Bytes32Utils.sol"; /* Interface Imports */ import { iOVM_DeployerWhitelist } from "../../iOVM/predeploys/iOVM_DeployerWhitelist.sol"; -import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol"; /** * @title OVM_DeployerWhitelist @@ -23,10 +22,11 @@ contract OVM_DeployerWhitelist is iOVM_DeployerWhitelist { /********************** * Contract Constants * **********************/ - - bytes32 internal constant KEY_INITIALIZED = 0x0000000000000000000000000000000000000000000000000000000000000010; - bytes32 internal constant KEY_OWNER = 0x0000000000000000000000000000000000000000000000000000000000000011; - bytes32 internal constant KEY_ALLOW_ARBITRARY_DEPLOYMENT = 0x0000000000000000000000000000000000000000000000000000000000000012; + + bool public initialized; + bool public allowArbitraryDeployment; + address public owner; + mapping (address => bool) public whitelist; /********************** @@ -37,14 +37,8 @@ contract OVM_DeployerWhitelist is iOVM_DeployerWhitelist { * Blocks functions to anyone except the contract owner. */ modifier onlyOwner() { - address owner = Lib_Bytes32Utils.toAddress( - Lib_SafeExecutionManagerWrapper.safeSLOAD( - KEY_OWNER - ) - ); - - Lib_SafeExecutionManagerWrapper.safeREQUIRE( - Lib_SafeExecutionManagerWrapper.safeCALLER() == owner, + require( + msg.sender == owner, "Function can only be called by the owner of this contract." ); _; @@ -67,43 +61,13 @@ contract OVM_DeployerWhitelist is iOVM_DeployerWhitelist { override public { - bool initialized = Lib_Bytes32Utils.toBool( - Lib_SafeExecutionManagerWrapper.safeSLOAD(KEY_INITIALIZED) - ); - if (initialized == true) { return; } - Lib_SafeExecutionManagerWrapper.safeSSTORE( - KEY_INITIALIZED, - Lib_Bytes32Utils.fromBool(true) - ); - Lib_SafeExecutionManagerWrapper.safeSSTORE( - KEY_OWNER, - Lib_Bytes32Utils.fromAddress(_owner) - ); - Lib_SafeExecutionManagerWrapper.safeSSTORE( - KEY_ALLOW_ARBITRARY_DEPLOYMENT, - Lib_Bytes32Utils.fromBool(_allowArbitraryDeployment) - ); - } - - /** - * Gets the owner of the whitelist. - */ - function getOwner() - override - public - returns( - address - ) - { - return Lib_Bytes32Utils.toAddress( - Lib_SafeExecutionManagerWrapper.safeSLOAD( - KEY_OWNER - ) - ); + initialized = true; + allowArbitraryDeployment = _allowArbitraryDeployment; + owner = _owner; } /** @@ -119,10 +83,7 @@ contract OVM_DeployerWhitelist is iOVM_DeployerWhitelist { public onlyOwner { - Lib_SafeExecutionManagerWrapper.safeSSTORE( - Lib_Bytes32Utils.fromAddress(_deployer), - Lib_Bytes32Utils.fromBool(_isWhitelisted) - ); + whitelist[_deployer] = _isWhitelisted; } /** @@ -136,10 +97,7 @@ contract OVM_DeployerWhitelist is iOVM_DeployerWhitelist { public onlyOwner { - Lib_SafeExecutionManagerWrapper.safeSSTORE( - KEY_OWNER, - Lib_Bytes32Utils.fromAddress(_owner) - ); + owner = _owner; } /** @@ -153,10 +111,7 @@ contract OVM_DeployerWhitelist is iOVM_DeployerWhitelist { public onlyOwner { - Lib_SafeExecutionManagerWrapper.safeSSTORE( - KEY_ALLOW_ARBITRARY_DEPLOYMENT, - Lib_Bytes32Utils.fromBool(_allowArbitraryDeployment) - ); + allowArbitraryDeployment = _allowArbitraryDeployment; } /** @@ -185,28 +140,10 @@ contract OVM_DeployerWhitelist is iOVM_DeployerWhitelist { bool _allowed ) { - bool initialized = Lib_Bytes32Utils.toBool( - Lib_SafeExecutionManagerWrapper.safeSLOAD(KEY_INITIALIZED) - ); - - if (initialized == false) { - return true; - } - - bool allowArbitraryDeployment = Lib_Bytes32Utils.toBool( - Lib_SafeExecutionManagerWrapper.safeSLOAD(KEY_ALLOW_ARBITRARY_DEPLOYMENT) - ); - - if (allowArbitraryDeployment == true) { - return true; - } - - bool isWhitelisted = Lib_Bytes32Utils.toBool( - Lib_SafeExecutionManagerWrapper.safeSLOAD( - Lib_Bytes32Utils.fromAddress(_deployer) - ) - ); - - return isWhitelisted; + return ( + initialized == false + || allowArbitraryDeployment == true + || whitelist[_deployer] + ); } } diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_L1MessageSender.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_L1MessageSender.sol deleted file mode 100644 index e6c749b87014a..0000000000000 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_L1MessageSender.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.8.0; - -/* Interface Imports */ -import { iOVM_L1MessageSender } from "../../iOVM/predeploys/iOVM_L1MessageSender.sol"; -import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol"; - -/** - * @title OVM_L1MessageSender - * @dev The L1MessageSender is a predeploy contract running on L2. During the execution of cross - * domain transaction from L1 to L2, it returns the address of the L1 account (either an EOA or - * contract) which sent the message to L2 via the Canonical Transaction Chain's `enqueue()` - * function. - * - * This contract exclusively serves as a getter for the ovmL1TXORIGIN operation. This is necessary - * because there is no corresponding operation in the EVM which the the optimistic solidity compiler - * can be replaced with a call to the ExecutionManager's ovmL1TXORIGIN() function. - * - * - * Compiler used: solc - * Runtime target: OVM - */ -contract OVM_L1MessageSender is iOVM_L1MessageSender { - - /******************** - * Public Functions * - ********************/ - - /** - * @return _l1MessageSender L1 message sender address (msg.sender). - */ - function getL1MessageSender() - override - public - view - returns ( - address _l1MessageSender - ) - { - // Note that on L2 msg.sender (ie. evmCALLER) will always be the Execution Manager - return iOVM_ExecutionManager(msg.sender).ovmL1TXORIGIN(); - } -} diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_ProxySequencerEntrypoint.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_ProxySequencerEntrypoint.sol deleted file mode 100644 index 8ef0ca5df797b..0000000000000 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_ProxySequencerEntrypoint.sol +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.8.0; - -/* Library Imports */ -import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol"; - -/** - * @title OVM_ProxySequencerEntrypoint - * @dev The Proxy Sequencer Entrypoint is a predeployed proxy to the implementation of the - * Sequencer Entrypoint. This will enable the Optimism team to upgrade the Sequencer Entrypoint - * contract. - * - * Compiler used: solc - * Runtime target: OVM - */ -contract OVM_ProxySequencerEntrypoint { - - /********************* - * Fallback Function * - *********************/ - - fallback() - external - { - Lib_SafeExecutionManagerWrapper.safeDELEGATECALL( - gasleft(), - _getImplementation(), - msg.data - ); - } - - - /******************** - * Public Functions * - ********************/ - - function init( - address _implementation, - address _owner - ) - external - { - Lib_SafeExecutionManagerWrapper.safeREQUIRE( - _getOwner() == address(0), - "ProxySequencerEntrypoint has already been inited" - ); - _setOwner(_owner); - _setImplementation(_implementation); - } - - function upgrade( - address _implementation - ) - external - { - Lib_SafeExecutionManagerWrapper.safeREQUIRE( - _getOwner() == Lib_SafeExecutionManagerWrapper.safeCALLER(), - "Only owner can upgrade the Entrypoint" - ); - - _setImplementation(_implementation); - } - - - /********************** - * Internal Functions * - **********************/ - - function _setImplementation( - address _implementation - ) - internal - { - Lib_SafeExecutionManagerWrapper.safeSSTORE( - bytes32(uint256(0)), - bytes32(uint256(uint160(_implementation))) - ); - } - - function _getImplementation() - internal - returns ( - address _implementation - ) - { - return address(uint160(uint256( - Lib_SafeExecutionManagerWrapper.safeSLOAD( - bytes32(uint256(0)) - ) - ))); - } - - function _setOwner( - address _owner - ) - internal - { - Lib_SafeExecutionManagerWrapper.safeSSTORE( - bytes32(uint256(1)), - bytes32(uint256(uint160(_owner))) - ); - } - - function _getOwner() - internal - returns ( - address _owner - ) - { - return address(uint160(uint256( - Lib_SafeExecutionManagerWrapper.safeSLOAD( - bytes32(uint256(1)) - ) - ))); - } -} diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol index bba7dd59c90fc..c2138bc5a8d65 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol @@ -1,11 +1,15 @@ // SPDX-License-Identifier: MIT +// @unsupported: evm pragma solidity >0.5.0 <0.8.0; +/* Interface Imports */ +import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContractAccount.sol"; + /* Library Imports */ import { Lib_BytesUtils } from "../../libraries/utils/Lib_BytesUtils.sol"; import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; import { Lib_ECDSAUtils } from "../../libraries/utils/Lib_ECDSAUtils.sol"; -import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol"; +import { Lib_ExecutionManagerWrapper } from "../../libraries/wrappers/Lib_ExecutionManagerWrapper.sol"; /** * @title OVM_SequencerEntrypoint @@ -61,41 +65,48 @@ contract OVM_SequencerEntrypoint { // Need to decompress and then re-encode the transaction based on the original encoding. bytes memory encodedTx = Lib_OVMCodec.encodeEIP155Transaction( - Lib_OVMCodec.decompressEIP155Transaction(compressedTx), + Lib_OVMCodec.decompressEIP155Transaction( + compressedTx, + Lib_ExecutionManagerWrapper.ovmCHAINID() + ), isEthSignedMessage ); address target = Lib_ECDSAUtils.recover( encodedTx, isEthSignedMessage, - uint8(v), + v, r, s ); - if (Lib_SafeExecutionManagerWrapper.safeEXTCODESIZE(target) == 0) { + bool isEmptyContract; + assembly { + isEmptyContract := iszero(extcodesize(target)) + } + + if (isEmptyContract) { // ProxyEOA has not yet been deployed for this EOA. bytes32 messageHash = Lib_ECDSAUtils.getMessageHash(encodedTx, isEthSignedMessage); - Lib_SafeExecutionManagerWrapper.safeCREATEEOA(messageHash, uint8(v), r, s); + Lib_ExecutionManagerWrapper.ovmCREATEEOA(messageHash, v, r, s); + } + + Lib_OVMCodec.EOASignatureType sigtype; + if (isEthSignedMessage) { + sigtype = Lib_OVMCodec.EOASignatureType.ETH_SIGNED_MESSAGE; + } else { + sigtype = Lib_OVMCodec.EOASignatureType.EIP155_TRANSACTION; } - // ProxyEOA has been deployed for this EOA, continue to CALL. - bytes memory callbytes = abi.encodeWithSignature( - "execute(bytes,uint8,uint8,bytes32,bytes32)", + iOVM_ECDSAContractAccount(target).execute( encodedTx, - isEthSignedMessage, - uint8(v), + sigtype, + v, r, s ); - - Lib_SafeExecutionManagerWrapper.safeCALL( - gasleft(), - target, - callbytes - ); } - + /********************** * Internal Functions * @@ -119,9 +130,7 @@ contract OVM_SequencerEntrypoint { } if (_transactionType == 2) { return TransactionType.ETH_SIGNED_MESSAGE; } else { - Lib_SafeExecutionManagerWrapper.safeREVERT( - "Transaction type must be 0 or 2" - ); + revert("Transaction type must be 0 or 2"); } } } diff --git a/packages/contracts/contracts/optimistic-ethereum/iOVM/predeploys/iOVM_DeployerWhitelist.sol b/packages/contracts/contracts/optimistic-ethereum/iOVM/predeploys/iOVM_DeployerWhitelist.sol index 8274f6413eeb1..2ea149da85aee 100644 --- a/packages/contracts/contracts/optimistic-ethereum/iOVM/predeploys/iOVM_DeployerWhitelist.sol +++ b/packages/contracts/contracts/optimistic-ethereum/iOVM/predeploys/iOVM_DeployerWhitelist.sol @@ -11,7 +11,6 @@ interface iOVM_DeployerWhitelist { ********************/ function initialize(address _owner, bool _allowArbitraryDeployment) external; - function getOwner() external returns (address _owner); function setWhitelistedDeployer(address _deployer, bool _isWhitelisted) external; function setOwner(address _newOwner) external; function setAllowArbitraryDeployment(bool _allowArbitraryDeployment) external; diff --git a/packages/contracts/contracts/optimistic-ethereum/iOVM/predeploys/iOVM_L1MessageSender.sol b/packages/contracts/contracts/optimistic-ethereum/iOVM/predeploys/iOVM_L1MessageSender.sol deleted file mode 100644 index ead8e7783ed33..0000000000000 --- a/packages/contracts/contracts/optimistic-ethereum/iOVM/predeploys/iOVM_L1MessageSender.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.8.0; - -/** - * @title iOVM_L1MessageSender - */ -interface iOVM_L1MessageSender { - - /******************** - * Public Functions * - ********************/ - - function getL1MessageSender() external view returns (address _l1MessageSender); -} diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol index 0cb7245956a5b..174959d6966da 100644 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol @@ -7,7 +7,6 @@ import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol"; import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol"; import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol"; import { Lib_Bytes32Utils } from "../utils/Lib_Bytes32Utils.sol"; -import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol"; /** * @title Lib_OVMCodec @@ -155,10 +154,12 @@ library Lib_OVMCodec { /** * Decompresses a compressed EIP155 transaction. * @param _transaction Compressed EIP155 transaction bytes. + * @param _chainId Chain ID used to sign this transaction. * @return Transaction parsed into a struct. */ function decompressEIP155Transaction( - bytes memory _transaction + bytes memory _transaction, + uint256 _chainId ) internal returns ( @@ -171,7 +172,7 @@ library Lib_OVMCodec { nonce: Lib_BytesUtils.toUint24(_transaction, 6), to: Lib_BytesUtils.toAddress(_transaction, 9), data: Lib_BytesUtils.slice(_transaction, 29), - chainId: Lib_SafeExecutionManagerWrapper.safeCHAINID(), + chainId: _chainId, value: 0 }); } diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_ExecutionManagerWrapper.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_ExecutionManagerWrapper.sol new file mode 100644 index 0000000000000..37429ad7d383f --- /dev/null +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_ExecutionManagerWrapper.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: MIT +// @unsupported: evm +pragma solidity >0.5.0 <0.8.0; + +/* Library Imports */ +import { Lib_ErrorUtils } from "../utils/Lib_ErrorUtils.sol"; + +/** + * @title Lib_ExecutionManagerWrapper + * @dev The Safe Execution Manager Wrapper provides functions which facilitate writing OVM safe + * code using the standard solidity compiler, by routing all its operations through the Execution + * Manager. + * + * Compiler used: solc + * Runtime target: OVM + */ +library Lib_ExecutionManagerWrapper { + + /********************** + * Internal Functions * + **********************/ + + /** + * Performs a safe ovmCHAINID call. + * @return _CHAINID Result of calling ovmCHAINID. + */ + function ovmCHAINID() + internal + returns ( + uint256 _CHAINID + ) + { + bytes memory returndata = _safeExecutionManagerInteraction( + abi.encodeWithSignature( + "ovmCHAINID()" + ) + ); + + return abi.decode(returndata, (uint256)); + } + + /** + * Performs a safe ovmGETNONCE call. + * @return _nonce Result of calling ovmGETNONCE. + */ + function ovmGETNONCE() + internal + returns ( + uint256 _nonce + ) + { + bytes memory returndata = _safeExecutionManagerInteraction( + abi.encodeWithSignature( + "ovmGETNONCE()" + ) + ); + + return abi.decode(returndata, (uint256)); + } + + /** + * Performs a safe ovmINCREMENTNONCE call. + */ + function ovmINCREMENTNONCE() + internal + { + _safeExecutionManagerInteraction( + abi.encodeWithSignature( + "ovmINCREMENTNONCE()" + ) + ); + } + + /** + * Performs a safe ovmCREATEEOA call. + * @param _messageHash Message hash which was signed by EOA + * @param _v v value of signature (0 or 1) + * @param _r r value of signature + * @param _s s value of signature + */ + function ovmCREATEEOA( + bytes32 _messageHash, + uint8 _v, + bytes32 _r, + bytes32 _s + ) + internal + { + _safeExecutionManagerInteraction( + abi.encodeWithSignature( + "ovmCREATEEOA(bytes32,uint8,bytes32,bytes32)", + _messageHash, + _v, + _r, + _s + ) + ); + } + + /** + * Calls the ovmL1TXORIGIN opcode. + * @return Address that sent this message from L1. + */ + function ovmL1TXORIGIN() + internal + returns ( + address + ) + { + bytes memory returndata = _safeExecutionManagerInteraction( + abi.encodeWithSignature( + "ovmL1TXORIGIN()" + ) + ); + + return abi.decode(returndata, (address)); + } + + + /********************* + * Private Functions * + *********************/ + + /** + * Performs an ovm interaction and the necessary safety checks. + * @param _calldata Data to send to the OVM_ExecutionManager (encoded with sighash). + * @return _returndata Data sent back by the OVM_ExecutionManager. + */ + function _safeExecutionManagerInteraction( + bytes memory _calldata + ) + private + returns ( + bytes memory + ) + { + bytes memory returndata; + assembly { + kall(add(_calldata, 0x20), mload(_calldata), 0x0, 0x0) + let size := returndatasize() + returndata := mload(0x40) + mstore(0x40, add(add(returndata, 0x20), size)) + mstore(returndata, size) + returndatacopy(add(returndata, 0x20), 0x0, size) + } + return returndata; + } +} diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol deleted file mode 100644 index 14dc89bdf8ed0..0000000000000 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol +++ /dev/null @@ -1,376 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.8.0; - -/* Library Imports */ -import { Lib_ErrorUtils } from "../utils/Lib_ErrorUtils.sol"; - -/** - * @title Lib_SafeExecutionManagerWrapper - * @dev The Safe Execution Manager Wrapper provides functions which facilitate writing OVM safe - * code using the standard solidity compiler, by routing all its operations through the Execution - * Manager. - * - * Compiler used: solc - * Runtime target: OVM - */ -library Lib_SafeExecutionManagerWrapper { - - /********************** - * Internal Functions * - **********************/ - - /** - * Performs a safe ovmCALL. - * @param _gasLimit Gas limit for the call. - * @param _target Address to call. - * @param _calldata Data to send to the call. - * @return _success Whether or not the call reverted. - * @return _returndata Data returned by the call. - */ - function safeCALL( - uint256 _gasLimit, - address _target, - bytes memory _calldata - ) - internal - returns ( - bool _success, - bytes memory _returndata - ) - { - bytes memory returndata = _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmCALL(uint256,address,bytes)", - _gasLimit, - _target, - _calldata - ) - ); - - return abi.decode(returndata, (bool, bytes)); - } - - /** - * Performs a safe ovmDELEGATECALL. - * @param _gasLimit Gas limit for the call. - * @param _target Address to call. - * @param _calldata Data to send to the call. - * @return _success Whether or not the call reverted. - * @return _returndata Data returned by the call. - */ - function safeDELEGATECALL( - uint256 _gasLimit, - address _target, - bytes memory _calldata - ) - internal - returns ( - bool _success, - bytes memory _returndata - ) - { - bytes memory returndata = _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmDELEGATECALL(uint256,address,bytes)", - _gasLimit, - _target, - _calldata - ) - ); - - return abi.decode(returndata, (bool, bytes)); - } - - /** - * Performs a safe ovmCREATE call. - * @param _gasLimit Gas limit for the creation. - * @param _bytecode Code for the new contract. - * @return _contract Address of the created contract. - */ - function safeCREATE( - uint256 _gasLimit, - bytes memory _bytecode - ) - internal - returns ( - address, - bytes memory - ) - { - bytes memory returndata = _safeExecutionManagerInteraction( - _gasLimit, - abi.encodeWithSignature( - "ovmCREATE(bytes)", - _bytecode - ) - ); - - return abi.decode(returndata, (address, bytes)); - } - - /** - * Performs a safe ovmEXTCODESIZE call. - * @param _contract Address of the contract to query the size of. - * @return _EXTCODESIZE Size of the requested contract in bytes. - */ - function safeEXTCODESIZE( - address _contract - ) - internal - returns ( - uint256 _EXTCODESIZE - ) - { - bytes memory returndata = _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmEXTCODESIZE(address)", - _contract - ) - ); - - return abi.decode(returndata, (uint256)); - } - - /** - * Performs a safe ovmCHAINID call. - * @return _CHAINID Result of calling ovmCHAINID. - */ - function safeCHAINID() - internal - returns ( - uint256 _CHAINID - ) - { - bytes memory returndata = _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmCHAINID()" - ) - ); - - return abi.decode(returndata, (uint256)); - } - - /** - * Performs a safe ovmCALLER call. - * @return _CALLER Result of calling ovmCALLER. - */ - function safeCALLER() - internal - returns ( - address _CALLER - ) - { - bytes memory returndata = _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmCALLER()" - ) - ); - - return abi.decode(returndata, (address)); - } - - /** - * Performs a safe ovmADDRESS call. - * @return _ADDRESS Result of calling ovmADDRESS. - */ - function safeADDRESS() - internal - returns ( - address _ADDRESS - ) - { - bytes memory returndata = _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmADDRESS()" - ) - ); - - return abi.decode(returndata, (address)); - } - - /** - * Performs a safe ovmGETNONCE call. - * @return _nonce Result of calling ovmGETNONCE. - */ - function safeGETNONCE() - internal - returns ( - uint256 _nonce - ) - { - bytes memory returndata = _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmGETNONCE()" - ) - ); - - return abi.decode(returndata, (uint256)); - } - - /** - * Performs a safe ovmINCREMENTNONCE call. - */ - function safeINCREMENTNONCE() - internal - { - _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmINCREMENTNONCE()" - ) - ); - } - - /** - * Performs a safe ovmCREATEEOA call. - * @param _messageHash Message hash which was signed by EOA - * @param _v v value of signature (0 or 1) - * @param _r r value of signature - * @param _s s value of signature - */ - function safeCREATEEOA( - bytes32 _messageHash, - uint8 _v, - bytes32 _r, - bytes32 _s - ) - internal - { - _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmCREATEEOA(bytes32,uint8,bytes32,bytes32)", - _messageHash, - _v, - _r, - _s - ) - ); - } - - /** - * Performs a safe REVERT. - * @param _reason String revert reason to pass along with the REVERT. - */ - function safeREVERT( - string memory _reason - ) - internal - { - _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmREVERT(bytes)", - Lib_ErrorUtils.encodeRevertString( - _reason - ) - ) - ); - } - - /** - * Performs a safe "require". - * @param _condition Boolean condition that must be true or will revert. - * @param _reason String revert reason to pass along with the REVERT. - */ - function safeREQUIRE( - bool _condition, - string memory _reason - ) - internal - { - if (!_condition) { - safeREVERT( - _reason - ); - } - } - - /** - * Performs a safe ovmSLOAD call. - */ - function safeSLOAD( - bytes32 _key - ) - internal - returns ( - bytes32 - ) - { - bytes memory returndata = _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmSLOAD(bytes32)", - _key - ) - ); - - return abi.decode(returndata, (bytes32)); - } - - /** - * Performs a safe ovmSSTORE call. - */ - function safeSSTORE( - bytes32 _key, - bytes32 _value - ) - internal - { - _safeExecutionManagerInteraction( - abi.encodeWithSignature( - "ovmSSTORE(bytes32,bytes32)", - _key, - _value - ) - ); - } - - /********************* - * Private Functions * - *********************/ - - /** - * Performs an ovm interaction and the necessary safety checks. - * @param _gasLimit Gas limit for the interaction. - * @param _calldata Data to send to the OVM_ExecutionManager (encoded with sighash). - * @return _returndata Data sent back by the OVM_ExecutionManager. - */ - function _safeExecutionManagerInteraction( - uint256 _gasLimit, - bytes memory _calldata - ) - private - returns ( - bytes memory _returndata - ) - { - address ovmExecutionManager = msg.sender; - ( - bool success, - bytes memory returndata - ) = ovmExecutionManager.call{gas: _gasLimit}(_calldata); - - if (success == false) { - assembly { - revert(add(returndata, 0x20), mload(returndata)) - } - } else if (returndata.length == 1) { - assembly { - return(0, 1) - } - } else { - return returndata; - } - } - - function _safeExecutionManagerInteraction( - bytes memory _calldata - ) - private - returns ( - bytes memory _returndata - ) - { - return _safeExecutionManagerInteraction( - gasleft(), - _calldata - ); - } -} diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeMathWrapper.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeMathWrapper.sol deleted file mode 100644 index 767be1ff0b11b..0000000000000 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeMathWrapper.sol +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: MIT -// Pulled from @openzeppelin/contracts/math/SafeMath.sol -// SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.8.0; - -/* Library Imports */ -import { Lib_SafeExecutionManagerWrapper } from "./Lib_SafeExecutionManagerWrapper.sol"; - -/** - * @title Lib_SafeMathWrapper - */ - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ - -library Lib_SafeMathWrapper { - /** - * @dev Returns the addition of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal returns (uint256) { - uint256 c = a + b; - Lib_SafeExecutionManagerWrapper.safeREQUIRE(c >= a, "Lib_SafeMathWrapper: addition overflow"); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - * - Subtraction cannot overflow. - */ - function sub(uint256 a, uint256 b) internal returns (uint256) { - return sub(a, b, "Lib_SafeMathWrapper: subtraction overflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - * - Subtraction cannot overflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal returns (uint256) { - Lib_SafeExecutionManagerWrapper.safeREQUIRE(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - Lib_SafeExecutionManagerWrapper.safeREQUIRE(c / a == b, "Lib_SafeMathWrapper: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal returns (uint256) { - return div(a, b, "Lib_SafeMathWrapper: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts with custom message on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal returns (uint256) { - Lib_SafeExecutionManagerWrapper.safeREQUIRE(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal returns (uint256) { - return mod(a, b, "Lib_SafeMathWrapper: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal returns (uint256) { - Lib_SafeExecutionManagerWrapper.safeREQUIRE(b != 0, errorMessage); - return a % b; - } -} \ No newline at end of file diff --git a/packages/contracts/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol b/packages/contracts/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol deleted file mode 100644 index 15c51fcf21fb3..0000000000000 --- a/packages/contracts/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.8.0; -pragma experimental ABIEncoderV2; - -/* Interface Imports */ -import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContractAccount.sol"; - -/* Library Imports */ -import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; -import { Lib_ECDSAUtils } from "../../libraries/utils/Lib_ECDSAUtils.sol"; -import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol"; - -/** - * @title mockOVM_ECDSAContractAccount - */ -contract mockOVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { - - /******************** - * Public Functions * - ********************/ - - /** - * Executes a signed transaction. - * @param _transaction Signed EOA transaction. - * @param _signatureType Hashing scheme used for the transaction (e.g., ETH signed message). - * param _v Signature `v` parameter. - * param _r Signature `r` parameter. - * param _s Signature `s` parameter. - * @return _success Whether or not the call returned (rather than reverted). - * @return _returndata Data returned by the call. - */ - function execute( - bytes memory _transaction, - Lib_OVMCodec.EOASignatureType _signatureType, - uint8, // _v, - bytes32, // _r, - bytes32 // _s - ) - override - public - returns ( - bool _success, - bytes memory _returndata - ) - { - bool isEthSign = _signatureType == Lib_OVMCodec.EOASignatureType.ETH_SIGNED_MESSAGE; - Lib_OVMCodec.EIP155Transaction memory decodedTx = Lib_OVMCodec.decodeEIP155Transaction(_transaction, isEthSign); - - // Need to make sure that the transaction nonce is right. - Lib_SafeExecutionManagerWrapper.safeREQUIRE( - decodedTx.nonce == Lib_SafeExecutionManagerWrapper.safeGETNONCE(), - "Transaction nonce does not match the expected nonce." - ); - - // Contract creations are signalled by sending a transaction to the zero address. - if (decodedTx.to == address(0)) { - (address created, ) = Lib_SafeExecutionManagerWrapper.safeCREATE( - decodedTx.gasLimit, - decodedTx.data - ); - - // If the created address is the ZERO_ADDRESS then we know the deployment failed, though not why - return (created != address(0), abi.encode(created)); - } else { - // We only want to bump the nonce for `ovmCALL` because `ovmCREATE` automatically bumps - // the nonce of the calling account. Normally an EOA would bump the nonce for both - // cases, but since this is a contract we'd end up bumping the nonce twice. - Lib_SafeExecutionManagerWrapper.safeINCREMENTNONCE(); - - return Lib_SafeExecutionManagerWrapper.safeCALL( - decodedTx.gasLimit, - decodedTx.to, - decodedTx.data - ); - } - } - - function qall( - uint256 _gasLimit, - address _to, - bytes memory _data - ) - public - returns ( - bool _success, - bytes memory _returndata - ) - { - return Lib_SafeExecutionManagerWrapper.safeCALL( - _gasLimit, - _to, - _data - ); - } -} diff --git a/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol b/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol index b9046ac8a7766..d162c1216e0e0 100644 --- a/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol +++ b/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol @@ -48,13 +48,17 @@ contract TestLib_OVMCodec { } function decompressEIP155Transaction( - bytes memory _transaction + bytes memory _transaction, + uint256 _chainId ) public returns ( Lib_OVMCodec.EIP155Transaction memory _decompressed ) { - return Lib_OVMCodec.decompressEIP155Transaction(_transaction); + return Lib_OVMCodec.decompressEIP155Transaction( + _transaction, + _chainId + ); } } diff --git a/packages/contracts/src/contract-deployment/config.ts b/packages/contracts/src/contract-deployment/config.ts index 5ddfc87b88ef7..8b117356f2214 100644 --- a/packages/contracts/src/contract-deployment/config.ts +++ b/packages/contracts/src/contract-deployment/config.ts @@ -172,10 +172,6 @@ export const makeContractDeployConfig = async ( factory: getContractFactory('OVM_DeployerWhitelist'), params: [], }, - OVM_L1MessageSender: { - factory: getContractFactory('OVM_L1MessageSender'), - params: [], - }, OVM_L2ToL1MessagePasser: { factory: getContractFactory('OVM_L2ToL1MessagePasser'), params: [], @@ -222,12 +218,6 @@ export const makeContractDeployConfig = async ( OVM_SequencerEntrypoint: { factory: getContractFactory('OVM_SequencerEntrypoint'), }, - OVM_ProxySequencerEntrypoint: { - factory: getContractFactory('OVM_ProxySequencerEntrypoint'), - }, - mockOVM_ECDSAContractAccount: { - factory: getContractFactory('mockOVM_ECDSAContractAccount'), - }, OVM_BondManager: { factory: getContractFactory('mockOVM_BondManager'), params: [AddressManager.address], diff --git a/packages/contracts/src/contract-dumps.ts b/packages/contracts/src/contract-dumps.ts index 697f35f1206d5..7cb64fc8958c4 100644 --- a/packages/contracts/src/contract-dumps.ts +++ b/packages/contracts/src/contract-dumps.ts @@ -142,18 +142,15 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise => { 'ERC1820Registry', 'Lib_AddressManager', 'OVM_DeployerWhitelist', - 'OVM_L1MessageSender', 'OVM_L2ToL1MessagePasser', 'OVM_ProxyEOA', 'OVM_ECDSAContractAccount', - 'OVM_ProxySequencerEntrypoint', 'OVM_SequencerEntrypoint', 'OVM_L2CrossDomainMessenger', 'OVM_SafetyChecker', 'OVM_ExecutionManager', 'OVM_StateManager', 'OVM_ETH', - 'mockOVM_ECDSAContractAccount', ], deployOverrides: {}, waitForReceipts: false, @@ -164,6 +161,8 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise => { const ovmCompiled = [ 'OVM_L2ToL1MessagePasser', 'OVM_L2CrossDomainMessenger', + 'OVM_DeployerWhitelist', + 'OVM_SequencerEntrypoint', 'Lib_AddressManager', 'OVM_ETH', ] diff --git a/packages/contracts/src/predeploys.ts b/packages/contracts/src/predeploys.ts index a442cf02c54fe..12fa4929ae608 100644 --- a/packages/contracts/src/predeploys.ts +++ b/packages/contracts/src/predeploys.ts @@ -1,6 +1,5 @@ export const predeploys = { OVM_L2ToL1MessagePasser: '0x4200000000000000000000000000000000000000', - OVM_L1MessageSender: '0x4200000000000000000000000000000000000001', OVM_DeployerWhitelist: '0x4200000000000000000000000000000000000002', OVM_ECDSAContractAccount: '0x4200000000000000000000000000000000000003', OVM_ProxySequencerEntrypoint: '0x4200000000000000000000000000000000000004', diff --git a/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts b/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts deleted file mode 100644 index 9bb7fc5bd1652..0000000000000 --- a/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts +++ /dev/null @@ -1,292 +0,0 @@ -import { expect } from '../../../setup' - -/* External Imports */ -import { ethers, waffle } from 'hardhat' -import { ContractFactory, Contract, Wallet } from 'ethers' -import { MockContract, smockit } from '@eth-optimism/smock' - -/* Internal Imports */ -import { NON_ZERO_ADDRESS } from '../../../helpers/constants' -import { - serializeNativeTransaction, - signNativeTransaction, - DEFAULT_EIP155_TX, - serializeEthSignTransaction, - signEthSignMessage, - decodeSolidityError, -} from '../../../helpers' - -const callPredeploy = async ( - Helper_PredeployCaller: Contract, - predeploy: Contract, - functionName: string, - functionParams?: any[], - gasLimit?: number -): Promise => { - if (gasLimit) { - return Helper_PredeployCaller.callPredeploy( - predeploy.address, - predeploy.interface.encodeFunctionData( - functionName, - functionParams || [] - ), - { gasLimit } - ) - } - return Helper_PredeployCaller.callPredeploy( - predeploy.address, - predeploy.interface.encodeFunctionData(functionName, functionParams || []) - ) -} - -describe('OVM_ECDSAContractAccount', () => { - let wallet: Wallet - let badWallet: Wallet - before(async () => { - const provider = waffle.provider - ;[wallet, badWallet] = provider.getWallets() - }) - - let Mock__OVM_ExecutionManager: MockContract - let Helper_PredeployCaller: Contract - before(async () => { - Mock__OVM_ExecutionManager = await smockit( - await ethers.getContractFactory('OVM_ExecutionManager') - ) - - Helper_PredeployCaller = await ( - await ethers.getContractFactory('Helper_PredeployCaller') - ).deploy() - Helper_PredeployCaller.setTarget(Mock__OVM_ExecutionManager.address) - }) - - let Factory__OVM_ECDSAContractAccount: ContractFactory - before(async () => { - Factory__OVM_ECDSAContractAccount = await ethers.getContractFactory( - 'OVM_ECDSAContractAccount' - ) - }) - - let OVM_ECDSAContractAccount: Contract - beforeEach(async () => { - OVM_ECDSAContractAccount = await Factory__OVM_ECDSAContractAccount.deploy() - - Mock__OVM_ExecutionManager.smocked.ovmADDRESS.will.return.with( - await wallet.getAddress() - ) - Mock__OVM_ExecutionManager.smocked.ovmCHAINID.will.return.with(420) - Mock__OVM_ExecutionManager.smocked.ovmGETNONCE.will.return.with(100) - Mock__OVM_ExecutionManager.smocked.ovmCALL.will.return.with([true, '0x']) - Mock__OVM_ExecutionManager.smocked.ovmCREATE.will.return.with([ - NON_ZERO_ADDRESS, - '0x', - ]) - Mock__OVM_ExecutionManager.smocked.ovmCALLER.will.return.with( - NON_ZERO_ADDRESS - ) - }) - - describe('fallback()', () => { - it(`should successfully execute an EIP155Transaction`, async () => { - const message = serializeNativeTransaction(DEFAULT_EIP155_TX) - const sig = await signNativeTransaction(wallet, DEFAULT_EIP155_TX) - - await callPredeploy( - Helper_PredeployCaller, - OVM_ECDSAContractAccount, - 'execute', - [ - message, - 0, // isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ] - ) - - // The ovmCALL is the 2nd call because the first call transfers the fee. - const ovmCALL: any = Mock__OVM_ExecutionManager.smocked.ovmCALL.calls[1] - expect(ovmCALL._address).to.equal(DEFAULT_EIP155_TX.to) - expect(ovmCALL._calldata).to.equal(DEFAULT_EIP155_TX.data) - }) - - it(`should successfully execute an ETHSignedTransaction`, async () => { - const message = serializeEthSignTransaction(DEFAULT_EIP155_TX) - const sig = await signEthSignMessage(wallet, DEFAULT_EIP155_TX) - - await callPredeploy( - Helper_PredeployCaller, - OVM_ECDSAContractAccount, - 'execute', - [ - message, - 1, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ] - ) - - // The ovmCALL is the 2nd call because the first call transfers the fee. - const ovmCALL: any = Mock__OVM_ExecutionManager.smocked.ovmCALL.calls[1] - expect(ovmCALL._address).to.equal(DEFAULT_EIP155_TX.to) - expect(ovmCALL._calldata).to.equal(DEFAULT_EIP155_TX.data) - }) - - it(`should ovmCREATE if EIP155Transaction.to is zero address`, async () => { - const createTx = { ...DEFAULT_EIP155_TX, to: '' } - const message = serializeNativeTransaction(createTx) - const sig = await signNativeTransaction(wallet, createTx) - - await callPredeploy( - Helper_PredeployCaller, - OVM_ECDSAContractAccount, - 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ] - ) - - const ovmCREATE: any = - Mock__OVM_ExecutionManager.smocked.ovmCREATE.calls[0] - expect(ovmCREATE._bytecode).to.equal(createTx.data) - }) - - it(`should revert on invalid signature`, async () => { - const message = serializeNativeTransaction(DEFAULT_EIP155_TX) - const sig = await signNativeTransaction(badWallet, DEFAULT_EIP155_TX) - - await callPredeploy( - Helper_PredeployCaller, - OVM_ECDSAContractAccount, - 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ] - ) - const ovmREVERT: any = - Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] - expect(decodeSolidityError(ovmREVERT._data)).to.equal( - 'Signature provided for EOA transaction execution is invalid.' - ) - }) - - it(`should revert on incorrect nonce`, async () => { - const alteredNonceTx = { - ...DEFAULT_EIP155_TX, - nonce: 99, - } - const message = serializeNativeTransaction(alteredNonceTx) - const sig = await signNativeTransaction(wallet, alteredNonceTx) - - await callPredeploy( - Helper_PredeployCaller, - OVM_ECDSAContractAccount, - 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ] - ) - const ovmREVERT: any = - Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] - expect(decodeSolidityError(ovmREVERT._data)).to.equal( - 'Transaction nonce does not match the expected nonce.' - ) - }) - - it(`should revert on incorrect chainId`, async () => { - const alteredChainIdTx = { - ...DEFAULT_EIP155_TX, - chainId: 421, - } - const message = serializeNativeTransaction(alteredChainIdTx) - const sig = await signNativeTransaction(wallet, alteredChainIdTx) - - await callPredeploy( - Helper_PredeployCaller, - OVM_ECDSAContractAccount, - 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ] - ) - const ovmREVERT: any = - Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] - expect(decodeSolidityError(ovmREVERT._data)).to.equal( - 'Transaction chainId does not match expected OVM chainId.' - ) - }) - - // TEMPORARY: Skip gas checks for minnet. - it.skip(`should revert on insufficient gas`, async () => { - const alteredInsufficientGasTx = { - ...DEFAULT_EIP155_TX, - gasLimit: 200000000, - } - const message = serializeNativeTransaction(alteredInsufficientGasTx) - const sig = await signNativeTransaction(wallet, alteredInsufficientGasTx) - - await callPredeploy( - Helper_PredeployCaller, - OVM_ECDSAContractAccount, - 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ], - 40000000 - ) - - const ovmREVERT: any = - Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] - expect(decodeSolidityError(ovmREVERT._data)).to.equal( - 'Gas is not sufficient to execute the transaction.' - ) - }) - - it(`should revert if fee is not transferred to the relayer`, async () => { - const message = serializeNativeTransaction(DEFAULT_EIP155_TX) - const sig = await signNativeTransaction(wallet, DEFAULT_EIP155_TX) - Mock__OVM_ExecutionManager.smocked.ovmCALL.will.return.with([false, '0x']) - - await callPredeploy( - Helper_PredeployCaller, - OVM_ECDSAContractAccount, - 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ], - 40000000 - ) - - const ovmREVERT: any = - Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] - expect(decodeSolidityError(ovmREVERT._data)).to.equal( - 'Fee was not transferred to relayer.' - ) - }) - }) -}) diff --git a/packages/contracts/test/contracts/OVM/accounts/OVM_ProxyEOA.spec.ts b/packages/contracts/test/contracts/OVM/accounts/OVM_ProxyEOA.spec.ts deleted file mode 100644 index ce576e23f7695..0000000000000 --- a/packages/contracts/test/contracts/OVM/accounts/OVM_ProxyEOA.spec.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { expect } from '../../../setup' - -/* External Imports */ -import { ethers, waffle } from 'hardhat' -import { ContractFactory, Contract, Wallet } from 'ethers' -import { MockContract, smockit } from '@eth-optimism/smock' -import { remove0x } from '@eth-optimism/core-utils' - -/* Internal Imports */ -import { decodeSolidityError } from '../../../helpers' - -const callPredeploy = async ( - Helper_PredeployCaller: Contract, - predeploy: Contract, - functionName: string, - functionParams?: any[], - ethCall: boolean = false -): Promise => { - if (ethCall) { - return Helper_PredeployCaller.callStatic.callPredeployAbi( - predeploy.address, - predeploy.interface.encodeFunctionData(functionName, functionParams || []) - ) - } - return Helper_PredeployCaller.callPredeploy( - predeploy.address, - predeploy.interface.encodeFunctionData(functionName, functionParams || []) - ) -} - -const addrToBytes32 = (addr: string) => '0x' + '00'.repeat(12) + remove0x(addr) - -const eoaDefaultAddr = '0x4200000000000000000000000000000000000003' - -describe('OVM_ProxyEOA', () => { - let wallet: Wallet - before(async () => { - const provider = waffle.provider - ;[wallet] = provider.getWallets() - }) - - let Mock__OVM_ExecutionManager: MockContract - let Mock__OVM_ECDSAContractAccount: MockContract - let Helper_PredeployCaller: Contract - before(async () => { - Mock__OVM_ExecutionManager = await smockit( - await ethers.getContractFactory('OVM_ExecutionManager') - ) - - Helper_PredeployCaller = await ( - await ethers.getContractFactory('Helper_PredeployCaller') - ).deploy() - - Helper_PredeployCaller.setTarget(Mock__OVM_ExecutionManager.address) - - Mock__OVM_ECDSAContractAccount = await smockit( - await ethers.getContractFactory('OVM_ECDSAContractAccount') - ) - }) - - let OVM_ProxyEOAFactory: ContractFactory - before(async () => { - OVM_ProxyEOAFactory = await ethers.getContractFactory('OVM_ProxyEOA') - }) - - let OVM_ProxyEOA: Contract - beforeEach(async () => { - OVM_ProxyEOA = await OVM_ProxyEOAFactory.deploy(eoaDefaultAddr) - - Mock__OVM_ExecutionManager.smocked.ovmADDRESS.will.return.with( - OVM_ProxyEOA.address - ) - Mock__OVM_ExecutionManager.smocked.ovmCALLER.will.return.with( - OVM_ProxyEOA.address - ) - }) - - describe('getImplementation()', () => { - it(`should be created with implementation at predeploy address`, async () => { - const eoaDefaultAddrBytes32 = addrToBytes32(eoaDefaultAddr) - Mock__OVM_ExecutionManager.smocked.ovmSLOAD.will.return.with( - eoaDefaultAddrBytes32 - ) - const implAddrBytes32 = await callPredeploy( - Helper_PredeployCaller, - OVM_ProxyEOA, - 'getImplementation', - [], - true - ) - expect(implAddrBytes32).to.equal(eoaDefaultAddrBytes32) - }) - }) - describe('upgrade()', () => { - const implSlotKey = - '0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead' - it(`should upgrade the proxy implementation`, async () => { - const newImpl = `0x${'81'.repeat(20)}` - const newImplBytes32 = addrToBytes32(newImpl) - await callPredeploy(Helper_PredeployCaller, OVM_ProxyEOA, 'upgrade', [ - newImpl, - ]) - const ovmSSTORE: any = - Mock__OVM_ExecutionManager.smocked.ovmSSTORE.calls[0] - expect(ovmSSTORE._key).to.equal(implSlotKey) - expect(ovmSSTORE._value).to.equal(newImplBytes32) - }) - it(`should not allow upgrade of the proxy implementation by another account`, async () => { - Mock__OVM_ExecutionManager.smocked.ovmCALLER.will.return.with( - await wallet.getAddress() - ) - const newImpl = `0x${'81'.repeat(20)}` - await callPredeploy(Helper_PredeployCaller, OVM_ProxyEOA, 'upgrade', [ - newImpl, - ]) - const ovmREVERT: any = - Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] - expect(decodeSolidityError(ovmREVERT._data)).to.equal( - 'EOAs can only upgrade their own EOA implementation' - ) - }) - }) - describe('fallback()', () => { - it(`should call delegateCall with right calldata`, async () => { - Mock__OVM_ExecutionManager.smocked.ovmSLOAD.will.return.with( - addrToBytes32(Mock__OVM_ECDSAContractAccount.address) - ) - Mock__OVM_ExecutionManager.smocked.ovmDELEGATECALL.will.return.with([ - true, - '0x1234', - ]) - const calldata = '0xdeadbeef' - await Helper_PredeployCaller.callPredeploy(OVM_ProxyEOA.address, calldata) - - const ovmDELEGATECALL: any = - Mock__OVM_ExecutionManager.smocked.ovmDELEGATECALL.calls[0] - expect(ovmDELEGATECALL._address).to.equal( - Mock__OVM_ECDSAContractAccount.address - ) - expect(ovmDELEGATECALL._calldata).to.equal(calldata) - }) - it.skip(`should return data from fallback`, async () => { - //TODO test return data from fallback - }) - it.skip(`should revert in fallback`, async () => { - //TODO test reversion from fallback - }) - }) -}) diff --git a/packages/contracts/test/contracts/OVM/bridge/base/OVM_L2CrossDomainMessenger.spec.ts b/packages/contracts/test/contracts/OVM/bridge/base/OVM_L2CrossDomainMessenger.spec.ts deleted file mode 100644 index f423de1fd5ec6..0000000000000 --- a/packages/contracts/test/contracts/OVM/bridge/base/OVM_L2CrossDomainMessenger.spec.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { expect } from '../../../../setup' - -/* External Imports */ -import { ethers } from 'hardhat' -import { Signer, ContractFactory, Contract, constants } from 'ethers' -import { smockit, MockContract } from '@eth-optimism/smock' - -/* Internal Imports */ -import { - makeAddressManager, - setProxyTarget, - NON_NULL_BYTES32, - NON_ZERO_ADDRESS, - getXDomainCalldata, -} from '../../../../helpers' -import { solidityKeccak256 } from 'ethers/lib/utils' - -describe('OVM_L2CrossDomainMessenger', () => { - let signer: Signer - before(async () => { - ;[signer] = await ethers.getSigners() - }) - - let AddressManager: Contract - before(async () => { - AddressManager = await makeAddressManager() - }) - - let Mock__TargetContract: MockContract - let Mock__OVM_L1CrossDomainMessenger: MockContract - let Mock__OVM_L1MessageSender: MockContract - let Mock__OVM_L2ToL1MessagePasser: MockContract - before(async () => { - Mock__TargetContract = await smockit( - await ethers.getContractFactory('Helper_SimpleProxy') - ) - Mock__OVM_L1CrossDomainMessenger = await smockit( - await ethers.getContractFactory('OVM_L1CrossDomainMessenger') - ) - Mock__OVM_L1MessageSender = await smockit( - await ethers.getContractFactory('OVM_L1MessageSender') - ) - Mock__OVM_L2ToL1MessagePasser = await smockit( - await ethers.getContractFactory('OVM_L2ToL1MessagePasser') - ) - - await AddressManager.setAddress( - 'OVM_L1CrossDomainMessenger', - Mock__OVM_L1CrossDomainMessenger.address - ) - - await setProxyTarget( - AddressManager, - 'OVM_L1MessageSender', - Mock__OVM_L1MessageSender - ) - await setProxyTarget( - AddressManager, - 'OVM_L2ToL1MessagePasser', - Mock__OVM_L2ToL1MessagePasser - ) - }) - - let Factory__OVM_L2CrossDomainMessenger: ContractFactory - before(async () => { - Factory__OVM_L2CrossDomainMessenger = await ethers.getContractFactory( - 'OVM_L2CrossDomainMessenger' - ) - }) - - let OVM_L2CrossDomainMessenger: Contract - beforeEach(async () => { - OVM_L2CrossDomainMessenger = await Factory__OVM_L2CrossDomainMessenger.deploy( - AddressManager.address - ) - }) - - describe('sendMessage', () => { - const target = NON_ZERO_ADDRESS - const message = NON_NULL_BYTES32 - const gasLimit = 100_000 - - it('should be able to send a single message', async () => { - await expect( - OVM_L2CrossDomainMessenger.sendMessage(target, message, gasLimit) - ).to.not.be.reverted - - expect( - Mock__OVM_L2ToL1MessagePasser.smocked.passMessageToL1.calls[0] - ).to.deep.equal([ - getXDomainCalldata(await signer.getAddress(), target, message, 0), - ]) - }) - - it('should be able to send the same message twice', async () => { - await OVM_L2CrossDomainMessenger.sendMessage(target, message, gasLimit) - - await expect( - OVM_L2CrossDomainMessenger.sendMessage(target, message, gasLimit) - ).to.not.be.reverted - }) - }) - - describe('relayMessage', () => { - let target: string - let message: string - let sender: string - before(async () => { - target = Mock__TargetContract.address - message = Mock__TargetContract.interface.encodeFunctionData('setTarget', [ - NON_ZERO_ADDRESS, - ]) - sender = await signer.getAddress() - }) - - beforeEach(async () => { - Mock__OVM_L1MessageSender.smocked.getL1MessageSender.will.return.with( - Mock__OVM_L1CrossDomainMessenger.address - ) - }) - - it('should revert if the L1 message sender is not the OVM_L1CrossDomainMessenger', async () => { - Mock__OVM_L1MessageSender.smocked.getL1MessageSender.will.return.with( - constants.AddressZero - ) - - await expect( - OVM_L2CrossDomainMessenger.relayMessage(target, sender, message, 0) - ).to.be.revertedWith('Provided message could not be verified.') - }) - - it('should send a call to the target contract', async () => { - await OVM_L2CrossDomainMessenger.relayMessage(target, sender, message, 0) - - expect(Mock__TargetContract.smocked.setTarget.calls[0]).to.deep.equal([ - NON_ZERO_ADDRESS, - ]) - }) - - it('the xDomainMessageSender is reset to the original value', async () => { - await expect( - OVM_L2CrossDomainMessenger.xDomainMessageSender() - ).to.be.revertedWith('xDomainMessageSender is not set') - await OVM_L2CrossDomainMessenger.relayMessage(target, sender, message, 0) - await expect( - OVM_L2CrossDomainMessenger.xDomainMessageSender() - ).to.be.revertedWith('xDomainMessageSender is not set') - }) - - it('should revert if trying to send the same message twice', async () => { - Mock__OVM_L1MessageSender.smocked.getL1MessageSender.will.return.with( - Mock__OVM_L1CrossDomainMessenger.address - ) - - await OVM_L2CrossDomainMessenger.relayMessage(target, sender, message, 0) - - await expect( - OVM_L2CrossDomainMessenger.relayMessage(target, sender, message, 0) - ).to.be.revertedWith('Provided message has already been received.') - }) - - it('should not make a call if the target is the L2 MessagePasser', async () => { - Mock__OVM_L1MessageSender.smocked.getL1MessageSender.will.return.with( - Mock__OVM_L1CrossDomainMessenger.address - ) - target = await AddressManager.getAddress('OVM_L2ToL1MessagePasser') - message = Mock__OVM_L2ToL1MessagePasser.interface.encodeFunctionData( - 'passMessageToL1(bytes)', - [NON_NULL_BYTES32] - ) - - const resProm = OVM_L2CrossDomainMessenger.relayMessage( - target, - sender, - message, - 0 - ) - - // The call to relayMessage() should succeed. - await expect(resProm).to.not.be.reverted - - // There should be no 'relayedMessage' event logged in the receipt. - const logs = ( - await Mock__OVM_L2ToL1MessagePasser.provider.getTransactionReceipt( - (await resProm).hash - ) - ).logs - expect(logs).to.deep.equal([]) - - // The message should be registered as successful. - expect( - await OVM_L2CrossDomainMessenger.successfulMessages( - solidityKeccak256( - ['bytes'], - [getXDomainCalldata(await signer.getAddress(), target, message, 0)] - ) - ) - ).to.be.true - }) - }) -}) diff --git a/packages/contracts/test/contracts/OVM/precompiles/OVM_L1MessageSender.spec.ts b/packages/contracts/test/contracts/OVM/precompiles/OVM_L1MessageSender.spec.ts deleted file mode 100644 index dbecd901800bc..0000000000000 --- a/packages/contracts/test/contracts/OVM/precompiles/OVM_L1MessageSender.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { expect } from '../../../setup' - -/* External Imports */ -import { ethers } from 'hardhat' -import { ContractFactory, Contract } from 'ethers' -import { MockContract, smockit } from '@eth-optimism/smock' -import { NON_ZERO_ADDRESS } from '../../../helpers/constants' - -const callPredeployStatic = async ( - Helper_PredeployCaller: Contract, - predeploy: Contract, - functionName: string, - functionParams?: any[] -): Promise => { - return Helper_PredeployCaller.callStatic[functionName]( - predeploy.address, - predeploy.interface.encodeFunctionData(functionName, functionParams || []) - ) -} - -describe('OVM_L1MessageSender', () => { - let Mock__OVM_ExecutionManager: MockContract - before(async () => { - Mock__OVM_ExecutionManager = await smockit( - await ethers.getContractFactory('OVM_ExecutionManager') - ) - }) - - let Helper_PredeployCaller: Contract - before(async () => { - Helper_PredeployCaller = await ( - await ethers.getContractFactory('Helper_PredeployCaller') - ).deploy() - - Helper_PredeployCaller.setTarget(Mock__OVM_ExecutionManager.address) - }) - - let Factory__OVM_L1MessageSender: ContractFactory - before(async () => { - Factory__OVM_L1MessageSender = await ethers.getContractFactory( - 'OVM_L1MessageSender' - ) - }) - - let OVM_L1MessageSender: Contract - beforeEach(async () => { - OVM_L1MessageSender = await Factory__OVM_L1MessageSender.deploy() - }) - - describe('getL1MessageSender', () => { - before(async () => { - Mock__OVM_ExecutionManager.smocked.ovmL1TXORIGIN.will.return.with( - NON_ZERO_ADDRESS - ) - }) - - it('should return the L1 message sender', async () => { - expect( - await callPredeployStatic( - Helper_PredeployCaller, - OVM_L1MessageSender, - 'getL1MessageSender' - ) - ).to.equal(NON_ZERO_ADDRESS) - }) - }) -}) diff --git a/packages/contracts/test/contracts/OVM/precompiles/OVM_ProxySequencerEntrypoint.spec.ts b/packages/contracts/test/contracts/OVM/precompiles/OVM_ProxySequencerEntrypoint.spec.ts deleted file mode 100644 index ec1e40fac3736..0000000000000 --- a/packages/contracts/test/contracts/OVM/precompiles/OVM_ProxySequencerEntrypoint.spec.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { expect } from '../../../setup' - -/* External Imports */ -import { ethers, waffle } from 'hardhat' -import { ContractFactory, Contract, Wallet, constants } from 'ethers' -import { MockContract, smockit } from '@eth-optimism/smock' -import { remove0x } from '@eth-optimism/core-utils' - -/* Internal Imports */ -import { decodeSolidityError } from '../../../helpers' - -const callPredeploy = async ( - Helper_PredeployCaller: Contract, - predeploy: Contract, - functionName: string, - functionParams?: any[] -): Promise => { - return Helper_PredeployCaller.callPredeploy( - predeploy.address, - predeploy.interface.encodeFunctionData(functionName, functionParams || []) - ) -} - -const addrToBytes32 = (addr: string) => - '0x' + '00'.repeat(12) + remove0x(addr.toLowerCase()) - -describe('OVM_ProxySequencerEntrypoint', () => { - let wallet: Wallet - before(async () => { - const provider = waffle.provider - ;[wallet] = provider.getWallets() - }) - - let Factory__OVM_ProxySequencerEntrypoint: ContractFactory - before(async () => { - Factory__OVM_ProxySequencerEntrypoint = await ethers.getContractFactory( - 'OVM_ProxySequencerEntrypoint' - ) - }) - - let Mock__OVM_ExecutionManager: MockContract - let Helper_PredeployCaller: Contract - let OVM_SequencerEntrypoint: Contract - before(async () => { - Mock__OVM_ExecutionManager = await smockit( - await ethers.getContractFactory('OVM_ExecutionManager') - ) - - Mock__OVM_ExecutionManager.smocked.ovmCALLER.will.return.with( - await wallet.getAddress() - ) - - Mock__OVM_ExecutionManager.smocked.ovmEXTCODESIZE.will.return.with(0) - Mock__OVM_ExecutionManager.smocked.ovmCHAINID.will.return.with(420) - - Helper_PredeployCaller = await ( - await ethers.getContractFactory('Helper_PredeployCaller') - ).deploy() - - Helper_PredeployCaller.setTarget(Mock__OVM_ExecutionManager.address) - - OVM_SequencerEntrypoint = await ( - await ethers.getContractFactory('OVM_SequencerEntrypoint') - ).deploy() - }) - - let OVM_ProxySequencerEntrypoint: Contract - beforeEach(async () => { - OVM_ProxySequencerEntrypoint = await Factory__OVM_ProxySequencerEntrypoint.deploy() - }) - it(`should init the proxy with owner and implementation`, async () => { - Mock__OVM_ExecutionManager.smocked.ovmSLOAD.will.return.with( - `0x${'00'.repeat(32)}` - ) - await callPredeploy( - Helper_PredeployCaller, - OVM_ProxySequencerEntrypoint, - 'init', - [OVM_SequencerEntrypoint.address, await wallet.getAddress()] - ) - const ovmSSTOREs: any = Mock__OVM_ExecutionManager.smocked.ovmSSTORE.calls - - expect(ovmSSTOREs[0]._key).to.equal(`0x${'00'.repeat(31)}01`) - expect(ovmSSTOREs[0]._value).to.equal( - addrToBytes32(await wallet.getAddress()) - ) - - expect(ovmSSTOREs[1]._key).to.equal(`0x${'00'.repeat(32)}`) - expect(ovmSSTOREs[1]._value).to.equal( - addrToBytes32(OVM_SequencerEntrypoint.address) - ) - - // expect(await OVM_ProxySequencerEntrypoint.implementation()).to.equal( - // OVM_SequencerEntrypoint.address - // ) - }) - it(`should revert if proxy has already been inited`, async () => { - Mock__OVM_ExecutionManager.smocked.ovmSLOAD.will.return.with( - addrToBytes32(await wallet.getAddress()) - ) - await callPredeploy( - Helper_PredeployCaller, - OVM_ProxySequencerEntrypoint, - 'init', - [constants.AddressZero, constants.AddressZero] - ) - - const ovmREVERT: any = Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] - expect(decodeSolidityError(ovmREVERT._data)).to.equal( - 'ProxySequencerEntrypoint has already been inited' - ) - }) - - it(`should allow owner to upgrade Entrypoint`, async () => { - Mock__OVM_ExecutionManager.smocked.ovmSLOAD.will.return.with( - addrToBytes32(await wallet.getAddress()) - ) - await callPredeploy( - Helper_PredeployCaller, - OVM_ProxySequencerEntrypoint, - 'upgrade', - [`0x${'12'.repeat(20)}`] - ) - - const ovmSSTORE: any = Mock__OVM_ExecutionManager.smocked.ovmSSTORE.calls[0] - expect(ovmSSTORE._key).to.equal(`0x${'00'.repeat(32)}`) - expect(ovmSSTORE._value).to.equal(addrToBytes32(`0x${'12'.repeat(20)}`)) - }) - - it(`should revert if non-owner tries to upgrade Entrypoint`, async () => { - Mock__OVM_ExecutionManager.smocked.ovmSLOAD.will.return.with( - `0x${'00'.repeat(32)}` - ) - await callPredeploy( - Helper_PredeployCaller, - OVM_ProxySequencerEntrypoint, - 'upgrade', - [`0x${'12'.repeat(20)}`] - ) - const ovmREVERT: any = Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] - expect(decodeSolidityError(ovmREVERT._data)).to.equal( - 'Only owner can upgrade the Entrypoint' - ) - }) - - it(`successfully calls ovmCREATEEOA through Entrypoint fallback`, async () => { - Mock__OVM_ExecutionManager.smocked.ovmSLOAD.will.return.with( - addrToBytes32(OVM_SequencerEntrypoint.address) - ) - Mock__OVM_ExecutionManager.smocked.ovmDELEGATECALL.will.return.with([ - true, - '0x', - ]) - const calldata = '0xdeadbeef' - await Helper_PredeployCaller.callPredeploy( - OVM_ProxySequencerEntrypoint.address, - calldata - ) - const ovmDELEGATECALL: any = - Mock__OVM_ExecutionManager.smocked.ovmDELEGATECALL.calls[0] - expect(ovmDELEGATECALL._address).to.equal(OVM_SequencerEntrypoint.address) - expect(ovmDELEGATECALL._calldata).to.equal(calldata) - }) -}) diff --git a/packages/contracts/test/data/json/libraries/codec/Lib_OVMCodec.test.json b/packages/contracts/test/data/json/libraries/codec/Lib_OVMCodec.test.json index b442f4e07c8cf..6808dcef02d4d 100644 --- a/packages/contracts/test/data/json/libraries/codec/Lib_OVMCodec.test.json +++ b/packages/contracts/test/data/json/libraries/codec/Lib_OVMCodec.test.json @@ -3,7 +3,8 @@ "decompressEIP155Transaction": { "decompression": { "in": [ - "0x0001f4000064000064121212121212121212121212121212121212121299999999999999999999" + "0x0001f4000064000064121212121212121212121212121212121212121299999999999999999999", + 420 ], "out": [ [ diff --git a/packages/hardhat-ovm/src/index.ts b/packages/hardhat-ovm/src/index.ts index 40d7212839056..6e32bd8a533bd 100644 --- a/packages/hardhat-ovm/src/index.ts +++ b/packages/hardhat-ovm/src/index.ts @@ -27,6 +27,9 @@ const DEFAULT_OVM_SOLC_VERSION = '0.7.6' * @return Path to the downloaded soljson.js file. */ const getOvmSolcPath = async (version: string): Promise => { + // TEMP + version = '0.7.6-allow_kall' + // If __DANGEROUS_OVM_IGNORE_ERRORS__ env var is not undefined we append the -no-errors suffix to the solc version. if (process.env.__DANGEROUS_OVM_IGNORE_ERRORS__) { console.log('\n\n__DANGEROUS_OVM_IGNORE_ERRORS__ IS ENABLED!\n\n') From e8baf2e9d186fd4c2a62b5114c4ab6180b8cf0c4 Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Thu, 15 Apr 2021 16:12:01 -0700 Subject: [PATCH 2/8] tweaks to get tests running --- .../OVM/accounts/OVM_ProxyEOA.sol | 10 +- .../OVM/execution/OVM_ExecutionManager.sol | 10 +- packages/contracts/src/contract-dumps.ts | 1 + packages/contracts/src/predeploys.ts | 1 + .../assets/OVM_L2DepositedERC20.spec.ts | 207 ------------------ .../base/OVM_L1CrossDomainMessenger.spec.ts | 16 +- .../OVM_SequencerEntrypoint.spec.ts | 182 --------------- .../contracts/test/helpers/codec/bridge.ts | 3 +- 8 files changed, 17 insertions(+), 413 deletions(-) delete mode 100644 packages/contracts/test/contracts/OVM/bridge/assets/OVM_L2DepositedERC20.spec.ts delete mode 100644 packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol index 2d1477aa109b3..d03c470a77c82 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol @@ -26,14 +26,8 @@ contract OVM_ProxyEOA { * Constructor * ***************/ - /** - * @param _implementation Address of the initial implementation contract. - */ - constructor( - address _implementation - ) - { - _setImplementation(_implementation); + constructor() { + _setImplementation(0x4200000000000000000000000000000000000003); } diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol index dba6fa1db2ff0..d9355b8eaeb2a 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol @@ -14,11 +14,6 @@ import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManage import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol"; import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol"; -/* Contract Imports */ -import { OVM_ECDSAContractAccount } from "../accounts/OVM_ECDSAContractAccount.sol"; -import { OVM_ProxyEOA } from "../accounts/OVM_ProxyEOA.sol"; -import { OVM_DeployerWhitelist } from "../predeploys/OVM_DeployerWhitelist.sol"; - /** * @title OVM_ExecutionManager * @dev The Execution Manager (EM) is the core of our OVM implementation, and provides a sandboxed @@ -534,9 +529,12 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { address prevADDRESS = messageContext.ovmADDRESS; messageContext.ovmADDRESS = eoa; + uint256 proxyEOAsize = ovmEXTCODESIZE(0x4200000000000000000000000000000000000009); + bytes memory proxyEOAcode = ovmEXTCODECOPY(0x4200000000000000000000000000000000000009, 0, proxyEOAsize); + // Now actually create the account and get its bytecode. We're not worried about reverts // (other than out of gas, which we can't capture anyway) because this contract is trusted. - OVM_ProxyEOA proxyEOA = new OVM_ProxyEOA(0x4200000000000000000000000000000000000003); + address proxyEOA = Lib_EthUtils.createContract(proxyEOAcode); // Reset the address now that we're done deploying. messageContext.ovmADDRESS = prevADDRESS; diff --git a/packages/contracts/src/contract-dumps.ts b/packages/contracts/src/contract-dumps.ts index 7cb64fc8958c4..d6991bdee28d8 100644 --- a/packages/contracts/src/contract-dumps.ts +++ b/packages/contracts/src/contract-dumps.ts @@ -165,6 +165,7 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise => { 'OVM_SequencerEntrypoint', 'Lib_AddressManager', 'OVM_ETH', + 'Proxy_EOA', ] const deploymentResult = await deploy(config) diff --git a/packages/contracts/src/predeploys.ts b/packages/contracts/src/predeploys.ts index 12fa4929ae608..9cb33e71841fd 100644 --- a/packages/contracts/src/predeploys.ts +++ b/packages/contracts/src/predeploys.ts @@ -7,5 +7,6 @@ export const predeploys = { OVM_ETH: '0x4200000000000000000000000000000000000006', OVM_L2CrossDomainMessenger: '0x4200000000000000000000000000000000000007', Lib_AddressManager: '0x4200000000000000000000000000000000000008', + Proxy_EOA: '0x4200000000000000000000000000000000000009', ERC1820Registry: '0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24', } diff --git a/packages/contracts/test/contracts/OVM/bridge/assets/OVM_L2DepositedERC20.spec.ts b/packages/contracts/test/contracts/OVM/bridge/assets/OVM_L2DepositedERC20.spec.ts deleted file mode 100644 index 94e22562931e7..0000000000000 --- a/packages/contracts/test/contracts/OVM/bridge/assets/OVM_L2DepositedERC20.spec.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { expect } from '../../../../setup' - -/* External Imports */ -import { ethers } from 'hardhat' -import { Signer, ContractFactory, Contract, constants } from 'ethers' -import { - smockit, - MockContract, - smoddit, - ModifiableContract, -} from '@eth-optimism/smock' - -/* Internal Imports */ -import { NON_ZERO_ADDRESS } from '../../../../helpers' - -const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenticated' -const ERR_INVALID_X_DOMAIN_MSG_SENDER = - 'OVM_XCHAIN: wrong sender of cross-domain message' -const MOCK_L1GATEWAY_ADDRESS: string = - '0x1234123412341234123412341234123412341234' - -describe('OVM_L2DepositedERC20', () => { - let alice: Signer - let bob: Signer - let Factory__OVM_L1ERC20Gateway: ContractFactory - before(async () => { - ;[alice, bob] = await ethers.getSigners() - Factory__OVM_L1ERC20Gateway = await ethers.getContractFactory( - 'OVM_L1ERC20Gateway' - ) - }) - - let OVM_L2DepositedERC20: Contract - let Mock__OVM_L2CrossDomainMessenger: MockContract - let finalizeWithdrawalGasLimit: number - beforeEach(async () => { - // Create a special signer which will enable us to send messages from the L2Messenger contract - let l2MessengerImpersonator: Signer - ;[l2MessengerImpersonator] = await ethers.getSigners() - - // Get a new mock L2 messenger - Mock__OVM_L2CrossDomainMessenger = await smockit( - await ethers.getContractFactory('OVM_L2CrossDomainMessenger'), - // This allows us to use an ethers override {from: Mock__OVM_L2CrossDomainMessenger.address} to mock calls - { address: await l2MessengerImpersonator.getAddress() } - ) - - // Deploy the contract under test - OVM_L2DepositedERC20 = await ( - await ethers.getContractFactory('OVM_L2DepositedERC20') - ).deploy(Mock__OVM_L2CrossDomainMessenger.address, 'ovmWETH', 'oWETH') - - // initialize the L2 Gateway with the L1G ateway addrss - await OVM_L2DepositedERC20.init(MOCK_L1GATEWAY_ADDRESS) - - finalizeWithdrawalGasLimit = await OVM_L2DepositedERC20.getFinalizeWithdrawalL1Gas() - }) - - // test the transfer flow of moving a token from L2 to L1 - describe('finalizeDeposit', () => { - it('onlyFromCrossDomainAccount: should revert on calls from a non-crossDomainMessenger L2 account', async () => { - // Deploy new gateway, initialize with random messenger - OVM_L2DepositedERC20 = await ( - await ethers.getContractFactory('OVM_L2DepositedERC20') - ).deploy(NON_ZERO_ADDRESS, 'ovmWETH', 'oWETH') - await OVM_L2DepositedERC20.init(NON_ZERO_ADDRESS) - - await expect( - OVM_L2DepositedERC20.finalizeDeposit(constants.AddressZero, 0) - ).to.be.revertedWith(ERR_INVALID_MESSENGER) - }) - - it('onlyFromCrossDomainAccount: should revert on calls from the right crossDomainMessenger, but wrong xDomainMessageSender (ie. not the L1ERC20Gateway)', async () => { - Mock__OVM_L2CrossDomainMessenger.smocked.xDomainMessageSender.will.return.with( - NON_ZERO_ADDRESS - ) - - await expect( - OVM_L2DepositedERC20.finalizeDeposit(constants.AddressZero, 0, { - from: Mock__OVM_L2CrossDomainMessenger.address, - }) - ).to.be.revertedWith(ERR_INVALID_X_DOMAIN_MSG_SENDER) - }) - - it('should credit funds to the depositor', async () => { - const depositAmount = 100 - Mock__OVM_L2CrossDomainMessenger.smocked.xDomainMessageSender.will.return.with( - () => MOCK_L1GATEWAY_ADDRESS - ) - - await OVM_L2DepositedERC20.finalizeDeposit( - await alice.getAddress(), - depositAmount, - { from: Mock__OVM_L2CrossDomainMessenger.address } - ) - - const aliceBalance = await OVM_L2DepositedERC20.balanceOf( - await alice.getAddress() - ) - aliceBalance.should.equal(depositAmount) - }) - }) - - describe('withdrawals', () => { - const INITIAL_TOTAL_SUPPLY = 100_000 - const ALICE_INITIAL_BALANCE = 50_000 - const withdrawAmount = 1_000 - let SmoddedL2Gateway: ModifiableContract - beforeEach(async () => { - // Deploy a smodded gateway so we can give some balances to withdraw - SmoddedL2Gateway = await ( - await smoddit('OVM_L2DepositedERC20', alice) - ).deploy(Mock__OVM_L2CrossDomainMessenger.address, 'ovmWETH', 'oWETH') - await SmoddedL2Gateway.init(MOCK_L1GATEWAY_ADDRESS) - - // Populate the initial state with a total supply and some money in alice's balance - const aliceAddress = await alice.getAddress() - SmoddedL2Gateway.smodify.put({ - totalSupply: INITIAL_TOTAL_SUPPLY, - balanceOf: { - [aliceAddress]: ALICE_INITIAL_BALANCE, - }, - }) - }) - - it('withdraw() burns and sends the correct withdrawal message', async () => { - await SmoddedL2Gateway.withdraw(withdrawAmount) - const withdrawalCallToMessenger = - Mock__OVM_L2CrossDomainMessenger.smocked.sendMessage.calls[0] - - // Assert Alice's balance went down - const aliceBalance = await SmoddedL2Gateway.balanceOf( - await alice.getAddress() - ) - expect(aliceBalance).to.deep.equal( - ethers.BigNumber.from(ALICE_INITIAL_BALANCE - withdrawAmount) - ) - - // Assert totalSupply went down - const newTotalSupply = await SmoddedL2Gateway.totalSupply() - expect(newTotalSupply).to.deep.equal( - ethers.BigNumber.from(INITIAL_TOTAL_SUPPLY - withdrawAmount) - ) - - // Assert the correct cross-chain call was sent: - // Message should be sent to the L1ERC20Gateway on L1 - expect(withdrawalCallToMessenger._target).to.equal(MOCK_L1GATEWAY_ADDRESS) - // Message data should be a call telling the L1ERC20Gateway to finalize the withdrawal - expect(withdrawalCallToMessenger._message).to.equal( - await Factory__OVM_L1ERC20Gateway.interface.encodeFunctionData( - 'finalizeWithdrawal', - [await alice.getAddress(), withdrawAmount] - ) - ) - // Hardcoded gaslimit should be correct - expect(withdrawalCallToMessenger._gasLimit).to.equal( - finalizeWithdrawalGasLimit - ) - }) - - it('withdrawTo() burns and sends the correct withdrawal message', async () => { - await SmoddedL2Gateway.withdrawTo(await bob.getAddress(), withdrawAmount) - const withdrawalCallToMessenger = - Mock__OVM_L2CrossDomainMessenger.smocked.sendMessage.calls[0] - - // Assert Alice's balance went down - const aliceBalance = await SmoddedL2Gateway.balanceOf( - await alice.getAddress() - ) - expect(aliceBalance).to.deep.equal( - ethers.BigNumber.from(ALICE_INITIAL_BALANCE - withdrawAmount) - ) - - // Assert totalSupply went down - const newTotalSupply = await SmoddedL2Gateway.totalSupply() - expect(newTotalSupply).to.deep.equal( - ethers.BigNumber.from(INITIAL_TOTAL_SUPPLY - withdrawAmount) - ) - - // Assert the correct cross-chain call was sent. - // Message should be sent to the L1ERC20Gateway on L1 - expect(withdrawalCallToMessenger._target).to.equal(MOCK_L1GATEWAY_ADDRESS) - // The message data should be a call telling the L1ERC20Gateway to finalize the withdrawal - expect(withdrawalCallToMessenger._message).to.equal( - await Factory__OVM_L1ERC20Gateway.interface.encodeFunctionData( - 'finalizeWithdrawal', - [await bob.getAddress(), withdrawAmount] - ) - ) - // Hardcoded gaslimit should be correct - expect(withdrawalCallToMessenger._gasLimit).to.equal( - finalizeWithdrawalGasLimit - ) - }) - }) - - // low priority todos: see question in contract - describe.skip('Initialization logic', () => { - it('should not allow calls to onlyInitialized functions', async () => { - // TODO - }) - - it('should only allow initialization once and emits initialized event', async () => { - // TODO - }) - }) -}) diff --git a/packages/contracts/test/contracts/OVM/bridge/base/OVM_L1CrossDomainMessenger.spec.ts b/packages/contracts/test/contracts/OVM/bridge/base/OVM_L1CrossDomainMessenger.spec.ts index bc88722cabf59..5f4396c70b6ac 100644 --- a/packages/contracts/test/contracts/OVM/bridge/base/OVM_L1CrossDomainMessenger.spec.ts +++ b/packages/contracts/test/contracts/OVM/bridge/base/OVM_L1CrossDomainMessenger.spec.ts @@ -45,17 +45,16 @@ describe('OVM_L1CrossDomainMessenger', () => { AddressManager = await makeAddressManager() }) + const dummy_L2CrossDomainMessenger = + '0x1234123412341234123412341234123412341234' + let Mock__TargetContract: MockContract - let Mock__OVM_L2CrossDomainMessenger: MockContract let Mock__OVM_CanonicalTransactionChain: MockContract let Mock__OVM_StateCommitmentChain: MockContract before(async () => { Mock__TargetContract = await smockit( await ethers.getContractFactory('Helper_SimpleProxy') ) - Mock__OVM_L2CrossDomainMessenger = await smockit( - await ethers.getContractFactory('OVM_L2CrossDomainMessenger') - ) Mock__OVM_CanonicalTransactionChain = await smockit( await ethers.getContractFactory('OVM_CanonicalTransactionChain') ) @@ -65,7 +64,7 @@ describe('OVM_L1CrossDomainMessenger', () => { await AddressManager.setAddress( 'OVM_L2CrossDomainMessenger', - Mock__OVM_L2CrossDomainMessenger.address + dummy_L2CrossDomainMessenger ) await setProxyTarget( @@ -111,7 +110,7 @@ describe('OVM_L1CrossDomainMessenger', () => { expect( Mock__OVM_CanonicalTransactionChain.smocked.enqueue.calls[0] ).to.deep.equal([ - Mock__OVM_L2CrossDomainMessenger.address, + dummy_L2CrossDomainMessenger, BigNumber.from(gasLimit), getXDomainCalldata(await signer.getAddress(), target, message, 0), ]) @@ -176,9 +175,8 @@ describe('OVM_L1CrossDomainMessenger', () => { const precompile = '0x4200000000000000000000000000000000000000' const storageKey = keccak256( - keccak256( - calldata + remove0x(Mock__OVM_L2CrossDomainMessenger.address) - ) + '00'.repeat(32) + keccak256(calldata + remove0x(dummy_L2CrossDomainMessenger)) + + '00'.repeat(32) ) const storageGenerator = await TrieTestGenerator.fromNodes({ nodes: [ diff --git a/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts b/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts deleted file mode 100644 index 2979ad3bc33eb..0000000000000 --- a/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { expect } from '../../../setup' - -/* External Imports */ -import { waffle, ethers } from 'hardhat' -import { ContractFactory, Wallet, Contract } from 'ethers' -import { smockit, MockContract } from '@eth-optimism/smock' - -/* Internal Imports */ -import { getContractInterface } from '../../../../src' -import { - encodeSequencerCalldata, - signNativeTransaction, - signEthSignMessage, - DEFAULT_EIP155_TX, - serializeNativeTransaction, - serializeEthSignTransaction, -} from '../../../helpers' - -describe('OVM_SequencerEntrypoint', () => { - let wallet: Wallet - before(async () => { - const provider = waffle.provider - ;[wallet] = provider.getWallets() - }) - - let Mock__OVM_ExecutionManager: MockContract - let Helper_PredeployCaller: Contract - before(async () => { - Mock__OVM_ExecutionManager = await smockit( - await ethers.getContractFactory('OVM_ExecutionManager') - ) - - Mock__OVM_ExecutionManager.smocked.ovmCHAINID.will.return.with(420) - Mock__OVM_ExecutionManager.smocked.ovmCALL.will.return.with([true, '0x']) - - Helper_PredeployCaller = await ( - await ethers.getContractFactory('Helper_PredeployCaller') - ).deploy() - - Helper_PredeployCaller.setTarget(Mock__OVM_ExecutionManager.address) - }) - - let OVM_SequencerEntrypointFactory: ContractFactory - before(async () => { - OVM_SequencerEntrypointFactory = await ethers.getContractFactory( - 'OVM_SequencerEntrypoint' - ) - }) - - let OVM_SequencerEntrypoint: Contract - beforeEach(async () => { - OVM_SequencerEntrypoint = await OVM_SequencerEntrypointFactory.deploy() - Mock__OVM_ExecutionManager.smocked.ovmEXTCODESIZE.will.return.with(1) - Mock__OVM_ExecutionManager.smocked.ovmREVERT.will.revert() - }) - - describe('fallback()', async () => { - it('should call EIP155 if the transaction type is 0', async () => { - const calldata = await encodeSequencerCalldata( - wallet, - DEFAULT_EIP155_TX, - 0 - ) - await Helper_PredeployCaller.callPredeploy( - OVM_SequencerEntrypoint.address, - calldata - ) - - const encodedTx = serializeNativeTransaction(DEFAULT_EIP155_TX) - const sig = await signNativeTransaction(wallet, DEFAULT_EIP155_TX) - - const expectedEOACalldata = getContractInterface( - 'OVM_ECDSAContractAccount' - ).encodeFunctionData('execute', [ - encodedTx, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ]) - const ovmCALL: any = Mock__OVM_ExecutionManager.smocked.ovmCALL.calls[0] - expect(ovmCALL._address).to.equal(await wallet.getAddress()) - expect(ovmCALL._calldata).to.equal(expectedEOACalldata) - }) - - it('should send correct calldata if tx is a create and the transaction type is 0', async () => { - const createTx = { ...DEFAULT_EIP155_TX, to: '' } - const calldata = await encodeSequencerCalldata(wallet, createTx, 0) - await Helper_PredeployCaller.callPredeploy( - OVM_SequencerEntrypoint.address, - calldata - ) - - const encodedTx = serializeNativeTransaction(createTx) - const sig = await signNativeTransaction(wallet, createTx) - - const expectedEOACalldata = getContractInterface( - 'OVM_ECDSAContractAccount' - ).encodeFunctionData('execute', [ - encodedTx, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ]) - const ovmCALL: any = Mock__OVM_ExecutionManager.smocked.ovmCALL.calls[0] - expect(ovmCALL._address).to.equal(await wallet.getAddress()) - expect(ovmCALL._calldata).to.equal(expectedEOACalldata) - }) - - for (let i = 0; i < 3; i += 2) { - it(`should call ovmCreateEOA when tx type is ${i} and ovmEXTCODESIZE returns 0`, async () => { - Mock__OVM_ExecutionManager.smocked.ovmEXTCODESIZE.will.return.with(0) - const calldata = await encodeSequencerCalldata( - wallet, - DEFAULT_EIP155_TX, - i - ) - await Helper_PredeployCaller.callPredeploy( - OVM_SequencerEntrypoint.address, - calldata - ) - const call: any = - Mock__OVM_ExecutionManager.smocked.ovmCREATEEOA.calls[0] - const eoaAddress = ethers.utils.recoverAddress(call._messageHash, { - v: call._v + 27, - r: call._r, - s: call._s, - }) - expect(eoaAddress).to.equal(await wallet.getAddress()) - }) - } - - it('should submit ETHSignedTypedData if TransactionType is 2', async () => { - const calldata = await encodeSequencerCalldata( - wallet, - DEFAULT_EIP155_TX, - 2 - ) - await Helper_PredeployCaller.callPredeploy( - OVM_SequencerEntrypoint.address, - calldata - ) - - const encodedTx = serializeEthSignTransaction(DEFAULT_EIP155_TX) - const sig = await signEthSignMessage(wallet, DEFAULT_EIP155_TX) - - const expectedEOACalldata = getContractInterface( - 'OVM_ECDSAContractAccount' - ).encodeFunctionData('execute', [ - encodedTx, - 1, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ]) - const ovmCALL: any = Mock__OVM_ExecutionManager.smocked.ovmCALL.calls[0] - expect(ovmCALL._address).to.equal(await wallet.getAddress()) - expect(ovmCALL._calldata).to.equal(expectedEOACalldata) - }) - - it('should revert if TransactionType is >2', async () => { - const calldata = '0x03' - await expect( - Helper_PredeployCaller.callPredeploy( - OVM_SequencerEntrypoint.address, - calldata - ) - ).to.be.reverted - }) - - it('should revert if TransactionType is 1', async () => { - const calldata = '0x01' - await expect( - Helper_PredeployCaller.callPredeploy( - OVM_SequencerEntrypoint.address, - calldata - ) - ).to.be.reverted - }) - }) -}) diff --git a/packages/contracts/test/helpers/codec/bridge.ts b/packages/contracts/test/helpers/codec/bridge.ts index 7a70787bd6a9b..1aef4a98b15d8 100644 --- a/packages/contracts/test/helpers/codec/bridge.ts +++ b/packages/contracts/test/helpers/codec/bridge.ts @@ -7,6 +7,7 @@ export const getXDomainCalldata = ( messageNonce: number ): string => { return getContractInterface( - 'OVM_L2CrossDomainMessenger' + 'OVM_L2CrossDomainMessenger', + true ).encodeFunctionData('relayMessage', [target, sender, message, messageNonce]) } From a283439a0e2f0e26e2d84b040a9a2374fccd04a8 Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Thu, 15 Apr 2021 18:04:24 -0700 Subject: [PATCH 3/8] got tests to work --- .../OVM/execution/OVM_ExecutionManager.sol | 1 + .../OVM/predeploys/OVM_DeployerWhitelist.sol | 2 +- .../OVM_ExecutionManager/ovmCREATE.spec.ts | 41 +++++++++---------- .../OVM_ExecutionManager/ovmCREATEEOA.spec.ts | 2 +- .../test/helpers/test-runner/test-runner.ts | 26 ++++++++++-- 5 files changed, 44 insertions(+), 28 deletions(-) diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol index d9355b8eaeb2a..01ff70a32296e 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol @@ -1067,6 +1067,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { if (msg.sender != address(this)) { return; } + // Check that there is not already code at this address. if (_hasEmptyAccount(_address) == false) { // Note: in the EVM, this case burns all allotted gas. For improved diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol index 08de2e7f32b21..fd395b7658f79 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol @@ -144,6 +144,6 @@ contract OVM_DeployerWhitelist is iOVM_DeployerWhitelist { initialized == false || allowArbitraryDeployment == true || whitelist[_deployer] - ); + ); } } diff --git a/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATE.spec.ts b/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATE.spec.ts index 147fac7be9f0f..8281cd5516af3 100644 --- a/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATE.spec.ts +++ b/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATE.spec.ts @@ -24,14 +24,21 @@ const DUMMY_REVERT_DATA = '0xdeadbeef1e5420deadbeef1e5420deadbeef1e5420deadbeef1e5420deadbeef1e5420' const NON_WHITELISTED_DEPLOYER = '0x1234123412341234123412341234123412341234' -const NON_WHITELISTED_DEPLOYER_KEY = - '0x0000000000000000000000001234123412341234123412341234123412341234' +const NON_WHITELISTED_DEPLOYER_KEY = ethers.utils.keccak256( + '0x' + + '0000000000000000000000001234123412341234123412341234123412341234' + + '0000000000000000000000000000000000000000000000000000000000000001' +) const CREATED_BY_NON_WHITELISTED_DEPLOYER = '0x794e4aa3be128b0fc01ba12543b70bf9d77072fc' const WHITELISTED_DEPLOYER = '0x3456345634563456345634563456345634563456' -const WHITELISTED_DEPLOYER_KEY = - '0x0000000000000000000000003456345634563456345634563456345634563456' +const WHITELISTED_DEPLOYER_KEY = ethers.utils.keccak256( + '0x' + + '0000000000000000000000003456345634563456345634563456345634563456' + + '0000000000000000000000000000000000000000000000000000000000000001' +) + const CREATED_BY_WHITELISTED_DEPLOYER = '0x9f397a91ccb7cc924d1585f1053bc697d30f343f' @@ -766,13 +773,9 @@ const test_ovmCREATE: TestDefinition = { }, contractStorage: { ['0x4200000000000000000000000000000000000002']: { - // initialized? true - '0x0000000000000000000000000000000000000000000000000000000000000010': getStorageXOR( - '0x' + '00'.repeat(31) + '01' - ), - // allowArbitraryDeployment? false - '0x0000000000000000000000000000000000000000000000000000000000000012': getStorageXOR( - ethers.constants.HashZero + // initialized? true, allowArbitraryDeployment? false + '0x0000000000000000000000000000000000000000000000000000000000000000': getStorageXOR( + '0x0000000000000000000000000000000000000000000000000000000000000001' ), // non-whitelisted deployer is whitelisted? false [NON_WHITELISTED_DEPLOYER_KEY]: getStorageXOR( @@ -786,8 +789,7 @@ const test_ovmCREATE: TestDefinition = { }, verifiedContractStorage: { ['0x4200000000000000000000000000000000000002']: { - '0x0000000000000000000000000000000000000000000000000000000000000010': 1, - '0x0000000000000000000000000000000000000000000000000000000000000012': 1, + '0x0000000000000000000000000000000000000000000000000000000000000000': 1, [NON_WHITELISTED_DEPLOYER_KEY]: 1, [WHITELISTED_DEPLOYER_KEY]: 1, }, @@ -901,13 +903,9 @@ const test_ovmCREATE: TestDefinition = { }, contractStorage: { ['0x4200000000000000000000000000000000000002']: { - // initialized? true - '0x0000000000000000000000000000000000000000000000000000000000000010': getStorageXOR( - '0x' + '00'.repeat(31) + '01' - ), - // allowArbitraryDeployment? true - '0x0000000000000000000000000000000000000000000000000000000000000012': getStorageXOR( - '0x' + '00'.repeat(31) + '01' + // initialized? true, allowArbitraryDeployment? true + '0x0000000000000000000000000000000000000000000000000000000000000000': getStorageXOR( + '0x0000000000000000000000000000000000000000000000000000000000000101' ), // non-whitelisted deployer is whitelisted? false [NON_WHITELISTED_DEPLOYER_KEY]: getStorageXOR( @@ -921,8 +919,7 @@ const test_ovmCREATE: TestDefinition = { }, verifiedContractStorage: { ['0x4200000000000000000000000000000000000002']: { - '0x0000000000000000000000000000000000000000000000000000000000000010': 1, - '0x0000000000000000000000000000000000000000000000000000000000000012': 1, + '0x0000000000000000000000000000000000000000000000000000000000000000': 1, [NON_WHITELISTED_DEPLOYER_KEY]: 1, [WHITELISTED_DEPLOYER_KEY]: 1, }, diff --git a/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATEEOA.spec.ts b/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATEEOA.spec.ts index 665479e61867b..fac05477a0718 100644 --- a/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATEEOA.spec.ts +++ b/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATEEOA.spec.ts @@ -73,7 +73,7 @@ const test_ovmCREATEEOA: TestDefinition = { }, expectedReturnStatus: true, expectedReturnValue: fromHexString( - getContractDefinition('OVM_ProxyEOA').deployedBytecode + getContractDefinition('OVM_ProxyEOA', true).deployedBytecode ).length, }, ], diff --git a/packages/contracts/test/helpers/test-runner/test-runner.ts b/packages/contracts/test/helpers/test-runner/test-runner.ts index 91eb6f7e61ba0..977547709018c 100644 --- a/packages/contracts/test/helpers/test-runner/test-runner.ts +++ b/packages/contracts/test/helpers/test-runner/test-runner.ts @@ -37,6 +37,8 @@ import { } from '../constants' import { getStorageXOR } from '../' import { UNSAFE_BYTECODE } from '../dummy' +import { getContractDefinition, getContractFactory } from '../../../src' +import { deployContractCode } from '../utils' export class ExecutionManagerTestRunner { private snapshot: string @@ -47,6 +49,7 @@ export class ExecutionManagerTestRunner { Helper_TestRunner: Contract Factory__Helper_TestRunner_CREATE: ContractFactory OVM_DeployerWhitelist: Contract + OVM_ProxyEOA: string } = { OVM_SafetyChecker: undefined, OVM_StateManager: undefined, @@ -54,6 +57,7 @@ export class ExecutionManagerTestRunner { Helper_TestRunner: undefined, Factory__Helper_TestRunner_CREATE: undefined, OVM_DeployerWhitelist: undefined, + OVM_ProxyEOA: undefined, } // Default pre-state with contract deployer whitelist NOT initialized. @@ -65,17 +69,21 @@ export class ExecutionManagerTestRunner { codeHash: NON_NULL_BYTES32, ethAddress: '$OVM_DEPLOYER_WHITELIST', }, + ['0x4200000000000000000000000000000000000009']: { + codeHash: NON_NULL_BYTES32, + ethAddress: '$OVM_PROXY_EOA', + }, }, contractStorage: { ['0x4200000000000000000000000000000000000002']: { - '0x0000000000000000000000000000000000000000000000000000000000000010': getStorageXOR( + '0x0000000000000000000000000000000000000000000000000000000000000000': getStorageXOR( ethers.constants.HashZero ), }, }, verifiedContractStorage: { ['0x4200000000000000000000000000000000000002']: { - '0x0000000000000000000000000000000000000000000000000000000000000010': true, + '0x0000000000000000000000000000000000000000000000000000000000000000': true, }, }, }, @@ -211,12 +219,20 @@ export class ExecutionManagerTestRunner { this.contracts.OVM_SafetyChecker.address ) - const DeployerWhitelist = await ( - await ethers.getContractFactory('OVM_DeployerWhitelist') + const DeployerWhitelist = await getContractFactory( + 'OVM_DeployerWhitelist', + AddressManager.signer, + true ).deploy() this.contracts.OVM_DeployerWhitelist = DeployerWhitelist + this.contracts.OVM_ProxyEOA = await deployContractCode( + getContractDefinition('OVM_ProxyEOA', true).bytecode, + AddressManager.signer, + 8_000_000 + ) + this.contracts.OVM_ExecutionManager = await ( await smoddit('OVM_ExecutionManager') ).deploy( @@ -266,6 +282,8 @@ export class ExecutionManagerTestRunner { return this.contracts.Helper_TestRunner.address } else if (kv === '$OVM_DEPLOYER_WHITELIST') { return this.contracts.OVM_DeployerWhitelist.address + } else if (kv === '$OVM_PROXY_EOA') { + return this.contracts.OVM_ProxyEOA } else if (kv.startsWith('$DUMMY_OVM_ADDRESS_')) { return ExecutionManagerTestRunner.getDummyAddress(kv) } else { From 36869a57a6e607c3da0d1ef7b232d8dff97d1775 Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Fri, 16 Apr 2021 14:37:26 -0700 Subject: [PATCH 4/8] fix nuisance gas check --- .../OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts b/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts index 821ee3fd9b820..d9a4c725eb61e 100644 --- a/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts +++ b/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts @@ -188,7 +188,7 @@ const test_nuisanceGas: TestDefinition = { // This is because there is natural gas consumption between the ovmCALL(GAS/2) and ovmCREATE, which allots nuisance gas via _getNuisanceGasLimit. // This means that the ovmCREATE exception, DOES consumes all nuisance gas allotted, but that allotment // is less than the full OVM_TX_GAS_LIMIT / 2 which is alloted to the parent ovmCALL. - nuisanceGasLeft: 4184829, + nuisanceGasLeft: 4169443, }, }, }, From d76f0ce33b7e012539fe7839b0acc51c985e56cd Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Fri, 16 Apr 2021 18:01:21 -0700 Subject: [PATCH 5/8] fix dump script --- packages/contracts/src/contract-deployment/config.ts | 10 +++++++--- packages/contracts/src/contract-dumps.ts | 9 ++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/contracts/src/contract-deployment/config.ts b/packages/contracts/src/contract-deployment/config.ts index 8b117356f2214..5f0519a7917d9 100644 --- a/packages/contracts/src/contract-deployment/config.ts +++ b/packages/contracts/src/contract-deployment/config.ts @@ -66,7 +66,11 @@ export const makeContractDeployConfig = async ( return { OVM_L2CrossDomainMessenger: { - factory: getContractFactory('OVM_L2CrossDomainMessenger'), + factory: getContractFactory( + 'OVM_L2CrossDomainMessenger', + undefined, + true + ), params: [AddressManager.address], }, OVM_L1CrossDomainMessenger: { @@ -213,10 +217,10 @@ export const makeContractDeployConfig = async ( params: [AddressManager.address], }, OVM_ECDSAContractAccount: { - factory: getContractFactory('OVM_ECDSAContractAccount'), + factory: getContractFactory('OVM_ECDSAContractAccount', undefined, true), }, OVM_SequencerEntrypoint: { - factory: getContractFactory('OVM_SequencerEntrypoint'), + factory: getContractFactory('OVM_SequencerEntrypoint', undefined, true), }, OVM_BondManager: { factory: getContractFactory('mockOVM_BondManager'), diff --git a/packages/contracts/src/contract-dumps.ts b/packages/contracts/src/contract-dumps.ts index d6991bdee28d8..75244a4852110 100644 --- a/packages/contracts/src/contract-dumps.ts +++ b/packages/contracts/src/contract-dumps.ts @@ -211,12 +211,19 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise => { predeploys[name] || `0xdeaddeaddeaddeaddeaddeaddeaddeaddead${i.toString(16).padStart(4, '0')}` + let def: any + try { + def = getContractDefinition(name.replace('Proxy__', '')) + } catch (err) { + def = getContractDefinition(name.replace('Proxy__', ''), true) + } + dump.accounts[name] = { address: deadAddress, code, codeHash: keccak256(code), storage: await getStorageDump(cStateManager, contract.address), - abi: getContractDefinition(name.replace('Proxy__', '')).abi, + abi: def.abi, } } From a4f042a6af628ef03e1e8f9e638563f50dff16d3 Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Tue, 20 Apr 2021 19:11:19 -0400 Subject: [PATCH 6/8] added back in some unit tests + use new compiler --- .../OVM/accounts/OVM_ECDSAContractAccount.sol | 2 +- .../OVM/accounts/OVM_ProxyEOA.sol | 2 +- .../predeploys/OVM_SequencerEntrypoint.sol | 8 +- .../libraries/utils/Lib_ECDSAUtils.sol | 20 +- .../wrappers/Lib_ExecutionManagerWrapper.sol | 2 +- packages/contracts/package.json | 1 + .../accounts/OVM_ECDSAContractAccount.spec.ts | 338 ++++++++++++++++++ .../OVM/accounts/OVM_ProxyEOA.spec.ts | 150 ++++++++ .../OVM_SequencerEntrypoint.spec.ts | 235 ++++++++++++ packages/hardhat-ovm/src/index.ts | 2 +- packages/smock/src/smockit/types.ts | 4 +- yarn.lock | 2 +- 12 files changed, 746 insertions(+), 20 deletions(-) create mode 100644 packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts create mode 100644 packages/contracts/test/contracts/OVM/accounts/OVM_ProxyEOA.spec.ts create mode 100644 packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol index 90565026dfe04..3dfbec3a91a9b 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol @@ -121,7 +121,7 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { if iszero(created) { let size := returndatasize() revertdata := mload(0x40) - mstore(0x40, add(add(revertdata, 0x20), size)) + mstore(0x40, add(revertdata, and(add(add(size, 0x20), 0x1f), not(0x1f)))) mstore(revertdata, size) returndatacopy(add(revertdata, 0x20), 0x0, size) } diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol index d03c470a77c82..bc9f35860403d 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol @@ -38,7 +38,7 @@ contract OVM_ProxyEOA { fallback() external { - (bool success, bytes memory returndata) = getImplementation().call(msg.data); + (bool success, bytes memory returndata) = getImplementation().delegatecall(msg.data); if (success) { assembly { diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol index c2138bc5a8d65..8bb8cd6d233cf 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol @@ -19,7 +19,7 @@ import { Lib_ExecutionManagerWrapper } from "../../libraries/wrappers/Lib_Execut * This contract is the implementation referenced by the Proxy Sequencer Entrypoint, thus enabling * the Optimism team to upgrade the decompression of calldata from the Sequencer. * - * Compiler used: solc + * Compiler used: optimistic-solc * Runtime target: OVM */ contract OVM_SequencerEntrypoint { @@ -80,12 +80,12 @@ contract OVM_SequencerEntrypoint { s ); - bool isEmptyContract; + uint256 eoaContractSize; assembly { - isEmptyContract := iszero(extcodesize(target)) + eoaContractSize := extcodesize(target) } - if (isEmptyContract) { + if (eoaContractSize == 0) { // ProxyEOA has not yet been deployed for this EOA. bytes32 messageHash = Lib_ECDSAUtils.getMessageHash(encodedTx, isEthSignedMessage); Lib_ExecutionManagerWrapper.ovmCREATEEOA(messageHash, v, r, s); diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol index 9d973758b920c..4c90ea72bb20a 100644 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol @@ -29,7 +29,7 @@ library Lib_ECDSAUtils { internal pure returns ( - address _sender + address ) { bytes32 messageHash = getMessageHash(_message, _isEthSignedMessage); @@ -48,11 +48,15 @@ library Lib_ECDSAUtils { ) internal pure - returns (bytes32) { + returns ( + bytes32 + ) + { if (_isEthSignedMessage) { return getEthSignedMessageHash(_message); + } else { + return getNativeMessageHash(_message); } - return getNativeMessageHash(_message); } @@ -63,7 +67,7 @@ library Lib_ECDSAUtils { /** * Gets the native message hash (simple keccak256) for a message. * @param _message Message to hash. - * @return _messageHash Native message hash. + * @return Native message hash. */ function getNativeMessageHash( bytes memory _message @@ -71,7 +75,7 @@ library Lib_ECDSAUtils { private pure returns ( - bytes32 _messageHash + bytes32 ) { return keccak256(_message); @@ -80,7 +84,7 @@ library Lib_ECDSAUtils { /** * Gets the hash of a message with the `Ethereum Signed Message` prefix. * @param _message Message to hash. - * @return _messageHash Prefixed message hash. + * @return Prefixed message hash. */ function getEthSignedMessageHash( bytes memory _message @@ -88,11 +92,11 @@ library Lib_ECDSAUtils { private pure returns ( - bytes32 _messageHash + bytes32 ) { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 messageHash = keccak256(_message); return keccak256(abi.encodePacked(prefix, messageHash)); } -} \ No newline at end of file +} diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_ExecutionManagerWrapper.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_ExecutionManagerWrapper.sol index 37429ad7d383f..ae2c0189f1033 100644 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_ExecutionManagerWrapper.sol +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_ExecutionManagerWrapper.sol @@ -139,7 +139,7 @@ library Lib_ExecutionManagerWrapper { kall(add(_calldata, 0x20), mload(_calldata), 0x0, 0x0) let size := returndatasize() returndata := mload(0x40) - mstore(0x40, add(add(returndata, 0x20), size)) + mstore(0x40, add(returndata, and(add(add(size, 0x20), 0x1f), not(0x1f)))) mstore(returndata, size) returndatacopy(add(returndata, 0x20), 0x0, size) } diff --git a/packages/contracts/package.json b/packages/contracts/package.json index b9ac7a2d79092..5f163ea73f03b 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -63,6 +63,7 @@ "directory-tree": "^2.2.7", "dotenv": "^8.2.0", "ethereum-waffle": "^3.3.0", + "ethereumjs-util": "^7.0.10", "ethers": "^5.0.31", "hardhat": "^2.0.8", "hardhat-deploy": "^0.7.4", diff --git a/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts b/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts new file mode 100644 index 0000000000000..122a53d9a3811 --- /dev/null +++ b/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts @@ -0,0 +1,338 @@ +import { expect } from '../../../setup' + +/* External Imports */ +import { ethers, waffle } from 'hardhat' +import { ContractFactory, Contract, Wallet, BigNumber } from 'ethers' +import { MockContract, smockit } from '@eth-optimism/smock' +import { fromHexString, toHexString } from '@eth-optimism/core-utils' +import { ecrecover, publicToAddress } from 'ethereumjs-util' + +/* Internal Imports */ +import { + serializeNativeTransaction, + signNativeTransaction, + DEFAULT_EIP155_TX, + serializeEthSignTransaction, + signEthSignMessage, + decodeSolidityError, + NON_ZERO_ADDRESS, +} from '../../../helpers' +import { getContractFactory, getContractInterface } from '../../../../src' + +const callPredeploy = async ( + Helper_PredeployCaller: Contract, + predeploy: Contract, + functionName: string, + functionParams?: any[], + gasLimit?: number +): Promise => { + if (gasLimit) { + return Helper_PredeployCaller.callPredeploy( + predeploy.address, + predeploy.interface.encodeFunctionData( + functionName, + functionParams || [] + ), + { gasLimit } + ) + } + return Helper_PredeployCaller.callPredeploy( + predeploy.address, + predeploy.interface.encodeFunctionData(functionName, functionParams || []) + ) +} + +describe('OVM_ECDSAContractAccount', () => { + let wallet: Wallet + let badWallet: Wallet + before(async () => { + const provider = waffle.provider + ;[wallet, badWallet] = provider.getWallets() + }) + + let Mock__OVM_ExecutionManager: MockContract + let Helper_PredeployCaller: Contract + before(async () => { + Mock__OVM_ExecutionManager = await smockit( + await ethers.getContractFactory('OVM_ExecutionManager') + ) + + Helper_PredeployCaller = await ( + await ethers.getContractFactory('Helper_PredeployCaller') + ).deploy() + + Helper_PredeployCaller.setTarget(Mock__OVM_ExecutionManager.address) + }) + + let Factory__OVM_ECDSAContractAccount: ContractFactory + before(async () => { + Factory__OVM_ECDSAContractAccount = getContractFactory( + 'OVM_ECDSAContractAccount', + wallet, + true + ) + }) + + let OVM_ECDSAContractAccount: Contract + beforeEach(async () => { + OVM_ECDSAContractAccount = await Factory__OVM_ECDSAContractAccount.deploy() + + Mock__OVM_ExecutionManager.smocked.ovmADDRESS.will.return.with( + await wallet.getAddress() + ) + Mock__OVM_ExecutionManager.smocked.ovmEXTCODESIZE.will.return.with(1) + Mock__OVM_ExecutionManager.smocked.ovmCHAINID.will.return.with(420) + Mock__OVM_ExecutionManager.smocked.ovmGETNONCE.will.return.with(100) + Mock__OVM_ExecutionManager.smocked.ovmCALL.will.return.with( + (gasLimit, target, data) => { + if (target === '0x4200000000000000000000000000000000000006') { + return [ + true, + '0x0000000000000000000000000000000000000000000000000000000000000001', + ] + } else { + return [true, '0x'] + } + } + ) + Mock__OVM_ExecutionManager.smocked.ovmSTATICCALL.will.return.with( + (gasLimit, target, data) => { + if (target === '0x0000000000000000000000000000000000000001') { + const databuf = fromHexString(data) + const msghash = databuf.slice(0, 32) + const v = databuf.slice(32, 64) + const r = databuf.slice(64, 96) + const s = databuf.slice(96, 128) + const pubkey = ecrecover(msghash, BigNumber.from(v).toNumber(), r, s) + const addr = toHexString(publicToAddress(pubkey)) + const ret = ethers.utils.defaultAbiCoder.encode(['address'], [addr]) + return [true, ret] + } else { + return [true, '0x'] + } + } + ) + Mock__OVM_ExecutionManager.smocked.ovmCREATE.will.return.with([ + NON_ZERO_ADDRESS, + '0x', + ]) + Mock__OVM_ExecutionManager.smocked.ovmCALLER.will.return.with( + NON_ZERO_ADDRESS + ) + }) + + describe('fallback()', () => { + it(`should successfully execute an EIP155Transaction`, async () => { + const message = serializeNativeTransaction(DEFAULT_EIP155_TX) + const sig = await signNativeTransaction(wallet, DEFAULT_EIP155_TX) + + await callPredeploy( + Helper_PredeployCaller, + OVM_ECDSAContractAccount, + 'execute', + [ + message, + 0, // isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ] + ) + + // The ovmCALL is the 2nd call because the first call transfers the fee. + const ovmCALL: any = Mock__OVM_ExecutionManager.smocked.ovmCALL.calls[1] + expect(ovmCALL._address).to.equal(DEFAULT_EIP155_TX.to) + expect(ovmCALL._calldata).to.equal(DEFAULT_EIP155_TX.data) + }) + + it(`should successfully execute an ETHSignedTransaction`, async () => { + const message = serializeEthSignTransaction(DEFAULT_EIP155_TX) + const sig = await signEthSignMessage(wallet, DEFAULT_EIP155_TX) + + await callPredeploy( + Helper_PredeployCaller, + OVM_ECDSAContractAccount, + 'execute', + [ + message, + 1, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ] + ) + + // The ovmCALL is the 2nd call because the first call transfers the fee. + const ovmCALL: any = Mock__OVM_ExecutionManager.smocked.ovmCALL.calls[1] + expect(ovmCALL._address).to.equal(DEFAULT_EIP155_TX.to) + expect(ovmCALL._calldata).to.equal(DEFAULT_EIP155_TX.data) + }) + + it(`should ovmCREATE if EIP155Transaction.to is zero address`, async () => { + const createTx = { ...DEFAULT_EIP155_TX, to: '' } + const message = serializeNativeTransaction(createTx) + const sig = await signNativeTransaction(wallet, createTx) + + await callPredeploy( + Helper_PredeployCaller, + OVM_ECDSAContractAccount, + 'execute', + [ + message, + 0, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ] + ) + + const ovmCREATE: any = + Mock__OVM_ExecutionManager.smocked.ovmCREATE.calls[0] + expect(ovmCREATE._bytecode).to.equal(createTx.data) + }) + + it(`should revert on invalid signature`, async () => { + const message = serializeNativeTransaction(DEFAULT_EIP155_TX) + const sig = await signNativeTransaction(badWallet, DEFAULT_EIP155_TX) + + await callPredeploy( + Helper_PredeployCaller, + OVM_ECDSAContractAccount, + 'execute', + [ + message, + 0, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ] + ) + const ovmREVERT: any = + Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] + expect(decodeSolidityError(ovmREVERT._data)).to.equal( + 'Signature provided for EOA transaction execution is invalid.' + ) + }) + + it(`should revert on incorrect nonce`, async () => { + const alteredNonceTx = { + ...DEFAULT_EIP155_TX, + nonce: 99, + } + const message = serializeNativeTransaction(alteredNonceTx) + const sig = await signNativeTransaction(wallet, alteredNonceTx) + + await callPredeploy( + Helper_PredeployCaller, + OVM_ECDSAContractAccount, + 'execute', + [ + message, + 0, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ] + ) + const ovmREVERT: any = + Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] + expect(decodeSolidityError(ovmREVERT._data)).to.equal( + 'Transaction nonce does not match the expected nonce.' + ) + }) + + it(`should revert on incorrect chainId`, async () => { + const alteredChainIdTx = { + ...DEFAULT_EIP155_TX, + chainId: 421, + } + const message = serializeNativeTransaction(alteredChainIdTx) + const sig = await signNativeTransaction(wallet, alteredChainIdTx) + + await callPredeploy( + Helper_PredeployCaller, + OVM_ECDSAContractAccount, + 'execute', + [ + message, + 0, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ] + ) + const ovmREVERT: any = + Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] + expect(decodeSolidityError(ovmREVERT._data)).to.equal( + 'Transaction chainId does not match expected OVM chainId.' + ) + }) + + // TEMPORARY: Skip gas checks for minnet. + it.skip(`should revert on insufficient gas`, async () => { + const alteredInsufficientGasTx = { + ...DEFAULT_EIP155_TX, + gasLimit: 200000000, + } + const message = serializeNativeTransaction(alteredInsufficientGasTx) + const sig = await signNativeTransaction(wallet, alteredInsufficientGasTx) + + await callPredeploy( + Helper_PredeployCaller, + OVM_ECDSAContractAccount, + 'execute', + [ + message, + 0, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ], + 40000000 + ) + + const ovmREVERT: any = + Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] + expect(decodeSolidityError(ovmREVERT._data)).to.equal( + 'Gas is not sufficient to execute the transaction.' + ) + }) + + it(`should revert if fee is not transferred to the relayer`, async () => { + const message = serializeNativeTransaction(DEFAULT_EIP155_TX) + const sig = await signNativeTransaction(wallet, DEFAULT_EIP155_TX) + Mock__OVM_ExecutionManager.smocked.ovmCALL.will.return.with( + (gasLimit, target, data) => { + if (target === '0x4200000000000000000000000000000000000006') { + return [ + true, + '0x0000000000000000000000000000000000000000000000000000000000000000', + ] + } else { + return [true, '0x'] + } + } + ) + + await callPredeploy( + Helper_PredeployCaller, + OVM_ECDSAContractAccount, + 'execute', + [ + message, + 0, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ], + 40000000 + ) + + const ovmREVERT: any = + Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] + expect(decodeSolidityError(ovmREVERT._data)).to.equal( + 'Fee was not transferred to relayer.' + ) + }) + }) +}) diff --git a/packages/contracts/test/contracts/OVM/accounts/OVM_ProxyEOA.spec.ts b/packages/contracts/test/contracts/OVM/accounts/OVM_ProxyEOA.spec.ts new file mode 100644 index 0000000000000..2d9f00f9939dc --- /dev/null +++ b/packages/contracts/test/contracts/OVM/accounts/OVM_ProxyEOA.spec.ts @@ -0,0 +1,150 @@ +import { expect } from '../../../setup' + +/* External Imports */ +import { ethers, waffle } from 'hardhat' +import { ContractFactory, Contract, Wallet } from 'ethers' +import { MockContract, smockit } from '@eth-optimism/smock' +import { remove0x } from '@eth-optimism/core-utils' + +/* Internal Imports */ +import { decodeSolidityError } from '../../../helpers' +import { getContractInterface, getContractFactory } from '../../../../src' + +const callPredeploy = async ( + Helper_PredeployCaller: Contract, + predeploy: Contract, + functionName: string, + functionParams?: any[], + ethCall: boolean = false +): Promise => { + if (ethCall) { + return Helper_PredeployCaller.callStatic.callPredeployAbi( + predeploy.address, + predeploy.interface.encodeFunctionData(functionName, functionParams || []) + ) + } + return Helper_PredeployCaller.callPredeploy( + predeploy.address, + predeploy.interface.encodeFunctionData(functionName, functionParams || []) + ) +} + +const addrToBytes32 = (addr: string) => '0x' + '00'.repeat(12) + remove0x(addr) + +const eoaDefaultAddr = '0x4200000000000000000000000000000000000003' + +describe('OVM_ProxyEOA', () => { + let wallet: Wallet + before(async () => { + const provider = waffle.provider + ;[wallet] = provider.getWallets() + }) + + let Mock__OVM_ExecutionManager: MockContract + let Mock__OVM_ECDSAContractAccount: MockContract + let Helper_PredeployCaller: Contract + before(async () => { + Mock__OVM_ExecutionManager = await smockit( + await ethers.getContractFactory('OVM_ExecutionManager') + ) + + Helper_PredeployCaller = await ( + await ethers.getContractFactory('Helper_PredeployCaller') + ).deploy() + + Helper_PredeployCaller.setTarget(Mock__OVM_ExecutionManager.address) + + Mock__OVM_ECDSAContractAccount = await smockit( + getContractInterface('OVM_ECDSAContractAccount', true) + ) + }) + + let OVM_ProxyEOAFactory: ContractFactory + before(async () => { + OVM_ProxyEOAFactory = getContractFactory('OVM_ProxyEOA', wallet, true) + }) + + let OVM_ProxyEOA: Contract + beforeEach(async () => { + OVM_ProxyEOA = await OVM_ProxyEOAFactory.deploy() + + Mock__OVM_ExecutionManager.smocked.ovmADDRESS.will.return.with( + OVM_ProxyEOA.address + ) + Mock__OVM_ExecutionManager.smocked.ovmCALLER.will.return.with( + OVM_ProxyEOA.address + ) + }) + + describe('getImplementation()', () => { + it(`should be created with implementation at predeploy address`, async () => { + const eoaDefaultAddrBytes32 = addrToBytes32(eoaDefaultAddr) + Mock__OVM_ExecutionManager.smocked.ovmSLOAD.will.return.with( + eoaDefaultAddrBytes32 + ) + const implAddrBytes32 = await callPredeploy( + Helper_PredeployCaller, + OVM_ProxyEOA, + 'getImplementation', + [], + true + ) + expect(implAddrBytes32).to.equal(eoaDefaultAddrBytes32) + }) + }) + describe('upgrade()', () => { + const implSlotKey = + '0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead' + it(`should upgrade the proxy implementation`, async () => { + const newImpl = `0x${'81'.repeat(20)}` + const newImplBytes32 = addrToBytes32(newImpl) + await callPredeploy(Helper_PredeployCaller, OVM_ProxyEOA, 'upgrade', [ + newImpl, + ]) + const ovmSSTORE: any = + Mock__OVM_ExecutionManager.smocked.ovmSSTORE.calls[0] + expect(ovmSSTORE._key).to.equal(implSlotKey) + expect(ovmSSTORE._value).to.equal(newImplBytes32) + }) + it(`should not allow upgrade of the proxy implementation by another account`, async () => { + Mock__OVM_ExecutionManager.smocked.ovmCALLER.will.return.with( + await wallet.getAddress() + ) + const newImpl = `0x${'81'.repeat(20)}` + await callPredeploy(Helper_PredeployCaller, OVM_ProxyEOA, 'upgrade', [ + newImpl, + ]) + const ovmREVERT: any = + Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] + expect(decodeSolidityError(ovmREVERT._data)).to.equal( + 'EOAs can only upgrade their own EOA implementation' + ) + }) + }) + describe('fallback()', () => { + it(`should call delegateCall with right calldata`, async () => { + Mock__OVM_ExecutionManager.smocked.ovmSLOAD.will.return.with( + addrToBytes32(Mock__OVM_ECDSAContractAccount.address) + ) + Mock__OVM_ExecutionManager.smocked.ovmDELEGATECALL.will.return.with([ + true, + '0x1234', + ]) + const calldata = '0xdeadbeef' + await Helper_PredeployCaller.callPredeploy(OVM_ProxyEOA.address, calldata) + + const ovmDELEGATECALL: any = + Mock__OVM_ExecutionManager.smocked.ovmDELEGATECALL.calls[0] + expect(ovmDELEGATECALL._address).to.equal( + Mock__OVM_ECDSAContractAccount.address + ) + expect(ovmDELEGATECALL._calldata).to.equal(calldata) + }) + it.skip(`should return data from fallback`, async () => { + //TODO test return data from fallback + }) + it.skip(`should revert in fallback`, async () => { + //TODO test reversion from fallback + }) + }) +}) diff --git a/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts b/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts new file mode 100644 index 0000000000000..4046eaf7abdf2 --- /dev/null +++ b/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts @@ -0,0 +1,235 @@ +import { expect } from '../../../setup' + +/* External Imports */ +import { waffle, ethers } from 'hardhat' +import { ContractFactory, Wallet, Contract, BigNumber } from 'ethers' +import { smockit, MockContract } from '@eth-optimism/smock' +import { fromHexString, toHexString } from '@eth-optimism/core-utils' +import { ecrecover, publicToAddress } from 'ethereumjs-util' + +/* Internal Imports */ +import { getContractInterface, getContractFactory } from '../../../../src' +import { + encodeSequencerCalldata, + signNativeTransaction, + signEthSignMessage, + DEFAULT_EIP155_TX, + serializeNativeTransaction, + serializeEthSignTransaction, +} from '../../../helpers' + +describe('OVM_SequencerEntrypoint', () => { + let wallet: Wallet + before(async () => { + const provider = waffle.provider + ;[wallet] = provider.getWallets() + }) + + let Mock__OVM_ExecutionManager: MockContract + let Helper_PredeployCaller: Contract + before(async () => { + Mock__OVM_ExecutionManager = await smockit( + await ethers.getContractFactory('OVM_ExecutionManager') + ) + + Mock__OVM_ExecutionManager.smocked.ovmCHAINID.will.return.with(420) + Mock__OVM_ExecutionManager.smocked.ovmCALL.will.return.with( + (gasLimit, target, data) => { + if (target === wallet.address) { + return [ + true, + iOVM_ECDSAContractAccount.encodeFunctionResult('execute', [ + true, + '0x', + ]), + ] + } else { + return [true, '0x'] + } + } + ) + Mock__OVM_ExecutionManager.smocked.ovmSTATICCALL.will.return.with( + (gasLimit, target, data) => { + if (target === '0x0000000000000000000000000000000000000001') { + const databuf = fromHexString(data) + const msghash = databuf.slice(0, 32) + const v = databuf.slice(32, 64) + const r = databuf.slice(64, 96) + const s = databuf.slice(96, 128) + const pubkey = ecrecover(msghash, BigNumber.from(v).toNumber(), r, s) + const addr = toHexString(publicToAddress(pubkey)) + const ret = ethers.utils.defaultAbiCoder.encode(['address'], [addr]) + return [true, ret] + } else { + return [true, '0x'] + } + } + ) + + Helper_PredeployCaller = await ( + await ethers.getContractFactory('Helper_PredeployCaller') + ).deploy() + + Helper_PredeployCaller.setTarget(Mock__OVM_ExecutionManager.address) + }) + + let OVM_SequencerEntrypointFactory: ContractFactory + before(async () => { + OVM_SequencerEntrypointFactory = getContractFactory( + 'OVM_SequencerEntrypoint', + wallet, + true + ) + }) + + const iOVM_ECDSAContractAccount = getContractInterface( + 'OVM_ECDSAContractAccount', + true + ) + + let OVM_SequencerEntrypoint: Contract + beforeEach(async () => { + OVM_SequencerEntrypoint = await OVM_SequencerEntrypointFactory.deploy() + Mock__OVM_ExecutionManager.smocked.ovmEXTCODESIZE.will.return.with(1) + Mock__OVM_ExecutionManager.smocked.ovmREVERT.will.revert() + }) + + describe('fallback()', async () => { + it('should call EIP155 if the transaction type is 0', async () => { + const calldata = await encodeSequencerCalldata( + wallet, + DEFAULT_EIP155_TX, + 0 + ) + await Helper_PredeployCaller.callPredeploy( + OVM_SequencerEntrypoint.address, + calldata + ) + + const encodedTx = serializeNativeTransaction(DEFAULT_EIP155_TX) + const sig = await signNativeTransaction(wallet, DEFAULT_EIP155_TX) + + const expectedEOACalldata = iOVM_ECDSAContractAccount.encodeFunctionData( + 'execute', + [ + encodedTx, + 0, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ] + ) + const ovmCALL: any = Mock__OVM_ExecutionManager.smocked.ovmCALL.calls[0] + expect(ovmCALL._address).to.equal(await wallet.getAddress()) + expect(ovmCALL._calldata).to.equal(expectedEOACalldata) + }) + + it('should send correct calldata if tx is a create and the transaction type is 0', async () => { + const createTx = { ...DEFAULT_EIP155_TX, to: '' } + const calldata = await encodeSequencerCalldata(wallet, createTx, 0) + await Helper_PredeployCaller.callPredeploy( + OVM_SequencerEntrypoint.address, + calldata + ) + + const encodedTx = serializeNativeTransaction(createTx) + const sig = await signNativeTransaction(wallet, createTx) + + const expectedEOACalldata = iOVM_ECDSAContractAccount.encodeFunctionData( + 'execute', + [ + encodedTx, + 0, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ] + ) + const ovmCALL: any = Mock__OVM_ExecutionManager.smocked.ovmCALL.calls[0] + expect(ovmCALL._address).to.equal(await wallet.getAddress()) + expect(ovmCALL._calldata).to.equal(expectedEOACalldata) + }) + + for (let i = 0; i < 3; i += 2) { + it(`should call ovmCreateEOA when tx type is ${i} and ovmEXTCODESIZE returns 0`, async () => { + let firstCheck = true + Mock__OVM_ExecutionManager.smocked.ovmEXTCODESIZE.will.return.with( + () => { + if (firstCheck) { + firstCheck = false + return 0 + } else { + return 1 + } + } + ) + const calldata = await encodeSequencerCalldata( + wallet, + DEFAULT_EIP155_TX, + i + ) + await Helper_PredeployCaller.callPredeploy( + OVM_SequencerEntrypoint.address, + calldata + ) + const call: any = + Mock__OVM_ExecutionManager.smocked.ovmCREATEEOA.calls[0] + const eoaAddress = ethers.utils.recoverAddress(call._messageHash, { + v: call._v + 27, + r: call._r, + s: call._s, + }) + expect(eoaAddress).to.equal(await wallet.getAddress()) + }) + } + + it('should submit ETHSignedTypedData if TransactionType is 2', async () => { + const calldata = await encodeSequencerCalldata( + wallet, + DEFAULT_EIP155_TX, + 2 + ) + await Helper_PredeployCaller.callPredeploy( + OVM_SequencerEntrypoint.address, + calldata + ) + + const encodedTx = serializeEthSignTransaction(DEFAULT_EIP155_TX) + const sig = await signEthSignMessage(wallet, DEFAULT_EIP155_TX) + + const expectedEOACalldata = iOVM_ECDSAContractAccount.encodeFunctionData( + 'execute', + [ + encodedTx, + 1, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ] + ) + const ovmCALL: any = Mock__OVM_ExecutionManager.smocked.ovmCALL.calls[0] + expect(ovmCALL._address).to.equal(await wallet.getAddress()) + expect(ovmCALL._calldata).to.equal(expectedEOACalldata) + }) + + it('should revert if TransactionType is >2', async () => { + const calldata = '0x03' + await expect( + Helper_PredeployCaller.callPredeploy( + OVM_SequencerEntrypoint.address, + calldata + ) + ).to.be.reverted + }) + + it('should revert if TransactionType is 1', async () => { + const calldata = '0x01' + await expect( + Helper_PredeployCaller.callPredeploy( + OVM_SequencerEntrypoint.address, + calldata + ) + ).to.be.reverted + }) + }) +}) diff --git a/packages/hardhat-ovm/src/index.ts b/packages/hardhat-ovm/src/index.ts index 6e32bd8a533bd..6afff50e2fe92 100644 --- a/packages/hardhat-ovm/src/index.ts +++ b/packages/hardhat-ovm/src/index.ts @@ -28,7 +28,7 @@ const DEFAULT_OVM_SOLC_VERSION = '0.7.6' */ const getOvmSolcPath = async (version: string): Promise => { // TEMP - version = '0.7.6-allow_kall' + version = '0.7.6-allow_kall_2' // If __DANGEROUS_OVM_IGNORE_ERRORS__ env var is not undefined we append the -no-errors suffix to the solc version. if (process.env.__DANGEROUS_OVM_IGNORE_ERRORS__) { diff --git a/packages/smock/src/smockit/types.ts b/packages/smock/src/smockit/types.ts index 85c31bb9ccd9f..9f6b21febd79f 100644 --- a/packages/smock/src/smockit/types.ts +++ b/packages/smock/src/smockit/types.ts @@ -35,9 +35,7 @@ export interface MockContractFunction { } revert: { (): void - with: ( - revertValue?: string | (() => string) | (() => Promise) - ) => void + with: (returnValue?: MockReturnValue) => void } resolve: 'return' | 'revert' } diff --git a/yarn.lock b/yarn.lock index 2c0ed0d0c6c31..f2a2de370113f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5310,7 +5310,7 @@ ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereum rlp "^2.0.0" safe-buffer "^5.1.1" -ethereumjs-util@^7.0.2, ethereumjs-util@^7.0.8: +ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.2, ethereumjs-util@^7.0.8: version "7.0.10" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.10.tgz#5fb7b69fa1fda0acc59634cf39d6b0291180fc1f" integrity sha512-c/xThw6A+EAnej5Xk5kOzFzyoSnw0WX0tSlZ6pAsfGVvQj3TItaDg9b1+Fz1RJXA+y2YksKwQnuzgt1eY6LKzw== From e77b1cded2732979f9fbf0b01cc2bb7ec094dec0 Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Tue, 20 Apr 2021 19:21:41 -0400 Subject: [PATCH 7/8] fix nuisance gas test return value --- .../OVM/predeploys/OVM_SequencerEntrypoint.sol | 6 +++--- .../OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol index 8bb8cd6d233cf..8a151dee389e0 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol @@ -80,12 +80,12 @@ contract OVM_SequencerEntrypoint { s ); - uint256 eoaContractSize; + bool isEmptyContract; assembly { - eoaContractSize := extcodesize(target) + isEmptyContract := iszero(extcodesize(target)) } - if (eoaContractSize == 0) { + if (isEmptyContract) { // ProxyEOA has not yet been deployed for this EOA. bytes32 messageHash = Lib_ECDSAUtils.getMessageHash(encodedTx, isEthSignedMessage); Lib_ExecutionManagerWrapper.ovmCREATEEOA(messageHash, v, r, s); diff --git a/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts b/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts index d9a4c725eb61e..4fe10c65a77ad 100644 --- a/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts +++ b/packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts @@ -188,7 +188,7 @@ const test_nuisanceGas: TestDefinition = { // This is because there is natural gas consumption between the ovmCALL(GAS/2) and ovmCREATE, which allots nuisance gas via _getNuisanceGasLimit. // This means that the ovmCREATE exception, DOES consumes all nuisance gas allotted, but that allotment // is less than the full OVM_TX_GAS_LIMIT / 2 which is alloted to the parent ovmCALL. - nuisanceGasLeft: 4169443, + nuisanceGasLeft: 4169343, }, }, }, From 7881bc6c1b85518acdcc2917cefe417bfac4f5a1 Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Tue, 20 Apr 2021 20:19:50 -0400 Subject: [PATCH 8/8] Fix incorrect naming in predeploys --- packages/contracts/src/contract-dumps.ts | 4 ++-- packages/contracts/src/predeploys.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contracts/src/contract-dumps.ts b/packages/contracts/src/contract-dumps.ts index 75244a4852110..d521681703ddf 100644 --- a/packages/contracts/src/contract-dumps.ts +++ b/packages/contracts/src/contract-dumps.ts @@ -159,13 +159,13 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise => { config = { ...config, ...cfg } const ovmCompiled = [ + 'Lib_AddressManager', 'OVM_L2ToL1MessagePasser', 'OVM_L2CrossDomainMessenger', 'OVM_DeployerWhitelist', 'OVM_SequencerEntrypoint', - 'Lib_AddressManager', + 'OVM_ProxyEOA', 'OVM_ETH', - 'Proxy_EOA', ] const deploymentResult = await deploy(config) diff --git a/packages/contracts/src/predeploys.ts b/packages/contracts/src/predeploys.ts index 9cb33e71841fd..116c0417920ec 100644 --- a/packages/contracts/src/predeploys.ts +++ b/packages/contracts/src/predeploys.ts @@ -7,6 +7,6 @@ export const predeploys = { OVM_ETH: '0x4200000000000000000000000000000000000006', OVM_L2CrossDomainMessenger: '0x4200000000000000000000000000000000000007', Lib_AddressManager: '0x4200000000000000000000000000000000000008', - Proxy_EOA: '0x4200000000000000000000000000000000000009', + OVM_ProxyEOA: '0x4200000000000000000000000000000000000009', ERC1820Registry: '0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24', }