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
// @unsupported: evm
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 +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
* 'account abstraction' on layer 2.
*
* Compiler used: solc
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
contract OVM_ProxyEOA {
......@@ -22,24 +20,10 @@ contract OVM_ProxyEOA {
* Constants *
*************/
address constant DEFAULT_IMPLEMENTATION = 0x4200000000000000000000000000000000000003;
bytes32 constant IMPLEMENTATION_KEY = 0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead;
/***************
* Constructor *
***************/
/**
* @param _implementation Address of the initial implementation contract.
*/
constructor(
address _implementation
)
{
_setImplementation(_implementation);
}
/*********************
* Fallback Function *
*********************/
......@@ -47,23 +31,23 @@ contract OVM_ProxyEOA {
fallback()
external
{
(bool success, bytes memory returndata) = Lib_SafeExecutionManagerWrapper.safeDELEGATECALL(
gasleft(),
getImplementation(),
msg.data
);
(bool success, bytes memory returndata) = getImplementation().delegatecall(msg.data);
if (success) {
assembly {
return(add(returndata, 0x20), mload(returndata))
}
} else {
Lib_SafeExecutionManagerWrapper.safeREVERT(
string(returndata)
);
assembly {
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 *
......@@ -78,8 +62,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 +80,17 @@ contract OVM_ProxyEOA {
address
)
{
return Lib_Bytes32Utils.toAddress(
Lib_SafeExecutionManagerWrapper.safeSLOAD(
IMPLEMENTATION_KEY
)
);
bytes32 addr32;
assembly {
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 {
)
internal
{
Lib_SafeExecutionManagerWrapper.safeSSTORE(
IMPLEMENTATION_KEY,
Lib_Bytes32Utils.fromAddress(_implementation)
);
bytes32 addr32 = Lib_Bytes32Utils.fromAddress(_implementation);
assembly {
sstore(IMPLEMENTATION_KEY, addr32)
}
}
}
......@@ -16,7 +16,6 @@ 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";
/**
......@@ -534,9 +533,25 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
address prevADDRESS = messageContext.ovmADDRESS;
messageContext.ovmADDRESS = eoa;
// 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);
// Creates a duplicate of the OVM_ProxyEOA located at 0x42....09. Uses the following
// "magic" prefix to deploy an exact copy of the code:
// 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.
messageContext.ovmADDRESS = prevADDRESS;
......
......@@ -254,5 +254,8 @@ export const makeContractDeployConfig = async (
ERC1820Registry: {
factory: getContractFactory('ERC1820Registry'),
},
OVM_ProxyEOA: {
factory: getContractFactory('OVM_ProxyEOA', undefined, true),
},
}
}
......@@ -167,6 +167,7 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise<any> => {
'OVM_SequencerEntrypoint',
'Lib_AddressManager',
'OVM_ETH',
'OVM_ProxyEOA',
]
const deploymentResult = await deploy(config)
......
......@@ -8,5 +8,6 @@ export const predeploys = {
OVM_ETH: '0x4200000000000000000000000000000000000006',
OVM_L2CrossDomainMessenger: '0x4200000000000000000000000000000000000007',
Lib_AddressManager: '0x4200000000000000000000000000000000000008',
OVM_ProxyEOA: '0x4200000000000000000000000000000000000009',
ERC1820Registry: '0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24',
}
......@@ -8,6 +8,7 @@ import { remove0x } from '@eth-optimism/core-utils'
/* Internal Imports */
import { decodeSolidityError } from '../../../helpers'
import { getContractFactory } from '../../../../src'
const callPredeploy = async (
Helper_PredeployCaller: Contract,
......@@ -60,12 +61,12 @@ describe('OVM_ProxyEOA', () => {
let OVM_ProxyEOAFactory: ContractFactory
before(async () => {
OVM_ProxyEOAFactory = await ethers.getContractFactory('OVM_ProxyEOA')
OVM_ProxyEOAFactory = getContractFactory('OVM_ProxyEOA', wallet, true)
})
let OVM_ProxyEOA: Contract
beforeEach(async () => {
OVM_ProxyEOA = await OVM_ProxyEOAFactory.deploy(eoaDefaultAddr)
OVM_ProxyEOA = await OVM_ProxyEOAFactory.deploy()
Mock__OVM_ExecutionManager.smocked.ovmADDRESS.will.return.with(
OVM_ProxyEOA.address
......
......@@ -73,7 +73,7 @@ const test_ovmCREATEEOA: TestDefinition = {
},
expectedReturnStatus: true,
expectedReturnValue: fromHexString(
getContractDefinition('OVM_ProxyEOA').deployedBytecode
getContractDefinition('OVM_ProxyEOA', true).deployedBytecode
).length,
},
],
......
......@@ -37,6 +37,7 @@ import {
} from '../constants'
import { getStorageXOR } from '../'
import { UNSAFE_BYTECODE } from '../dummy'
import { getContractFactory } from '../../../src'
export class ExecutionManagerTestRunner {
private snapshot: string
......@@ -47,6 +48,7 @@ export class ExecutionManagerTestRunner {
Helper_TestRunner: Contract
Factory__Helper_TestRunner_CREATE: ContractFactory
OVM_DeployerWhitelist: Contract
OVM_ProxyEOA: Contract
} = {
OVM_SafetyChecker: undefined,
OVM_StateManager: undefined,
......@@ -54,6 +56,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,6 +68,10 @@ export class ExecutionManagerTestRunner {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_DEPLOYER_WHITELIST',
},
['0x4200000000000000000000000000000000000009']: {
codeHash: NON_NULL_BYTES32,
ethAddress: '$OVM_PROXY_EOA',
},
},
contractStorage: {
['0x4200000000000000000000000000000000000002']: {
......@@ -217,6 +224,12 @@ export class ExecutionManagerTestRunner {
this.contracts.OVM_DeployerWhitelist = DeployerWhitelist
this.contracts.OVM_ProxyEOA = await getContractFactory(
'OVM_ProxyEOA',
AddressManager.signer,
true
).deploy()
this.contracts.OVM_ExecutionManager = await (
await smoddit('OVM_ExecutionManager')
).deploy(
......@@ -266,6 +279,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.address
} else if (kv.startsWith('$DUMMY_OVM_ADDRESS_')) {
return ExecutionManagerTestRunner.getDummyAddress(kv)
} 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