Commit edb43461 authored by smartcontracts's avatar smartcontracts Committed by GitHub

refactor[contracts]: Port OVM_ProxyEOA to use ovm-solc (#545)

* Port OVM_ProxyEOA to use ovm-solc

* Remove all constructor logic from ProxyEOA

* chore[contracts]: add changeset
parent b95dc228
---
"@eth-optimism/contracts": patch
---
Ports OVM_ProxyEOA to use optimistic-solc instead of the standard solc compiler.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
// @unsupported: evm
pragma solidity >0.5.0 <0.8.0; pragma solidity >0.5.0 <0.8.0;
/* Library Imports */ /* Library Imports */
import { Lib_Bytes32Utils } from "../../libraries/utils/Lib_Bytes32Utils.sol"; 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 * @title OVM_ProxyEOA
...@@ -13,7 +11,7 @@ import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_Sa ...@@ -13,7 +11,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 * In combination with the logic implemented in the ECDSA Contract Account, this enables a form of upgradable
* 'account abstraction' on layer 2. * 'account abstraction' on layer 2.
* *
* Compiler used: solc * Compiler used: optimistic-solc
* Runtime target: OVM * Runtime target: OVM
*/ */
contract OVM_ProxyEOA { contract OVM_ProxyEOA {
...@@ -22,24 +20,10 @@ contract OVM_ProxyEOA { ...@@ -22,24 +20,10 @@ contract OVM_ProxyEOA {
* Constants * * Constants *
*************/ *************/
address constant DEFAULT_IMPLEMENTATION = 0x4200000000000000000000000000000000000003;
bytes32 constant IMPLEMENTATION_KEY = 0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead; bytes32 constant IMPLEMENTATION_KEY = 0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead;
/***************
* Constructor *
***************/
/**
* @param _implementation Address of the initial implementation contract.
*/
constructor(
address _implementation
)
{
_setImplementation(_implementation);
}
/********************* /*********************
* Fallback Function * * Fallback Function *
*********************/ *********************/
...@@ -47,23 +31,23 @@ contract OVM_ProxyEOA { ...@@ -47,23 +31,23 @@ contract OVM_ProxyEOA {
fallback() fallback()
external external
{ {
(bool success, bytes memory returndata) = Lib_SafeExecutionManagerWrapper.safeDELEGATECALL( (bool success, bytes memory returndata) = getImplementation().delegatecall(msg.data);
gasleft(),
getImplementation(),
msg.data
);
if (success) { if (success) {
assembly { assembly {
return(add(returndata, 0x20), mload(returndata)) return(add(returndata, 0x20), mload(returndata))
} }
} else { } else {
Lib_SafeExecutionManagerWrapper.safeREVERT( assembly {
string(returndata) revert(add(returndata, 0x20), mload(returndata))
); }
} }
} }
// WARNING: We use the deployed bytecode of this contract as a template to create ProxyEOA
// contracts. As a result, we must *not* perform any constructor logic. Use initialization
// functions if necessary.
/******************** /********************
* Public Functions * * Public Functions *
...@@ -78,8 +62,8 @@ contract OVM_ProxyEOA { ...@@ -78,8 +62,8 @@ contract OVM_ProxyEOA {
) )
external external
{ {
Lib_SafeExecutionManagerWrapper.safeREQUIRE( require(
Lib_SafeExecutionManagerWrapper.safeADDRESS() == Lib_SafeExecutionManagerWrapper.safeCALLER(), msg.sender == address(this),
"EOAs can only upgrade their own EOA implementation" "EOAs can only upgrade their own EOA implementation"
); );
...@@ -96,11 +80,17 @@ contract OVM_ProxyEOA { ...@@ -96,11 +80,17 @@ contract OVM_ProxyEOA {
address address
) )
{ {
return Lib_Bytes32Utils.toAddress( bytes32 addr32;
Lib_SafeExecutionManagerWrapper.safeSLOAD( assembly {
IMPLEMENTATION_KEY addr32 := sload(IMPLEMENTATION_KEY)
) }
);
address implementation = Lib_Bytes32Utils.toAddress(addr32);
if (implementation == address(0)) {
return DEFAULT_IMPLEMENTATION;
} else {
return implementation;
}
} }
...@@ -113,9 +103,9 @@ contract OVM_ProxyEOA { ...@@ -113,9 +103,9 @@ contract OVM_ProxyEOA {
) )
internal internal
{ {
Lib_SafeExecutionManagerWrapper.safeSSTORE( bytes32 addr32 = Lib_Bytes32Utils.fromAddress(_implementation);
IMPLEMENTATION_KEY, assembly {
Lib_Bytes32Utils.fromAddress(_implementation) sstore(IMPLEMENTATION_KEY, addr32)
); }
} }
} }
...@@ -16,7 +16,6 @@ import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol" ...@@ -16,7 +16,6 @@ import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol"
/* Contract Imports */ /* Contract Imports */
import { OVM_ECDSAContractAccount } from "../accounts/OVM_ECDSAContractAccount.sol"; import { OVM_ECDSAContractAccount } from "../accounts/OVM_ECDSAContractAccount.sol";
import { OVM_ProxyEOA } from "../accounts/OVM_ProxyEOA.sol";
import { OVM_DeployerWhitelist } from "../predeploys/OVM_DeployerWhitelist.sol"; import { OVM_DeployerWhitelist } from "../predeploys/OVM_DeployerWhitelist.sol";
/** /**
...@@ -534,9 +533,25 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -534,9 +533,25 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
address prevADDRESS = messageContext.ovmADDRESS; address prevADDRESS = messageContext.ovmADDRESS;
messageContext.ovmADDRESS = eoa; messageContext.ovmADDRESS = eoa;
// Now actually create the account and get its bytecode. We're not worried about reverts // Creates a duplicate of the OVM_ProxyEOA located at 0x42....09. Uses the following
// (other than out of gas, which we can't capture anyway) because this contract is trusted. // "magic" prefix to deploy an exact copy of the code:
OVM_ProxyEOA proxyEOA = new OVM_ProxyEOA(0x4200000000000000000000000000000000000003); // PUSH1 0x0D # size of this prefix in bytes
// CODESIZE
// SUB # subtract prefix size from codesize
// DUP1
// PUSH1 0x0D
// PUSH1 0x00
// CODECOPY # copy everything after prefix into memory at pos 0
// PUSH1 0x00
// RETURN # return the copied code
address proxyEOA = Lib_EthUtils.createContract(abi.encodePacked(
hex"600D380380600D6000396000f3",
ovmEXTCODECOPY(
0x4200000000000000000000000000000000000009,
0,
ovmEXTCODESIZE(0x4200000000000000000000000000000000000009)
)
));
// Reset the address now that we're done deploying. // Reset the address now that we're done deploying.
messageContext.ovmADDRESS = prevADDRESS; messageContext.ovmADDRESS = prevADDRESS;
......
...@@ -254,5 +254,8 @@ export const makeContractDeployConfig = async ( ...@@ -254,5 +254,8 @@ export const makeContractDeployConfig = async (
ERC1820Registry: { ERC1820Registry: {
factory: getContractFactory('ERC1820Registry'), factory: getContractFactory('ERC1820Registry'),
}, },
OVM_ProxyEOA: {
factory: getContractFactory('OVM_ProxyEOA', undefined, true),
},
} }
} }
...@@ -167,6 +167,7 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise<any> => { ...@@ -167,6 +167,7 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise<any> => {
'OVM_SequencerEntrypoint', 'OVM_SequencerEntrypoint',
'Lib_AddressManager', 'Lib_AddressManager',
'OVM_ETH', 'OVM_ETH',
'OVM_ProxyEOA',
] ]
const deploymentResult = await deploy(config) const deploymentResult = await deploy(config)
......
...@@ -8,5 +8,6 @@ export const predeploys = { ...@@ -8,5 +8,6 @@ export const predeploys = {
OVM_ETH: '0x4200000000000000000000000000000000000006', OVM_ETH: '0x4200000000000000000000000000000000000006',
OVM_L2CrossDomainMessenger: '0x4200000000000000000000000000000000000007', OVM_L2CrossDomainMessenger: '0x4200000000000000000000000000000000000007',
Lib_AddressManager: '0x4200000000000000000000000000000000000008', Lib_AddressManager: '0x4200000000000000000000000000000000000008',
OVM_ProxyEOA: '0x4200000000000000000000000000000000000009',
ERC1820Registry: '0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24', ERC1820Registry: '0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24',
} }
...@@ -8,6 +8,7 @@ import { remove0x } from '@eth-optimism/core-utils' ...@@ -8,6 +8,7 @@ import { remove0x } from '@eth-optimism/core-utils'
/* Internal Imports */ /* Internal Imports */
import { decodeSolidityError } from '../../../helpers' import { decodeSolidityError } from '../../../helpers'
import { getContractFactory } from '../../../../src'
const callPredeploy = async ( const callPredeploy = async (
Helper_PredeployCaller: Contract, Helper_PredeployCaller: Contract,
...@@ -60,12 +61,12 @@ describe('OVM_ProxyEOA', () => { ...@@ -60,12 +61,12 @@ describe('OVM_ProxyEOA', () => {
let OVM_ProxyEOAFactory: ContractFactory let OVM_ProxyEOAFactory: ContractFactory
before(async () => { before(async () => {
OVM_ProxyEOAFactory = await ethers.getContractFactory('OVM_ProxyEOA') OVM_ProxyEOAFactory = getContractFactory('OVM_ProxyEOA', wallet, true)
}) })
let OVM_ProxyEOA: Contract let OVM_ProxyEOA: Contract
beforeEach(async () => { beforeEach(async () => {
OVM_ProxyEOA = await OVM_ProxyEOAFactory.deploy(eoaDefaultAddr) OVM_ProxyEOA = await OVM_ProxyEOAFactory.deploy()
Mock__OVM_ExecutionManager.smocked.ovmADDRESS.will.return.with( Mock__OVM_ExecutionManager.smocked.ovmADDRESS.will.return.with(
OVM_ProxyEOA.address OVM_ProxyEOA.address
......
...@@ -73,7 +73,7 @@ const test_ovmCREATEEOA: TestDefinition = { ...@@ -73,7 +73,7 @@ const test_ovmCREATEEOA: TestDefinition = {
}, },
expectedReturnStatus: true, expectedReturnStatus: true,
expectedReturnValue: fromHexString( expectedReturnValue: fromHexString(
getContractDefinition('OVM_ProxyEOA').deployedBytecode getContractDefinition('OVM_ProxyEOA', true).deployedBytecode
).length, ).length,
}, },
], ],
......
...@@ -37,6 +37,7 @@ import { ...@@ -37,6 +37,7 @@ import {
} from '../constants' } from '../constants'
import { getStorageXOR } from '../' import { getStorageXOR } from '../'
import { UNSAFE_BYTECODE } from '../dummy' import { UNSAFE_BYTECODE } from '../dummy'
import { getContractFactory } from '../../../src'
export class ExecutionManagerTestRunner { export class ExecutionManagerTestRunner {
private snapshot: string private snapshot: string
...@@ -47,6 +48,7 @@ export class ExecutionManagerTestRunner { ...@@ -47,6 +48,7 @@ export class ExecutionManagerTestRunner {
Helper_TestRunner: Contract Helper_TestRunner: Contract
Factory__Helper_TestRunner_CREATE: ContractFactory Factory__Helper_TestRunner_CREATE: ContractFactory
OVM_DeployerWhitelist: Contract OVM_DeployerWhitelist: Contract
OVM_ProxyEOA: Contract
} = { } = {
OVM_SafetyChecker: undefined, OVM_SafetyChecker: undefined,
OVM_StateManager: undefined, OVM_StateManager: undefined,
...@@ -54,6 +56,7 @@ export class ExecutionManagerTestRunner { ...@@ -54,6 +56,7 @@ export class ExecutionManagerTestRunner {
Helper_TestRunner: undefined, Helper_TestRunner: undefined,
Factory__Helper_TestRunner_CREATE: undefined, Factory__Helper_TestRunner_CREATE: undefined,
OVM_DeployerWhitelist: undefined, OVM_DeployerWhitelist: undefined,
OVM_ProxyEOA: undefined,
} }
// Default pre-state with contract deployer whitelist NOT initialized. // Default pre-state with contract deployer whitelist NOT initialized.
...@@ -65,6 +68,10 @@ export class ExecutionManagerTestRunner { ...@@ -65,6 +68,10 @@ export class ExecutionManagerTestRunner {
codeHash: NON_NULL_BYTES32, codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_DEPLOYER_WHITELIST', ethAddress: '$OVM_DEPLOYER_WHITELIST',
}, },
['0x4200000000000000000000000000000000000009']: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_PROXY_EOA',
},
}, },
contractStorage: { contractStorage: {
['0x4200000000000000000000000000000000000002']: { ['0x4200000000000000000000000000000000000002']: {
...@@ -217,6 +224,12 @@ export class ExecutionManagerTestRunner { ...@@ -217,6 +224,12 @@ export class ExecutionManagerTestRunner {
this.contracts.OVM_DeployerWhitelist = DeployerWhitelist this.contracts.OVM_DeployerWhitelist = DeployerWhitelist
this.contracts.OVM_ProxyEOA = await getContractFactory(
'OVM_ProxyEOA',
AddressManager.signer,
true
).deploy()
this.contracts.OVM_ExecutionManager = await ( this.contracts.OVM_ExecutionManager = await (
await smoddit('OVM_ExecutionManager') await smoddit('OVM_ExecutionManager')
).deploy( ).deploy(
...@@ -266,6 +279,8 @@ export class ExecutionManagerTestRunner { ...@@ -266,6 +279,8 @@ export class ExecutionManagerTestRunner {
return this.contracts.Helper_TestRunner.address return this.contracts.Helper_TestRunner.address
} else if (kv === '$OVM_DEPLOYER_WHITELIST') { } else if (kv === '$OVM_DEPLOYER_WHITELIST') {
return this.contracts.OVM_DeployerWhitelist.address return this.contracts.OVM_DeployerWhitelist.address
} else if (kv === '$OVM_PROXY_EOA') {
return this.contracts.OVM_ProxyEOA.address
} else if (kv.startsWith('$DUMMY_OVM_ADDRESS_')) { } else if (kv.startsWith('$DUMMY_OVM_ADDRESS_')) {
return ExecutionManagerTestRunner.getDummyAddress(kv) return ExecutionManagerTestRunner.getDummyAddress(kv)
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment