diff --git a/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol b/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol index 947357b00..d5f50d7ef 100644 --- a/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol +++ b/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol @@ -6,8 +6,7 @@ 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"; @@ -21,6 +20,8 @@ import { Lib_SafeMathWrapper } from "../../libraries/wrappers/Lib_SafeMathWrappe * 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,34 +53,32 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { bytes memory ) { - bool isEthSign = _signatureType == Lib_OVMCodec.EOASignatureType.ETH_SIGNED_MESSAGE; + Lib_EIP155Tx.EIP155Tx memory transaction = 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( + transaction.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(), + transaction.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(), + transaction.nonce == Lib_SafeExecutionManagerWrapper.safeGETNONCE(), "Transaction nonce does not match the expected nonce." ); @@ -98,24 +89,30 @@ 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); + uint256 fee = Lib_SafeMathWrapper.mul(transaction.gasLimit, transaction.gasPrice); (bool success, ) = Lib_SafeExecutionManagerWrapper.safeCALL( gasleft(), ETH_ERC20_ADDRESS, - abi.encodeWithSignature("transfer(address,uint256)", relayer, fee) + abi.encodeWithSignature( + "transfer(address,uint256)", + relayer, + fee + ) ); + + // Make sure the transfer was actually successful. Lib_SafeExecutionManagerWrapper.safeREQUIRE( success == true, "Fee was not transferred to relayer." ); - // Contract creations are signalled by sending a transaction to the zero address. - if (decodedTx.to == address(0)) { + if (transaction.isCreate) { (address created, bytes memory revertData) = Lib_SafeExecutionManagerWrapper.safeCREATE( - decodedTx.gasLimit, - decodedTx.data + transaction.gasLimit, + transaction.data ); // Return true if the contract creation succeeded, false w/ revertData otherwise. @@ -128,12 +125,12 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { // We only want to bump the nonce for `ovmCALL` because `ovmCREATE` automatically bumps // the nonce of the calling account. Normally an EOA would bump the nonce for both // cases, but since this is a contract we'd end up bumping the nonce twice. - Lib_SafeExecutionManagerWrapper.safeSETNONCE(decodedTx.nonce + 1); + Lib_SafeExecutionManagerWrapper.safeSETNONCE(transaction.nonce + 1); return Lib_SafeExecutionManagerWrapper.safeCALL( - decodedTx.gasLimit, - decodedTx.to, - decodedTx.data + transaction.gasLimit, + transaction.to, + transaction.data ); } } diff --git a/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol b/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol index 0f376f821..16127eb28 100644 --- a/contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol +++ b/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/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol b/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol index 9c30f819b..fecd50fcd 100644 --- a/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol +++ b/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol @@ -353,6 +353,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ) override public + view { _revertWithFlag(RevertFlag.INTENTIONAL_REVERT, _data); } @@ -1538,6 +1539,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { RevertFlag _flag ) internal + view { _revertWithFlag(_flag, bytes('')); } diff --git a/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol b/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol index bba7dd59c..0d4194c49 100644 --- a/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol +++ b/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/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol b/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol index 16c956580..7f3fb0f82 100644 --- a/contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol +++ b/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/contracts/optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol b/contracts/optimistic-ethereum/libraries/codec/Lib_EIP155Tx.sol new file mode 100644 index 000000000..8fa764332 --- /dev/null +++ b/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/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol b/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol index 24400667c..0a27865bd 100644 --- a/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol +++ b/contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol @@ -18,11 +18,6 @@ library Lib_OVMCodec { * Enums * *********/ - enum EOASignatureType { - EIP155_TRANSACTON, - 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/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol b/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol index 8040eac0a..4b9c5247b 100644 --- a/contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol +++ b/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/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol b/contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol deleted file mode 100644 index 9d973758b..000000000 --- a/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/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol b/contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol deleted file mode 100644 index ea2469c64..000000000 --- a/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.safeSETNONCE(decodedTx.nonce + 1); - - 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/contracts/test-libraries/codec/TestLib_EIP155Tx.sol b/contracts/test-libraries/codec/TestLib_EIP155Tx.sol new file mode 100644 index 000000000..6019b8695 --- /dev/null +++ b/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/contracts/test-libraries/codec/TestLib_OVMCodec.sol b/contracts/test-libraries/codec/TestLib_OVMCodec.sol index b9046ac8a..9e96dd0cd 100644 --- a/contracts/test-libraries/codec/TestLib_OVMCodec.sol +++ b/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/contracts/test-libraries/utils/TestLib_ECDSAUtils.sol b/contracts/test-libraries/utils/TestLib_ECDSAUtils.sol deleted file mode 100644 index 4b66bf7f0..000000000 --- a/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/src/contract-deployment/config.ts b/src/contract-deployment/config.ts index b12d04960..f4b0072c9 100644 --- a/src/contract-deployment/config.ts +++ b/src/contract-deployment/config.ts @@ -212,9 +212,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/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts b/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts index 166e55596..afecda26c 100644 --- a/test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts +++ b/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,48 +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._gasLimit).to.equal(DEFAULT_EIP155_TX.gasLimit) - expect(ovmCALL._address).to.equal(DEFAULT_EIP155_TX.to) - expect(ovmCALL._calldata).to.equal(DEFAULT_EIP155_TX.data) - - const ovmSETNONCE: any = - Mock__OVM_ExecutionManager.smocked.ovmSETNONCE.calls[0] - expect(ovmSETNONCE._nonce).to.equal(DEFAULT_EIP155_TX.nonce + 1) - }) - - 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. @@ -144,43 +102,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] @@ -190,24 +138,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] @@ -217,52 +155,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 ) @@ -274,21 +192,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/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts b/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts index 2979ad3bc..81bd75986 100644 --- a/test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts +++ b/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/test/contracts/libraries/codec/Lib_EIP155Tx.ts b/test/contracts/libraries/codec/Lib_EIP155Tx.ts new file mode 100644 index 000000000..021f14edc --- /dev/null +++ b/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/test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts b/test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts deleted file mode 100644 index baf3c5a99..000000000 --- a/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/test/data/index.ts b/test/data/index.ts index 8a4a1f7e6..5c9103f5c 100644 --- a/test/data/index.ts +++ b/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/test/data/json/libraries/codec/Lib_EIP155Tx.test.json b/test/data/json/libraries/codec/Lib_EIP155Tx.test.json new file mode 100644 index 000000000..a7536ad4f --- /dev/null +++ b/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/test/data/json/libraries/codec/Lib_OVMCodec.test.json b/test/data/json/libraries/codec/Lib_OVMCodec.test.json index b442f4e07..a55ce0122 100644 --- a/test/data/json/libraries/codec/Lib_OVMCodec.test.json +++ b/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/test/data/json/libraries/utils/Lib_ECDSAUtils.test.json b/test/data/json/libraries/utils/Lib_ECDSAUtils.test.json deleted file mode 100644 index 40f158194..000000000 --- a/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/test/helpers/codec/encoding.ts b/test/helpers/codec/encoding.ts index f7e16531f..869e4feff 100644 --- a/test/helpers/codec/encoding.ts +++ b/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/test/helpers/test-runner/json-test-runner.ts b/test/helpers/test-runner/json-test-runner.ts index 0380ee849..d32626835 100644 --- a/test/helpers/test-runner/json-test-runner.ts +++ b/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)) } })