From 98097a5d322e00ecee9170b234320f6bcd946c8a Mon Sep 17 00:00:00 2001 From: Ben Jones Date: Sun, 14 Mar 2021 21:49:51 -0700 Subject: [PATCH 1/7] fix last compiler warns, add value transfer --- .../OVM/accounts/OVM_ECDSAContractAccount.sol | 58 +++++++++++++++---- 1 file changed, 47 insertions(+), 11 deletions(-) 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 ee013f1e6934..2dbee61def19 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol @@ -101,13 +101,10 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { // 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, + _attemptETHTransfer( + relayer, fee + ), "Fee was not transferred to relayer." ); @@ -130,11 +127,50 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { // cases, but since this is a contract we'd end up bumping the nonce twice. Lib_SafeExecutionManagerWrapper.safeINCREMENTNONCE(); - return Lib_SafeExecutionManagerWrapper.safeCALL( - gasleft(), - decodedTx.to, - decodedTx.data - ); + if (transaction.value > 0) { + Lib_SafeExecutionManagerWrapper.safeREQUIRE( + transaction.data.length == 0, + "Sending ETH with data is currently unsupported." + ); + + return ( + _attemptETHTransfer(transaction.to, transaction.value), + bytes('') + ); + } else { + return Lib_SafeExecutionManagerWrapper.safeCALL( + gasleft(), + decodedTx.to, + decodedTx.data + ); + } } } + + /** + * Attempts to tansfer OVM_ETH. + * @param _to Address to send the L2 ETH to. + * @param _value Amount of L2 ETH to send. + * @return Whether the transfer was successful. + */ + function _attemptETHTransfer( + address _to, + uint256 _value + ) + internal + returns( + bool + ) + { + (bool success, ) = Lib_SafeExecutionManagerWrapper.safeCALL( + gasleft(), + ETH_ERC20_ADDRESS, + abi.encodeWithSignature( + "transfer(address,uint256)", + _to, + _value + ) + ); + return success; + } } From 220b80e3a51180e10dc7577384f0087abf85556b Mon Sep 17 00:00:00 2001 From: Ben Jones Date: Sun, 14 Mar 2021 22:49:56 -0700 Subject: [PATCH 2/7] lower nonce size --- .../OVM/accounts/OVM_ECDSAContractAccount.sol | 6 ++--- .../OVM/execution/OVM_ExecutionManager.sol | 18 +++++++-------- .../OVM/execution/OVM_StateManager.sol | 4 ++-- .../iOVM/execution/iOVM_ExecutionManager.sol | 2 +- .../iOVM/execution/iOVM_StateManager.sol | 4 ++-- .../libraries/codec/Lib_OVMCodec.sol | 8 +++---- .../libraries/rlp/Lib_RLPReader.sol | 22 +++++++++++++++++++ .../Lib_SafeExecutionManagerWrapper.sol | 10 ++++----- .../OVM_ExecutionManager/ovmCREATE.spec.ts | 18 +++++++++++++++ 9 files changed, 66 insertions(+), 26 deletions(-) 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 2dbee61def19..1e13cc04b23b 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol @@ -127,14 +127,14 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { // cases, but since this is a contract we'd end up bumping the nonce twice. Lib_SafeExecutionManagerWrapper.safeINCREMENTNONCE(); - if (transaction.value > 0) { + if (decodedTx.value > 0) { Lib_SafeExecutionManagerWrapper.safeREQUIRE( - transaction.data.length == 0, + decodedTx.data.length == 0, "Sending ETH with data is currently unsupported." ); return ( - _attemptETHTransfer(transaction.to, transaction.value), + _attemptETHTransfer(decodedTx.to, decodedTx.value), bytes('') ); } else { 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 dba6fa1db2ff..b05273245471 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol @@ -460,7 +460,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { override public returns ( - uint256 _nonce + uint64 _nonce ) { return _getAccountNonce(ovmADDRESS()); @@ -475,7 +475,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { notStatic { address account = ovmADDRESS(); - uint256 nonce = _getAccountNonce(account); + uint64 nonce = _getAccountNonce(account); // Prevent overflow. if (nonce + 1 > nonce) { @@ -1050,15 +1050,15 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { * This function sanitizes the return types for creation messages to match calls (bool, bytes), * by being an external function which the EM can call, that mimics the success/fail case of the CREATE. * This allows for consistent handling of both types of messages in _handleExternalMessage(). - * Having this step occur as a separate call frame also allows us to easily revert the + * Having this step occur as a separate call frame also allows us to easily revert the * contract deployment in the event that the code is unsafe. - * - * @param _gasLimit Amount of gas to be passed into this creation. + * + * param _gasLimit Amount of gas to be passed into this creation. * @param _creationCode Code to pass into CREATE for deployment. * @param _address OVM address being deployed to. */ function safeCREATE( - uint _gasLimit, + uint, // _gasLimit bytes memory _creationCode, address _address ) @@ -1097,7 +1097,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { if (ethAddress == address(0)) { // If the creation fails, the EVM lets us grab its revert data. This may contain a revert flag // to be used above in _handleExternalMessage, so we pass the revert data back up unmodified. - assembly { + assembly { returndatacopy(0,0,returndatasize()) revert(0, returndatasize()) } @@ -1167,7 +1167,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { */ function _setAccountNonce( address _address, - uint256 _nonce + uint64 _nonce ) internal { @@ -1185,7 +1185,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ) internal returns ( - uint256 _nonce + uint64 _nonce ) { _checkAccountLoad(_address); diff --git a/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_StateManager.sol b/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_StateManager.sol index 2d8a95bc13e6..0f08a30d976b 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_StateManager.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_StateManager.sol @@ -207,7 +207,7 @@ contract OVM_StateManager is iOVM_StateManager { */ function setAccountNonce( address _address, - uint256 _nonce + uint64 _nonce ) override public @@ -228,7 +228,7 @@ contract OVM_StateManager is iOVM_StateManager { public view returns ( - uint256 + uint64 ) { return accounts[_address].nonce; diff --git a/packages/contracts/contracts/optimistic-ethereum/iOVM/execution/iOVM_ExecutionManager.sol b/packages/contracts/contracts/optimistic-ethereum/iOVM/execution/iOVM_ExecutionManager.sol index 9be045cfc748..3f4cfe889004 100644 --- a/packages/contracts/contracts/optimistic-ethereum/iOVM/execution/iOVM_ExecutionManager.sol +++ b/packages/contracts/contracts/optimistic-ethereum/iOVM/execution/iOVM_ExecutionManager.sol @@ -117,7 +117,7 @@ interface iOVM_ExecutionManager { * Account Abstraction Opcodes * ******************************/ - function ovmGETNONCE() external returns (uint256 _nonce); + function ovmGETNONCE() external returns (uint64 _nonce); function ovmINCREMENTNONCE() external; function ovmCREATEEOA(bytes32 _messageHash, uint8 _v, bytes32 _r, bytes32 _s) external; diff --git a/packages/contracts/contracts/optimistic-ethereum/iOVM/execution/iOVM_StateManager.sol b/packages/contracts/contracts/optimistic-ethereum/iOVM/execution/iOVM_StateManager.sol index 1c4870a5841a..9497752ad9ba 100644 --- a/packages/contracts/contracts/optimistic-ethereum/iOVM/execution/iOVM_StateManager.sol +++ b/packages/contracts/contracts/optimistic-ethereum/iOVM/execution/iOVM_StateManager.sol @@ -45,8 +45,8 @@ interface iOVM_StateManager { function getAccount(address _address) external view returns (Lib_OVMCodec.Account memory _account); function hasAccount(address _address) external view returns (bool _exists); function hasEmptyAccount(address _address) external view returns (bool _exists); - function setAccountNonce(address _address, uint256 _nonce) external; - function getAccountNonce(address _address) external view returns (uint256 _nonce); + function setAccountNonce(address _address, uint64 _nonce) external; + function getAccountNonce(address _address) external view returns (uint64 _nonce); function getAccountEthAddress(address _address) external view returns (address _ethAddress); function getAccountStorageRoot(address _address) external view returns (bytes32 _storageRoot); function initPendingAccount(address _address) external; 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 0cb7245956a5..4c3c94a7424b 100644 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol @@ -34,7 +34,7 @@ library Lib_OVMCodec { ***********/ struct Account { - uint256 nonce; + uint64 nonce; uint256 balance; bytes32 storageRoot; bytes32 codeHash; @@ -43,7 +43,7 @@ library Lib_OVMCodec { } struct EVMAccount { - uint256 nonce; + uint64 nonce; uint256 balance; bytes32 storageRoot; bytes32 codeHash; @@ -307,7 +307,7 @@ library Lib_OVMCodec { // index-by-index circumvents this issue. raw[0] = Lib_RLPWriter.writeBytes( Lib_Bytes32Utils.removeLeadingZeros( - bytes32(_account.nonce) + bytes32(uint256(_account.nonce)) ) ); raw[1] = Lib_RLPWriter.writeBytes( @@ -338,7 +338,7 @@ library Lib_OVMCodec { Lib_RLPReader.RLPItem[] memory accountState = Lib_RLPReader.readList(_encoded); return EVMAccount({ - nonce: Lib_RLPReader.readUint256(accountState[0]), + nonce: uint64(Lib_RLPReader.readUint256(accountState[0])), balance: Lib_RLPReader.readUint256(accountState[1]), storageRoot: Lib_RLPReader.readBytes32(accountState[2]), codeHash: Lib_RLPReader.readBytes32(accountState[3]) diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPReader.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPReader.sol index 5e81c5de2ae6..b0b198996a8a 100644 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPReader.sol +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPReader.sol @@ -425,6 +425,28 @@ library Lib_RLPReader { ); } + /** + * Reads an RLP Uint64 value into a uint64. + * @param _in RLP uint64 value. + * @return Decoded uint64. + */ + function readUint64( + RLPItem memory _in + ) + internal + pure + returns ( + uint64 + ) + { + require( + _in.length <= 9, + "Invalid RLP uint64 value." + ); + + return uint64(readUint256(_in)); + } + /** * Reads the raw bytes of an RLP item. * @param _in RLP item to read. diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol index 14dc89bdf8ed..b0885d6a879f 100644 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol @@ -6,10 +6,10 @@ 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 + * @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 */ @@ -195,7 +195,7 @@ library Lib_SafeExecutionManagerWrapper { function safeGETNONCE() internal returns ( - uint256 _nonce + uint64 _nonce ) { bytes memory returndata = _safeExecutionManagerInteraction( @@ -204,7 +204,7 @@ library Lib_SafeExecutionManagerWrapper { ) ); - return abi.decode(returndata, (uint256)); + return abi.decode(returndata, (uint64)); } /** 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 147fac7be9f0..c4caf60103cd 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 @@ -744,6 +744,24 @@ const test_ovmCREATE: TestDefinition = { }, ], }, + { + name: 'ovmCREATE(UNSAFE_CODE)', + steps: [ + { + functionName: 'ovmCREATE', + functionParams: { + bytecode: UNSAFE_BYTECODE, + }, + expectedReturnStatus: true, + expectedReturnValue: { + address: constants.AddressZero, + revertData: encodeSolidityError( + 'Constructor attempted to deploy unsafe bytecode.' + ), + }, + }, + ], + }, ], subTests: [ { From af9f9a65a452755f64cd33999426c8238ed081c7 Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Mon, 8 Mar 2021 15:06:36 -0800 Subject: [PATCH 3/7] Merge branch 'master' into feat/standard-rlp-transaction --- .../OVM/accounts/OVM_ECDSAContractAccount.sol | 52 +- .../OVM/accounts/OVM_ProxyEOA.sol | 2 - .../predeploys/OVM_SequencerEntrypoint.sol | 118 +-- .../accounts/iOVM_ECDSAContractAccount.sol | 16 +- .../libraries/codec/Lib_EIP155Tx.sol | 196 +++++ .../libraries/codec/Lib_OVMCodec.sol | 137 ---- .../libraries/rlp/Lib_RLPWriter.sol | 17 + .../libraries/utils/Lib_ECDSAUtils.sol | 98 --- .../accounts/mockOVM_ECDSAContractAccount.sol | 95 --- .../test-libraries/codec/TestLib_EIP155Tx.sol | 71 ++ .../test-libraries/codec/TestLib_OVMCodec.sol | 24 - .../utils/TestLib_ECDSAUtils.sol | 33 - .../src/contract-deployment/config.ts | 3 - .../accounts/OVM_ECDSAContractAccount.spec.ts | 140 +--- .../OVM_SequencerEntrypoint.spec.ts | 128 +--- .../contracts/libraries/codec/Lib_EIP155Tx.ts | 15 + .../libraries/utils/Lib_ECDSAUtils.spec.ts | 9 - packages/contracts/test/data/index.ts | 2 +- .../libraries/codec/Lib_EIP155Tx.test.json | 725 ++++++++++++++++++ .../libraries/codec/Lib_OVMCodec.test.json | 18 - .../libraries/utils/Lib_ECDSAUtils.test.json | 126 --- .../contracts/test/helpers/codec/encoding.ts | 116 --- .../helpers/test-runner/json-test-runner.ts | 10 +- 23 files changed, 1148 insertions(+), 1003 deletions(-) create mode 100644 packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol delete mode 100644 packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol delete mode 100644 packages/contracts/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol create mode 100644 packages/contracts/contracts/test-libraries/codec/TestLib_EIP155Tx.sol delete mode 100644 packages/contracts/contracts/test-libraries/utils/TestLib_ECDSAUtils.sol create mode 100644 packages/contracts/test/contracts/libraries/codec/Lib_EIP155Tx.ts delete mode 100644 packages/contracts/test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts create mode 100644 packages/contracts/test/data/json/libraries/codec/Lib_EIP155Tx.test.json delete mode 100644 packages/contracts/test/data/json/libraries/utils/Lib_ECDSAUtils.test.json 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 1e13cc04b23b..10c0aa57e76f 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol @@ -6,21 +6,22 @@ pragma experimental ABIEncoderV2; 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_EIP155Tx } from "../../libraries/codec/Lib_EIP155Tx.sol"; import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol"; import { Lib_SafeMathWrapper } from "../../libraries/wrappers/Lib_SafeMathWrapper.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 + * ovmCREATEEOA operation. It enables backwards compatibility with Ethereum's Layer 1, by * providing eth_sign and EIP155 formatted transaction encodings. * * Compiler used: solc * Runtime target: OVM */ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { + using Lib_EIP155Tx for Lib_EIP155Tx.EIP155Tx; + /************* * Constants * @@ -38,20 +39,12 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { /** * 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. + * @param _encodedTransaction Signed EIP155 transaction. * @return Whether or not the call returned (rather than reverted). * @return Data returned by the call. */ function execute( - bytes memory _transaction, - Lib_OVMCodec.EOASignatureType _signatureType, - uint8 _v, - bytes32 _r, - bytes32 _s + bytes memory _encodedTransaction ) override public @@ -60,31 +53,29 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { bytes memory ) { - bool isEthSign = _signatureType == Lib_OVMCodec.EOASignatureType.ETH_SIGNED_MESSAGE; + Lib_EIP155Tx.EIP155Tx memory decodedTx = Lib_EIP155Tx.decode( + _encodedTransaction, + Lib_SafeExecutionManagerWrapper.safeCHAINID() + ); + + // Recovery parameter being something other than 0 or 1 indicates that this transaction was + // signed using the wrong chain ID. We really should have this logic inside of Lib_EIP155Tx + // but I'd prefer not to add the "safeREQUIRE" logic into that library. So it'll live here + // for now. + Lib_SafeExecutionManagerWrapper.safeREQUIRE( + decodedTx.recoveryParam < 2, + "OVM_ECDSAContractAccount: Transaction was signed with the wrong chain ID." + ); // 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. // Need to make sure that the transaction nonce is right and bump it if so. Lib_SafeExecutionManagerWrapper.safeREQUIRE( - Lib_ECDSAUtils.recover( - _transaction, - isEthSign, - _v, - _r, - _s - ) == Lib_SafeExecutionManagerWrapper.safeADDRESS(), + decodedTx.sender() == Lib_SafeExecutionManagerWrapper.safeADDRESS(), "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(), - "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(), @@ -98,7 +89,8 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { // "Gas is not sufficient to execute the transaction." // ); - // Transfer fee to relayer. + // Transfer fee to relayer. We assume that whoever called this function is the relayer, + // hence the usage of CALLER. Fee is computed as gasLimit * gasPrice. address relayer = Lib_SafeExecutionManagerWrapper.safeCALLER(); uint256 fee = Lib_SafeMathWrapper.mul(decodedTx.gasLimit, decodedTx.gasPrice); Lib_SafeExecutionManagerWrapper.safeREQUIRE( 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 0f376f821fee..16127eb28ea1 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol @@ -3,8 +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"; /** 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 bba7dd59c90f..0d4194c49290 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol @@ -2,9 +2,7 @@ pragma solidity >0.5.0 <0.8.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_EIP155Tx } from "../../libraries/codec/Lib_EIP155Tx.sol"; import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol"; /** @@ -19,15 +17,7 @@ import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_Sa * Runtime target: OVM */ contract OVM_SequencerEntrypoint { - - /********* - * Enums * - *********/ - - enum TransactionType { - NATIVE_ETH_TRANSACTION, - ETH_SIGNED_MESSAGE - } + using Lib_EIP155Tx for Lib_EIP155Tx.EIP155Tx; /********************* @@ -35,93 +25,47 @@ contract OVM_SequencerEntrypoint { *********************/ /** - * Uses a custom "compressed" format to save on calldata gas: - * calldata[00:01]: transaction type (0 == EIP 155, 2 == Eth Sign Message) - * calldata[01:33]: signature "r" parameter - * calldata[33:65]: signature "s" parameter - * calldata[65:66]: signature "v" parameter - * calldata[66:69]: transaction gas limit - * calldata[69:72]: transaction gas price - * calldata[72:75]: transaction nonce - * calldata[75:95]: transaction target address - * calldata[95:XX]: transaction data + * Expects an RLP-encoded EIP155 transaction as input. See the EIP for a more detailed + * description of this transaction format: + * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md */ fallback() external { - TransactionType transactionType = _getTransactionType(Lib_BytesUtils.toUint8(msg.data, 0)); - - bytes32 r = Lib_BytesUtils.toBytes32(Lib_BytesUtils.slice(msg.data, 1, 32)); - bytes32 s = Lib_BytesUtils.toBytes32(Lib_BytesUtils.slice(msg.data, 33, 32)); - uint8 v = Lib_BytesUtils.toUint8(msg.data, 65); - - // Remainder is the transaction to execute. - bytes memory compressedTx = Lib_BytesUtils.slice(msg.data, 66); - bool isEthSignedMessage = transactionType == TransactionType.ETH_SIGNED_MESSAGE; - - // Need to decompress and then re-encode the transaction based on the original encoding. - bytes memory encodedTx = Lib_OVMCodec.encodeEIP155Transaction( - Lib_OVMCodec.decompressEIP155Transaction(compressedTx), - isEthSignedMessage + Lib_EIP155Tx.EIP155Tx memory transaction = Lib_EIP155Tx.decode( + msg.data, + Lib_SafeExecutionManagerWrapper.safeCHAINID() ); - address target = Lib_ECDSAUtils.recover( - encodedTx, - isEthSignedMessage, - uint8(v), - r, - s + // Recovery parameter being something other than 0 or 1 indicates that this transaction was + // signed using the wrong chain ID. We really should have this logic inside of the + Lib_SafeExecutionManagerWrapper.safeREQUIRE( + transaction.recoveryParam < 2, + "OVM_SequencerEntrypoint: Transaction was signed with the wrong chain ID." ); - if (Lib_SafeExecutionManagerWrapper.safeEXTCODESIZE(target) == 0) { - // ProxyEOA has not yet been deployed for this EOA. - bytes32 messageHash = Lib_ECDSAUtils.getMessageHash(encodedTx, isEthSignedMessage); - Lib_SafeExecutionManagerWrapper.safeCREATEEOA(messageHash, uint8(v), r, s); - } + // Cache this result since we use it twice. Maybe we could move this caching into + // Lib_EIP155Tx but I'd rather not make optimizations like that right now. + address sender = transaction.sender(); - // ProxyEOA has been deployed for this EOA, continue to CALL. - bytes memory callbytes = abi.encodeWithSignature( - "execute(bytes,uint8,uint8,bytes32,bytes32)", - encodedTx, - isEthSignedMessage, - uint8(v), - r, - s - ); + // Create an EOA contract for this account if it doesn't already exist. + if (Lib_SafeExecutionManagerWrapper.safeEXTCODESIZE(sender) == 0) { + Lib_SafeExecutionManagerWrapper.safeCREATEEOA( + transaction.hash(), + transaction.recoveryParam, + transaction.r, + transaction.s + ); + } + // Now call into the EOA contract (which should definitely exist). Lib_SafeExecutionManagerWrapper.safeCALL( gasleft(), - target, - callbytes + sender, + abi.encodeWithSignature( + "execute(bytes)", + msg.data + ) ); } - - - /********************** - * Internal Functions * - **********************/ - - /** - * Converts a uint256 into a TransactionType enum. - * @param _transactionType Transaction type index. - * @return _txType Transaction type enum value. - */ - function _getTransactionType( - uint8 _transactionType - ) - internal - returns ( - TransactionType _txType - ) - { - if (_transactionType == 0) { - return TransactionType.NATIVE_ETH_TRANSACTION; - } if (_transactionType == 2) { - return TransactionType.ETH_SIGNED_MESSAGE; - } else { - Lib_SafeExecutionManagerWrapper.safeREVERT( - "Transaction type must be 0 or 2" - ); - } - } } diff --git a/packages/contracts/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol b/packages/contracts/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol index 16c956580f85..7f3fb0f82b52 100644 --- a/packages/contracts/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol +++ b/packages/contracts/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol @@ -2,9 +2,6 @@ pragma solidity >0.5.0 <0.8.0; pragma experimental ABIEncoderV2; -/* Library Imports */ -import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; - /** * @title iOVM_ECDSAContractAccount */ @@ -15,10 +12,11 @@ interface iOVM_ECDSAContractAccount { ********************/ function execute( - bytes memory _transaction, - Lib_OVMCodec.EOASignatureType _signatureType, - uint8 _v, - bytes32 _r, - bytes32 _s - ) external returns (bool _success, bytes memory _returndata); + bytes memory _encodedTransaction + ) + external + returns ( + bool, + bytes memory + ); } diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol new file mode 100644 index 000000000000..8fa76433247b --- /dev/null +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.5.0 <0.8.0; +pragma experimental ABIEncoderV2; + +/* Library Imports */ +import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol"; +import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol"; + +/** + * @title Lib_EIP155Tx + * @dev A simple library for dealing with the transaction type defined by EIP155: + * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md + */ +library Lib_EIP155Tx { + + /*********** + * Structs * + ***********/ + + // Struct representing an EIP155 transaction. See EIP link above for more information. + struct EIP155Tx { + // These fields correspond to the actual RLP-encoded fields specified by EIP155. + uint256 nonce; + uint256 gasPrice; + uint256 gasLimit; + address to; + uint256 value; + bytes data; + uint8 v; + bytes32 r; + bytes32 s; + + // Chain ID to associate this transaction with. Used all over the place, seemed easier to + // set this once when we create the transaction rather than providing it as an input to + // each function. I don't see a strong need to have a transaction with a mutable chain ID. + uint256 chainId; + + // The ECDSA "recovery parameter," should always be 0 or 1. EIP155 specifies that: + // `v = {0,1} + CHAIN_ID * 2 + 35` + // Where `{0,1}` is a stand in for our `recovery_parameter`. Now computing our formula for + // the recovery parameter: + // 1. `v = {0,1} + CHAIN_ID * 2 + 35` + // 2. `v = recovery_parameter + CHAIN_ID * 2 + 35` + // 3. `v - CHAIN_ID * 2 - 35 = recovery_parameter` + // So we're left with the final formula: + // `recovery_parameter = v - CHAIN_ID * 2 - 35` + // NOTE: This variable is a uint8 because `v` is inherently limited to a uint8. If we + // didn't use a uint8, then recovery_parameter would always be a negative number for chain + // IDs greater than 110 (`255 - 110 * 2 - 35 = 0`). So we need to wrap around to support + // anything larger. + uint8 recoveryParam; + + // Whether or not the transaction is a creation. Necessary because we can't make an address + // "nil". Using the zero address creates a potential conflict if the user did actually + // intend to send a transaction to the zero address. + bool isCreate; + } + + // Lets us use nicer syntax. + using Lib_EIP155Tx for EIP155Tx; + + + /********************** + * Internal Functions * + **********************/ + + /** + * Decodes an EIP155 transaction and attaches a given Chain ID. + * Transaction *must* be RLP-encoded. + * @param _encoded RLP-encoded EIP155 transaction. + * @param _chainId Chain ID to assocaite with this transaction. + * @return Parsed transaction. + */ + function decode( + bytes memory _encoded, + uint256 _chainId + ) + internal + pure + returns ( + EIP155Tx memory + ) + { + Lib_RLPReader.RLPItem[] memory decoded = Lib_RLPReader.readList(_encoded); + + // Note formula above about how recoveryParam is computed. + uint8 v = uint8(Lib_RLPReader.readUint256(decoded[6])); + uint8 recoveryParam = uint8(v - 2 * _chainId - 35); + + // Creations can be detected by looking at the byte length here. + bool isCreate = Lib_RLPReader.readBytes(decoded[3]).length == 0; + + return EIP155Tx({ + nonce: Lib_RLPReader.readUint256(decoded[0]), + gasPrice: Lib_RLPReader.readUint256(decoded[1]), + gasLimit: Lib_RLPReader.readUint256(decoded[2]), + to: Lib_RLPReader.readAddress(decoded[3]), + value: Lib_RLPReader.readUint256(decoded[4]), + data: Lib_RLPReader.readBytes(decoded[5]), + v: v, + r: Lib_RLPReader.readBytes32(decoded[7]), + s: Lib_RLPReader.readBytes32(decoded[8]), + chainId: _chainId, + recoveryParam: recoveryParam, + isCreate: isCreate + }); + } + + /** + * Encodes an EIP155 transaction into RLP. + * @param _transaction EIP155 transaction to encode. + * @param _includeSignature Whether or not to encode the signature. + * @return RLP-encoded transaction. + */ + function encode( + EIP155Tx memory _transaction, + bool _includeSignature + ) + internal + pure + returns ( + bytes memory + ) + { + bytes[] memory raw = new bytes[](9); + + raw[0] = Lib_RLPWriter.writeUint(_transaction.nonce); + raw[1] = Lib_RLPWriter.writeUint(_transaction.gasPrice); + raw[2] = Lib_RLPWriter.writeUint(_transaction.gasLimit); + + // We write the encoding of empty bytes when the transaction is a creation, *not* the zero + // address as one might assume. + if (_transaction.isCreate) { + raw[3] = Lib_RLPWriter.writeBytes(''); + } else { + raw[3] = Lib_RLPWriter.writeAddress(_transaction.to); + } + + raw[4] = Lib_RLPWriter.writeUint(_transaction.value); + raw[5] = Lib_RLPWriter.writeBytes(_transaction.data); + + if (_includeSignature) { + raw[6] = Lib_RLPWriter.writeUint(_transaction.v); + raw[7] = Lib_RLPWriter.writeBytes32(_transaction.r); + raw[8] = Lib_RLPWriter.writeBytes32(_transaction.s); + } else { + // Chain ID *is* included in the unsigned transaction. + raw[6] = Lib_RLPWriter.writeUint(_transaction.chainId); + raw[7] = Lib_RLPWriter.writeBytes(''); + raw[8] = Lib_RLPWriter.writeBytes(''); + } + + return Lib_RLPWriter.writeList(raw); + } + + /** + * Computes the hash of an EIP155 transaction. Assumes that you don't want to include the + * signature in this hash because that's a very uncommon usecase. If you really want to include + * the signature, just encode with the signature and take the hash yourself. + */ + function hash( + EIP155Tx memory _transaction + ) + internal + pure + returns ( + bytes32 + ) + { + return keccak256( + _transaction.encode(false) + ); + } + + /** + * Computes the sender of an EIP155 transaction. + * @param _transaction EIP155 transaction to get a sender for. + * @return Address corresponding to the private key that signed this transaction. + */ + function sender( + EIP155Tx memory _transaction + ) + internal + pure + returns ( + address + ) + { + return ecrecover( + _transaction.hash(), + _transaction.recoveryParam + 27, + _transaction.r, + _transaction.s + ); + } +} 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 4c3c94a7424b..341db0b24381 100644 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol @@ -18,11 +18,6 @@ library Lib_OVMCodec { * Enums * *********/ - enum EOASignatureType { - EIP155_TRANSACTION, - ETH_SIGNED_MESSAGE - } - enum QueueOrigin { SEQUENCER_QUEUE, L1TOL2_QUEUE @@ -86,142 +81,10 @@ library Lib_OVMCodec { uint40 blockNumber; } - struct EIP155Transaction { - uint256 nonce; - uint256 gasPrice; - uint256 gasLimit; - address to; - uint256 value; - bytes data; - uint256 chainId; - } - - /********************** * Internal Functions * **********************/ - /** - * Decodes an EOA transaction (i.e., native Ethereum RLP encoding). - * @param _transaction Encoded EOA transaction. - * @return Transaction decoded into a struct. - */ - function decodeEIP155Transaction( - bytes memory _transaction, - bool _isEthSignedMessage - ) - internal - pure - returns ( - EIP155Transaction memory - ) - { - if (_isEthSignedMessage) { - ( - uint256 _nonce, - uint256 _gasLimit, - uint256 _gasPrice, - uint256 _chainId, - address _to, - bytes memory _data - ) = abi.decode( - _transaction, - (uint256, uint256, uint256, uint256, address ,bytes) - ); - return EIP155Transaction({ - nonce: _nonce, - gasPrice: _gasPrice, - gasLimit: _gasLimit, - to: _to, - value: 0, - data: _data, - chainId: _chainId - }); - } else { - Lib_RLPReader.RLPItem[] memory decoded = Lib_RLPReader.readList(_transaction); - - return EIP155Transaction({ - nonce: Lib_RLPReader.readUint256(decoded[0]), - gasPrice: Lib_RLPReader.readUint256(decoded[1]), - gasLimit: Lib_RLPReader.readUint256(decoded[2]), - to: Lib_RLPReader.readAddress(decoded[3]), - value: Lib_RLPReader.readUint256(decoded[4]), - data: Lib_RLPReader.readBytes(decoded[5]), - chainId: Lib_RLPReader.readUint256(decoded[6]) - }); - } - } - - /** - * Decompresses a compressed EIP155 transaction. - * @param _transaction Compressed EIP155 transaction bytes. - * @return Transaction parsed into a struct. - */ - function decompressEIP155Transaction( - bytes memory _transaction - ) - internal - returns ( - EIP155Transaction memory - ) - { - return EIP155Transaction({ - gasLimit: Lib_BytesUtils.toUint24(_transaction, 0), - gasPrice: uint256(Lib_BytesUtils.toUint24(_transaction, 3)) * 1000000, - nonce: Lib_BytesUtils.toUint24(_transaction, 6), - to: Lib_BytesUtils.toAddress(_transaction, 9), - data: Lib_BytesUtils.slice(_transaction, 29), - chainId: Lib_SafeExecutionManagerWrapper.safeCHAINID(), - value: 0 - }); - } - - /** - * Encodes an EOA transaction back into the original transaction. - * @param _transaction EIP155transaction to encode. - * @param _isEthSignedMessage Whether or not this was an eth signed message. - * @return Encoded transaction. - */ - function encodeEIP155Transaction( - EIP155Transaction memory _transaction, - bool _isEthSignedMessage - ) - internal - pure - returns ( - bytes memory - ) - { - if (_isEthSignedMessage) { - return abi.encode( - _transaction.nonce, - _transaction.gasLimit, - _transaction.gasPrice, - _transaction.chainId, - _transaction.to, - _transaction.data - ); - } else { - bytes[] memory raw = new bytes[](9); - - raw[0] = Lib_RLPWriter.writeUint(_transaction.nonce); - raw[1] = Lib_RLPWriter.writeUint(_transaction.gasPrice); - raw[2] = Lib_RLPWriter.writeUint(_transaction.gasLimit); - if (_transaction.to == address(0)) { - raw[3] = Lib_RLPWriter.writeBytes(''); - } else { - raw[3] = Lib_RLPWriter.writeAddress(_transaction.to); - } - raw[4] = Lib_RLPWriter.writeUint(0); - raw[5] = Lib_RLPWriter.writeBytes(_transaction.data); - raw[6] = Lib_RLPWriter.writeUint(_transaction.chainId); - raw[7] = Lib_RLPWriter.writeBytes(bytes('')); - raw[8] = Lib_RLPWriter.writeBytes(bytes('')); - - return Lib_RLPWriter.writeList(raw); - } - } - /** * Encodes a standard OVM transaction. * @param _transaction OVM transaction to encode. diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol index 8040eac0a2fa..4b9c5247bec4 100644 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol @@ -92,6 +92,23 @@ library Lib_RLPWriter { return writeBytes(abi.encodePacked(_in)); } + /** + * RLP encodes a bytes32 value. + * @param _in The bytes32 to encode. + * @return _out The RLP encoded bytes32 in bytes. + */ + function writeBytes32( + bytes32 _in + ) + internal + pure + returns ( + bytes memory _out + ) + { + return writeBytes(abi.encodePacked(_in)); + } + /** * RLP encodes a uint. * @param _in The uint256 to encode. diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol deleted file mode 100644 index 9d973758b920..000000000000 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.8.0; - -/** - * @title Lib_ECDSAUtils - */ -library Lib_ECDSAUtils { - - /************************************** - * Internal Functions: ECDSA Recovery * - **************************************/ - - /** - * Recovers a signed address given a message and signature. - * @param _message Message that was originally signed. - * @param _isEthSignedMessage Whether or not the user used the `Ethereum Signed Message` prefix. - * @param _v Signature `v` parameter. - * @param _r Signature `r` parameter. - * @param _s Signature `s` parameter. - * @return _sender Signer address. - */ - function recover( - bytes memory _message, - bool _isEthSignedMessage, - uint8 _v, - bytes32 _r, - bytes32 _s - ) - internal - pure - returns ( - address _sender - ) - { - bytes32 messageHash = getMessageHash(_message, _isEthSignedMessage); - - return ecrecover( - messageHash, - _v + 27, - _r, - _s - ); - } - - function getMessageHash( - bytes memory _message, - bool _isEthSignedMessage - ) - internal - pure - returns (bytes32) { - if (_isEthSignedMessage) { - return getEthSignedMessageHash(_message); - } - return getNativeMessageHash(_message); - } - - - /************************************* - * Private Functions: ECDSA Recovery * - *************************************/ - - /** - * Gets the native message hash (simple keccak256) for a message. - * @param _message Message to hash. - * @return _messageHash Native message hash. - */ - function getNativeMessageHash( - bytes memory _message - ) - private - pure - returns ( - bytes32 _messageHash - ) - { - return keccak256(_message); - } - - /** - * Gets the hash of a message with the `Ethereum Signed Message` prefix. - * @param _message Message to hash. - * @return _messageHash Prefixed message hash. - */ - function getEthSignedMessageHash( - bytes memory _message - ) - private - pure - returns ( - bytes32 _messageHash - ) - { - 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/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol b/packages/contracts/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol deleted file mode 100644 index 15c51fcf21fb..000000000000 --- 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_EIP155Tx.sol b/packages/contracts/contracts/test-libraries/codec/TestLib_EIP155Tx.sol new file mode 100644 index 000000000000..6019b8695f8c --- /dev/null +++ b/packages/contracts/contracts/test-libraries/codec/TestLib_EIP155Tx.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.5.0 <0.8.0; +pragma experimental ABIEncoderV2; + +/* Library Imports */ +import { Lib_EIP155Tx } from "../../optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol"; + +/** + * @title TestLib_EIP155Tx + */ +contract TestLib_EIP155Tx { + function decode( + bytes memory _encoded, + uint256 _chainId + ) + public + pure + returns ( + Lib_EIP155Tx.EIP155Tx memory + ) + { + return Lib_EIP155Tx.decode( + _encoded, + _chainId + ); + } + + function encode( + Lib_EIP155Tx.EIP155Tx memory _transaction, + bool _includeSignature + ) + public + pure + returns ( + bytes memory + ) + { + return Lib_EIP155Tx.encode( + _transaction, + _includeSignature + ); + } + + function hash( + Lib_EIP155Tx.EIP155Tx memory _transaction + ) + public + pure + returns ( + bytes32 + ) + { + return Lib_EIP155Tx.hash( + _transaction + ); + } + + function sender( + Lib_EIP155Tx.EIP155Tx memory _transaction + ) + public + pure + returns ( + address + ) + { + return Lib_EIP155Tx.sender( + _transaction + ); + } +} diff --git a/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol b/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol index b9046ac8a776..9e96dd0cd800 100644 --- a/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol +++ b/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol @@ -10,19 +10,6 @@ import { Lib_OVMCodec } from "../../optimistic-ethereum/libraries/codec/Lib_OVMC */ contract TestLib_OVMCodec { - function decodeEIP155Transaction( - bytes memory _transaction, - bool _isEthSignedMessage - ) - public - pure - returns ( - Lib_OVMCodec.EIP155Transaction memory _decoded - ) - { - return Lib_OVMCodec.decodeEIP155Transaction(_transaction, _isEthSignedMessage); - } - function encodeTransaction( Lib_OVMCodec.Transaction memory _transaction ) @@ -46,15 +33,4 @@ contract TestLib_OVMCodec { { return Lib_OVMCodec.hashTransaction(_transaction); } - - function decompressEIP155Transaction( - bytes memory _transaction - ) - public - returns ( - Lib_OVMCodec.EIP155Transaction memory _decompressed - ) - { - return Lib_OVMCodec.decompressEIP155Transaction(_transaction); - } } diff --git a/packages/contracts/contracts/test-libraries/utils/TestLib_ECDSAUtils.sol b/packages/contracts/contracts/test-libraries/utils/TestLib_ECDSAUtils.sol deleted file mode 100644 index 4b66bf7f0ec8..000000000000 --- a/packages/contracts/contracts/test-libraries/utils/TestLib_ECDSAUtils.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.8.0; - -/* Library Imports */ -import { Lib_ECDSAUtils } from "../../optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol"; - -/** - * @title TestLib_ECDSAUtils - */ -contract TestLib_ECDSAUtils { - - function recover( - bytes memory _message, - bool _isEthSignedMessage, - uint8 _v, - bytes32 _r, - bytes32 _s - ) - public - pure - returns ( - address _sender - ) - { - return Lib_ECDSAUtils.recover( - _message, - _isEthSignedMessage, - _v, - _r, - _s - ); - } -} diff --git a/packages/contracts/src/contract-deployment/config.ts b/packages/contracts/src/contract-deployment/config.ts index 5ddfc87b88ef..64b662ec17bf 100644 --- a/packages/contracts/src/contract-deployment/config.ts +++ b/packages/contracts/src/contract-deployment/config.ts @@ -225,9 +225,6 @@ export const makeContractDeployConfig = async ( 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/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts b/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts index 9bb7fc5bd165..0189e9c57bc1 100644 --- a/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts +++ b/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts @@ -7,14 +7,7 @@ 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' +import { DEFAULT_EIP155_TX, decodeSolidityError } from '../../../helpers' const callPredeploy = async ( Helper_PredeployCaller: Contract, @@ -41,10 +34,9 @@ const callPredeploy = async ( describe('OVM_ECDSAContractAccount', () => { let wallet: Wallet - let badWallet: Wallet before(async () => { const provider = waffle.provider - ;[wallet, badWallet] = provider.getWallets() + ;[wallet] = provider.getWallets() }) let Mock__OVM_ExecutionManager: MockContract @@ -88,43 +80,14 @@ describe('OVM_ECDSAContractAccount', () => { describe('fallback()', () => { it(`should successfully execute an EIP155Transaction`, async () => { - const message = serializeNativeTransaction(DEFAULT_EIP155_TX) - const sig = await signNativeTransaction(wallet, DEFAULT_EIP155_TX) + const transaction = DEFAULT_EIP155_TX + const encodedTransaction = await wallet.signTransaction(transaction) 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 - ] + [encodedTransaction] ) // The ovmCALL is the 2nd call because the first call transfers the fee. @@ -134,43 +97,33 @@ describe('OVM_ECDSAContractAccount', () => { }) 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) + const transaction = { ...DEFAULT_EIP155_TX, to: '' } + const encodedTransaction = await wallet.signTransaction(transaction) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ] + [encodedTransaction] ) const ovmCREATE: any = Mock__OVM_ExecutionManager.smocked.ovmCREATE.calls[0] - expect(ovmCREATE._bytecode).to.equal(createTx.data) + expect(ovmCREATE._bytecode).to.equal(transaction.data) }) it(`should revert on invalid signature`, async () => { - const message = serializeNativeTransaction(DEFAULT_EIP155_TX) - const sig = await signNativeTransaction(badWallet, DEFAULT_EIP155_TX) + const transaction = DEFAULT_EIP155_TX + const encodedTransaction = ethers.utils.serializeTransaction( + transaction, + '0x' + '00'.repeat(65) + ) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ] + [encodedTransaction] ) const ovmREVERT: any = Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] @@ -180,24 +133,14 @@ describe('OVM_ECDSAContractAccount', () => { }) it(`should revert on incorrect nonce`, async () => { - const alteredNonceTx = { - ...DEFAULT_EIP155_TX, - nonce: 99, - } - const message = serializeNativeTransaction(alteredNonceTx) - const sig = await signNativeTransaction(wallet, alteredNonceTx) + const transaction = { ...DEFAULT_EIP155_TX, nonce: 99 } + const encodedTransaction = await wallet.signTransaction(transaction) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ] + [encodedTransaction] ) const ovmREVERT: any = Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] @@ -207,52 +150,32 @@ describe('OVM_ECDSAContractAccount', () => { }) it(`should revert on incorrect chainId`, async () => { - const alteredChainIdTx = { - ...DEFAULT_EIP155_TX, - chainId: 421, - } - const message = serializeNativeTransaction(alteredChainIdTx) - const sig = await signNativeTransaction(wallet, alteredChainIdTx) + const transaction = { ...DEFAULT_EIP155_TX, chainId: 421 } + const encodedTransaction = await wallet.signTransaction(transaction) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ] + [encodedTransaction] ) const ovmREVERT: any = Mock__OVM_ExecutionManager.smocked.ovmREVERT.calls[0] expect(decodeSolidityError(ovmREVERT._data)).to.equal( - 'Transaction chainId does not match expected OVM chainId.' + 'OVM_ECDSAContractAccount: Transaction was signed with the wrong chain ID.' ) }) // 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) + const transaction = { ...DEFAULT_EIP155_TX, gasLimit: 200000000 } + const encodedTransaction = await wallet.signTransaction(transaction) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [ - message, - 0, //isEthSignedMessage - `0x${sig.v}`, //v - `0x${sig.r}`, //r - `0x${sig.s}`, //s - ], + [encodedTransaction], 40000000 ) @@ -264,21 +187,16 @@ describe('OVM_ECDSAContractAccount', () => { }) 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) + const transaction = DEFAULT_EIP155_TX + const encodedTransaction = await wallet.signTransaction(transaction) + 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 - ], + [encodedTransaction], 40000000 ) diff --git a/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts b/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts index 2979ad3bc33e..81bd75986c94 100644 --- a/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts +++ b/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts @@ -7,14 +7,7 @@ import { smockit, MockContract } from '@eth-optimism/smock' /* Internal Imports */ import { getContractInterface } from '../../../../src' -import { - encodeSequencerCalldata, - signNativeTransaction, - signEthSignMessage, - DEFAULT_EIP155_TX, - serializeNativeTransaction, - serializeEthSignTransaction, -} from '../../../helpers' +import { DEFAULT_EIP155_TX } from '../../../helpers' describe('OVM_SequencerEntrypoint', () => { let wallet: Wallet @@ -55,128 +48,59 @@ describe('OVM_SequencerEntrypoint', () => { }) describe('fallback()', async () => { - it('should call EIP155 if the transaction type is 0', async () => { - const calldata = await encodeSequencerCalldata( - wallet, - DEFAULT_EIP155_TX, - 0 - ) + it('should call EIP155', async () => { + const transaction = DEFAULT_EIP155_TX + const encodedTransaction = await wallet.signTransaction(transaction) + await Helper_PredeployCaller.callPredeploy( OVM_SequencerEntrypoint.address, - calldata + encodedTransaction ) - 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 - ]) + ).encodeFunctionData('execute', [encodedTransaction]) 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) + it('should send correct calldata if tx is a create', async () => { + const transaction = { ...DEFAULT_EIP155_TX, to: '' } + const encodedTransaction = await wallet.signTransaction(transaction) + await Helper_PredeployCaller.callPredeploy( OVM_SequencerEntrypoint.address, - calldata + encodedTransaction ) - 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 - ]) + ).encodeFunctionData('execute', [encodedTransaction]) 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 call ovmCreateEOA when ovmEXTCODESIZE returns 0`, async () => { + Mock__OVM_ExecutionManager.smocked.ovmEXTCODESIZE.will.return.with(0) + + const transaction = DEFAULT_EIP155_TX + const encodedTransaction = await wallet.signTransaction(transaction) - 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 + encodedTransaction ) - 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 - }) + 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, + }) - it('should revert if TransactionType is 1', async () => { - const calldata = '0x01' - await expect( - Helper_PredeployCaller.callPredeploy( - OVM_SequencerEntrypoint.address, - calldata - ) - ).to.be.reverted + expect(eoaAddress).to.equal(await wallet.getAddress()) }) }) }) diff --git a/packages/contracts/test/contracts/libraries/codec/Lib_EIP155Tx.ts b/packages/contracts/test/contracts/libraries/codec/Lib_EIP155Tx.ts new file mode 100644 index 000000000000..021f14edcb19 --- /dev/null +++ b/packages/contracts/test/contracts/libraries/codec/Lib_EIP155Tx.ts @@ -0,0 +1,15 @@ +/* tslint:disable:no-empty */ +import '../../../setup' + +/* Internal Imports */ +import { Lib_EIP155Tx_TEST_JSON } from '../../../data' +import { runJsonTest } from '../../../helpers' + +// Currently running tests from here: +// https://github.com/ethereumjs/ethereumjs-tx/blob/master/test/ttTransactionTestEip155VitaliksTests.json + +describe('Lib_EIP155Tx', () => { + describe('JSON tests', () => { + runJsonTest('TestLib_EIP155Tx', Lib_EIP155Tx_TEST_JSON) + }) +}) diff --git a/packages/contracts/test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts b/packages/contracts/test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts deleted file mode 100644 index baf3c5a999b2..000000000000 --- a/packages/contracts/test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* Internal Imports */ -import { Lib_ECDSAUtils_TEST_JSON } from '../../../data' -import { runJsonTest } from '../../../helpers' - -describe('Lib_ECDSAUtils', () => { - describe('JSON tests', () => { - runJsonTest('TestLib_ECDSAUtils', Lib_ECDSAUtils_TEST_JSON) - }) -}) diff --git a/packages/contracts/test/data/index.ts b/packages/contracts/test/data/index.ts index 8a4a1f7e65b8..5c9103f5c2d5 100644 --- a/packages/contracts/test/data/index.ts +++ b/packages/contracts/test/data/index.ts @@ -2,8 +2,8 @@ export { tests as Lib_RLPWriter_TEST_JSON } from './json/libraries/rlp/Lib_RLPWr export { tests as Lib_RLPReader_TEST_JSON } from './json/libraries/rlp/Lib_RLPReader.test.json' export { tests as Lib_Bytes32Utils_TEST_JSON } from './json/libraries/utils/Lib_Bytes32Utils.test.json' export { tests as Lib_BytesUtils_TEST_JSON } from './json/libraries/utils/Lib_BytesUtils.test.json' -export { tests as Lib_ECDSAUtils_TEST_JSON } from './json/libraries/utils/Lib_ECDSAUtils.test.json' export { tests as Lib_MerkleTrie_TEST_JSON } from './json/libraries/trie/Lib_MerkleTrie.test.json' +export { tests as Lib_EIP155Tx_TEST_JSON } from './json/libraries/codec/Lib_EIP155Tx.test.json' export { tests as Lib_OVMCodec_TEST_JSON } from './json/libraries/codec/Lib_OVMCodec.test.json' export { tests as CREATE2_TEST_JSON } from './json/create2.test.json' export { tests as SAFETY_CHECKER_TEST_JSON } from './json/safety-checker.test.json' diff --git a/packages/contracts/test/data/json/libraries/codec/Lib_EIP155Tx.test.json b/packages/contracts/test/data/json/libraries/codec/Lib_EIP155Tx.test.json new file mode 100644 index 000000000000..a7536ad4fa3b --- /dev/null +++ b/packages/contracts/test/data/json/libraries/codec/Lib_EIP155Tx.test.json @@ -0,0 +1,725 @@ +{ + "tests": { + "decode": { + "vitalik test 0": { + "in": [ + "0xf864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + 1 + ], + "out": [ + [ + "0x00", + "0x04a817c800", + "0x5208", + "0x3535353535353535353535353535353535353535", + "0x00", + "0x", + "0x25", + "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + "0x01", + "0x00", + false + ] + ] + }, + "vitalik test 1": { + "in": [ + "0xf867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", + 1 + ], + "out": [ + [ + "0x08", + "0x04a817c808", + "0x02e248", + "0x3535353535353535353535353535353535353535", + "0x0200", + "0x", + "0x25", + "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12", + "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", + "0x01", + "0x00", + false + ] + ] + }, + "vitalik test 2": { + "in": [ + "0xf867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", + 1 + ], + "out": [ + [ + "0x09", + "0x04a817c809", + "0x033450", + "0x3535353535353535353535353535353535353535", + "0x02d9", + "0x", + "0x25", + "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", + "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", + "0x01", + "0x00", + false + ] + ] + }, + "vitalik test 3": { + "in": [ + "0xf864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", + 1 + ], + "out": [ + [ + "0x01", + "0x04a817c801", + "0xa410", + "0x3535353535353535353535353535353535353535", + "0x01", + "0x", + "0x25", + "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bca", + "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", + "0x01", + "0x00", + false + ] + ] + }, + "vitalik test 4": { + "in": [ + "0xf864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + 1 + ], + "out": [ + [ + "0x02", + "0x04a817c802", + "0xf618", + "0x3535353535353535353535353535353535353535", + "0x08", + "0x", + "0x25", + "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + "0x01", + "0x00", + false + ] + ] + }, + "vitalik test 5": { + "in": [ + "0xf865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", + 1 + ], + "out": [ + [ + "0x03", + "0x04a817c803", + "0x014820", + "0x3535353535353535353535353535353535353535", + "0x1b", + "0x", + "0x25", + "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0", + "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", + "0x01", + "0x00", + false + ] + ] + }, + "vitalik test 6": { + "in": [ + "0xf865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", + 1 + ], + "out": [ + [ + "0x04", + "0x04a817c804", + "0x019a28", + "0x3535353535353535353535353535353535353535", + "0x40", + "0x", + "0x25", + "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063", + "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", + "0x01", + "0x00", + false + ] + ] + }, + "vitalik test 7": { + "in": [ + "0xf865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + 1 + ], + "out": [ + [ + "0x05", + "0x04a817c805", + "0x01ec30", + "0x3535353535353535353535353535353535353535", + "0x7d", + "0x", + "0x25", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x01", + "0x00", + false + ] + ] + }, + "vitalik test 8": { + "in": [ + "0xf865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + 1 + ], + "out": [ + [ + "0x05", + "0x04a817c805", + "0x01ec30", + "0x3535353535353535353535353535353535353535", + "0x7d", + "0x", + "0x25", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x01", + "0x00", + false + ] + ] + }, + "vitalik test 9": { + "in": [ + "0xf866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", + 1 + ], + "out": [ + [ + "0x06", + "0x04a817c806", + "0x023e38", + "0x3535353535353535353535353535353535353535", + "0xd8", + "0x", + "0x25", + "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2f", + "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", + "0x01", + "0x00", + false + ] + ] + }, + "vitalik test 10": { + "in": [ + "0xf867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", + 1 + ], + "out": [ + [ + "0x07", + "0x04a817c807", + "0x029040", + "0x3535353535353535353535353535353535353535", + "0x0157", + "0x", + "0x25", + "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "0x01", + "0x00", + false + ] + ] + } + }, + "encode": { + "vitalik test 0": { + "in": [ + [ + "0x00", + "0x04a817c800", + "0x5208", + "0x3535353535353535353535353535353535353535", + "0x00", + "0x", + "0x25", + "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d" + ] + }, + "vitalik test 1": { + "in": [ + [ + "0x08", + "0x04a817c808", + "0x02e248", + "0x3535353535353535353535353535353535353535", + "0x0200", + "0x", + "0x25", + "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12", + "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10" + ] + }, + "vitalik test 2": { + "in": [ + [ + "0x09", + "0x04a817c809", + "0x033450", + "0x3535353535353535353535353535353535353535", + "0x02d9", + "0x", + "0x25", + "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", + "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb" + ] + }, + "vitalik test 3": { + "in": [ + [ + "0x01", + "0x04a817c801", + "0xa410", + "0x3535353535353535353535353535353535353535", + "0x01", + "0x", + "0x25", + "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bca", + "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6" + ] + }, + "vitalik test 4": { + "in": [ + [ + "0x02", + "0x04a817c802", + "0xf618", + "0x3535353535353535353535353535353535353535", + "0x08", + "0x", + "0x25", + "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5" + ] + }, + "vitalik test 5": { + "in": [ + [ + "0x03", + "0x04a817c803", + "0x014820", + "0x3535353535353535353535353535353535353535", + "0x1b", + "0x", + "0x25", + "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0", + "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de" + ] + }, + "vitalik test 6": { + "in": [ + [ + "0x04", + "0x04a817c804", + "0x019a28", + "0x3535353535353535353535353535353535353535", + "0x40", + "0x", + "0x25", + "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063", + "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060" + ] + }, + "vitalik test 7": { + "in": [ + [ + "0x05", + "0x04a817c805", + "0x01ec30", + "0x3535353535353535353535353535353535353535", + "0x7d", + "0x", + "0x25", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1" + ] + }, + "vitalik test 8": { + "in": [ + [ + "0x05", + "0x04a817c805", + "0x01ec30", + "0x3535353535353535353535353535353535353535", + "0x7d", + "0x", + "0x25", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1" + ] + }, + "vitalik test 9": { + "in": [ + [ + "0x06", + "0x04a817c806", + "0x023e38", + "0x3535353535353535353535353535353535353535", + "0xd8", + "0x", + "0x25", + "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2f", + "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d" + ] + }, + "vitalik test 10": { + "in": [ + [ + "0x07", + "0x04a817c807", + "0x029040", + "0x3535353535353535353535353535353535353535", + "0x0157", + "0x", + "0x25", + "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "0x01", + "0x00", + false + ], + true + ], + "out": [ + "0xf867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021" + ] + } + }, + "sender": { + "vitalik test 0": { + "in": [ + [ + "0x00", + "0x04a817c800", + "0x5208", + "0x3535353535353535353535353535353535353535", + "0x00", + "0x", + "0x25", + "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0xf0f6f18bca1b28cd68e4357452947e021241e9ce" + ] + }, + "vitalik test 1": { + "in": [ + [ + "0x08", + "0x04a817c808", + "0x02e248", + "0x3535353535353535353535353535353535353535", + "0x0200", + "0x", + "0x25", + "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12", + "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0x9bddad43f934d313c2b79ca28a432dd2b7281029" + ] + }, + "vitalik test 2": { + "in": [ + [ + "0x09", + "0x04a817c809", + "0x033450", + "0x3535353535353535353535353535353535353535", + "0x02d9", + "0x", + "0x25", + "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", + "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f" + ] + }, + "vitalik test 3": { + "in": [ + [ + "0x01", + "0x04a817c801", + "0xa410", + "0x3535353535353535353535353535353535353535", + "0x01", + "0x", + "0x25", + "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bca", + "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112" + ] + }, + "vitalik test 4": { + "in": [ + [ + "0x02", + "0x04a817c802", + "0xf618", + "0x3535353535353535353535353535353535353535", + "0x08", + "0x", + "0x25", + "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be" + ] + }, + "vitalik test 5": { + "in": [ + [ + "0x03", + "0x04a817c803", + "0x014820", + "0x3535353535353535353535353535353535353535", + "0x1b", + "0x", + "0x25", + "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0", + "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0x82a88539669a3fd524d669e858935de5e5410cf0" + ] + }, + "vitalik test 6": { + "in": [ + [ + "0x04", + "0x04a817c804", + "0x019a28", + "0x3535353535353535353535353535353535353535", + "0x40", + "0x", + "0x25", + "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063", + "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0xf9358f2538fd5ccfeb848b64a96b743fcc930554" + ] + }, + "vitalik test 7": { + "in": [ + [ + "0x05", + "0x04a817c805", + "0x01ec30", + "0x3535353535353535353535353535353535353535", + "0x7d", + "0x", + "0x25", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0xa8f7aba377317440bc5b26198a363ad22af1f3a4" + ] + }, + "vitalik test 8": { + "in": [ + [ + "0x05", + "0x04a817c805", + "0x01ec30", + "0x3535353535353535353535353535353535353535", + "0x7d", + "0x", + "0x25", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0xa8f7aba377317440bc5b26198a363ad22af1f3a4" + ] + }, + "vitalik test 9": { + "in": [ + [ + "0x06", + "0x04a817c806", + "0x023e38", + "0x3535353535353535353535353535353535353535", + "0xd8", + "0x", + "0x25", + "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2f", + "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35" + ] + }, + "vitalik test 10": { + "in": [ + [ + "0x07", + "0x04a817c807", + "0x029040", + "0x3535353535353535353535353535353535353535", + "0x0157", + "0x", + "0x25", + "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "0x01", + "0x00", + false + ] + ], + "out": [ + "0xd37922162ab7cea97c97a87551ed02c9a38b7332" + ] + } + } + } +} 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 b442f4e07c8c..a55ce0122c21 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 @@ -1,22 +1,4 @@ { "tests": { - "decompressEIP155Transaction": { - "decompression": { - "in": [ - "0x0001f4000064000064121212121212121212121212121212121212121299999999999999999999" - ], - "out": [ - [ - 100, - 100000000, - 500, - "0x1212121212121212121212121212121212121212", - 0, - "0x99999999999999999999", - 420 - ] - ] - } - } } } diff --git a/packages/contracts/test/data/json/libraries/utils/Lib_ECDSAUtils.test.json b/packages/contracts/test/data/json/libraries/utils/Lib_ECDSAUtils.test.json deleted file mode 100644 index 40f15819442f..000000000000 --- a/packages/contracts/test/data/json/libraries/utils/Lib_ECDSAUtils.test.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "tests": { - "recover": { - "standard hash, valid signature": { - "in": [ - "0xf83d80808094121212121212121212121212121212121212121280a0bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a6c8080", - false, - "0x01", - "0x057bf1c0edf0a9002a79f8c9b39683f6453a18e73e02364270a2b6ee8117f11a", - "0x5f8181365a222c7b05a84c29a29754e6a925952d3bf4bd65a6259ef37ee048e3" - ], - "out": [ - "0x17ec8597ff92C3F44523bDc65BF0f1bE632917ff" - ] - }, - "standard hash, invalid v parameter": { - "in": [ - "0xf83d80808094121212121212121212121212121212121212121280a0bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a6c8080", - false, - "0xfc", - "0x057bf1c0edf0a9002a79f8c9b39683f6453a18e73e02364270a2b6ee8117f11a", - "0x5f8181365a222c7b05a84c29a29754e6a925952d3bf4bd65a6259ef37ee048e3" - ], - "out": [ - "0x0000000000000000000000000000000000000000" - ] - }, - "standard hash, invalid r parameter": { - "in": [ - "0xf83d80808094121212121212121212121212121212121212121280a0bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a6c8080", - false, - "0x01", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x5f8181365a222c7b05a84c29a29754e6a925952d3bf4bd65a6259ef37ee048e3" - ], - "out": [ - "0x0000000000000000000000000000000000000000" - ] - }, - "standard hash, invalid s parameter": { - "in": [ - "0xf83d80808094121212121212121212121212121212121212121280a0bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a6c8080", - false, - "0x01", - "0x057bf1c0edf0a9002a79f8c9b39683f6453a18e73e02364270a2b6ee8117f11a", - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "out": [ - "0x0000000000000000000000000000000000000000" - ] - }, - "standard hash, invalid message": { - "in": [ - "0x0000000000000000000000000000000000000000000000000000000000000000", - false, - "0x01", - "0x057bf1c0edf0a9002a79f8c9b39683f6453a18e73e02364270a2b6ee8117f11a", - "0x5f8181365a222c7b05a84c29a29754e6a925952d3bf4bd65a6259ef37ee048e3" - ], - "out": [ - "0x1397890fcfC2D7563Aa01cE93A217b9809D3447B" - ] - }, - "eth signed message hash, valid signature": { - "in": [ - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000121212121212121212121212121212121212121200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000020bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a", - true, - "0x01", - "0xe5a2edb71b6d76a8aacd59467d3063fd455ca13a4e9cb57da6f25849d40e4e2a", - "0x5465373d68d521845e3ffd2baf4c51f3d21c990914c09490b32ffc0b322dbf98" - ], - "out": [ - "0x17ec8597ff92C3F44523bDc65BF0f1bE632917ff" - ] - }, - "eth signed message hash, invalid v parameter": { - "in": [ - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000121212121212121212121212121212121212121200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000020bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a", - true, - "0x1c", - "0xe5a2edb71b6d76a8aacd59467d3063fd455ca13a4e9cb57da6f25849d40e4e2a", - "0x5465373d68d521845e3ffd2baf4c51f3d21c990914c09490b32ffc0b322dbf98" - ], - "out": [ - "0x0000000000000000000000000000000000000000" - ] - }, - "eth signed message hash, invalid r parameter": { - "in": [ - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000121212121212121212121212121212121212121200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000020bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a", - true, - "0x01", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x5465373d68d521845e3ffd2baf4c51f3d21c990914c09490b32ffc0b322dbf98" - ], - "out": [ - "0x0000000000000000000000000000000000000000" - ] - }, - "eth signed message hash, invalid s parameter": { - "in": [ - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000121212121212121212121212121212121212121200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000020bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a", - true, - "0x01", - "0xe5a2edb71b6d76a8aacd59467d3063fd455ca13a4e9cb57da6f25849d40e4e2a", - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "out": [ - "0x0000000000000000000000000000000000000000" - ] - }, - "eth signed message hash, invalid message": { - "in": [ - "0x0000000000000000000000000000000000000000000000000000000000000000", - true, - "0x01", - "0xe5a2edb71b6d76a8aacd59467d3063fd455ca13a4e9cb57da6f25849d40e4e2a", - "0x5465373d68d521845e3ffd2baf4c51f3d21c990914c09490b32ffc0b322dbf98" - ], - "out": [ - "0xf8bd1421f9D28C8F58f33B25a6faB16F3f89b749" - ] - } - } - } -} diff --git a/packages/contracts/test/helpers/codec/encoding.ts b/packages/contracts/test/helpers/codec/encoding.ts index f7e16531fcd6..869e4feffca0 100644 --- a/packages/contracts/test/helpers/codec/encoding.ts +++ b/packages/contracts/test/helpers/codec/encoding.ts @@ -1,9 +1,5 @@ /* External Imports */ import { ethers } from 'hardhat' -import { constants, Wallet } from 'ethers' - -/* Internal Imports */ -import { remove0x, fromHexString } from '@eth-optimism/core-utils' export interface EIP155Transaction { nonce: number @@ -37,115 +33,3 @@ export const getRawSignedComponents = (signed: string): any[] => { export const getSignedComponents = (signed: string): any[] => { return ethers.utils.RLP.decode(signed).slice(-3) } - -export const encodeCompactTransaction = (transaction: any): string => { - const nonce = ethers.utils.zeroPad(transaction.nonce, 3) - const gasLimit = ethers.utils.zeroPad(transaction.gasLimit, 3) - if (transaction.gasPrice % 1000000 !== 0) - throw Error('gas price must be a multiple of 1000000') - const compressedGasPrice: any = transaction.gasPrice / 1000000 - const gasPrice = ethers.utils.zeroPad(compressedGasPrice, 3) - const to = !transaction.to.length - ? fromHexString(constants.AddressZero) - : fromHexString(transaction.to) - const data = fromHexString(transaction.data) - - return Buffer.concat([ - Buffer.from(gasLimit), - Buffer.from(gasPrice), - Buffer.from(nonce), - Buffer.from(to), - data, - ]).toString('hex') -} - -export const serializeEthSignTransaction = ( - transaction: EIP155Transaction -): string => { - return ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256', 'uint256', 'uint256', 'address', 'bytes'], - [ - transaction.nonce, - transaction.gasLimit, - transaction.gasPrice, - transaction.chainId, - transaction.to, - transaction.data, - ] - ) -} - -export const serializeNativeTransaction = ( - transaction: EIP155Transaction -): string => { - return ethers.utils.serializeTransaction(transaction) -} - -export const signEthSignMessage = async ( - wallet: Wallet, - transaction: EIP155Transaction -): Promise => { - const serializedTransaction = serializeEthSignTransaction(transaction) - const transactionHash = ethers.utils.keccak256(serializedTransaction) - const transactionHashBytes = ethers.utils.arrayify(transactionHash) - const transactionSignature = await wallet.signMessage(transactionHashBytes) - - const messageHash = ethers.utils.hashMessage(transactionHashBytes) - const [v, r, s] = getRawSignedComponents(transactionSignature).map( - (component) => { - return remove0x(component) - } - ) - return { - messageHash, - v: '0' + (parseInt(v, 16) - 27), - r, - s, - } -} - -export const signNativeTransaction = async ( - wallet: Wallet, - transaction: EIP155Transaction -): Promise => { - const serializedTransaction = serializeNativeTransaction(transaction) - const transactionSignature = await wallet.signTransaction(transaction) - - const messageHash = ethers.utils.keccak256(serializedTransaction) - const [v, r, s] = getSignedComponents(transactionSignature).map( - (component) => { - return remove0x(component) - } - ) - return { - messageHash, - v: '0' + (parseInt(v, 16) - transaction.chainId * 2 - 8 - 27), - r, - s, - } -} - -export const signTransaction = async ( - wallet: Wallet, - transaction: EIP155Transaction, - transactionType: number -): Promise => { - return transactionType === 2 - ? signEthSignMessage(wallet, transaction) //ETH Signed tx - : signNativeTransaction(wallet, transaction) //Create EOA tx or EIP155 tx -} - -export const encodeSequencerCalldata = async ( - wallet: Wallet, - transaction: EIP155Transaction, - transactionType: number -) => { - const sig = await signTransaction(wallet, transaction, transactionType) - const encodedTransaction = encodeCompactTransaction(transaction) - const dataPrefix = `0x0${transactionType}${sig.r}${sig.s}${sig.v}` - const calldata = - transactionType === 1 - ? `${dataPrefix}${remove0x(sig.messageHash)}` // Create EOA tx - : `${dataPrefix}${encodedTransaction}` // EIP155 tx or ETH Signed Tx - return calldata -} diff --git a/packages/contracts/test/helpers/test-runner/json-test-runner.ts b/packages/contracts/test/helpers/test-runner/json-test-runner.ts index 0380ee849f06..d32626835f5f 100644 --- a/packages/contracts/test/helpers/test-runner/json-test-runner.ts +++ b/packages/contracts/test/helpers/test-runner/json-test-runner.ts @@ -4,10 +4,16 @@ import { expect } from '../../setup' import { ethers } from 'hardhat' import { Contract, BigNumber } from 'ethers' -const bigNumberify = (arr) => { +const bnRegex = /^\d+n$/gm + +const bigNumberify = (arr: any[]) => { return arr.map((el: any) => { if (typeof el === 'number') { return BigNumber.from(el) + } else if (typeof el === 'string' && bnRegex.test(el)) { + return BigNumber.from(el.slice(0, el.length - 1)) + } else if (typeof el === 'string' && el.length > 2 && el.startsWith('0x')) { + return BigNumber.from(el.toLowerCase()) } else if (Array.isArray(el)) { return bigNumberify(el) } else { @@ -31,7 +37,7 @@ export const runJsonTest = (contractName: string, json: any): void => { .reverted } else { expect( - await contract.functions[functionName](...test.in) + bigNumberify(await contract.functions[functionName](...test.in)) ).to.deep.equal(bigNumberify(test.out)) } }) From d071f0f415c9e2aafe8abe13b8bfa00a8e5ad57e Mon Sep 17 00:00:00 2001 From: Maurelian Date: Thu, 15 Apr 2021 19:29:30 -0400 Subject: [PATCH 4/7] fix hardcoded test val --- .../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 821ee3fd9b82..0b60db0926ca 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: 4185958, }, }, }, From 1e3276d2134807793777ad2f947a90449f8fb3e2 Mon Sep 17 00:00:00 2001 From: Maurelian Date: Thu, 15 Apr 2021 19:39:01 -0400 Subject: [PATCH 5/7] chore: add changeset --- .changeset/ten-baboons-compete.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/ten-baboons-compete.md diff --git a/.changeset/ten-baboons-compete.md b/.changeset/ten-baboons-compete.md new file mode 100644 index 000000000000..c7acd3945d47 --- /dev/null +++ b/.changeset/ten-baboons-compete.md @@ -0,0 +1,8 @@ +--- +"@eth-optimism/contracts": minor +--- + +- Remove ETH_SIGNED_MESSAGE and standardize on EIP-155 messages +- Reduce nonce size to uint64 +- Ban ovmCALLER opcode when it would return ZERO +- Add value transfer in OVM_ECDSAContractAccount From 3855dcd3a9ed790b33b1edca3d5d33ebf5a220b6 Mon Sep 17 00:00:00 2001 From: Maurelian Date: Thu, 15 Apr 2021 22:02:19 -0400 Subject: [PATCH 6/7] Revert "Merge branch 'master' into feat/standard-rlp-transaction" This reverts commit af9f9a65a452755f64cd33999426c8238ed081c7. --- .../OVM/accounts/OVM_ECDSAContractAccount.sol | 52 +- .../OVM/accounts/OVM_ProxyEOA.sol | 2 + .../predeploys/OVM_SequencerEntrypoint.sol | 118 ++- .../accounts/iOVM_ECDSAContractAccount.sol | 16 +- .../libraries/codec/Lib_EIP155Tx.sol | 196 ----- .../libraries/codec/Lib_OVMCodec.sol | 137 ++++ .../libraries/rlp/Lib_RLPWriter.sol | 17 - .../libraries/utils/Lib_ECDSAUtils.sol | 98 +++ .../accounts/mockOVM_ECDSAContractAccount.sol | 95 +++ .../test-libraries/codec/TestLib_EIP155Tx.sol | 71 -- .../test-libraries/codec/TestLib_OVMCodec.sol | 24 + .../utils/TestLib_ECDSAUtils.sol | 33 + .../src/contract-deployment/config.ts | 3 + .../accounts/OVM_ECDSAContractAccount.spec.ts | 140 +++- .../OVM_SequencerEntrypoint.spec.ts | 128 +++- .../contracts/libraries/codec/Lib_EIP155Tx.ts | 15 - .../libraries/utils/Lib_ECDSAUtils.spec.ts | 9 + packages/contracts/test/data/index.ts | 2 +- .../libraries/codec/Lib_EIP155Tx.test.json | 725 ------------------ .../libraries/codec/Lib_OVMCodec.test.json | 18 + .../libraries/utils/Lib_ECDSAUtils.test.json | 126 +++ .../contracts/test/helpers/codec/encoding.ts | 116 +++ .../helpers/test-runner/json-test-runner.ts | 10 +- 23 files changed, 1003 insertions(+), 1148 deletions(-) delete mode 100644 packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol create mode 100644 packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol create mode 100644 packages/contracts/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol delete mode 100644 packages/contracts/contracts/test-libraries/codec/TestLib_EIP155Tx.sol create mode 100644 packages/contracts/contracts/test-libraries/utils/TestLib_ECDSAUtils.sol delete mode 100644 packages/contracts/test/contracts/libraries/codec/Lib_EIP155Tx.ts create mode 100644 packages/contracts/test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts delete mode 100644 packages/contracts/test/data/json/libraries/codec/Lib_EIP155Tx.test.json create mode 100644 packages/contracts/test/data/json/libraries/utils/Lib_ECDSAUtils.test.json 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 10c0aa57e76f..1e13cc04b23b 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol @@ -6,22 +6,21 @@ pragma experimental ABIEncoderV2; import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContractAccount.sol"; /* Library Imports */ -import { Lib_EIP155Tx } from "../../libraries/codec/Lib_EIP155Tx.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_SafeMathWrapper } from "../../libraries/wrappers/Lib_SafeMathWrapper.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 + * ovmCREATEEOA operation. It enables backwards compatibility with Ethereum's Layer 1, by * providing eth_sign and EIP155 formatted transaction encodings. * * Compiler used: solc * Runtime target: OVM */ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { - using Lib_EIP155Tx for Lib_EIP155Tx.EIP155Tx; - /************* * Constants * @@ -39,12 +38,20 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { /** * Executes a signed transaction. - * @param _encodedTransaction Signed EIP155 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 Whether or not the call returned (rather than reverted). * @return Data returned by the call. */ function execute( - bytes memory _encodedTransaction + bytes memory _transaction, + Lib_OVMCodec.EOASignatureType _signatureType, + uint8 _v, + bytes32 _r, + bytes32 _s ) override public @@ -53,29 +60,31 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { bytes memory ) { - Lib_EIP155Tx.EIP155Tx memory decodedTx = Lib_EIP155Tx.decode( - _encodedTransaction, - Lib_SafeExecutionManagerWrapper.safeCHAINID() - ); - - // Recovery parameter being something other than 0 or 1 indicates that this transaction was - // signed using the wrong chain ID. We really should have this logic inside of Lib_EIP155Tx - // but I'd prefer not to add the "safeREQUIRE" logic into that library. So it'll live here - // for now. - Lib_SafeExecutionManagerWrapper.safeREQUIRE( - decodedTx.recoveryParam < 2, - "OVM_ECDSAContractAccount: Transaction was signed with the wrong chain ID." - ); + 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. // Need to make sure that the transaction nonce is right and bump it if so. Lib_SafeExecutionManagerWrapper.safeREQUIRE( - decodedTx.sender() == Lib_SafeExecutionManagerWrapper.safeADDRESS(), + Lib_ECDSAUtils.recover( + _transaction, + isEthSign, + _v, + _r, + _s + ) == Lib_SafeExecutionManagerWrapper.safeADDRESS(), "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(), + "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(), @@ -89,8 +98,7 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { // "Gas is not sufficient to execute the transaction." // ); - // Transfer fee to relayer. We assume that whoever called this function is the relayer, - // hence the usage of CALLER. Fee is computed as gasLimit * gasPrice. + // Transfer fee to relayer. address relayer = Lib_SafeExecutionManagerWrapper.safeCALLER(); uint256 fee = Lib_SafeMathWrapper.mul(decodedTx.gasLimit, decodedTx.gasPrice); Lib_SafeExecutionManagerWrapper.safeREQUIRE( 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 16127eb28ea1..0f376f821fee 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol @@ -3,6 +3,8 @@ 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"; /** 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 0d4194c49290..bba7dd59c90f 100644 --- a/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol +++ b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol @@ -2,7 +2,9 @@ pragma solidity >0.5.0 <0.8.0; /* Library Imports */ -import { Lib_EIP155Tx } from "../../libraries/codec/Lib_EIP155Tx.sol"; +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"; /** @@ -17,7 +19,15 @@ import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_Sa * Runtime target: OVM */ contract OVM_SequencerEntrypoint { - using Lib_EIP155Tx for Lib_EIP155Tx.EIP155Tx; + + /********* + * Enums * + *********/ + + enum TransactionType { + NATIVE_ETH_TRANSACTION, + ETH_SIGNED_MESSAGE + } /********************* @@ -25,47 +35,93 @@ contract OVM_SequencerEntrypoint { *********************/ /** - * Expects an RLP-encoded EIP155 transaction as input. See the EIP for a more detailed - * description of this transaction format: - * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md + * Uses a custom "compressed" format to save on calldata gas: + * calldata[00:01]: transaction type (0 == EIP 155, 2 == Eth Sign Message) + * calldata[01:33]: signature "r" parameter + * calldata[33:65]: signature "s" parameter + * calldata[65:66]: signature "v" parameter + * calldata[66:69]: transaction gas limit + * calldata[69:72]: transaction gas price + * calldata[72:75]: transaction nonce + * calldata[75:95]: transaction target address + * calldata[95:XX]: transaction data */ fallback() external { - Lib_EIP155Tx.EIP155Tx memory transaction = Lib_EIP155Tx.decode( - msg.data, - Lib_SafeExecutionManagerWrapper.safeCHAINID() - ); + TransactionType transactionType = _getTransactionType(Lib_BytesUtils.toUint8(msg.data, 0)); + + bytes32 r = Lib_BytesUtils.toBytes32(Lib_BytesUtils.slice(msg.data, 1, 32)); + bytes32 s = Lib_BytesUtils.toBytes32(Lib_BytesUtils.slice(msg.data, 33, 32)); + uint8 v = Lib_BytesUtils.toUint8(msg.data, 65); + + // Remainder is the transaction to execute. + bytes memory compressedTx = Lib_BytesUtils.slice(msg.data, 66); + bool isEthSignedMessage = transactionType == TransactionType.ETH_SIGNED_MESSAGE; - // Recovery parameter being something other than 0 or 1 indicates that this transaction was - // signed using the wrong chain ID. We really should have this logic inside of the - Lib_SafeExecutionManagerWrapper.safeREQUIRE( - transaction.recoveryParam < 2, - "OVM_SequencerEntrypoint: Transaction was signed with the wrong chain ID." + // Need to decompress and then re-encode the transaction based on the original encoding. + bytes memory encodedTx = Lib_OVMCodec.encodeEIP155Transaction( + Lib_OVMCodec.decompressEIP155Transaction(compressedTx), + isEthSignedMessage ); - // Cache this result since we use it twice. Maybe we could move this caching into - // Lib_EIP155Tx but I'd rather not make optimizations like that right now. - address sender = transaction.sender(); + address target = Lib_ECDSAUtils.recover( + encodedTx, + isEthSignedMessage, + uint8(v), + r, + s + ); - // Create an EOA contract for this account if it doesn't already exist. - if (Lib_SafeExecutionManagerWrapper.safeEXTCODESIZE(sender) == 0) { - Lib_SafeExecutionManagerWrapper.safeCREATEEOA( - transaction.hash(), - transaction.recoveryParam, - transaction.r, - transaction.s - ); + if (Lib_SafeExecutionManagerWrapper.safeEXTCODESIZE(target) == 0) { + // ProxyEOA has not yet been deployed for this EOA. + bytes32 messageHash = Lib_ECDSAUtils.getMessageHash(encodedTx, isEthSignedMessage); + Lib_SafeExecutionManagerWrapper.safeCREATEEOA(messageHash, uint8(v), r, s); } - // Now call into the EOA contract (which should definitely exist). + // ProxyEOA has been deployed for this EOA, continue to CALL. + bytes memory callbytes = abi.encodeWithSignature( + "execute(bytes,uint8,uint8,bytes32,bytes32)", + encodedTx, + isEthSignedMessage, + uint8(v), + r, + s + ); + Lib_SafeExecutionManagerWrapper.safeCALL( gasleft(), - sender, - abi.encodeWithSignature( - "execute(bytes)", - msg.data - ) + target, + callbytes ); } + + + /********************** + * Internal Functions * + **********************/ + + /** + * Converts a uint256 into a TransactionType enum. + * @param _transactionType Transaction type index. + * @return _txType Transaction type enum value. + */ + function _getTransactionType( + uint8 _transactionType + ) + internal + returns ( + TransactionType _txType + ) + { + if (_transactionType == 0) { + return TransactionType.NATIVE_ETH_TRANSACTION; + } if (_transactionType == 2) { + return TransactionType.ETH_SIGNED_MESSAGE; + } else { + Lib_SafeExecutionManagerWrapper.safeREVERT( + "Transaction type must be 0 or 2" + ); + } + } } diff --git a/packages/contracts/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol b/packages/contracts/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol index 7f3fb0f82b52..16c956580f85 100644 --- a/packages/contracts/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol +++ b/packages/contracts/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol @@ -2,6 +2,9 @@ pragma solidity >0.5.0 <0.8.0; pragma experimental ABIEncoderV2; +/* Library Imports */ +import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; + /** * @title iOVM_ECDSAContractAccount */ @@ -12,11 +15,10 @@ interface iOVM_ECDSAContractAccount { ********************/ function execute( - bytes memory _encodedTransaction - ) - external - returns ( - bool, - bytes memory - ); + bytes memory _transaction, + Lib_OVMCodec.EOASignatureType _signatureType, + uint8 _v, + bytes32 _r, + bytes32 _s + ) external returns (bool _success, bytes memory _returndata); } diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol deleted file mode 100644 index 8fa76433247b..000000000000 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol +++ /dev/null @@ -1,196 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.8.0; -pragma experimental ABIEncoderV2; - -/* Library Imports */ -import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol"; -import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol"; - -/** - * @title Lib_EIP155Tx - * @dev A simple library for dealing with the transaction type defined by EIP155: - * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md - */ -library Lib_EIP155Tx { - - /*********** - * Structs * - ***********/ - - // Struct representing an EIP155 transaction. See EIP link above for more information. - struct EIP155Tx { - // These fields correspond to the actual RLP-encoded fields specified by EIP155. - uint256 nonce; - uint256 gasPrice; - uint256 gasLimit; - address to; - uint256 value; - bytes data; - uint8 v; - bytes32 r; - bytes32 s; - - // Chain ID to associate this transaction with. Used all over the place, seemed easier to - // set this once when we create the transaction rather than providing it as an input to - // each function. I don't see a strong need to have a transaction with a mutable chain ID. - uint256 chainId; - - // The ECDSA "recovery parameter," should always be 0 or 1. EIP155 specifies that: - // `v = {0,1} + CHAIN_ID * 2 + 35` - // Where `{0,1}` is a stand in for our `recovery_parameter`. Now computing our formula for - // the recovery parameter: - // 1. `v = {0,1} + CHAIN_ID * 2 + 35` - // 2. `v = recovery_parameter + CHAIN_ID * 2 + 35` - // 3. `v - CHAIN_ID * 2 - 35 = recovery_parameter` - // So we're left with the final formula: - // `recovery_parameter = v - CHAIN_ID * 2 - 35` - // NOTE: This variable is a uint8 because `v` is inherently limited to a uint8. If we - // didn't use a uint8, then recovery_parameter would always be a negative number for chain - // IDs greater than 110 (`255 - 110 * 2 - 35 = 0`). So we need to wrap around to support - // anything larger. - uint8 recoveryParam; - - // Whether or not the transaction is a creation. Necessary because we can't make an address - // "nil". Using the zero address creates a potential conflict if the user did actually - // intend to send a transaction to the zero address. - bool isCreate; - } - - // Lets us use nicer syntax. - using Lib_EIP155Tx for EIP155Tx; - - - /********************** - * Internal Functions * - **********************/ - - /** - * Decodes an EIP155 transaction and attaches a given Chain ID. - * Transaction *must* be RLP-encoded. - * @param _encoded RLP-encoded EIP155 transaction. - * @param _chainId Chain ID to assocaite with this transaction. - * @return Parsed transaction. - */ - function decode( - bytes memory _encoded, - uint256 _chainId - ) - internal - pure - returns ( - EIP155Tx memory - ) - { - Lib_RLPReader.RLPItem[] memory decoded = Lib_RLPReader.readList(_encoded); - - // Note formula above about how recoveryParam is computed. - uint8 v = uint8(Lib_RLPReader.readUint256(decoded[6])); - uint8 recoveryParam = uint8(v - 2 * _chainId - 35); - - // Creations can be detected by looking at the byte length here. - bool isCreate = Lib_RLPReader.readBytes(decoded[3]).length == 0; - - return EIP155Tx({ - nonce: Lib_RLPReader.readUint256(decoded[0]), - gasPrice: Lib_RLPReader.readUint256(decoded[1]), - gasLimit: Lib_RLPReader.readUint256(decoded[2]), - to: Lib_RLPReader.readAddress(decoded[3]), - value: Lib_RLPReader.readUint256(decoded[4]), - data: Lib_RLPReader.readBytes(decoded[5]), - v: v, - r: Lib_RLPReader.readBytes32(decoded[7]), - s: Lib_RLPReader.readBytes32(decoded[8]), - chainId: _chainId, - recoveryParam: recoveryParam, - isCreate: isCreate - }); - } - - /** - * Encodes an EIP155 transaction into RLP. - * @param _transaction EIP155 transaction to encode. - * @param _includeSignature Whether or not to encode the signature. - * @return RLP-encoded transaction. - */ - function encode( - EIP155Tx memory _transaction, - bool _includeSignature - ) - internal - pure - returns ( - bytes memory - ) - { - bytes[] memory raw = new bytes[](9); - - raw[0] = Lib_RLPWriter.writeUint(_transaction.nonce); - raw[1] = Lib_RLPWriter.writeUint(_transaction.gasPrice); - raw[2] = Lib_RLPWriter.writeUint(_transaction.gasLimit); - - // We write the encoding of empty bytes when the transaction is a creation, *not* the zero - // address as one might assume. - if (_transaction.isCreate) { - raw[3] = Lib_RLPWriter.writeBytes(''); - } else { - raw[3] = Lib_RLPWriter.writeAddress(_transaction.to); - } - - raw[4] = Lib_RLPWriter.writeUint(_transaction.value); - raw[5] = Lib_RLPWriter.writeBytes(_transaction.data); - - if (_includeSignature) { - raw[6] = Lib_RLPWriter.writeUint(_transaction.v); - raw[7] = Lib_RLPWriter.writeBytes32(_transaction.r); - raw[8] = Lib_RLPWriter.writeBytes32(_transaction.s); - } else { - // Chain ID *is* included in the unsigned transaction. - raw[6] = Lib_RLPWriter.writeUint(_transaction.chainId); - raw[7] = Lib_RLPWriter.writeBytes(''); - raw[8] = Lib_RLPWriter.writeBytes(''); - } - - return Lib_RLPWriter.writeList(raw); - } - - /** - * Computes the hash of an EIP155 transaction. Assumes that you don't want to include the - * signature in this hash because that's a very uncommon usecase. If you really want to include - * the signature, just encode with the signature and take the hash yourself. - */ - function hash( - EIP155Tx memory _transaction - ) - internal - pure - returns ( - bytes32 - ) - { - return keccak256( - _transaction.encode(false) - ); - } - - /** - * Computes the sender of an EIP155 transaction. - * @param _transaction EIP155 transaction to get a sender for. - * @return Address corresponding to the private key that signed this transaction. - */ - function sender( - EIP155Tx memory _transaction - ) - internal - pure - returns ( - address - ) - { - return ecrecover( - _transaction.hash(), - _transaction.recoveryParam + 27, - _transaction.r, - _transaction.s - ); - } -} 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 341db0b24381..4c3c94a7424b 100644 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol @@ -18,6 +18,11 @@ library Lib_OVMCodec { * Enums * *********/ + enum EOASignatureType { + EIP155_TRANSACTION, + ETH_SIGNED_MESSAGE + } + enum QueueOrigin { SEQUENCER_QUEUE, L1TOL2_QUEUE @@ -81,10 +86,142 @@ library Lib_OVMCodec { uint40 blockNumber; } + struct EIP155Transaction { + uint256 nonce; + uint256 gasPrice; + uint256 gasLimit; + address to; + uint256 value; + bytes data; + uint256 chainId; + } + + /********************** * Internal Functions * **********************/ + /** + * Decodes an EOA transaction (i.e., native Ethereum RLP encoding). + * @param _transaction Encoded EOA transaction. + * @return Transaction decoded into a struct. + */ + function decodeEIP155Transaction( + bytes memory _transaction, + bool _isEthSignedMessage + ) + internal + pure + returns ( + EIP155Transaction memory + ) + { + if (_isEthSignedMessage) { + ( + uint256 _nonce, + uint256 _gasLimit, + uint256 _gasPrice, + uint256 _chainId, + address _to, + bytes memory _data + ) = abi.decode( + _transaction, + (uint256, uint256, uint256, uint256, address ,bytes) + ); + return EIP155Transaction({ + nonce: _nonce, + gasPrice: _gasPrice, + gasLimit: _gasLimit, + to: _to, + value: 0, + data: _data, + chainId: _chainId + }); + } else { + Lib_RLPReader.RLPItem[] memory decoded = Lib_RLPReader.readList(_transaction); + + return EIP155Transaction({ + nonce: Lib_RLPReader.readUint256(decoded[0]), + gasPrice: Lib_RLPReader.readUint256(decoded[1]), + gasLimit: Lib_RLPReader.readUint256(decoded[2]), + to: Lib_RLPReader.readAddress(decoded[3]), + value: Lib_RLPReader.readUint256(decoded[4]), + data: Lib_RLPReader.readBytes(decoded[5]), + chainId: Lib_RLPReader.readUint256(decoded[6]) + }); + } + } + + /** + * Decompresses a compressed EIP155 transaction. + * @param _transaction Compressed EIP155 transaction bytes. + * @return Transaction parsed into a struct. + */ + function decompressEIP155Transaction( + bytes memory _transaction + ) + internal + returns ( + EIP155Transaction memory + ) + { + return EIP155Transaction({ + gasLimit: Lib_BytesUtils.toUint24(_transaction, 0), + gasPrice: uint256(Lib_BytesUtils.toUint24(_transaction, 3)) * 1000000, + nonce: Lib_BytesUtils.toUint24(_transaction, 6), + to: Lib_BytesUtils.toAddress(_transaction, 9), + data: Lib_BytesUtils.slice(_transaction, 29), + chainId: Lib_SafeExecutionManagerWrapper.safeCHAINID(), + value: 0 + }); + } + + /** + * Encodes an EOA transaction back into the original transaction. + * @param _transaction EIP155transaction to encode. + * @param _isEthSignedMessage Whether or not this was an eth signed message. + * @return Encoded transaction. + */ + function encodeEIP155Transaction( + EIP155Transaction memory _transaction, + bool _isEthSignedMessage + ) + internal + pure + returns ( + bytes memory + ) + { + if (_isEthSignedMessage) { + return abi.encode( + _transaction.nonce, + _transaction.gasLimit, + _transaction.gasPrice, + _transaction.chainId, + _transaction.to, + _transaction.data + ); + } else { + bytes[] memory raw = new bytes[](9); + + raw[0] = Lib_RLPWriter.writeUint(_transaction.nonce); + raw[1] = Lib_RLPWriter.writeUint(_transaction.gasPrice); + raw[2] = Lib_RLPWriter.writeUint(_transaction.gasLimit); + if (_transaction.to == address(0)) { + raw[3] = Lib_RLPWriter.writeBytes(''); + } else { + raw[3] = Lib_RLPWriter.writeAddress(_transaction.to); + } + raw[4] = Lib_RLPWriter.writeUint(0); + raw[5] = Lib_RLPWriter.writeBytes(_transaction.data); + raw[6] = Lib_RLPWriter.writeUint(_transaction.chainId); + raw[7] = Lib_RLPWriter.writeBytes(bytes('')); + raw[8] = Lib_RLPWriter.writeBytes(bytes('')); + + return Lib_RLPWriter.writeList(raw); + } + } + /** * Encodes a standard OVM transaction. * @param _transaction OVM transaction to encode. diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol index 4b9c5247bec4..8040eac0a2fa 100644 --- a/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol @@ -92,23 +92,6 @@ library Lib_RLPWriter { return writeBytes(abi.encodePacked(_in)); } - /** - * RLP encodes a bytes32 value. - * @param _in The bytes32 to encode. - * @return _out The RLP encoded bytes32 in bytes. - */ - function writeBytes32( - bytes32 _in - ) - internal - pure - returns ( - bytes memory _out - ) - { - return writeBytes(abi.encodePacked(_in)); - } - /** * RLP encodes a uint. * @param _in The uint256 to encode. diff --git a/packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol b/packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol new file mode 100644 index 000000000000..9d973758b920 --- /dev/null +++ b/packages/contracts/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.5.0 <0.8.0; + +/** + * @title Lib_ECDSAUtils + */ +library Lib_ECDSAUtils { + + /************************************** + * Internal Functions: ECDSA Recovery * + **************************************/ + + /** + * Recovers a signed address given a message and signature. + * @param _message Message that was originally signed. + * @param _isEthSignedMessage Whether or not the user used the `Ethereum Signed Message` prefix. + * @param _v Signature `v` parameter. + * @param _r Signature `r` parameter. + * @param _s Signature `s` parameter. + * @return _sender Signer address. + */ + function recover( + bytes memory _message, + bool _isEthSignedMessage, + uint8 _v, + bytes32 _r, + bytes32 _s + ) + internal + pure + returns ( + address _sender + ) + { + bytes32 messageHash = getMessageHash(_message, _isEthSignedMessage); + + return ecrecover( + messageHash, + _v + 27, + _r, + _s + ); + } + + function getMessageHash( + bytes memory _message, + bool _isEthSignedMessage + ) + internal + pure + returns (bytes32) { + if (_isEthSignedMessage) { + return getEthSignedMessageHash(_message); + } + return getNativeMessageHash(_message); + } + + + /************************************* + * Private Functions: ECDSA Recovery * + *************************************/ + + /** + * Gets the native message hash (simple keccak256) for a message. + * @param _message Message to hash. + * @return _messageHash Native message hash. + */ + function getNativeMessageHash( + bytes memory _message + ) + private + pure + returns ( + bytes32 _messageHash + ) + { + return keccak256(_message); + } + + /** + * Gets the hash of a message with the `Ethereum Signed Message` prefix. + * @param _message Message to hash. + * @return _messageHash Prefixed message hash. + */ + function getEthSignedMessageHash( + bytes memory _message + ) + private + pure + returns ( + bytes32 _messageHash + ) + { + 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/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol b/packages/contracts/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol new file mode 100644 index 000000000000..15c51fcf21fb --- /dev/null +++ b/packages/contracts/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol @@ -0,0 +1,95 @@ +// 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_EIP155Tx.sol b/packages/contracts/contracts/test-libraries/codec/TestLib_EIP155Tx.sol deleted file mode 100644 index 6019b8695f8c..000000000000 --- a/packages/contracts/contracts/test-libraries/codec/TestLib_EIP155Tx.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.8.0; -pragma experimental ABIEncoderV2; - -/* Library Imports */ -import { Lib_EIP155Tx } from "../../optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol"; - -/** - * @title TestLib_EIP155Tx - */ -contract TestLib_EIP155Tx { - function decode( - bytes memory _encoded, - uint256 _chainId - ) - public - pure - returns ( - Lib_EIP155Tx.EIP155Tx memory - ) - { - return Lib_EIP155Tx.decode( - _encoded, - _chainId - ); - } - - function encode( - Lib_EIP155Tx.EIP155Tx memory _transaction, - bool _includeSignature - ) - public - pure - returns ( - bytes memory - ) - { - return Lib_EIP155Tx.encode( - _transaction, - _includeSignature - ); - } - - function hash( - Lib_EIP155Tx.EIP155Tx memory _transaction - ) - public - pure - returns ( - bytes32 - ) - { - return Lib_EIP155Tx.hash( - _transaction - ); - } - - function sender( - Lib_EIP155Tx.EIP155Tx memory _transaction - ) - public - pure - returns ( - address - ) - { - return Lib_EIP155Tx.sender( - _transaction - ); - } -} diff --git a/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol b/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol index 9e96dd0cd800..b9046ac8a776 100644 --- a/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol +++ b/packages/contracts/contracts/test-libraries/codec/TestLib_OVMCodec.sol @@ -10,6 +10,19 @@ import { Lib_OVMCodec } from "../../optimistic-ethereum/libraries/codec/Lib_OVMC */ contract TestLib_OVMCodec { + function decodeEIP155Transaction( + bytes memory _transaction, + bool _isEthSignedMessage + ) + public + pure + returns ( + Lib_OVMCodec.EIP155Transaction memory _decoded + ) + { + return Lib_OVMCodec.decodeEIP155Transaction(_transaction, _isEthSignedMessage); + } + function encodeTransaction( Lib_OVMCodec.Transaction memory _transaction ) @@ -33,4 +46,15 @@ contract TestLib_OVMCodec { { return Lib_OVMCodec.hashTransaction(_transaction); } + + function decompressEIP155Transaction( + bytes memory _transaction + ) + public + returns ( + Lib_OVMCodec.EIP155Transaction memory _decompressed + ) + { + return Lib_OVMCodec.decompressEIP155Transaction(_transaction); + } } diff --git a/packages/contracts/contracts/test-libraries/utils/TestLib_ECDSAUtils.sol b/packages/contracts/contracts/test-libraries/utils/TestLib_ECDSAUtils.sol new file mode 100644 index 000000000000..4b66bf7f0ec8 --- /dev/null +++ b/packages/contracts/contracts/test-libraries/utils/TestLib_ECDSAUtils.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.5.0 <0.8.0; + +/* Library Imports */ +import { Lib_ECDSAUtils } from "../../optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol"; + +/** + * @title TestLib_ECDSAUtils + */ +contract TestLib_ECDSAUtils { + + function recover( + bytes memory _message, + bool _isEthSignedMessage, + uint8 _v, + bytes32 _r, + bytes32 _s + ) + public + pure + returns ( + address _sender + ) + { + return Lib_ECDSAUtils.recover( + _message, + _isEthSignedMessage, + _v, + _r, + _s + ); + } +} diff --git a/packages/contracts/src/contract-deployment/config.ts b/packages/contracts/src/contract-deployment/config.ts index 64b662ec17bf..5ddfc87b88ef 100644 --- a/packages/contracts/src/contract-deployment/config.ts +++ b/packages/contracts/src/contract-deployment/config.ts @@ -225,6 +225,9 @@ export const makeContractDeployConfig = async ( 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/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts b/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts index 0189e9c57bc1..9bb7fc5bd165 100644 --- a/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts +++ b/packages/contracts/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts @@ -7,7 +7,14 @@ import { MockContract, smockit } from '@eth-optimism/smock' /* Internal Imports */ import { NON_ZERO_ADDRESS } from '../../../helpers/constants' -import { DEFAULT_EIP155_TX, decodeSolidityError } from '../../../helpers' +import { + serializeNativeTransaction, + signNativeTransaction, + DEFAULT_EIP155_TX, + serializeEthSignTransaction, + signEthSignMessage, + decodeSolidityError, +} from '../../../helpers' const callPredeploy = async ( Helper_PredeployCaller: Contract, @@ -34,9 +41,10 @@ const callPredeploy = async ( describe('OVM_ECDSAContractAccount', () => { let wallet: Wallet + let badWallet: Wallet before(async () => { const provider = waffle.provider - ;[wallet] = provider.getWallets() + ;[wallet, badWallet] = provider.getWallets() }) let Mock__OVM_ExecutionManager: MockContract @@ -80,14 +88,43 @@ describe('OVM_ECDSAContractAccount', () => { describe('fallback()', () => { it(`should successfully execute an EIP155Transaction`, async () => { - const transaction = DEFAULT_EIP155_TX - const encodedTransaction = await wallet.signTransaction(transaction) + const message = serializeNativeTransaction(DEFAULT_EIP155_TX) + const sig = await signNativeTransaction(wallet, DEFAULT_EIP155_TX) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [encodedTransaction] + [ + 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. @@ -97,33 +134,43 @@ describe('OVM_ECDSAContractAccount', () => { }) it(`should ovmCREATE if EIP155Transaction.to is zero address`, async () => { - const transaction = { ...DEFAULT_EIP155_TX, to: '' } - const encodedTransaction = await wallet.signTransaction(transaction) + const createTx = { ...DEFAULT_EIP155_TX, to: '' } + const message = serializeNativeTransaction(createTx) + const sig = await signNativeTransaction(wallet, createTx) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [encodedTransaction] + [ + 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(transaction.data) + expect(ovmCREATE._bytecode).to.equal(createTx.data) }) it(`should revert on invalid signature`, async () => { - const transaction = DEFAULT_EIP155_TX - const encodedTransaction = ethers.utils.serializeTransaction( - transaction, - '0x' + '00'.repeat(65) - ) + const message = serializeNativeTransaction(DEFAULT_EIP155_TX) + const sig = await signNativeTransaction(badWallet, DEFAULT_EIP155_TX) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [encodedTransaction] + [ + 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] @@ -133,14 +180,24 @@ describe('OVM_ECDSAContractAccount', () => { }) it(`should revert on incorrect nonce`, async () => { - const transaction = { ...DEFAULT_EIP155_TX, nonce: 99 } - const encodedTransaction = await wallet.signTransaction(transaction) + const alteredNonceTx = { + ...DEFAULT_EIP155_TX, + nonce: 99, + } + const message = serializeNativeTransaction(alteredNonceTx) + const sig = await signNativeTransaction(wallet, alteredNonceTx) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [encodedTransaction] + [ + 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] @@ -150,32 +207,52 @@ describe('OVM_ECDSAContractAccount', () => { }) it(`should revert on incorrect chainId`, async () => { - const transaction = { ...DEFAULT_EIP155_TX, chainId: 421 } - const encodedTransaction = await wallet.signTransaction(transaction) + const alteredChainIdTx = { + ...DEFAULT_EIP155_TX, + chainId: 421, + } + const message = serializeNativeTransaction(alteredChainIdTx) + const sig = await signNativeTransaction(wallet, alteredChainIdTx) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [encodedTransaction] + [ + 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( - 'OVM_ECDSAContractAccount: Transaction was signed with the wrong chain ID.' + 'Transaction chainId does not match expected OVM chainId.' ) }) // TEMPORARY: Skip gas checks for minnet. it.skip(`should revert on insufficient gas`, async () => { - const transaction = { ...DEFAULT_EIP155_TX, gasLimit: 200000000 } - const encodedTransaction = await wallet.signTransaction(transaction) + const alteredInsufficientGasTx = { + ...DEFAULT_EIP155_TX, + gasLimit: 200000000, + } + const message = serializeNativeTransaction(alteredInsufficientGasTx) + const sig = await signNativeTransaction(wallet, alteredInsufficientGasTx) await callPredeploy( Helper_PredeployCaller, OVM_ECDSAContractAccount, 'execute', - [encodedTransaction], + [ + message, + 0, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ], 40000000 ) @@ -187,16 +264,21 @@ describe('OVM_ECDSAContractAccount', () => { }) it(`should revert if fee is not transferred to the relayer`, async () => { - const transaction = DEFAULT_EIP155_TX - const encodedTransaction = await wallet.signTransaction(transaction) - + 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', - [encodedTransaction], + [ + message, + 0, //isEthSignedMessage + `0x${sig.v}`, //v + `0x${sig.r}`, //r + `0x${sig.s}`, //s + ], 40000000 ) diff --git a/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts b/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts index 81bd75986c94..2979ad3bc33e 100644 --- a/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts +++ b/packages/contracts/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts @@ -7,7 +7,14 @@ import { smockit, MockContract } from '@eth-optimism/smock' /* Internal Imports */ import { getContractInterface } from '../../../../src' -import { DEFAULT_EIP155_TX } from '../../../helpers' +import { + encodeSequencerCalldata, + signNativeTransaction, + signEthSignMessage, + DEFAULT_EIP155_TX, + serializeNativeTransaction, + serializeEthSignTransaction, +} from '../../../helpers' describe('OVM_SequencerEntrypoint', () => { let wallet: Wallet @@ -48,59 +55,128 @@ describe('OVM_SequencerEntrypoint', () => { }) describe('fallback()', async () => { - it('should call EIP155', async () => { - const transaction = DEFAULT_EIP155_TX - const encodedTransaction = await wallet.signTransaction(transaction) - + 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, - encodedTransaction + calldata ) + const encodedTx = serializeNativeTransaction(DEFAULT_EIP155_TX) + const sig = await signNativeTransaction(wallet, DEFAULT_EIP155_TX) + const expectedEOACalldata = getContractInterface( 'OVM_ECDSAContractAccount' - ).encodeFunctionData('execute', [encodedTransaction]) + ).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', async () => { - const transaction = { ...DEFAULT_EIP155_TX, to: '' } - const encodedTransaction = await wallet.signTransaction(transaction) - + 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, - encodedTransaction + calldata ) + const encodedTx = serializeNativeTransaction(createTx) + const sig = await signNativeTransaction(wallet, createTx) + const expectedEOACalldata = getContractInterface( 'OVM_ECDSAContractAccount' - ).encodeFunctionData('execute', [encodedTransaction]) + ).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 call ovmCreateEOA when ovmEXTCODESIZE returns 0`, async () => { - Mock__OVM_ExecutionManager.smocked.ovmEXTCODESIZE.will.return.with(0) - - const transaction = DEFAULT_EIP155_TX - const encodedTransaction = await wallet.signTransaction(transaction) + 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, - encodedTransaction + 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, - }) + 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 + }) - expect(eoaAddress).to.equal(await wallet.getAddress()) + 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/contracts/libraries/codec/Lib_EIP155Tx.ts b/packages/contracts/test/contracts/libraries/codec/Lib_EIP155Tx.ts deleted file mode 100644 index 021f14edcb19..000000000000 --- a/packages/contracts/test/contracts/libraries/codec/Lib_EIP155Tx.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* tslint:disable:no-empty */ -import '../../../setup' - -/* Internal Imports */ -import { Lib_EIP155Tx_TEST_JSON } from '../../../data' -import { runJsonTest } from '../../../helpers' - -// Currently running tests from here: -// https://github.com/ethereumjs/ethereumjs-tx/blob/master/test/ttTransactionTestEip155VitaliksTests.json - -describe('Lib_EIP155Tx', () => { - describe('JSON tests', () => { - runJsonTest('TestLib_EIP155Tx', Lib_EIP155Tx_TEST_JSON) - }) -}) diff --git a/packages/contracts/test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts b/packages/contracts/test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts new file mode 100644 index 000000000000..baf3c5a999b2 --- /dev/null +++ b/packages/contracts/test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts @@ -0,0 +1,9 @@ +/* Internal Imports */ +import { Lib_ECDSAUtils_TEST_JSON } from '../../../data' +import { runJsonTest } from '../../../helpers' + +describe('Lib_ECDSAUtils', () => { + describe('JSON tests', () => { + runJsonTest('TestLib_ECDSAUtils', Lib_ECDSAUtils_TEST_JSON) + }) +}) diff --git a/packages/contracts/test/data/index.ts b/packages/contracts/test/data/index.ts index 5c9103f5c2d5..8a4a1f7e65b8 100644 --- a/packages/contracts/test/data/index.ts +++ b/packages/contracts/test/data/index.ts @@ -2,8 +2,8 @@ export { tests as Lib_RLPWriter_TEST_JSON } from './json/libraries/rlp/Lib_RLPWr export { tests as Lib_RLPReader_TEST_JSON } from './json/libraries/rlp/Lib_RLPReader.test.json' export { tests as Lib_Bytes32Utils_TEST_JSON } from './json/libraries/utils/Lib_Bytes32Utils.test.json' export { tests as Lib_BytesUtils_TEST_JSON } from './json/libraries/utils/Lib_BytesUtils.test.json' +export { tests as Lib_ECDSAUtils_TEST_JSON } from './json/libraries/utils/Lib_ECDSAUtils.test.json' export { tests as Lib_MerkleTrie_TEST_JSON } from './json/libraries/trie/Lib_MerkleTrie.test.json' -export { tests as Lib_EIP155Tx_TEST_JSON } from './json/libraries/codec/Lib_EIP155Tx.test.json' export { tests as Lib_OVMCodec_TEST_JSON } from './json/libraries/codec/Lib_OVMCodec.test.json' export { tests as CREATE2_TEST_JSON } from './json/create2.test.json' export { tests as SAFETY_CHECKER_TEST_JSON } from './json/safety-checker.test.json' diff --git a/packages/contracts/test/data/json/libraries/codec/Lib_EIP155Tx.test.json b/packages/contracts/test/data/json/libraries/codec/Lib_EIP155Tx.test.json deleted file mode 100644 index a7536ad4fa3b..000000000000 --- a/packages/contracts/test/data/json/libraries/codec/Lib_EIP155Tx.test.json +++ /dev/null @@ -1,725 +0,0 @@ -{ - "tests": { - "decode": { - "vitalik test 0": { - "in": [ - "0xf864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", - 1 - ], - "out": [ - [ - "0x00", - "0x04a817c800", - "0x5208", - "0x3535353535353535353535353535353535353535", - "0x00", - "0x", - "0x25", - "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", - "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", - "0x01", - "0x00", - false - ] - ] - }, - "vitalik test 1": { - "in": [ - "0xf867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", - 1 - ], - "out": [ - [ - "0x08", - "0x04a817c808", - "0x02e248", - "0x3535353535353535353535353535353535353535", - "0x0200", - "0x", - "0x25", - "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12", - "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", - "0x01", - "0x00", - false - ] - ] - }, - "vitalik test 2": { - "in": [ - "0xf867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", - 1 - ], - "out": [ - [ - "0x09", - "0x04a817c809", - "0x033450", - "0x3535353535353535353535353535353535353535", - "0x02d9", - "0x", - "0x25", - "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", - "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", - "0x01", - "0x00", - false - ] - ] - }, - "vitalik test 3": { - "in": [ - "0xf864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", - 1 - ], - "out": [ - [ - "0x01", - "0x04a817c801", - "0xa410", - "0x3535353535353535353535353535353535353535", - "0x01", - "0x", - "0x25", - "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bca", - "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", - "0x01", - "0x00", - false - ] - ] - }, - "vitalik test 4": { - "in": [ - "0xf864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", - 1 - ], - "out": [ - [ - "0x02", - "0x04a817c802", - "0xf618", - "0x3535353535353535353535353535353535353535", - "0x08", - "0x", - "0x25", - "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", - "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", - "0x01", - "0x00", - false - ] - ] - }, - "vitalik test 5": { - "in": [ - "0xf865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", - 1 - ], - "out": [ - [ - "0x03", - "0x04a817c803", - "0x014820", - "0x3535353535353535353535353535353535353535", - "0x1b", - "0x", - "0x25", - "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0", - "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", - "0x01", - "0x00", - false - ] - ] - }, - "vitalik test 6": { - "in": [ - "0xf865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", - 1 - ], - "out": [ - [ - "0x04", - "0x04a817c804", - "0x019a28", - "0x3535353535353535353535353535353535353535", - "0x40", - "0x", - "0x25", - "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063", - "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", - "0x01", - "0x00", - false - ] - ] - }, - "vitalik test 7": { - "in": [ - "0xf865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - 1 - ], - "out": [ - [ - "0x05", - "0x04a817c805", - "0x01ec30", - "0x3535353535353535353535353535353535353535", - "0x7d", - "0x", - "0x25", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x01", - "0x00", - false - ] - ] - }, - "vitalik test 8": { - "in": [ - "0xf865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - 1 - ], - "out": [ - [ - "0x05", - "0x04a817c805", - "0x01ec30", - "0x3535353535353535353535353535353535353535", - "0x7d", - "0x", - "0x25", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x01", - "0x00", - false - ] - ] - }, - "vitalik test 9": { - "in": [ - "0xf866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", - 1 - ], - "out": [ - [ - "0x06", - "0x04a817c806", - "0x023e38", - "0x3535353535353535353535353535353535353535", - "0xd8", - "0x", - "0x25", - "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2f", - "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", - "0x01", - "0x00", - false - ] - ] - }, - "vitalik test 10": { - "in": [ - "0xf867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", - 1 - ], - "out": [ - [ - "0x07", - "0x04a817c807", - "0x029040", - "0x3535353535353535353535353535353535353535", - "0x0157", - "0x", - "0x25", - "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", - "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", - "0x01", - "0x00", - false - ] - ] - } - }, - "encode": { - "vitalik test 0": { - "in": [ - [ - "0x00", - "0x04a817c800", - "0x5208", - "0x3535353535353535353535353535353535353535", - "0x00", - "0x", - "0x25", - "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", - "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d" - ] - }, - "vitalik test 1": { - "in": [ - [ - "0x08", - "0x04a817c808", - "0x02e248", - "0x3535353535353535353535353535353535353535", - "0x0200", - "0x", - "0x25", - "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12", - "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10" - ] - }, - "vitalik test 2": { - "in": [ - [ - "0x09", - "0x04a817c809", - "0x033450", - "0x3535353535353535353535353535353535353535", - "0x02d9", - "0x", - "0x25", - "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", - "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb" - ] - }, - "vitalik test 3": { - "in": [ - [ - "0x01", - "0x04a817c801", - "0xa410", - "0x3535353535353535353535353535353535353535", - "0x01", - "0x", - "0x25", - "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bca", - "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6" - ] - }, - "vitalik test 4": { - "in": [ - [ - "0x02", - "0x04a817c802", - "0xf618", - "0x3535353535353535353535353535353535353535", - "0x08", - "0x", - "0x25", - "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", - "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5" - ] - }, - "vitalik test 5": { - "in": [ - [ - "0x03", - "0x04a817c803", - "0x014820", - "0x3535353535353535353535353535353535353535", - "0x1b", - "0x", - "0x25", - "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0", - "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de" - ] - }, - "vitalik test 6": { - "in": [ - [ - "0x04", - "0x04a817c804", - "0x019a28", - "0x3535353535353535353535353535353535353535", - "0x40", - "0x", - "0x25", - "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063", - "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060" - ] - }, - "vitalik test 7": { - "in": [ - [ - "0x05", - "0x04a817c805", - "0x01ec30", - "0x3535353535353535353535353535353535353535", - "0x7d", - "0x", - "0x25", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1" - ] - }, - "vitalik test 8": { - "in": [ - [ - "0x05", - "0x04a817c805", - "0x01ec30", - "0x3535353535353535353535353535353535353535", - "0x7d", - "0x", - "0x25", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1" - ] - }, - "vitalik test 9": { - "in": [ - [ - "0x06", - "0x04a817c806", - "0x023e38", - "0x3535353535353535353535353535353535353535", - "0xd8", - "0x", - "0x25", - "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2f", - "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d" - ] - }, - "vitalik test 10": { - "in": [ - [ - "0x07", - "0x04a817c807", - "0x029040", - "0x3535353535353535353535353535353535353535", - "0x0157", - "0x", - "0x25", - "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", - "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", - "0x01", - "0x00", - false - ], - true - ], - "out": [ - "0xf867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021" - ] - } - }, - "sender": { - "vitalik test 0": { - "in": [ - [ - "0x00", - "0x04a817c800", - "0x5208", - "0x3535353535353535353535353535353535353535", - "0x00", - "0x", - "0x25", - "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", - "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0xf0f6f18bca1b28cd68e4357452947e021241e9ce" - ] - }, - "vitalik test 1": { - "in": [ - [ - "0x08", - "0x04a817c808", - "0x02e248", - "0x3535353535353535353535353535353535353535", - "0x0200", - "0x", - "0x25", - "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12", - "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0x9bddad43f934d313c2b79ca28a432dd2b7281029" - ] - }, - "vitalik test 2": { - "in": [ - [ - "0x09", - "0x04a817c809", - "0x033450", - "0x3535353535353535353535353535353535353535", - "0x02d9", - "0x", - "0x25", - "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", - "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f" - ] - }, - "vitalik test 3": { - "in": [ - [ - "0x01", - "0x04a817c801", - "0xa410", - "0x3535353535353535353535353535353535353535", - "0x01", - "0x", - "0x25", - "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bca", - "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112" - ] - }, - "vitalik test 4": { - "in": [ - [ - "0x02", - "0x04a817c802", - "0xf618", - "0x3535353535353535353535353535353535353535", - "0x08", - "0x", - "0x25", - "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", - "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be" - ] - }, - "vitalik test 5": { - "in": [ - [ - "0x03", - "0x04a817c803", - "0x014820", - "0x3535353535353535353535353535353535353535", - "0x1b", - "0x", - "0x25", - "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0", - "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0x82a88539669a3fd524d669e858935de5e5410cf0" - ] - }, - "vitalik test 6": { - "in": [ - [ - "0x04", - "0x04a817c804", - "0x019a28", - "0x3535353535353535353535353535353535353535", - "0x40", - "0x", - "0x25", - "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063", - "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0xf9358f2538fd5ccfeb848b64a96b743fcc930554" - ] - }, - "vitalik test 7": { - "in": [ - [ - "0x05", - "0x04a817c805", - "0x01ec30", - "0x3535353535353535353535353535353535353535", - "0x7d", - "0x", - "0x25", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0xa8f7aba377317440bc5b26198a363ad22af1f3a4" - ] - }, - "vitalik test 8": { - "in": [ - [ - "0x05", - "0x04a817c805", - "0x01ec30", - "0x3535353535353535353535353535353535353535", - "0x7d", - "0x", - "0x25", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0xa8f7aba377317440bc5b26198a363ad22af1f3a4" - ] - }, - "vitalik test 9": { - "in": [ - [ - "0x06", - "0x04a817c806", - "0x023e38", - "0x3535353535353535353535353535353535353535", - "0xd8", - "0x", - "0x25", - "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2f", - "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35" - ] - }, - "vitalik test 10": { - "in": [ - [ - "0x07", - "0x04a817c807", - "0x029040", - "0x3535353535353535353535353535353535353535", - "0x0157", - "0x", - "0x25", - "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", - "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", - "0x01", - "0x00", - false - ] - ], - "out": [ - "0xd37922162ab7cea97c97a87551ed02c9a38b7332" - ] - } - } - } -} 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 a55ce0122c21..b442f4e07c8c 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 @@ -1,4 +1,22 @@ { "tests": { + "decompressEIP155Transaction": { + "decompression": { + "in": [ + "0x0001f4000064000064121212121212121212121212121212121212121299999999999999999999" + ], + "out": [ + [ + 100, + 100000000, + 500, + "0x1212121212121212121212121212121212121212", + 0, + "0x99999999999999999999", + 420 + ] + ] + } + } } } diff --git a/packages/contracts/test/data/json/libraries/utils/Lib_ECDSAUtils.test.json b/packages/contracts/test/data/json/libraries/utils/Lib_ECDSAUtils.test.json new file mode 100644 index 000000000000..40f15819442f --- /dev/null +++ b/packages/contracts/test/data/json/libraries/utils/Lib_ECDSAUtils.test.json @@ -0,0 +1,126 @@ +{ + "tests": { + "recover": { + "standard hash, valid signature": { + "in": [ + "0xf83d80808094121212121212121212121212121212121212121280a0bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a6c8080", + false, + "0x01", + "0x057bf1c0edf0a9002a79f8c9b39683f6453a18e73e02364270a2b6ee8117f11a", + "0x5f8181365a222c7b05a84c29a29754e6a925952d3bf4bd65a6259ef37ee048e3" + ], + "out": [ + "0x17ec8597ff92C3F44523bDc65BF0f1bE632917ff" + ] + }, + "standard hash, invalid v parameter": { + "in": [ + "0xf83d80808094121212121212121212121212121212121212121280a0bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a6c8080", + false, + "0xfc", + "0x057bf1c0edf0a9002a79f8c9b39683f6453a18e73e02364270a2b6ee8117f11a", + "0x5f8181365a222c7b05a84c29a29754e6a925952d3bf4bd65a6259ef37ee048e3" + ], + "out": [ + "0x0000000000000000000000000000000000000000" + ] + }, + "standard hash, invalid r parameter": { + "in": [ + "0xf83d80808094121212121212121212121212121212121212121280a0bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a6c8080", + false, + "0x01", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x5f8181365a222c7b05a84c29a29754e6a925952d3bf4bd65a6259ef37ee048e3" + ], + "out": [ + "0x0000000000000000000000000000000000000000" + ] + }, + "standard hash, invalid s parameter": { + "in": [ + "0xf83d80808094121212121212121212121212121212121212121280a0bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a6c8080", + false, + "0x01", + "0x057bf1c0edf0a9002a79f8c9b39683f6453a18e73e02364270a2b6ee8117f11a", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "out": [ + "0x0000000000000000000000000000000000000000" + ] + }, + "standard hash, invalid message": { + "in": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + false, + "0x01", + "0x057bf1c0edf0a9002a79f8c9b39683f6453a18e73e02364270a2b6ee8117f11a", + "0x5f8181365a222c7b05a84c29a29754e6a925952d3bf4bd65a6259ef37ee048e3" + ], + "out": [ + "0x1397890fcfC2D7563Aa01cE93A217b9809D3447B" + ] + }, + "eth signed message hash, valid signature": { + "in": [ + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000121212121212121212121212121212121212121200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000020bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a", + true, + "0x01", + "0xe5a2edb71b6d76a8aacd59467d3063fd455ca13a4e9cb57da6f25849d40e4e2a", + "0x5465373d68d521845e3ffd2baf4c51f3d21c990914c09490b32ffc0b322dbf98" + ], + "out": [ + "0x17ec8597ff92C3F44523bDc65BF0f1bE632917ff" + ] + }, + "eth signed message hash, invalid v parameter": { + "in": [ + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000121212121212121212121212121212121212121200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000020bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a", + true, + "0x1c", + "0xe5a2edb71b6d76a8aacd59467d3063fd455ca13a4e9cb57da6f25849d40e4e2a", + "0x5465373d68d521845e3ffd2baf4c51f3d21c990914c09490b32ffc0b322dbf98" + ], + "out": [ + "0x0000000000000000000000000000000000000000" + ] + }, + "eth signed message hash, invalid r parameter": { + "in": [ + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000121212121212121212121212121212121212121200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000020bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a", + true, + "0x01", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x5465373d68d521845e3ffd2baf4c51f3d21c990914c09490b32ffc0b322dbf98" + ], + "out": [ + "0x0000000000000000000000000000000000000000" + ] + }, + "eth signed message hash, invalid s parameter": { + "in": [ + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000121212121212121212121212121212121212121200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000020bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a", + true, + "0x01", + "0xe5a2edb71b6d76a8aacd59467d3063fd455ca13a4e9cb57da6f25849d40e4e2a", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "out": [ + "0x0000000000000000000000000000000000000000" + ] + }, + "eth signed message hash, invalid message": { + "in": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + true, + "0x01", + "0xe5a2edb71b6d76a8aacd59467d3063fd455ca13a4e9cb57da6f25849d40e4e2a", + "0x5465373d68d521845e3ffd2baf4c51f3d21c990914c09490b32ffc0b322dbf98" + ], + "out": [ + "0xf8bd1421f9D28C8F58f33B25a6faB16F3f89b749" + ] + } + } + } +} diff --git a/packages/contracts/test/helpers/codec/encoding.ts b/packages/contracts/test/helpers/codec/encoding.ts index 869e4feffca0..f7e16531fcd6 100644 --- a/packages/contracts/test/helpers/codec/encoding.ts +++ b/packages/contracts/test/helpers/codec/encoding.ts @@ -1,5 +1,9 @@ /* External Imports */ import { ethers } from 'hardhat' +import { constants, Wallet } from 'ethers' + +/* Internal Imports */ +import { remove0x, fromHexString } from '@eth-optimism/core-utils' export interface EIP155Transaction { nonce: number @@ -33,3 +37,115 @@ export const getRawSignedComponents = (signed: string): any[] => { export const getSignedComponents = (signed: string): any[] => { return ethers.utils.RLP.decode(signed).slice(-3) } + +export const encodeCompactTransaction = (transaction: any): string => { + const nonce = ethers.utils.zeroPad(transaction.nonce, 3) + const gasLimit = ethers.utils.zeroPad(transaction.gasLimit, 3) + if (transaction.gasPrice % 1000000 !== 0) + throw Error('gas price must be a multiple of 1000000') + const compressedGasPrice: any = transaction.gasPrice / 1000000 + const gasPrice = ethers.utils.zeroPad(compressedGasPrice, 3) + const to = !transaction.to.length + ? fromHexString(constants.AddressZero) + : fromHexString(transaction.to) + const data = fromHexString(transaction.data) + + return Buffer.concat([ + Buffer.from(gasLimit), + Buffer.from(gasPrice), + Buffer.from(nonce), + Buffer.from(to), + data, + ]).toString('hex') +} + +export const serializeEthSignTransaction = ( + transaction: EIP155Transaction +): string => { + return ethers.utils.defaultAbiCoder.encode( + ['uint256', 'uint256', 'uint256', 'uint256', 'address', 'bytes'], + [ + transaction.nonce, + transaction.gasLimit, + transaction.gasPrice, + transaction.chainId, + transaction.to, + transaction.data, + ] + ) +} + +export const serializeNativeTransaction = ( + transaction: EIP155Transaction +): string => { + return ethers.utils.serializeTransaction(transaction) +} + +export const signEthSignMessage = async ( + wallet: Wallet, + transaction: EIP155Transaction +): Promise => { + const serializedTransaction = serializeEthSignTransaction(transaction) + const transactionHash = ethers.utils.keccak256(serializedTransaction) + const transactionHashBytes = ethers.utils.arrayify(transactionHash) + const transactionSignature = await wallet.signMessage(transactionHashBytes) + + const messageHash = ethers.utils.hashMessage(transactionHashBytes) + const [v, r, s] = getRawSignedComponents(transactionSignature).map( + (component) => { + return remove0x(component) + } + ) + return { + messageHash, + v: '0' + (parseInt(v, 16) - 27), + r, + s, + } +} + +export const signNativeTransaction = async ( + wallet: Wallet, + transaction: EIP155Transaction +): Promise => { + const serializedTransaction = serializeNativeTransaction(transaction) + const transactionSignature = await wallet.signTransaction(transaction) + + const messageHash = ethers.utils.keccak256(serializedTransaction) + const [v, r, s] = getSignedComponents(transactionSignature).map( + (component) => { + return remove0x(component) + } + ) + return { + messageHash, + v: '0' + (parseInt(v, 16) - transaction.chainId * 2 - 8 - 27), + r, + s, + } +} + +export const signTransaction = async ( + wallet: Wallet, + transaction: EIP155Transaction, + transactionType: number +): Promise => { + return transactionType === 2 + ? signEthSignMessage(wallet, transaction) //ETH Signed tx + : signNativeTransaction(wallet, transaction) //Create EOA tx or EIP155 tx +} + +export const encodeSequencerCalldata = async ( + wallet: Wallet, + transaction: EIP155Transaction, + transactionType: number +) => { + const sig = await signTransaction(wallet, transaction, transactionType) + const encodedTransaction = encodeCompactTransaction(transaction) + const dataPrefix = `0x0${transactionType}${sig.r}${sig.s}${sig.v}` + const calldata = + transactionType === 1 + ? `${dataPrefix}${remove0x(sig.messageHash)}` // Create EOA tx + : `${dataPrefix}${encodedTransaction}` // EIP155 tx or ETH Signed Tx + return calldata +} diff --git a/packages/contracts/test/helpers/test-runner/json-test-runner.ts b/packages/contracts/test/helpers/test-runner/json-test-runner.ts index d32626835f5f..0380ee849f06 100644 --- a/packages/contracts/test/helpers/test-runner/json-test-runner.ts +++ b/packages/contracts/test/helpers/test-runner/json-test-runner.ts @@ -4,16 +4,10 @@ import { expect } from '../../setup' import { ethers } from 'hardhat' import { Contract, BigNumber } from 'ethers' -const bnRegex = /^\d+n$/gm - -const bigNumberify = (arr: any[]) => { +const bigNumberify = (arr) => { return arr.map((el: any) => { if (typeof el === 'number') { return BigNumber.from(el) - } else if (typeof el === 'string' && bnRegex.test(el)) { - return BigNumber.from(el.slice(0, el.length - 1)) - } else if (typeof el === 'string' && el.length > 2 && el.startsWith('0x')) { - return BigNumber.from(el.toLowerCase()) } else if (Array.isArray(el)) { return bigNumberify(el) } else { @@ -37,7 +31,7 @@ export const runJsonTest = (contractName: string, json: any): void => { .reverted } else { expect( - bigNumberify(await contract.functions[functionName](...test.in)) + await contract.functions[functionName](...test.in) ).to.deep.equal(bigNumberify(test.out)) } }) From 93f81c3cab4eeb4a740786309ecb02773370b547 Mon Sep 17 00:00:00 2001 From: Maurelian Date: Thu, 15 Apr 2021 22:15:37 -0400 Subject: [PATCH 7/7] Update .changeset/ten-baboons-compete.md --- .changeset/ten-baboons-compete.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/ten-baboons-compete.md b/.changeset/ten-baboons-compete.md index c7acd3945d47..66a3b3f6af3a 100644 --- a/.changeset/ten-baboons-compete.md +++ b/.changeset/ten-baboons-compete.md @@ -2,7 +2,6 @@ "@eth-optimism/contracts": minor --- -- Remove ETH_SIGNED_MESSAGE and standardize on EIP-155 messages - Reduce nonce size to uint64 - Ban ovmCALLER opcode when it would return ZERO - Add value transfer in OVM_ECDSAContractAccount