Commit 2ff18bb4 authored by Georgios Konstantopoulos's avatar Georgios Konstantopoulos Committed by GitHub

Import contracts (#18)

* feat: add contracts

* fix: configure tsconfig and replace build => dist

* chore: remove CI files

* chore: use monorepo tslint / prettier
parent c0915588
node_modules node_modules
**/dist
results results
temp temp
.nyc_output .nyc_output
*.tsbuildinfo *.tsbuildinfo
build
dist
artifacts
artifacts-ovm
cache
cache-ovm
*.sol linguist-language=Solidity
# Changelog
## v0.1.11
- cleanup: ECDSAContractAccount
- cleanup: Proxy_EOA
- cleanup: StateManagerFactory
- cleanup: Bytes32Utils
- cleanup: Minor cleanup to state manager
- cleanup: SafetyChecker
- Remove gas estimators from gateway interface
- Add ERC1820 Registry as a precompile
- dev: Remove usage of custom concat function in Solidity
- Fix revert string generated by EM wrapper
- Update OVM_L1ERC20Gateway.sol
- Move OVM_BondManager test into the right location
## v0.1.10
Adds extensible ERC20Gateway and Improve CI.
- dev: Apply linting to all test files
- Test gas consumption of EM.run()
- Extensible deposit withdraw
- Update OVM_L2DepositedERC20.sol
- Commit state dumps to regenesis repo for new tags
- Update OVM_ChainStorageContainer.sol
- Update OVM_ECDSAContractAccount.sol
- Update OVM_CanonicalTransactionChain.sol
- Reset Context on invalid gaslimit
- [Fix] CI on merge
- [Fix] Run integration tests in forked context
## v0.1.9
Standardized ETH and ERC20 Gateways.
- Add ETH deposit contract.
- Add standard deposit/withdrawal interfaces.
## v0.1.5
Various cleanup and maintenance tasks.
- Improving comments and some names (#211)
- Add descriptive comments above the contract declaration for all 'non-abstract contracts' (#200)
- Add generic mock xdomain messenger (#209)
- Move everything over to hardhat (#208)
- Add comment to document v argument (#199)
- Add security related comments (#191)
## v0.1.4
Fix single contract redeployment & state dump script for
mainnet.
## v0.1.3
Add events to fraud proof initialization and finalization.
## v0.1.2
Npm publish integrity.
## v0.1.1
Audit fixes, deployment fixes & final parameterization.
- Add build mainnet command to package.json (#186)
- revert chain ID 422 -> 420 (#185)
- add `AddressSet` event (#184)
- Add mint & burn to L2 ETH (#178)
- Wait for deploy transactions (#180)
- Final Parameterization of Constants (#176)
- re-enable monotonicity tests (#177)
- make ovmSETNONCE notStatic (#179)
- Add reentry protection to ExecutionManager.run() (#175)
- Add nonReentrant to `relayMessage()` (#172)
- ctc: public getters, remove dead variable (#174)
- fix tainted memory bug in `Lib_BytesUtils.slice` (#171)
## v0.1.0
Initial Release
(The MIT License)
Copyright 2020 Optimism
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
# Optimistic Ethereum Smart Contracts
`@eth-optimism/contracts` contains the various Solidity smart contracts used within the Optimistic Ethereum system.
Some of these contracts are deployed on Ethereum ("Layer 1"), while others are meant to be deployed to Optimistic Ethereum ("Layer 2").
Within each contract file you'll find a comment that lists:
1. The compiler with which a contract is intended to be compiled, `solc` or `optimistic-solc`.
2. The network upon to which the contract will be deployed, `OVM` or `EVM`.
A more detailed overview of these contracts can be found on the [community hub](http://community.optimism.io/docs/protocol/protocol.html#system-overview).
<!-- TODO: Add link to final contract docs here when finished. -->
## Usage (npm)
If your development stack is based on Node/npm:
```shell
npm install @eth-optimism/contracts
```
Within your contracts:
```solidity
import { SomeContract } from "@eth-optimism/contracts/SomeContract.sol";
```
## Guide for Developers
### Setup
Install the following:
- [`Node.js` (14+)](https://nodejs.org/en/)
- [`npm`](https://www.npmjs.com/get-npm)
- [`yarn`](https://classic.yarnpkg.com/en/docs/install/)
Clone the repo:
```shell
git clone https://github.com/ethereum-optimism/contracts.git
cd contracts
```
Install `npm` packages:
```shell
yarn install
```
### Running Tests
Tests are executed via `yarn`:
```shell
yarn test
```
Run specific tests by giving a path to the file you want to run:
```shell
yarn test ./test/path/to/my/test.spec.ts
```
### Compiling and Building
Easiest way is to run the primary build script:
```shell
yarn build
```
Running the full build command will perform the following actions:
1. `build:contracts` - Compile all Solidity contracts with both the EVM and OVM compilers.
2. `build:typescript` - Builds the typescript files that are used to export utilities into js.
3. `build:copy` - Copies various other files into the dist folder.
4. `build:dump` - Generates a genesis state from the contracts that L2 geth will use.
5. `build:typechain` - Generates [TypeChain](https://github.com/ethereum-ts/TypeChain) artifacts.
You can also build specific components as follows:
```shell
yarn build:contracts
```
## Security
Please refer to our [Security Policy](https://github.com/ethereum-optimism/.github/security/policy) for information about how to disclose security issues with this code.
#!/usr/bin/env node
const contracts = require('../dist/src/contract-deployment/deploy');
const { providers, Wallet, utils, ethers } = require('ethers');
const { LedgerSigner } = require('@ethersproject/hardware-wallets');
const { JsonRpcProvider } = providers;
const env = process.env;
const key = env.DEPLOYER_PRIVATE_KEY;
const sequencerKey = env.SEQUENCER_PRIVATE_KEY;
let SEQUENCER_ADDRESS = env.SEQUENCER_ADDRESS;
const web3Url = env.L1_NODE_WEB3_URL || 'http://127.0.0.1:8545';
const DEPLOY_TX_GAS_LIMIT = env.DEPLOY_TX_GAS_LIMIT || 5000000;
const MIN_TRANSACTION_GAS_LIMIT = env.MIN_TRANSACTION_GAS_LIMIT || 50000;
const MAX_TRANSACTION_GAS_LIMIT = env.MAX_TRANSACTION_GAS_LIMIT || 9000000;
const MAX_GAS_PER_QUEUE_PER_EPOCH = env.MAX_GAS_PER_QUEUE_PER_EPOCH || 250000000;
const SECONDS_PER_EPOCH = env.SECONDS_PER_EPOCH || 0;
const WAIT_FOR_RECEIPTS = env.WAIT_FOR_RECEIPTS === 'true';
let WHITELIST_OWNER = env.WHITELIST_OWNER;
const WHITELIST_ALLOW_ARBITRARY_CONTRACT_DEPLOYMENT = env.WHITELIST_ALLOW_ARBITRARY_CONTRACT_DEPLOYMENT || true;
const FORCE_INCLUSION_PERIOD_SECONDS = env.FORCE_INCLUSION_PERIOD_SECONDS || 2592000; // 30 days
const FRAUD_PROOF_WINDOW_SECONDS = env.FRAUD_PROOF_WINDOW_SECONDS || (60 * 60 * 24 * 7); // 7 days
const SEQUENCER_PUBLISH_WINDOW_SECONDS = env.SEQUENCER_PUBLISH_WINDOW_SECONDS || (60 * 30); // 30 min
const CHAIN_ID = env.CHAIN_ID || 420; // layer 2 chainid
const USE_LEDGER = env.USE_LEDGER || false;
const ADDRESS_MANAGER_ADDRESS = env.ADDRESS_MANAGER_ADDRESS || undefined;
const HD_PATH = env.HD_PATH || utils.defaultPath;
const BLOCK_TIME_SECONDS = env.BLOCK_TIME_SECONDS || 15;
const L2_CROSS_DOMAIN_MESSENGER_ADDRESS =
env.L2_CROSS_DOMAIN_MESSENGER_ADDRESS || '0x4200000000000000000000000000000000000007';
let RELAYER_ADDRESS = env.RELAYER_ADDRESS || '0x0000000000000000000000000000000000000000';
const RELAYER_PRIVATE_KEY = env.RELAYER_PRIVATE_KEY;
(async () => {
const provider = new JsonRpcProvider(web3Url);
let signer;
// Use the ledger for the deployer
if (USE_LEDGER) {
signer = new LedgerSigner(provider, 'default', HD_PATH);
} else {
if (typeof key === 'undefined')
throw new Error('Must pass deployer key as DEPLOYER_PRIVATE_KEY');
signer = new Wallet(key, provider);
}
if (SEQUENCER_ADDRESS) {
if (!utils.isAddress(SEQUENCER_ADDRESS))
throw new Error(`Invalid Sequencer Address: ${SEQUENCER_ADDRESS}`);
} else {
if (!sequencerKey)
throw new Error('Must pass sequencer key as SEQUENCER_PRIVATE_KEY');
const sequencer = new Wallet(sequencerKey, provider);
SEQUENCER_ADDRESS = await sequencer.getAddress();
}
if (typeof WHITELIST_OWNER === 'undefined')
WHITELIST_OWNER = signer;
// Use the address derived from RELAYER_PRIVATE_KEY if a private key
// is passed. Using the zero address as the relayer address will mean
// there is no relayer authentication.
if (RELAYER_PRIVATE_KEY) {
if (!utils.isAddress(RELAYER_ADDRESS))
throw new Error(`Invalid Relayer Address: ${RELAYER_ADDRESS}`);
const relayer = new Wallet(RELAYER_PRIVATE_KEY, provider);
RELAYER_ADDRESS = await relayer.getAddress();
}
const result = await contracts.deploy({
deploymentSigner: signer,
transactionChainConfig: {
forceInclusionPeriodSeconds: FORCE_INCLUSION_PERIOD_SECONDS,
sequencer: SEQUENCER_ADDRESS,
forceInclusionPeriodBlocks: Math.ceil(FORCE_INCLUSION_PERIOD_SECONDS/BLOCK_TIME_SECONDS),
},
stateChainConfig: {
fraudProofWindowSeconds: FRAUD_PROOF_WINDOW_SECONDS,
sequencerPublishWindowSeconds: SEQUENCER_PUBLISH_WINDOW_SECONDS,
},
ovmGlobalContext: {
ovmCHAINID: CHAIN_ID,
L2CrossDomainMessengerAddress: L2_CROSS_DOMAIN_MESSENGER_ADDRESS
},
l1CrossDomainMessengerConfig: {
relayerAddress: RELAYER_ADDRESS,
},
ovmGasMeteringConfig: {
minTransactionGasLimit: MIN_TRANSACTION_GAS_LIMIT,
maxTransactionGasLimit: MAX_TRANSACTION_GAS_LIMIT,
maxGasPerQueuePerEpoch: MAX_GAS_PER_QUEUE_PER_EPOCH,
secondsPerEpoch: SECONDS_PER_EPOCH
},
whitelistConfig: {
owner: WHITELIST_OWNER,
allowArbitraryContractDeployment: WHITELIST_ALLOW_ARBITRARY_CONTRACT_DEPLOYMENT
},
deployOverrides: {
gasLimit: DEPLOY_TX_GAS_LIMIT
},
waitForReceipts: WAIT_FOR_RECEIPTS,
addressManager: ADDRESS_MANAGER_ADDRESS,
});
const { failedDeployments, AddressManager } = result;
if (failedDeployments.length !== 0)
throw new Error(`Contract deployment failed: ${failedDeployments.join(',')}`);
const out = {};
out.AddressManager = AddressManager.address;
out.OVM_Sequencer = SEQUENCER_ADDRESS;
out.Deployer = await signer.getAddress()
for (const [name, contract] of Object.entries(result.contracts)) {
out[name] = contract.address;
}
console.log(JSON.stringify(out, null, 2));
})().catch(err => {
console.log(JSON.stringify({error: err.message, stack: err.stack}, null, 2));
process.exit(1);
});
#!/usr/bin/env python3
# pip3 install pyevmasm
from pyevmasm import instruction_tables
#print(instruction_tables.keys())
def asm(x):
return [instruction_tables['istanbul'][i].opcode for i in x]
push_opcodes = asm(["PUSH%d" % i for i in range(1,33)])
stop_opcodes = asm(["STOP", "JUMP", "RETURN", "INVALID"])
caller_opcodes = asm(["CALLER"])
blacklist_ops = set([
"ADDRESS", "BALANCE", "BLOCKHASH",
"CALL", "CALLCODE", "CHAINID", "COINBASE",
"CREATE", "CREATE2", "DELEGATECALL", "DIFFICULTY",
"EXTCODESIZE", "EXTCODECOPY", "EXTCODEHASH",
"GASLIMIT", "GASPRICE", "NUMBER",
"ORIGIN", "REVERT", "SELFBALANCE", "SELFDESTRUCT",
"SLOAD", "SSTORE", "STATICCALL", "TIMESTAMP"])
whitelist_opcodes = []
for x in instruction_tables['istanbul']:
if x.name not in blacklist_ops:
whitelist_opcodes.append(x.opcode)
pushmask = 0
for x in push_opcodes:
pushmask |= 1 << x
stopmask = 0
for x in stop_opcodes:
stopmask |= 1 << x
stoplist = [0]*256
procmask = 0
for i in range(256):
if i in whitelist_opcodes and \
i not in push_opcodes and \
i not in stop_opcodes and \
i not in caller_opcodes:
# can skip this opcode
stoplist[i] = 1
else:
procmask |= 1 << i
# PUSH1 through PUSH4, can't skip in slow
for i in range(0x60, 0x64):
stoplist[i] = i-0x5e
rr = "uint256[8] memory opcodeSkippableBytes = [\n"
for i in range(0, 0x100, 0x20):
ret = "uint256(0x"
for j in range(i, i+0x20, 1):
ret += ("%02X" % stoplist[j])
rr += ret+"),\n"
rr = rr[:-2] + "];"
print(rr)
print("// Mask to gate opcode specific cases")
print("uint256 opcodeGateMask = ~uint256(0x%x);" % procmask)
print("// Halting opcodes")
print("uint256 opcodeHaltingMask = ~uint256(0x%x);" % stopmask)
print("// PUSH opcodes")
print("uint256 opcodePushMask = ~uint256(0x%x);" % pushmask)
#!/bin/bash
# Run this script to serve the latest state dump from
# an http server. This is useful to serve the state dump
# to a local instance of the sequencer/verifier during
# development. The state dump can be found at
# `GET /state-dump.latest.json`
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )"
PYTHON=${PYTHON:-python}
HOST=${HOST:-0.0.0.0}
PORT=${PORT:-8081}
DIRECTORY=$DIR/../dist/dumps
if [ ! command -v $PYTHON&>/dev/null ]; then
echo "Please install python"
exit 1
fi
VERSION=$($PYTHON --version 2>&1 \
| cut -d ' ' -f2 \
| sed -Ee's#([^/]).([^/]).([^/])#\1#')
if [[ $VERSION == 3 ]]; then
$PYTHON -m http.server \
--bind $HOST $PORT \
--directory $DIRECTORY
else
(
echo "Serving HTTP on $HOST port $PORT"
cd $DIRECTORY
$PYTHON -c \
'import BaseHTTPServer as bhs, SimpleHTTPServer as shs; bhs.HTTPServer(("'$HOST'", '"$PORT"'), shs.SimpleHTTPRequestHandler).serve_forever()'
)
fi
/* External Imports */
import * as fs from 'fs'
import * as path from 'path'
import * as mkdirp from 'mkdirp'
const env = process.env
const CHAIN_ID = env.CHAIN_ID || '420'
/* Internal Imports */
import { makeStateDump } from '../src/contract-dumps'
import { RollupDeployConfig } from '../src/contract-deployment'
;(async () => {
const outdir = path.resolve(__dirname, '../dist/dumps')
const outfile = path.join(outdir, 'state-dump.latest.json')
mkdirp.sync(outdir)
const config = {
ovmGlobalContext: {
ovmCHAINID: parseInt(CHAIN_ID, 10),
},
}
const dump = await makeStateDump(config as RollupDeployConfig)
fs.writeFileSync(outfile, JSON.stringify(dump, null, 4))
})()
// 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";
import { Lib_SafeMathWrapper } from "../../libraries/wrappers/Lib_SafeMathWrapper.sol";
/**
* @title OVM_ECDSAContractAccount
* @dev The ECDSA Contract Account can be used as the implementation for a ProxyEOA deployed by the
* ovmCREATEEOA operation. It enables backwards compatibility with Ethereum's Layer 1, by
* providing eth_sign and EIP155 formatted transaction encodings.
*
* Compiler used: solc
* Runtime target: OVM
*/
contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {
/*************
* Constants *
*************/
// TODO: should be the amount sufficient to cover the gas costs of all of the transactions up
// to and including the CALL/CREATE which forms the entrypoint of the transaction.
uint256 constant EXECUTION_VALIDATION_GAS_OVERHEAD = 25000;
address constant ETH_ERC20_ADDRESS = 0x4200000000000000000000000000000000000006;
/********************
* 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 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
)
override
public
returns (
bool,
bytes memory
)
{
bool isEthSign = _signatureType == Lib_OVMCodec.EOASignatureType.ETH_SIGNED_MESSAGE;
// Address of this contract within the ovm (ovmADDRESS) should be the same as the
// recovered address of the user who signed this message. This is how we manage to shim
// account abstraction even though the user isn't a contract.
// Need to make sure that the transaction nonce is right and bump it if so.
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
Lib_ECDSAUtils.recover(
_transaction,
isEthSign,
_v,
_r,
_s
) == Lib_SafeExecutionManagerWrapper.safeADDRESS(),
"Signature provided for EOA transaction execution is invalid."
);
Lib_OVMCodec.EIP155Transaction memory decodedTx = Lib_OVMCodec.decodeEIP155Transaction(_transaction, isEthSign);
// Need to make sure that the transaction chainId is correct.
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
decodedTx.chainId == Lib_SafeExecutionManagerWrapper.safeCHAINID(),
"Transaction chainId does not match expected OVM chainId."
);
// Need to make sure that the transaction nonce is right.
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
decodedTx.nonce == Lib_SafeExecutionManagerWrapper.safeGETNONCE(),
"Transaction nonce does not match the expected nonce."
);
// TEMPORARY: Disable gas checks for mainnet.
// // Need to make sure that the gas is sufficient to execute the transaction.
// Lib_SafeExecutionManagerWrapper.safeREQUIRE(
// gasleft() >= Lib_SafeMathWrapper.add(decodedTx.gasLimit, EXECUTION_VALIDATION_GAS_OVERHEAD),
// "Gas is not sufficient to execute the transaction."
// );
// Transfer fee to relayer.
address relayer = Lib_SafeExecutionManagerWrapper.safeCALLER();
uint256 fee = Lib_SafeMathWrapper.mul(decodedTx.gasLimit, decodedTx.gasPrice);
(bool success, ) = Lib_SafeExecutionManagerWrapper.safeCALL(
gasleft(),
ETH_ERC20_ADDRESS,
abi.encodeWithSignature("transfer(address,uint256)", relayer, fee)
);
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
success == true,
"Fee was not transferred to relayer."
);
// Contract creations are signalled by sending a transaction to the zero address.
if (decodedTx.to == address(0)) {
(address created, bytes memory revertData) = Lib_SafeExecutionManagerWrapper.safeCREATE(
decodedTx.gasLimit,
decodedTx.data
);
// Return true if the contract creation succeeded, false w/ revertData otherwise.
if (created != address(0)) {
return (true, abi.encode(created));
} else {
return (false, revertData);
}
} else {
// We only want to bump the nonce for `ovmCALL` because `ovmCREATE` automatically bumps
// the nonce of the calling account. Normally an EOA would bump the nonce for both
// cases, but since this is a contract we'd end up bumping the nonce twice.
Lib_SafeExecutionManagerWrapper.safeINCREMENTNONCE();
return Lib_SafeExecutionManagerWrapper.safeCALL(
decodedTx.gasLimit,
decodedTx.to,
decodedTx.data
);
}
}
}
// SPDX-License-Identifier: MIT
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";
/**
* @title OVM_ProxyEOA
* @dev The Proxy EOA contract uses a delegate call to execute the logic in an implementation contract.
* In combination with the logic implemented in the ECDSA Contract Account, this enables a form of upgradable
* 'account abstraction' on layer 2.
*
* Compiler used: solc
* Runtime target: OVM
*/
contract OVM_ProxyEOA {
/*************
* Constants *
*************/
bytes32 constant IMPLEMENTATION_KEY = 0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead;
/***************
* Constructor *
***************/
/**
* @param _implementation Address of the initial implementation contract.
*/
constructor(
address _implementation
)
{
_setImplementation(_implementation);
}
/*********************
* Fallback Function *
*********************/
fallback()
external
{
(bool success, bytes memory returndata) = Lib_SafeExecutionManagerWrapper.safeDELEGATECALL(
gasleft(),
getImplementation(),
msg.data
);
if (success) {
assembly {
return(add(returndata, 0x20), mload(returndata))
}
} else {
Lib_SafeExecutionManagerWrapper.safeREVERT(
string(returndata)
);
}
}
/********************
* Public Functions *
********************/
/**
* Changes the implementation address.
* @param _implementation New implementation address.
*/
function upgrade(
address _implementation
)
external
{
Lib_SafeExecutionManagerWrapper.safeREQUIRE(
Lib_SafeExecutionManagerWrapper.safeADDRESS() == Lib_SafeExecutionManagerWrapper.safeCALLER(),
"EOAs can only upgrade their own EOA implementation"
);
_setImplementation(_implementation);
}
/**
* Gets the address of the current implementation.
* @return Current implementation address.
*/
function getImplementation()
public
returns (
address
)
{
return Lib_Bytes32Utils.toAddress(
Lib_SafeExecutionManagerWrapper.safeSLOAD(
IMPLEMENTATION_KEY
)
);
}
/**********************
* Internal Functions *
**********************/
function _setImplementation(
address _implementation
)
internal
{
Lib_SafeExecutionManagerWrapper.safeSSTORE(
IMPLEMENTATION_KEY,
Lib_Bytes32Utils.fromAddress(_implementation)
);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iAbs_BaseCrossDomainMessenger } from "../../../iOVM/bridge/messaging/iAbs_BaseCrossDomainMessenger.sol";
/* Library Imports */
import { Lib_ReentrancyGuard } from "../../../libraries/utils/Lib_ReentrancyGuard.sol";
/**
* @title Abs_BaseCrossDomainMessenger
* @dev The Base Cross Domain Messenger is an abstract contract providing the interface and common functionality used in the
* L1 and L2 Cross Domain Messengers. It can also serve as a template for developers wishing to implement a custom bridge
* contract to suit their needs.
*
* Compiler used: defined by child contract
* Runtime target: defined by child contract
*/
abstract contract Abs_BaseCrossDomainMessenger is iAbs_BaseCrossDomainMessenger, Lib_ReentrancyGuard {
/**************
* Constants *
**************/
// The default x-domain message sender being set to a non-zero value makes
// deployment a bit more expensive, but in exchange the refund on every call to
// `relayMessage` by the L1 and L2 messengers will be higher.
address internal constant DEFAULT_XDOMAIN_SENDER = 0x000000000000000000000000000000000000dEaD;
/**********************
* Contract Variables *
**********************/
mapping (bytes32 => bool) public relayedMessages;
mapping (bytes32 => bool) public successfulMessages;
mapping (bytes32 => bool) public sentMessages;
uint256 public messageNonce;
address internal xDomainMsgSender = DEFAULT_XDOMAIN_SENDER;
/********************
* Public Functions *
********************/
constructor() Lib_ReentrancyGuard() {}
function xDomainMessageSender() public override view returns (address) {
require(xDomainMsgSender != DEFAULT_XDOMAIN_SENDER, "xDomainMessageSender is not set");
return xDomainMsgSender;
}
/**
* Sends a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _message Message to send to the target.
* @param _gasLimit Gas limit for the provided message.
*/
function sendMessage(
address _target,
bytes memory _message,
uint32 _gasLimit
)
override
public
{
bytes memory xDomainCalldata = _getXDomainCalldata(
_target,
msg.sender,
_message,
messageNonce
);
messageNonce += 1;
sentMessages[keccak256(xDomainCalldata)] = true;
_sendXDomainMessage(xDomainCalldata, _gasLimit);
emit SentMessage(xDomainCalldata);
}
/**********************
* Internal Functions *
**********************/
/**
* Generates the correct cross domain calldata for a message.
* @param _target Target contract address.
* @param _sender Message sender address.
* @param _message Message to send to the target.
* @param _messageNonce Nonce for the provided message.
* @return ABI encoded cross domain calldata.
*/
function _getXDomainCalldata(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce
)
internal
pure
returns (
bytes memory
)
{
return abi.encodeWithSignature(
"relayMessage(address,address,bytes,uint256)",
_target,
_sender,
_message,
_messageNonce
);
}
/**
* Sends a cross domain message.
* param // Message to send.
* param // Gas limit for the provided message.
*/
function _sendXDomainMessage(
bytes memory, // _message,
uint256 // _gasLimit
)
virtual
internal
{
revert("Implement me in child contracts!");
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_AddressManager } from "../../../libraries/resolver/Lib_AddressManager.sol";
import { Lib_SecureMerkleTrie } from "../../../libraries/trie/Lib_SecureMerkleTrie.sol";
import { Lib_ReentrancyGuard } from "../../../libraries/utils/Lib_ReentrancyGuard.sol";
/* Interface Imports */
import { iOVM_L1CrossDomainMessenger } from "../../../iOVM/bridge/messaging/iOVM_L1CrossDomainMessenger.sol";
import { iOVM_CanonicalTransactionChain } from "../../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
import { iOVM_StateCommitmentChain } from "../../../iOVM/chain/iOVM_StateCommitmentChain.sol";
/* Contract Imports */
import { Abs_BaseCrossDomainMessenger } from "./Abs_BaseCrossDomainMessenger.sol";
/**
* @title OVM_L1CrossDomainMessenger
* @dev The L1 Cross Domain Messenger contract sends messages from L1 to L2, and relays messages from L2 onto L1.
* In the event that a message sent from L1 to L2 is rejected for exceeding the L2 epoch gas limit, it can be resubmitted
* via this contract's replay function.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, Abs_BaseCrossDomainMessenger, Lib_AddressResolver {
/***************
* Constructor *
***************/
/**
* Pass a default zero address to the address resolver. This will be updated when initialized.
*/
constructor()
Lib_AddressResolver(address(0))
{}
/**
* @param _libAddressManager Address of the Address Manager.
*/
function initialize(
address _libAddressManager
)
public
{
require(address(libAddressManager) == address(0), "L1CrossDomainMessenger already intialized.");
libAddressManager = Lib_AddressManager(_libAddressManager);
xDomainMsgSender = DEFAULT_XDOMAIN_SENDER;
}
/**********************
* Function Modifiers *
**********************/
/**
* Modifier to enforce that, if configured, only the OVM_L2MessageRelayer contract may successfully call a method.
*/
modifier onlyRelayer() {
address relayer = resolve("OVM_L2MessageRelayer");
if (relayer != address(0)) {
require(
msg.sender == relayer,
"Only OVM_L2MessageRelayer can relay L2-to-L1 messages."
);
}
_;
}
/********************
* Public Functions *
********************/
/**
* Relays a cross domain message to a contract.
* @inheritdoc iOVM_L1CrossDomainMessenger
*/
function relayMessage(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce,
L2MessageInclusionProof memory _proof
)
override
public
nonReentrant
onlyRelayer()
{
bytes memory xDomainCalldata = _getXDomainCalldata(
_target,
_sender,
_message,
_messageNonce
);
require(
_verifyXDomainMessage(
xDomainCalldata,
_proof
) == true,
"Provided message could not be verified."
);
bytes32 xDomainCalldataHash = keccak256(xDomainCalldata);
require(
successfulMessages[xDomainCalldataHash] == false,
"Provided message has already been received."
);
xDomainMsgSender = _sender;
(bool success, ) = _target.call(_message);
xDomainMsgSender = DEFAULT_XDOMAIN_SENDER;
// Mark the message as received if the call was successful. Ensures that a message can be
// relayed multiple times in the case that the call reverted.
if (success == true) {
successfulMessages[xDomainCalldataHash] = true;
emit RelayedMessage(xDomainCalldataHash);
}
// Store an identifier that can be used to prove that the given message was relayed by some
// user. Gives us an easy way to pay relayers for their work.
bytes32 relayId = keccak256(
abi.encodePacked(
xDomainCalldata,
msg.sender,
block.number
)
);
relayedMessages[relayId] = true;
}
/**
* Replays a cross domain message to the target messenger.
* @inheritdoc iOVM_L1CrossDomainMessenger
*/
function replayMessage(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce,
uint32 _gasLimit
)
override
public
{
bytes memory xDomainCalldata = _getXDomainCalldata(
_target,
_sender,
_message,
_messageNonce
);
require(
sentMessages[keccak256(xDomainCalldata)] == true,
"Provided message has not already been sent."
);
_sendXDomainMessage(xDomainCalldata, _gasLimit);
}
/**********************
* Internal Functions *
**********************/
/**
* Verifies that the given message is valid.
* @param _xDomainCalldata Calldata to verify.
* @param _proof Inclusion proof for the message.
* @return Whether or not the provided message is valid.
*/
function _verifyXDomainMessage(
bytes memory _xDomainCalldata,
L2MessageInclusionProof memory _proof
)
internal
view
returns (
bool
)
{
return (
_verifyStateRootProof(_proof)
&& _verifyStorageProof(_xDomainCalldata, _proof)
);
}
/**
* Verifies that the state root within an inclusion proof is valid.
* @param _proof Message inclusion proof.
* @return Whether or not the provided proof is valid.
*/
function _verifyStateRootProof(
L2MessageInclusionProof memory _proof
)
internal
view
returns (
bool
)
{
iOVM_StateCommitmentChain ovmStateCommitmentChain = iOVM_StateCommitmentChain(resolve("OVM_StateCommitmentChain"));
return (
ovmStateCommitmentChain.insideFraudProofWindow(_proof.stateRootBatchHeader) == false
&& ovmStateCommitmentChain.verifyStateCommitment(
_proof.stateRoot,
_proof.stateRootBatchHeader,
_proof.stateRootProof
)
);
}
/**
* Verifies that the storage proof within an inclusion proof is valid.
* @param _xDomainCalldata Encoded message calldata.
* @param _proof Message inclusion proof.
* @return Whether or not the provided proof is valid.
*/
function _verifyStorageProof(
bytes memory _xDomainCalldata,
L2MessageInclusionProof memory _proof
)
internal
view
returns (
bool
)
{
bytes32 storageKey = keccak256(
abi.encodePacked(
keccak256(
abi.encodePacked(
_xDomainCalldata,
resolve("OVM_L2CrossDomainMessenger")
)
),
uint256(0)
)
);
(
bool exists,
bytes memory encodedMessagePassingAccount
) = Lib_SecureMerkleTrie.get(
abi.encodePacked(0x4200000000000000000000000000000000000000),
_proof.stateTrieWitness,
_proof.stateRoot
);
require(
exists == true,
"Message passing predeploy has not been initialized or invalid proof provided."
);
Lib_OVMCodec.EVMAccount memory account = Lib_OVMCodec.decodeEVMAccount(
encodedMessagePassingAccount
);
return Lib_SecureMerkleTrie.verifyInclusionProof(
abi.encodePacked(storageKey),
abi.encodePacked(uint8(1)),
_proof.storageTrieWitness,
account.storageRoot
);
}
/**
* Sends a cross domain message.
* @param _message Message to send.
* @param _gasLimit OVM gas limit for the message.
*/
function _sendXDomainMessage(
bytes memory _message,
uint256 _gasLimit
)
override
internal
{
iOVM_CanonicalTransactionChain(resolve("OVM_CanonicalTransactionChain")).enqueue(
resolve("OVM_L2CrossDomainMessenger"),
_gasLimit,
_message
);
}
}
// SPDX-License-Identifier: MIT
// @unsupported: ovm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L1CrossDomainMessenger } from "../../../iOVM/bridge/messaging/iOVM_L1CrossDomainMessenger.sol";
import { iOVM_L1MultiMessageRelayer } from "../../../iOVM/bridge/messaging/iOVM_L1MultiMessageRelayer.sol";
/* Contract Imports */
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";
/**
* @title OVM_L1MultiMessageRelayer
* @dev The L1 Multi-Message Relayer contract is a gas efficiency optimization which enables the
* relayer to submit multiple messages in a single transaction to be relayed by the L1 Cross Domain
* Message Sender.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_L1MultiMessageRelayer is iOVM_L1MultiMessageRelayer, Lib_AddressResolver {
/***************
* Constructor *
***************/
constructor(
address _libAddressManager
)
Lib_AddressResolver(_libAddressManager)
{}
/**********************
* Function Modifiers *
**********************/
modifier onlyBatchRelayer() {
require(
msg.sender == resolve("OVM_L2BatchMessageRelayer"),
"OVM_L1MultiMessageRelayer: Function can only be called by the OVM_L2BatchMessageRelayer"
);
_;
}
/********************
* Public Functions *
********************/
/**
* @notice Forwards multiple cross domain messages to the L1 Cross Domain Messenger for relaying
* @param _messages An array of L2 to L1 messages
*/
function batchRelayMessages(L2ToL1Message[] calldata _messages)
override
external
onlyBatchRelayer
{
iOVM_L1CrossDomainMessenger messenger = iOVM_L1CrossDomainMessenger(resolve("Proxy__OVM_L1CrossDomainMessenger"));
for (uint256 i = 0; i < _messages.length; i++) {
L2ToL1Message memory message = _messages[i];
messenger.relayMessage(
message.target,
message.sender,
message.message,
message.messageNonce,
message.proof
);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_ReentrancyGuard } from "../../../libraries/utils/Lib_ReentrancyGuard.sol";
/* Interface Imports */
import { iOVM_L2CrossDomainMessenger } from "../../../iOVM/bridge/messaging/iOVM_L2CrossDomainMessenger.sol";
import { iOVM_L1MessageSender } from "../../../iOVM/predeploys/iOVM_L1MessageSender.sol";
import { iOVM_L2ToL1MessagePasser } from "../../../iOVM/predeploys/iOVM_L2ToL1MessagePasser.sol";
/* Contract Imports */
import { Abs_BaseCrossDomainMessenger } from "./Abs_BaseCrossDomainMessenger.sol";
/**
* @title OVM_L2CrossDomainMessenger
* @dev The L2 Cross Domain Messenger contract sends messages from L2 to L1, and is the entry point
* for L2 messages sent via the L1 Cross Domain Messenger.
*
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, Abs_BaseCrossDomainMessenger, Lib_AddressResolver {
/***************
* Constructor *
***************/
/**
* @param _libAddressManager Address of the Address Manager.
*/
constructor(
address _libAddressManager
)
Lib_AddressResolver(_libAddressManager)
{}
/********************
* Public Functions *
********************/
/**
* Relays a cross domain message to a contract.
* @inheritdoc iOVM_L2CrossDomainMessenger
*/
function relayMessage(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce
)
override
nonReentrant
public
{
require(
_verifyXDomainMessage() == true,
"Provided message could not be verified."
);
bytes memory xDomainCalldata = _getXDomainCalldata(
_target,
_sender,
_message,
_messageNonce
);
bytes32 xDomainCalldataHash = keccak256(xDomainCalldata);
require(
successfulMessages[xDomainCalldataHash] == false,
"Provided message has already been received."
);
xDomainMsgSender = _sender;
(bool success, ) = _target.call(_message);
xDomainMsgSender = DEFAULT_XDOMAIN_SENDER;
// Mark the message as received if the call was successful. Ensures that a message can be
// relayed multiple times in the case that the call reverted.
if (success == true) {
successfulMessages[xDomainCalldataHash] = true;
emit RelayedMessage(xDomainCalldataHash);
}
// Store an identifier that can be used to prove that the given message was relayed by some
// user. Gives us an easy way to pay relayers for their work.
bytes32 relayId = keccak256(
abi.encodePacked(
xDomainCalldata,
msg.sender,
block.number
)
);
relayedMessages[relayId] = true;
}
/**********************
* Internal Functions *
**********************/
/**
* Verifies that a received cross domain message is valid.
* @return _valid Whether or not the message is valid.
*/
function _verifyXDomainMessage()
view
internal
returns (
bool _valid
)
{
return (
iOVM_L1MessageSender(resolve("OVM_L1MessageSender")).getL1MessageSender() == resolve("OVM_L1CrossDomainMessenger")
);
}
/**
* Sends a cross domain message.
* @param _message Message to send.
* param _gasLimit Gas limit for the provided message.
*/
function _sendXDomainMessage(
bytes memory _message,
uint256 // _gasLimit
)
override
internal
{
iOVM_L2ToL1MessagePasser(resolve("OVM_L2ToL1MessagePasser")).passMessageToL1(_message);
}
}
// SPDX-License-Identifier: MIT
// @unsupported: ovm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L1TokenGateway } from "../../../iOVM/bridge/tokens/iOVM_L1TokenGateway.sol";
import { iOVM_L2DepositedToken } from "../../../iOVM/bridge/tokens/iOVM_L2DepositedToken.sol";
/* Library Imports */
import { OVM_CrossDomainEnabled } from "../../../libraries/bridge/OVM_CrossDomainEnabled.sol";
/**
* @title Abs_L1TokenGateway
* @dev An L1 Token Gateway is a contract which stores deposited L1 funds that are in use on L2.
* It synchronizes a corresponding L2 representation of the "deposited token", informing it
* of new deposits and releasing L1 funds when there are newly finalized withdrawals.
*
* NOTE: This abstract contract gives all the core functionality of an L1 token gateway,
* but provides easy hooks in case developers need extensions in child contracts.
* In many cases, the default OVM_L1ERC20Gateway will suffice.
*
* Compiler used: solc
* Runtime target: EVM
*/
abstract contract Abs_L1TokenGateway is iOVM_L1TokenGateway, OVM_CrossDomainEnabled {
/********************************
* External Contract References *
********************************/
address public l2DepositedToken;
/***************
* Constructor *
***************/
/**
* @param _l2DepositedToken iOVM_L2DepositedToken-compatible address on the chain being deposited into.
* @param _l1messenger L1 Messenger address being used for cross-chain communications.
*/
constructor(
address _l2DepositedToken,
address _l1messenger
)
OVM_CrossDomainEnabled(_l1messenger)
{
l2DepositedToken = _l2DepositedToken;
}
/********************************
* Overridable Accounting logic *
********************************/
// Default gas value which can be overridden if more complex logic runs on L2.
uint32 public DEFAULT_FINALIZE_DEPOSIT_L2_GAS = 1200000;
/**
* @dev Core logic to be performed when a withdrawal is finalized on L1.
* In most cases, this will simply send locked funds to the withdrawer.
*
* param _to Address being withdrawn to.
* param _amount Amount being withdrawn.
*/
function _handleFinalizeWithdrawal(
address, // _to,
uint256 // _amount
)
internal
virtual
{
revert("Implement me in child contracts");
}
/**
* @dev Core logic to be performed when a deposit is initiated on L1.
* In most cases, this will simply send locked funds to the withdrawer.
*
* param _from Address being deposited from on L1.
* param _to Address being deposited into on L2.
* param _amount Amount being deposited.
*/
function _handleInitiateDeposit(
address, // _from,
address, // _to,
uint256 // _amount
)
internal
virtual
{
revert("Implement me in child contracts");
}
/**
* @dev Overridable getter for the L2 gas limit, in the case it may be
* dynamic, and the above public constant does not suffice.
*
*/
function getFinalizeDepositL2Gas()
public
view
returns(
uint32
)
{
return DEFAULT_FINALIZE_DEPOSIT_L2_GAS;
}
/**************
* Depositing *
**************/
/**
* @dev deposit an amount of the ERC20 to the caller's balance on L2
* @param _amount Amount of the ERC20 to deposit
*/
function deposit(
uint _amount
)
public
override
{
_initiateDeposit(msg.sender, msg.sender, _amount);
}
/**
* @dev deposit an amount of ERC20 to a recipients's balance on L2
* @param _to L2 address to credit the withdrawal to
* @param _amount Amount of the ERC20 to deposit
*/
function depositTo(
address _to,
uint _amount
)
public
override
{
_initiateDeposit(msg.sender, _to, _amount);
}
/**
* @dev Performs the logic for deposits by informing the L2 Deposited Token
* contract of the deposit and calling a handler to lock the L1 funds. (e.g. transferFrom)
*
* @param _from Account to pull the deposit from on L1
* @param _to Account to give the deposit to on L2
* @param _amount Amount of the ERC20 to deposit.
*/
function _initiateDeposit(
address _from,
address _to,
uint _amount
)
internal
{
// Call our deposit accounting handler implemented by child contracts.
_handleInitiateDeposit(
_from,
_to,
_amount
);
// Construct calldata for l2DepositedToken.finalizeDeposit(_to, _amount)
bytes memory data = abi.encodeWithSelector(
iOVM_L2DepositedToken.finalizeDeposit.selector,
_to,
_amount
);
// Send calldata into L2
sendCrossDomainMessage(
l2DepositedToken,
data,
getFinalizeDepositL2Gas()
);
emit DepositInitiated(_from, _to, _amount);
}
/*************************
* Cross-chain Functions *
*************************/
/**
* @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the
* L1 ERC20 token.
* This call will fail if the initialized withdrawal from L2 has not been finalized.
*
* @param _to L1 address to credit the withdrawal to
* @param _amount Amount of the ERC20 to withdraw
*/
function finalizeWithdrawal(
address _to,
uint _amount
)
external
override
onlyFromCrossDomainAccount(l2DepositedToken)
{
// Call our withdrawal accounting handler implemented by child contracts.
_handleFinalizeWithdrawal(
_to,
_amount
);
emit WithdrawalFinalized(_to, _amount);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L2DepositedToken } from "../../../iOVM/bridge/tokens/iOVM_L2DepositedToken.sol";
import { iOVM_L1TokenGateway } from "../../../iOVM/bridge/tokens/iOVM_L1TokenGateway.sol";
/* Library Imports */
import { OVM_CrossDomainEnabled } from "../../../libraries/bridge/OVM_CrossDomainEnabled.sol";
/**
* @title Abs_L2DepositedToken
* @dev An L2 Deposited Token is an L2 representation of funds which were deposited from L1.
* Usually contract mints new tokens when it hears about deposits into the L1 ERC20 gateway.
* This contract also burns the tokens intended for withdrawal, informing the L1 gateway to release L1 funds.
*
* NOTE: This abstract contract gives all the core functionality of a deposited token implementation except for the
* token's internal accounting itself. This gives developers an easy way to implement children with their own token code.
*
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
abstract contract Abs_L2DepositedToken is iOVM_L2DepositedToken, OVM_CrossDomainEnabled {
/*******************
* Contract Events *
*******************/
event Initialized(iOVM_L1TokenGateway _l1TokenGateway);
/********************************
* External Contract References *
********************************/
iOVM_L1TokenGateway public l1TokenGateway;
/********************************
* Constructor & Initialization *
********************************/
/**
* @param _l2CrossDomainMessenger L1 Messenger address being used for cross-chain communications.
*/
constructor(
address _l2CrossDomainMessenger
)
OVM_CrossDomainEnabled(_l2CrossDomainMessenger)
{}
/**
* @dev Initialize this contract with the L1 token gateway address.
* The flow: 1) this contract gets deployed on L2, 2) the L1
* gateway is deployed with addr from (1), 3) L1 gateway address passed here.
*
* @param _l1TokenGateway Address of the corresponding L1 gateway deployed to the main chain
*/
function init(
iOVM_L1TokenGateway _l1TokenGateway
)
public
{
require(address(l1TokenGateway) == address(0), "Contract has already been initialized");
l1TokenGateway = _l1TokenGateway;
emit Initialized(l1TokenGateway);
}
/**********************
* Function Modifiers *
**********************/
modifier onlyInitialized() {
require(address(l1TokenGateway) != address(0), "Contract has not yet been initialized");
_;
}
/********************************
* Overridable Accounting logic *
********************************/
// Default gas value which can be overridden if more complex logic runs on L2.
uint32 constant DEFAULT_FINALIZE_WITHDRAWAL_L1_GAS = 100000;
/**
* @dev Core logic to be performed when a withdrawal from L2 is initialized.
* In most cases, this will simply burn the withdrawn L2 funds.
*
* param _to Address being withdrawn to
* param _amount Amount being withdrawn
*/
function _handleInitiateWithdrawal(
address, // _to,
uint // _amount
)
internal
virtual
{
revert("Accounting must be implemented by child contract.");
}
/**
* @dev Core logic to be performed when a deposit from L2 is finalized on L2.
* In most cases, this will simply _mint() to credit L2 funds to the recipient.
*
* param _to Address being deposited to on L2
* param _amount Amount which was deposited on L1
*/
function _handleFinalizeDeposit(
address, // _to
uint // _amount
)
internal
virtual
{
revert("Accounting must be implemented by child contract.");
}
/**
* @dev Overridable getter for the *L1* gas limit of settling the withdrawal, in the case it may be
* dynamic, and the above public constant does not suffice.
*
*/
function getFinalizeWithdrawalL1Gas()
public
view
virtual
returns(
uint32
)
{
return DEFAULT_FINALIZE_WITHDRAWAL_L1_GAS;
}
/***************
* Withdrawing *
***************/
/**
* @dev initiate a withdraw of some tokens to the caller's account on L1
* @param _amount Amount of the token to withdraw
*/
function withdraw(
uint _amount
)
external
override
onlyInitialized()
{
_initiateWithdrawal(msg.sender, _amount);
}
/**
* @dev initiate a withdraw of some token to a recipient's account on L1
* @param _to L1 adress to credit the withdrawal to
* @param _amount Amount of the token to withdraw
*/
function withdrawTo(
address _to,
uint _amount
)
external
override
onlyInitialized()
{
_initiateWithdrawal(_to, _amount);
}
/**
* @dev Performs the logic for deposits by storing the token and informing the L2 token Gateway of the deposit.
*
* @param _to Account to give the withdrawal to on L1
* @param _amount Amount of the token to withdraw
*/
function _initiateWithdrawal(
address _to,
uint _amount
)
internal
{
// Call our withdrawal accounting handler implemented by child contracts (usually a _burn)
_handleInitiateWithdrawal(_to, _amount);
// Construct calldata for l1TokenGateway.finalizeWithdrawal(_to, _amount)
bytes memory data = abi.encodeWithSelector(
iOVM_L1TokenGateway.finalizeWithdrawal.selector,
_to,
_amount
);
// Send message up to L1 gateway
sendCrossDomainMessage(
address(l1TokenGateway),
data,
getFinalizeWithdrawalL1Gas()
);
emit WithdrawalInitiated(msg.sender, _to, _amount);
}
/************************************
* Cross-chain Function: Depositing *
************************************/
/**
* @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this
* L2 token.
* This call will fail if it did not originate from a corresponding deposit in OVM_l1TokenGateway.
*
* @param _to Address to receive the withdrawal at
* @param _amount Amount of the token to withdraw
*/
function finalizeDeposit(
address _to,
uint _amount
)
external
override
onlyInitialized()
onlyFromCrossDomainAccount(address(l1TokenGateway))
{
_handleFinalizeDeposit(_to, _amount);
emit DepositFinalized(_to, _amount);
}
}
// SPDX-License-Identifier: MIT
// @unsupported: ovm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L1TokenGateway } from "../../../iOVM/bridge/tokens/iOVM_L1TokenGateway.sol";
import { Abs_L1TokenGateway } from "./Abs_L1TokenGateway.sol";
import { iOVM_ERC20 } from "../../../iOVM/predeploys/iOVM_ERC20.sol";
/**
* @title OVM_L1ERC20Gateway
* @dev The L1 ERC20 Gateway is a contract which stores deposited L1 funds that are in use on L2.
* It synchronizes a corresponding L2 ERC20 Gateway, informing it of deposits, and listening to it
* for newly finalized withdrawals.
*
* NOTE: This contract extends Abs_L1TokenGateway, which is where we
* takes care of most of the initialization and the cross-chain logic.
* If you are looking to implement your own deposit/withdrawal contracts, you
* may also want to extend the abstract contract in a similar manner.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_L1ERC20Gateway is Abs_L1TokenGateway {
/********************************
* External Contract References *
********************************/
iOVM_ERC20 public l1ERC20;
/***************
* Constructor *
***************/
/**
* @param _l1ERC20 L1 ERC20 address this contract stores deposits for
* @param _l2DepositedERC20 L2 Gateway address on the chain being deposited into
*/
constructor(
iOVM_ERC20 _l1ERC20,
address _l2DepositedERC20,
address _l1messenger
)
Abs_L1TokenGateway(
_l2DepositedERC20,
_l1messenger
)
{
l1ERC20 = _l1ERC20;
}
/**************
* Accounting *
**************/
/**
* @dev When a deposit is initiated on L1, the L1 Gateway
* transfers the funds to itself for future withdrawals
*
* @param _from L1 address ETH is being deposited from
* param _to L2 address that the ETH is being deposited to
* @param _amount Amount of ERC20 to send
*/
function _handleInitiateDeposit(
address _from,
address, // _to,
uint256 _amount
)
internal
override
{
// Hold on to the newly deposited funds
l1ERC20.transferFrom(
_from,
address(this),
_amount
);
}
/**
* @dev When a withdrawal is finalized on L1, the L1 Gateway
* transfers the funds to the withdrawer
*
* @param _to L1 address that the ERC20 is being withdrawn to
* @param _amount Amount of ERC20 to send
*/
function _handleFinalizeWithdrawal(
address _to,
uint _amount
)
internal
override
{
// Transfer withdrawn funds out to withdrawer
l1ERC20.transfer(_to, _amount);
}
}
// SPDX-License-Identifier: MIT
// @unsupported: ovm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L1ETHGateway } from "../../../iOVM/bridge/tokens/iOVM_L1ETHGateway.sol";
import { iOVM_L2DepositedToken } from "../../../iOVM/bridge/tokens/iOVM_L2DepositedToken.sol";
/* Library Imports */
import { OVM_CrossDomainEnabled } from "../../../libraries/bridge/OVM_CrossDomainEnabled.sol";
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";
/**
* @title OVM_L1ETHGateway
* @dev The L1 ETH Gateway is a contract which stores deposited ETH that is in use on L2.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_AddressResolver {
/********************
* Public Constants *
********************/
uint32 public constant override getFinalizeDepositL2Gas = 1200000;
/********************************
* External Contract References *
********************************/
address public ovmEth;
/***************
* Constructor *
***************/
/**
* @param _libAddressManager Address manager for this OE deployment
* @param _ovmEth L2 OVM_ETH implementation of iOVM_DepositedToken
*/
constructor(
address _libAddressManager,
address _ovmEth
)
OVM_CrossDomainEnabled(address(0)) // overridden in constructor code
Lib_AddressResolver(_libAddressManager)
{
ovmEth = _ovmEth;
messenger = resolve("Proxy__OVM_L1CrossDomainMessenger"); // overrides OVM_CrossDomainEnabled constructor setting because resolve() is not yet accessible
}
/**************
* Depositing *
**************/
receive()
external
payable
{
_initiateDeposit(msg.sender, msg.sender);
}
/**
* @dev deposit an amount of the ETH to the caller's balance on L2
*/
function deposit()
external
override
payable
{
_initiateDeposit(msg.sender, msg.sender);
}
/**
* @dev deposit an amount of ETH to a recipients's balance on L2
* @param _to L2 address to credit the withdrawal to
*/
function depositTo(
address _to
)
external
override
payable
{
_initiateDeposit(msg.sender, _to);
}
/**
* @dev Performs the logic for deposits by storing the ETH and informing the L2 ETH Gateway of the deposit.
*
* @param _from Account to pull the deposit from on L1
* @param _to Account to give the deposit to on L2
*/
function _initiateDeposit(
address _from,
address _to
)
internal
{
// Construct calldata for l2ETHGateway.finalizeDeposit(_to, _amount)
bytes memory data =
abi.encodeWithSelector(
iOVM_L2DepositedToken.finalizeDeposit.selector,
_to,
msg.value
);
// Send calldata into L2
sendCrossDomainMessage(
ovmEth,
data,
getFinalizeDepositL2Gas
);
emit DepositInitiated(_from, _to, msg.value);
}
/*************************
* Cross-chain Functions *
*************************/
/**
* @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the
* L1 ETH token.
* Since only the xDomainMessenger can call this function, it will never be called before the withdrawal is finalized.
*
* @param _to L1 address to credit the withdrawal to
* @param _amount Amount of the ETH to withdraw
*/
function finalizeWithdrawal(
address _to,
uint256 _amount
)
external
override
onlyFromCrossDomainAccount(ovmEth)
{
_safeTransferETH(_to, _amount);
emit WithdrawalFinalized(_to, _amount);
}
/**********************************
* Internal Functions: Accounting *
**********************************/
/**
* @dev Internal accounting function for moving around L1 ETH.
*
* @param _to L1 address to transfer ETH to
* @param _value Amount of ETH to send to
*/
function _safeTransferETH(
address _to,
uint256 _value
)
internal
{
(bool success, ) = _to.call{value: _value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L1TokenGateway } from "../../../iOVM/bridge/tokens/iOVM_L1TokenGateway.sol";
/* Contract Imports */
import { UniswapV2ERC20 } from "../../../libraries/standards/UniswapV2ERC20.sol";
/* Library Imports */
import { Abs_L2DepositedToken } from "./Abs_L2DepositedToken.sol";
/**
* @title OVM_L2DepositedERC20
* @dev The L2 Deposited ERC20 is an ERC20 implementation which represents L1 assets deposited into L2.
* This contract mints new tokens when it hears about deposits into the L1 ERC20 gateway.
* This contract also burns the tokens intended for withdrawal, informing the L1 gateway to release L1 funds.
*
* NOTE: This contract implements the Abs_L2DepositedToken contract using Uniswap's ERC20 as the implementation.
* Alternative implementations can be used in this similar manner.
*
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
contract OVM_L2DepositedERC20 is Abs_L2DepositedToken, UniswapV2ERC20 {
/***************
* Constructor *
***************/
/**
* @param _l2CrossDomainMessenger Cross-domain messenger used by this contract.
* @param _name ERC20 name
* @param _symbol ERC20 symbol
*/
constructor(
address _l2CrossDomainMessenger,
string memory _name,
string memory _symbol
)
Abs_L2DepositedToken(_l2CrossDomainMessenger)
UniswapV2ERC20(_name, _symbol)
{}
// When a withdrawal is initiated, we burn the withdrawer's funds to prevent subsequent L2 usage.
function _handleInitiateWithdrawal(
address, // _to,
uint _amount
)
internal
override
{
_burn(msg.sender, _amount);
}
// When a deposit is finalized, we credit the account on L2 with the same amount of tokens.
function _handleFinalizeDeposit(
address _to,
uint _amount
)
internal
override
{
_mint(_to, _amount);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/* Library Imports */
import { Lib_RingBuffer } from "../../libraries/utils/Lib_RingBuffer.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
/* Interface Imports */
import { iOVM_ChainStorageContainer } from "../../iOVM/chain/iOVM_ChainStorageContainer.sol";
/**
* @title OVM_ChainStorageContainer
* @dev The Chain Storage Container provides its owner contract with read, write and delete functionality.
* This provides gas efficiency gains by enabling it to overwrite storage slots which can no longer be used
* in a fraud proof due to the fraud window having passed, and the associated chain state or
* transactions being finalized.
* Three distinct Chain Storage Containers will be deployed on Layer 1:
* 1. Stores transaction batches for the Canonical Transaction Chain
* 2. Stores queued transactions for the Canonical Transaction Chain
* 3. Stores chain state batches for the State Commitment Chain
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_ChainStorageContainer is iOVM_ChainStorageContainer, Lib_AddressResolver {
/*************
* Libraries *
*************/
using Lib_RingBuffer for Lib_RingBuffer.RingBuffer;
/*************
* Variables *
*************/
string public owner;
Lib_RingBuffer.RingBuffer internal buffer;
/***************
* Constructor *
***************/
/**
* @param _libAddressManager Address of the Address Manager.
* @param _owner Name of the contract that owns this container (will be resolved later).
*/
constructor(
address _libAddressManager,
string memory _owner
)
Lib_AddressResolver(_libAddressManager)
{
owner = _owner;
}
/**********************
* Function Modifiers *
**********************/
modifier onlyOwner() {
require(
msg.sender == resolve(owner),
"OVM_ChainStorageContainer: Function can only be called by the owner."
);
_;
}
/********************
* Public Functions *
********************/
/**
* @inheritdoc iOVM_ChainStorageContainer
*/
function setGlobalMetadata(
bytes27 _globalMetadata
)
override
public
onlyOwner
{
return buffer.setExtraData(_globalMetadata);
}
/**
* @inheritdoc iOVM_ChainStorageContainer
*/
function getGlobalMetadata()
override
public
view
returns (
bytes27
)
{
return buffer.getExtraData();
}
/**
* @inheritdoc iOVM_ChainStorageContainer
*/
function length()
override
public
view
returns (
uint256
)
{
return uint256(buffer.getLength());
}
/**
* @inheritdoc iOVM_ChainStorageContainer
*/
function push(
bytes32 _object
)
override
public
onlyOwner
{
buffer.push(_object);
}
/**
* @inheritdoc iOVM_ChainStorageContainer
*/
function push(
bytes32 _object,
bytes27 _globalMetadata
)
override
public
onlyOwner
{
buffer.push(_object, _globalMetadata);
}
/**
* @inheritdoc iOVM_ChainStorageContainer
*/
function get(
uint256 _index
)
override
public
view
returns (
bytes32
)
{
return buffer.get(uint40(_index));
}
/**
* @inheritdoc iOVM_ChainStorageContainer
*/
function deleteElementsAfterInclusive(
uint256 _index
)
override
public
onlyOwner
{
buffer.deleteElementsAfterInclusive(
uint40(_index)
);
}
/**
* @inheritdoc iOVM_ChainStorageContainer
*/
function deleteElementsAfterInclusive(
uint256 _index,
bytes27 _globalMetadata
)
override
public
onlyOwner
{
buffer.deleteElementsAfterInclusive(
uint40(_index),
_globalMetadata
);
}
/**
* @inheritdoc iOVM_ChainStorageContainer
*/
function setNextOverwritableIndex(
uint256 _index
)
override
public
onlyOwner
{
buffer.nextOverwritableIndex = _index;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/* Interface Imports */
import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol";
/**
* @title OVM_SafetyChecker
* @dev The Safety Checker verifies that contracts deployed on L2 do not contain any
* "unsafe" operations. An operation is considered unsafe if it would access state variables which
* are specific to the environment (ie. L1 or L2) in which it is executed, as this could be used
* to "escape the sandbox" of the OVM, resulting in non-deterministic fraud proofs.
* That is, an attacker would be able to "prove fraud" on an honestly applied transaction.
* Note that a "safe" contract requires opcodes to appear in a particular pattern;
* omission of "unsafe" opcodes is necessary, but not sufficient.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_SafetyChecker is iOVM_SafetyChecker {
/********************
* Public Functions *
********************/
/**
* Returns whether or not all of the provided bytecode is safe.
* @param _bytecode The bytecode to safety check.
* @return `true` if the bytecode is safe, `false` otherwise.
*/
function isBytecodeSafe(
bytes memory _bytecode
)
override
external
pure
returns (
bool
)
{
// autogenerated by gen_safety_checker_constants.py
// number of bytes to skip for each opcode
uint256[8] memory opcodeSkippableBytes = [
uint256(0x0001010101010101010101010000000001010101010101010101010101010000),
uint256(0x0100000000000000000000000000000000000000010101010101000000010100),
uint256(0x0000000000000000000000000000000001010101000000010101010100000000),
uint256(0x0203040500000000000000000000000000000000000000000000000000000000),
uint256(0x0101010101010101010101010101010101010101010101010101010101010101),
uint256(0x0101010101000000000000000000000000000000000000000000000000000000),
uint256(0x0000000000000000000000000000000000000000000000000000000000000000),
uint256(0x0000000000000000000000000000000000000000000000000000000000000000)
];
// Mask to gate opcode specific cases
uint256 opcodeGateMask = ~uint256(0xffffffffffffffffffffffe000000000fffffffff070ffff9c0ffffec000f001);
// Halting opcodes
uint256 opcodeHaltingMask = ~uint256(0x4008000000000000000000000000000000000000004000000000000000000001);
// PUSH opcodes
uint256 opcodePushMask = ~uint256(0xffffffff000000000000000000000000);
uint256 codeLength;
uint256 _pc;
assembly {
_pc := add(_bytecode, 0x20)
}
codeLength = _pc + _bytecode.length;
do {
// current opcode: 0x00...0xff
uint256 opNum;
// inline assembly removes the extra add + bounds check
assembly {
let word := mload(_pc) //load the next 32 bytes at pc into word
// Look up number of bytes to skip from opcodeSkippableBytes and then update indexInWord
// E.g. the 02030405 in opcodeSkippableBytes is the number of bytes to skip for PUSH1->4
// We repeat this 6 times, thus we can only skip bytes for up to PUSH4 ((1+4) * 6 = 30 < 32).
// If we see an opcode that is listed as 0 skippable bytes e.g. PUSH5,
// then we will get stuck on that indexInWord and then opNum will be set to the PUSH5 opcode.
let indexInWord := byte(0, mload(add(opcodeSkippableBytes, byte(0, word))))
indexInWord := add(indexInWord, byte(0, mload(add(opcodeSkippableBytes, byte(indexInWord, word)))))
indexInWord := add(indexInWord, byte(0, mload(add(opcodeSkippableBytes, byte(indexInWord, word)))))
indexInWord := add(indexInWord, byte(0, mload(add(opcodeSkippableBytes, byte(indexInWord, word)))))
indexInWord := add(indexInWord, byte(0, mload(add(opcodeSkippableBytes, byte(indexInWord, word)))))
indexInWord := add(indexInWord, byte(0, mload(add(opcodeSkippableBytes, byte(indexInWord, word)))))
_pc := add(_pc, indexInWord)
opNum := byte(indexInWord, word)
}
// + push opcodes
// + stop opcodes [STOP(0x00),JUMP(0x56),RETURN(0xf3),INVALID(0xfe)]
// + caller opcode CALLER(0x33)
// + blacklisted opcodes
uint256 opBit = 1 << opNum;
if (opBit & opcodeGateMask == 0) {
if (opBit & opcodePushMask == 0) {
// all pushes are valid opcodes
// subsequent bytes are not opcodes. Skip them.
_pc += (opNum - 0x5e); // PUSH1 is 0x60, so opNum-0x5f = PUSHed bytes and we +1 to
// skip the _pc++; line below in order to save gas ((-0x5f + 1) = -0x5e)
continue;
} else if (opBit & opcodeHaltingMask == 0) {
// STOP or JUMP or RETURN or INVALID (Note: REVERT is blacklisted, so not included here)
// We are now inside unreachable code until we hit a JUMPDEST!
do {
_pc++;
assembly {
opNum := byte(0, mload(_pc))
}
// encountered a JUMPDEST
if (opNum == 0x5b) break;
// skip PUSHed bytes
if ((1 << opNum) & opcodePushMask == 0) _pc += (opNum - 0x5f); // opNum-0x5f = PUSHed bytes (PUSH1 is 0x60)
} while (_pc < codeLength);
// opNum is 0x5b, so we don't continue here since the pc++ is fine
} else if (opNum == 0x33) { // Caller opcode
uint256 firstOps; // next 32 bytes of bytecode
uint256 secondOps; // following 32 bytes of bytecode
assembly {
firstOps := mload(_pc)
// 37 bytes total, 5 left over --> 32 - 5 bytes = 27 bytes = 216 bits
secondOps := shr(216, mload(add(_pc, 0x20)))
}
// Call identity precompile
// CALLER POP PUSH1 0x00 PUSH1 0x04 GAS CALL
// 32 - 8 bytes = 24 bytes = 192
if ((firstOps >> 192) == 0x3350600060045af1) {
_pc += 8;
// Call EM and abort execution if instructed
// CALLER PUSH1 0x00 SWAP1 GAS CALL PC PUSH1 0x0E ADD JUMPI RETURNDATASIZE PUSH1 0x00 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x00 REVERT JUMPDEST RETURNDATASIZE PUSH1 0x01 EQ ISZERO PC PUSH1 0x0a ADD JUMPI PUSH1 0x01 PUSH1 0x00 RETURN JUMPDEST
} else if (firstOps == 0x336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760 && secondOps == 0x016000f35b) {
_pc += 37;
} else {
return false;
}
continue;
} else {
// encountered a non-whitelisted opcode!
return false;
}
}
_pc++;
} while (_pc < codeLength);
return true;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/* Interface Imports */
import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
import { iOVM_StateManagerFactory } from "../../iOVM/execution/iOVM_StateManagerFactory.sol";
/* Contract Imports */
import { OVM_StateManager } from "./OVM_StateManager.sol";
/**
* @title OVM_StateManagerFactory
* @dev The State Manager Factory is called by a State Transitioner's init code, to create a new
* State Manager for use in the Fraud Verification process.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_StateManagerFactory is iOVM_StateManagerFactory {
/********************
* Public Functions *
********************/
/**
* Creates a new OVM_StateManager
* @param _owner Owner of the created contract.
* @return New OVM_StateManager instance.
*/
function create(
address _owner
)
override
public
returns (
iOVM_StateManager
)
{
return new OVM_StateManager(_owner);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/* Library Imports */
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
/* Interface Imports */
import { iOVM_L1TokenGateway } from "../../iOVM/bridge/tokens/iOVM_L1TokenGateway.sol";
/* Contract Imports */
import { OVM_L2DepositedERC20 } from "../bridge/tokens/OVM_L2DepositedERC20.sol";
/**
* @title OVM_ETH
* @dev The ETH predeploy provides an ERC20 interface for ETH deposited to Layer 2. Note that
* unlike on Layer 1, Layer 2 accounts do not have a balance field.
*
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
contract OVM_ETH is OVM_L2DepositedERC20 {
constructor(
address _l2CrossDomainMessenger,
address _l1ETHGateway
)
OVM_L2DepositedERC20(
_l2CrossDomainMessenger,
"Ether",
"ETH"
)
{
init(iOVM_L1TokenGateway(_l1ETHGateway));
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
/* Interface Imports */
import { iOVM_L1MessageSender } from "../../iOVM/predeploys/iOVM_L1MessageSender.sol";
import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol";
/**
* @title OVM_L1MessageSender
* @dev The L1MessageSender is a predeploy contract running on L2. During the execution of cross
* domain transaction from L1 to L2, it returns the address of the L1 account (either an EOA or
* contract) which sent the message to L2 via the Canonical Transaction Chain's `enqueue()`
* function.
*
* This contract exclusively serves as a getter for the ovmL1TXORIGIN operation. This is necessary
* because there is no corresponding operation in the EVM which the the optimistic solidity compiler
* can be replaced with a call to the ExecutionManager's ovmL1TXORIGIN() function.
*
*
* Compiler used: solc
* Runtime target: OVM
*/
contract OVM_L1MessageSender is iOVM_L1MessageSender {
/********************
* Public Functions *
********************/
/**
* @return _l1MessageSender L1 message sender address (msg.sender).
*/
function getL1MessageSender()
override
public
view
returns (
address _l1MessageSender
)
{
// Note that on L2 msg.sender (ie. evmCALLER) will always be the Execution Manager
return iOVM_ExecutionManager(msg.sender).ovmL1TXORIGIN();
}
}
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
import { iOVM_BondManager } from "../../iOVM/verification/iOVM_BondManager.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
/// Minimal contract to be inherited by contracts consumed by users that provide
/// data for fraud proofs
abstract contract Abs_FraudContributor is Lib_AddressResolver {
/// Decorate your functions with this modifier to store how much total gas was
/// consumed by the sender, to reward users fairly
modifier contributesToFraudProof(bytes32 preStateRoot, bytes32 txHash) {
uint256 startGas = gasleft();
_;
uint256 gasSpent = startGas - gasleft();
iOVM_BondManager(resolve('OVM_BondManager')).recordGasSpent(preStateRoot, txHash, msg.sender, gasSpent);
}
}
// SPDX-License-Identifier: MIT
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
*/
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);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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