Skip to content

Commit

Permalink
EOA and Decompressor (#33)
Browse files Browse the repository at this point in the history
* decompression (not working)

* start EIP155 serialization

* working decompressor

* working CreateEOA, working native EIP155tx

* all three tx types working

* remove only

* fix ECDSAUtil tests

* restore original version of smock

* add proxys

* clean up tests

* clean up decompressor tests

* clean up ProxyDecompressor

* clean up decompressor tests

* add CREATEEOA, SETNONCE, GETNONCE tests

* working ECDSAContractAccount

* fix decompressor

* renaming, add deploy

* add proxyeoa test, cleanup

* remove createEOA type, add extcodesize check

* fix decompressor test

* support create txs

* Decompressor -> Entrypoint

* use safeREVERT instead of requires

* add isAuthenticated state manager test

* update smock

* fix sequencerEntrypoint test

* add isAuthenticated

* Revert "update smock"

This reverts commit 286a222414accf9387dcd12ecbed0a66be586bc8.

* fix test

* Updates to EM

* removed kall from contract account

* Fixed SSLOAD and SSTORE problems

* Fix some broken tests

* Fix more bugs & rename to ProxyEOA

* WIP fix call test

* fix all tests

* add gas check

* update tests

* lint and remove 2000 gas check

* Add fees to default EOA (#56)

Co-authored-by: Kelvin Fichter <[email protected]>
Co-authored-by: Karl Floersch <[email protected]>
  • Loading branch information
3 people authored Nov 11, 2020
1 parent 21b3e5a commit f06c865
Show file tree
Hide file tree
Showing 33 changed files with 1,991 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_Sa
*/
contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {

address constant ETH_ERC20_ADDRESS = 0x4200000000000000000000000000000000000006;

/********************
* Public Functions *
********************/
Expand Down Expand Up @@ -44,35 +46,48 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {
)
{
address ovmExecutionManager = msg.sender;
bool isEthSign = _signatureType == Lib_OVMCodec.EOASignatureType.ETH_SIGNED_MESSAGE;

// Address of this contract within the ovm (ovmADDRESS) should be the same as the
// 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.
require(
// Need to make sure that the transaction nonce is right and bump it if so.
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
msg.sender,
Lib_ECDSAUtils.recover(
_transaction,
_signatureType == Lib_OVMCodec.EOASignatureType.ETH_SIGNED_MESSAGE,
isEthSign,
_v,
_r,
_s,
Lib_SafeExecutionManagerWrapper.safeCHAINID(ovmExecutionManager)
_s
) == Lib_SafeExecutionManagerWrapper.safeADDRESS(ovmExecutionManager),
"Signature provided for EOA transaction execution is invalid."
);

Lib_OVMCodec.EOATransaction memory decodedTx = Lib_OVMCodec.decodeEOATransaction(_transaction);
Lib_OVMCodec.EIP155Transaction memory decodedTx = Lib_OVMCodec.decodeEIP155Transaction(_transaction, isEthSign);

// Need to make sure that the transaction nonce is right and bump it if so.
require(
decodedTx.nonce == Lib_SafeExecutionManagerWrapper.safeGETNONCE(ovmExecutionManager) + 1,
// Need to make sure that the transaction nonce is right.
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
msg.sender,
decodedTx.nonce == Lib_SafeExecutionManagerWrapper.safeGETNONCE(ovmExecutionManager),
"Transaction nonce does not match the expected nonce."
);

// Transfer fee to relayer.
address relayer = Lib_SafeExecutionManagerWrapper.safeCALLER(ovmExecutionManager);
uint256 fee = decodedTx.gasLimit * decodedTx.gasPrice;
Lib_SafeExecutionManagerWrapper.safeCALL(
ovmExecutionManager,
gasleft(),
ETH_ERC20_ADDRESS,
abi.encodeWithSignature("transfer(address,uint256)", relayer, fee)
);

// Contract creations are signalled by sending a transaction to the zero address.
if (decodedTx.target == address(0)) {
if (decodedTx.to == address(0)) {
address created = Lib_SafeExecutionManagerWrapper.safeCREATE(
ovmExecutionManager,
decodedTx.gasLimit,
decodedTx.gasLimit - 2000,
decodedTx.data
);

Expand All @@ -83,12 +98,12 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {
// 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.safeSETNONCE(ovmExecutionManager, decodedTx.nonce);
Lib_SafeExecutionManagerWrapper.safeSETNONCE(ovmExecutionManager, decodedTx.nonce + 1);

return Lib_SafeExecutionManagerWrapper.safeCALL(
ovmExecutionManager,
decodedTx.gasLimit,
decodedTx.target,
decodedTx.to,
decodedTx.data
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
pragma solidity ^0.7.0;

/* 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";

/**
* @title OVM_ProxyEOA
*/
contract OVM_ProxyEOA {

/***************
* Constructor *
***************/

constructor(
address _implementation
) {
_setImplementation(_implementation);
}


/*********************
* Fallback Function *
*********************/

fallback()
external
{
(bool success, bytes memory returndata) = Lib_SafeExecutionManagerWrapper.safeDELEGATECALL(
msg.sender,
gasleft(),
getImplementation(),
msg.data
);

if (success) {
assembly {
return(add(returndata, 0x20), mload(returndata))
}
} else {
Lib_SafeExecutionManagerWrapper.safeREVERT(
msg.sender,
string(returndata)
);
}
}


/********************
* Public Functions *
********************/

function upgrade(
address _implementation
)
external
{
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
msg.sender,
Lib_SafeExecutionManagerWrapper.safeADDRESS(msg.sender) == Lib_SafeExecutionManagerWrapper.safeCALLER(msg.sender),
"EOAs can only upgrade their own EOA implementation"
);

_setImplementation(_implementation);
}

function getImplementation()
public
returns (
address _implementation
)
{
return address(uint160(uint256(
Lib_SafeExecutionManagerWrapper.safeSLOAD(
msg.sender,
bytes32(uint256(0))
)
)));
}

/**********************
* Internal Functions *
**********************/

function _setImplementation(
address _implementation
)
internal
{
Lib_SafeExecutionManagerWrapper.safeSSTORE(
msg.sender,
bytes32(uint256(0)),
bytes32(uint256(uint160(_implementation)))
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ 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";

/**
* @title OVM_ExecutionManager
Expand Down Expand Up @@ -71,7 +72,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
globalContext = _globalContext;
}


/**********************
* Function Modifiers *
**********************/
Expand Down Expand Up @@ -129,8 +130,8 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
// OVM_StateManager (expected to be an OVM_StateTransitioner). We can revert here because
// this would make the `run` itself invalid.
require(
msg.sender == ovmStateManager.owner(),
"Only the owner of the ovmStateManager can call this function"
ovmStateManager.isAuthenticated(msg.sender),
"Only authenticated addresses in ovmStateManager can call this function"
);

// Check whether we need to start a new epoch, do so if necessary.
Expand Down Expand Up @@ -444,7 +445,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
// actually execute the transaction).
address eoa = ecrecover(
_messageHash,
(_v - uint8(ovmCHAINID()) * 2) - 8,
_v + 27,
_r,
_s
);
Expand All @@ -463,16 +464,22 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
// We always need to initialize the contract with the default account values.
_initPendingAccount(eoa);

// Temporarily set the current address so it's easier to access on L2.
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_ECDSAContractAccount eoaContractAccount = new OVM_ECDSAContractAccount();
bytes memory deployedCode = Lib_EthUtils.getCode(address(eoaContractAccount));
OVM_ProxyEOA proxyEOA = new OVM_ProxyEOA(0x4200000000000000000000000000000000000003);

// Reset the address now that we're done deploying.
messageContext.ovmADDRESS = prevADDRESS;

// Commit the account with its final values.
_commitPendingAccount(
eoa,
address(eoaContractAccount),
keccak256(deployedCode)
address(proxyEOA),
keccak256(Lib_EthUtils.getCode(address(proxyEOA)))
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,26 @@ contract OVM_StateManager is iOVM_StateManager {
_;
}

/***************************
* Public Functions: Misc *
***************************/


function isAuthenticated(
address _address
)
override
public
view
returns (bool)
{
return (_address == owner || _address == ovmExecutionManager);
}

/***************************
* Public Functions: Setup *
***************************/

/**
* Sets the address of the OVM_ExecutionManager.
* @param _ovmExecutionManager Address of the OVM_ExecutionManager.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
pragma solidity ^0.7.0;

/* Library Imports */
import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol";

/**
* @title OVM_ProxySequencerEntrypoint
*/
contract OVM_ProxySequencerEntrypoint {

/*********************
* Fallback Function *
*********************/

fallback()
external
{
Lib_SafeExecutionManagerWrapper.safeDELEGATECALL(
msg.sender,
gasleft(),
_getImplementation(),
msg.data
);
}


/********************
* Public Functions *
********************/

function init(
address _implementation,
address _owner
)
external
{
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
msg.sender,
_getOwner() == address(0),
"ProxySequencerEntrypoint has already been inited"
);
_setOwner(_owner);
_setImplementation(_implementation);
}

function upgrade(
address _implementation
)
external
{
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
msg.sender,
_getOwner() == Lib_SafeExecutionManagerWrapper.safeCALLER(msg.sender),
"Only owner can upgrade the Entrypoint"
);

_setImplementation(_implementation);
}


/**********************
* Internal Functions *
**********************/

function _setImplementation(
address _implementation
)
internal
{
Lib_SafeExecutionManagerWrapper.safeSSTORE(
msg.sender,
bytes32(uint256(0)),
bytes32(uint256(uint160(_implementation)))
);
}

function _getImplementation()
internal
returns (
address _implementation
)
{
return address(uint160(uint256(
Lib_SafeExecutionManagerWrapper.safeSLOAD(
msg.sender,
bytes32(uint256(0))
)
)));
}

function _setOwner(
address _owner
)
internal
{
Lib_SafeExecutionManagerWrapper.safeSSTORE(
msg.sender,
bytes32(uint256(1)),
bytes32(uint256(uint160(_owner)))
);
}

function _getOwner()
internal
returns (
address _owner
)
{
return address(uint160(uint256(
Lib_SafeExecutionManagerWrapper.safeSLOAD(
msg.sender,
bytes32(uint256(1))
)
)));
}
}
Loading

0 comments on commit f06c865

Please sign in to comment.