Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/beige-needles-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@eth-optimism/contracts": patch
---

Ports OVM_ECDSAContractAccount to use optimistic-solc.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: MIT
// @unsupported: evm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;

Expand All @@ -8,16 +9,21 @@ import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContrac
/* 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";

/* Contract Imports */
import { OVM_ETH } from "../predeploys/OVM_ETH.sol";

/* External Imports */
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";

/**
* @title OVM_ECDSAContractAccount
* @dev The ECDSA Contract Account can be used as the implementation for a ProxyEOA deployed by the
* 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 {
Expand All @@ -29,7 +35,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;
OVM_ETH constant ovmETH = OVM_ETH(0x4200000000000000000000000000000000000006);


/********************
Expand Down Expand Up @@ -66,75 +72,75 @@ 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);
Lib_OVMCodec.EIP155Transaction memory decodedTx = Lib_OVMCodec.decodeEIP155Transaction(
_transaction,
isEthSign
);

// Grab the chain ID of the current network.
uint256 chainId;
assembly {
chainId := chainid()
}

// Need to make sure that the transaction chainId is correct.
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
decodedTx.chainId == Lib_SafeExecutionManagerWrapper.safeCHAINID(),
require(
decodedTx.chainId == chainId,
"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),
// require(
// 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(
ovmETH.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(),
(address created, bytes memory revertdata) = Lib_ExecutionManagerWrapper.ovmCREATE(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to wrap create?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see https://github.com/ethereum-optimism/optimism/pull/475/files#r617100336 for a discussion of the alternative using ovmCREATE. Personally I prefer having the wrapper handle this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agree with Ben here. Doing create in assembly is ugly :-/ much cleaner to wrap it.

decodedTx.data
);

// 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ 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_DeployerWhitelist } from "../predeploys/OVM_DeployerWhitelist.sol";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,30 @@ library Lib_ExecutionManagerWrapper {
* Internal Functions *
**********************/

/**
* Performs a safe ovmCREATE call.
* @param _bytecode Code for the new contract.
* @return _contract Address of the created contract.
*/
function ovmCREATE(
bytes memory _bytecode
)
internal
returns (
address,
bytes memory
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmCREATE(bytes)",
_bytecode
)
);

return abi.decode(returndata, (address, bytes));
}

/**
* Performs a safe ovmGETNONCE call.
* @return _nonce Result of calling ovmGETNONCE.
Expand Down

This file was deleted.

2 changes: 1 addition & 1 deletion packages/contracts/src/contract-deployment/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ 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', undefined, true),
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/src/contract-dumps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise<any> => {
'OVM_SequencerEntrypoint',
'Lib_AddressManager',
'OVM_ETH',
'OVM_ECDSAContractAccount',
'OVM_ProxyEOA',
]

Expand Down
1 change: 1 addition & 0 deletions packages/contracts/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './contract-defs'
export { getLatestStateDump, StateDump } from './contract-dumps'
export * from './contract-deployment'
export * from './predeploys'
Loading