Commit 9b464f1d authored by Kelvin Fichter's avatar Kelvin Fichter

Added comments to more contracts, added account abstraction

parent b439747a
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContractAccount.sol";
import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol";
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_ECDSAUtils } from "../../libraries/utils/Lib_ECDSAUtils.sol";
/**
* @title OVM_ECDSAContractAccount
*/
contract OVM_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
)
{
iOVM_ExecutionManager ovmExecutionManager = iOVM_ExecutionManager(msg.sender);
// Address of this contract within the ovm (ovmADDRESS) should be the same as the
// recovered address of the user who signed this message. This is how we manage to shim
// account abstraction even though the user isn't a contract.
require(
Lib_ECDSAUtils.recover(
_transaction,
_signatureType == Lib_OVMCodec.EOASignatureType.ETH_SIGNED_MESSAGE,
_v,
_r,
_s,
ovmExecutionManager.ovmCHAINID()
) == ovmExecutionManager.ovmADDRESS(),
"Signature provided for EOA transaction execution is invalid."
);
Lib_OVMCodec.EOATransaction memory decodedTx = Lib_OVMCodec.decodeEOATransaction(_transaction);
// Need to make sure that the transaction nonce is right and bump it if so.
require(
decodedTx.nonce == ovmExecutionManager.ovmGETNONCE() + 1,
"Transaction nonce does not match the expected nonce."
);
ovmExecutionManager.ovmSETNONCE(decodedTx.nonce);
// Contract creations are signalled by sending a transaction to the zero address.
if (decodedTx.target == address(0)) {
address created = ovmExecutionManager.ovmCREATE{gas: decodedTx.gasLimit}(
decodedTx.data
);
// EVM doesn't tell us whether a contract creation failed, even if it reverted during
// initialization. Always return `true` for our success value here.
return (true, abi.encode(created));
} else {
return ovmExecutionManager.ovmCALL(
decodedTx.gasLimit,
decodedTx.target,
decodedTx.data
);
}
}
}
......@@ -4,7 +4,20 @@ pragma solidity ^0.7.0;
/* Interface Imports */
import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol";
/**
* @title OVM_SafetyChecker
*/
contract OVM_SafetyChecker is iOVM_SafetyChecker {
/********************
* Public Functions *
********************/
/**
* Checks that a given bytecode string is considered safe.
* @param _bytecode Bytecode string to check.
* @return _safe Whether or not the bytecode is safe.
*/
function isBytecodeSafe(
bytes memory _bytecode
)
......
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/**
* @title iOVM_ECDSAContractAccount
*/
interface iOVM_ECDSAContractAccount {
/********************
* Public Functions *
********************/
function execute(
bytes memory _transaction,
Lib_OVMCodec.EOASignatureType _signatureType,
uint8 _v,
bytes32 _r,
bytes32 _s
) external returns (bool _success, bytes memory _returndata);
}
......@@ -2,10 +2,14 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_DataTypes } from "../codec/iOVM_DataTypes.sol";
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
interface iOVM_ExecutionManager {
/*******************
* Data Structures *
*******************/
enum RevertFlag {
DID_NOT_REVERT,
OUT_OF_GAS,
......@@ -42,8 +46,13 @@ interface iOVM_ExecutionManager {
RevertFlag revertFlag;
}
/************************************
* Transaction Execution Entrypoint *
************************************/
function run(
iOVM_DataTypes.OVMTransactionData calldata _transaction,
Lib_OVMCodec.Transaction calldata _transaction,
address _txStateManager
) external;
......@@ -73,7 +82,15 @@ interface iOVM_ExecutionManager {
function ovmCREATE(bytes memory _bytecode) external returns (address _contract);
function ovmCREATE2(bytes memory _bytecode, bytes32 _salt) external returns (address _contract);
function safeCREATE(address _address, bytes memory _bytecode) external;
/*******************************
* Account Abstraction Opcodes *
******************************/
function ovmGETNONCE() external returns (uint256 _nonce);
function ovmSETNONCE(uint256 _nonce) external;
function ovmCREATEEOA(bytes32 _messageHash, uint8 _v, bytes32 _r, bytes32 _s) external;
/****************************
......@@ -100,4 +117,11 @@ interface iOVM_ExecutionManager {
function ovmEXTCODECOPY(address _contract, uint256 _offset, uint256 _length) external returns (bytes memory _code);
function ovmEXTCODESIZE(address _contract) external returns (uint256 _size);
function ovmEXTCODEHASH(address _contract) external returns (bytes32 _hash);
/**************************************
* Public Functions: Execution Safety *
**************************************/
function safeCREATE(address _address, bytes memory _bytecode) external;
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
/**
* @title iOVM_SafetyChecker
*/
interface iOVM_SafetyChecker {
/********************
* Public Functions *
********************/
function isBytecodeSafe(bytes memory _bytecode) external view returns (bool _safe);
}
......@@ -2,25 +2,48 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_DataTypes } from "../codec/iOVM_DataTypes.sol";
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/**
* @title iOVM_StateManager
*/
interface iOVM_StateManager {
function putAccount(address _address, iOVM_DataTypes.OVMAccount memory _account) external;
function getAccount(address _address) external returns (iOVM_DataTypes.OVMAccount memory _account);
/*******************
* Data Structures *
*******************/
enum ItemState {
ITEM_UNTOUCHED,
ITEM_LOADED,
ITEM_CHANGED
}
/************************************
* Public Functions: Account Access *
************************************/
function putAccount(address _address, Lib_OVMCodec.Account memory _account) external;
function getAccount(address _address) external returns (Lib_OVMCodec.Account memory _account);
function hasAccount(address _address) external returns (bool _exists);
function incrementAccountNonce(address _address) external;
function setAccountNonce(address _address, uint256 _nonce) external;
function getAccountNonce(address _address) external returns (uint256 _nonce);
function getAccountEthAddress(address _address) external returns (address _ethAddress);
function initPendingAccount(address _address) external;
function commitPendingAccount(address _address, address _ethAddress, bytes32 _codeHash) external;
function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded);
function testAndSetAccountChanged(address _address) external returns (bool _wasAccountAlreadyChanged);
/************************************
* Public Functions: Storage Access *
************************************/
function putContractStorage(address _contract, bytes32 _key, bytes32 _value) external;
function getContractStorage(address _contract, bytes32 _key) external returns (bytes32 _value);
function hasContractStorage(address _contract, bytes32 _key) external returns (bool _exists);
function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded);
function testAndSetAccountChanged(address _address) external returns (bool _wasAccountAlreadyChanged);
function testAndSetContractStorageLoaded(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyLoaded);
function testAndSetContractStorageChanged(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyChanged);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
interface iOVM_DataTypes {
struct OVMAccount {
uint256 nonce;
uint256 balance;
bytes32 storageRoot;
bytes32 codeHash;
address ethAddress;
}
/* Library Imports */
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
/**
* @title Lib_OVMCodec
*/
library Lib_OVMCodec {
/*******************
* Data Structures *
*******************/
struct EVMAccount {
struct Account {
uint256 nonce;
uint256 balance;
bytes32 storageRoot;
bytes32 codeHash;
address ethAddress;
}
struct OVMChainBatchHeader {
struct ChainBatchHeader {
uint256 batchIndex;
bytes32 batchRoot;
uint256 batchSize;
......@@ -25,12 +30,12 @@ interface iOVM_DataTypes {
bytes extraData;
}
struct OVMChainInclusionProof {
struct ChainInclusionProof {
uint256 index;
bytes32[] siblings;
}
struct OVMTransactionData {
struct Transaction {
uint256 timestamp;
uint256 queueOrigin;
address entrypoint;
......@@ -40,16 +45,57 @@ interface iOVM_DataTypes {
bytes data;
}
struct OVMProofMatrix {
struct ProofMatrix {
bool checkNonce;
bool checkBalance;
bool checkStorageRoot;
bool checkCodeHash;
}
struct OVMQueueElement {
struct QueueElement {
uint256 timestamp;
bytes32 batchRoot;
bool isL1ToL2Batch;
}
struct EOATransaction {
address target;
uint256 nonce;
uint256 gasLimit;
bytes data;
}
enum EOASignatureType {
ETH_SIGNED_MESSAGE,
NATIVE_TRANSACTON
}
/*********************************************
* Internal Functions: Encoding and Decoding *
*********************************************/
/**
* Decodes an EOA transaction (i.e., native Ethereum RLP encoding).
* @param _transaction Encoded EOA transaction.
* @return _decoded Transaction decoded into a struct.
*/
function decodeEOATransaction(
bytes memory _transaction
)
internal
pure
returns (
EOATransaction memory _decoded
)
{
Lib_RLPReader.RLPItem[] memory decoded = Lib_RLPReader.toList(Lib_RLPReader.toRlpItem(_transaction));
return EOATransaction({
nonce: Lib_RLPReader.toUint(decoded[0]),
gasLimit: Lib_RLPReader.toUint(decoded[2]),
target: Lib_RLPReader.toAddress(decoded[3]),
data: Lib_RLPReader.toBytes(decoded[5])
});
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.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.
* @param _chainId Chain ID parameter.
* @return _sender Signer address.
*/
function recover(
bytes memory _message,
bool _isEthSignedMessage,
uint8 _v,
bytes32 _r,
bytes32 _s,
uint256 _chainId
)
internal
pure
returns (
address _sender
)
{
bytes32 messageHash;
if (_isEthSignedMessage) {
messageHash = getEthSignedMessageHash(_message);
} else {
messageHash = getNativeMessageHash(_message);
}
return ecrecover(
messageHash,
(_v - uint8(_chainId) * 2) - 8,
_r,
_s
);
}
/*************************************
* 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
......@@ -5,7 +5,22 @@ pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
/**
* @title Lib_EthUtils
*/
library Lib_EthUtils {
/***********************************
* Internal Functions: Code Access *
***********************************/
/**
* Gets the code for a given address.
* @param _address Address to get code for.
* @param _offset Offset to start reading from.
* @param _length Number of bytes to read.
* @return _code Code read from the contract.
*/
function getCode(
address _address,
uint256 _offset,
......@@ -27,6 +42,11 @@ library Lib_EthUtils {
return _code;
}
/**
* Gets the full code for a given address.
* @param _address Address to get code for.
* @return _code Full code of the contract.
*/
function getCode(
address _address
)
......@@ -43,6 +63,11 @@ library Lib_EthUtils {
);
}
/**
* Gets the size of a contract's code in bytes.
* @param _address Address to get code size for.
* @return _codeSize Size of the contract's code in bytes.
*/
function getCodeSize(
address _address
)
......@@ -59,6 +84,11 @@ library Lib_EthUtils {
return _codeSize;
}
/**
* Gets the hash of a contract's code.
* @param _address Address to get a code hash for.
* @return _codeHash Hash of the contract's code.
*/
function getCodeHash(
address _address
)
......@@ -75,6 +105,16 @@ library Lib_EthUtils {
return _codeHash;
}
/*****************************************
* Internal Functions: Contract Creation *
*****************************************/
/**
* Creates a contract with some given initialization code.
* @param _code Contract initialization code.
* @return _created Address of the created contract.
*/
function createContract(
bytes memory _code
)
......@@ -94,6 +134,12 @@ library Lib_EthUtils {
return _created;
}
/**
* Computes the address that would be generated by CREATE.
* @param _creator Address creating the contract.
* @param _nonce Creator's nonce.
* @return _address Address to be generated by CREATE.
*/
function getAddressForCREATE(
address _creator,
uint256 _nonce
......@@ -112,6 +158,13 @@ library Lib_EthUtils {
return getAddressFromHash(keccak256(encodedList));
}
/**
* Computes the address that would be generated by CREATE2.
* @param _creator Address creating the contract.
* @param _bytecode Bytecode of the contract to be created.
* @param _salt 32 byte salt value mixed into the hash.
* @return _address Address to be generated by CREATE2.
*/
function getAddressForCREATE2(
address _creator,
bytes memory _bytecode,
......@@ -131,19 +184,26 @@ library Lib_EthUtils {
return getAddressFromHash(hashedData);
}
/****************************************
* Private Functions: Contract Creation *
****************************************/
/**
* Determines an address from a 32 byte hash. Since addresses are only
* 20 bytes, we need to retrieve the last 20 bytes from the original
* hash. Converting to uint256 and then uint160 gives us these bytes.
* @param _hash Hash to convert to an address.
* @return Hash converted to an address.
* @return _address Hash converted to an address.
*/
function getAddressFromHash(
bytes32 _hash
)
private
pure
returns (address)
returns (
address _address
)
{
return address(bytes20(uint160(uint256(_hash))));
}
......
import { expect } from '../../setup'
/* External Imports */
import { ethers } from '@nomiclabs/buidler'
import { Contract, ContractFactory } from 'ethers'
describe('Proxy_Forwarder', () => {
describe('fallback', () => {
})
})
import { expect } from '../../setup'
/* External Imports */
import { ethers } from '@nomiclabs/buidler'
import { Contract, ContractFactory } from 'ethers'
describe('Proxy_Manager', () => {
describe('setProxy', () => {
})
describe('getProxy', () => {
})
describe('hasProxy', () => {
})
describe('isProxy', () => {
})
describe('setTarget', () => {
})
describe('getTarget', () => {
})
describe('hasTarget', () => {
})
describe('isTarget', () => {
})
})
import { expect } from '../../setup'
/* External Imports */
import { ethers } from '@nomiclabs/buidler'
import { Contract, ContractFactory } from 'ethers'
describe('Proxy_Resolver', () => {
describe('resolve', () => {
})
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment