Showing preview only (1,242K chars total). Download the full file or copy to clipboard to get everything.
Repository: ethereum-optimism/contracts
Branch: master
Commit: df10de974629
Files: 234
Total size: 1.1 MB
Directory structure:
gitextract_p1t8o229/
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ └── workflows/
│ ├── build-test-lint-contracts.yml
│ ├── dockerhub-build-push.yml
│ ├── integration.yml
│ ├── push-to-integration-repo.yml
│ └── tag-release.yml
├── .gitignore
├── .solcover.js
├── CHANGELOG.md
├── LICENSE.txt
├── README.md
├── bin/
│ ├── deploy.js
│ ├── deploy.ts
│ ├── gen_safety_checker_constants.py
│ ├── serve_dump.sh
│ └── take-dump.ts
├── contracts/
│ ├── optimistic-ethereum/
│ │ ├── OVM/
│ │ │ ├── accounts/
│ │ │ │ ├── OVM_ECDSAContractAccount.sol
│ │ │ │ └── OVM_ProxyEOA.sol
│ │ │ ├── bridge/
│ │ │ │ ├── messaging/
│ │ │ │ │ ├── Abs_BaseCrossDomainMessenger.sol
│ │ │ │ │ ├── OVM_L1CrossDomainMessenger.sol
│ │ │ │ │ ├── OVM_L1MultiMessageRelayer.sol
│ │ │ │ │ └── OVM_L2CrossDomainMessenger.sol
│ │ │ │ └── tokens/
│ │ │ │ ├── Abs_L1TokenGateway.sol
│ │ │ │ ├── Abs_L2DepositedToken.sol
│ │ │ │ ├── OVM_L1ERC20Gateway.sol
│ │ │ │ ├── OVM_L1ETHGateway.sol
│ │ │ │ └── OVM_L2DepositedERC20.sol
│ │ │ ├── chain/
│ │ │ │ ├── OVM_CanonicalTransactionChain.sol
│ │ │ │ ├── OVM_ChainStorageContainer.sol
│ │ │ │ └── OVM_StateCommitmentChain.sol
│ │ │ ├── execution/
│ │ │ │ ├── OVM_ExecutionManager.sol
│ │ │ │ ├── OVM_SafetyChecker.sol
│ │ │ │ ├── OVM_StateManager.sol
│ │ │ │ └── OVM_StateManagerFactory.sol
│ │ │ ├── predeploys/
│ │ │ │ ├── ERC1820Registry.sol
│ │ │ │ ├── OVM_DeployerWhitelist.sol
│ │ │ │ ├── OVM_ETH.sol
│ │ │ │ ├── OVM_L1MessageSender.sol
│ │ │ │ ├── OVM_L2ToL1MessagePasser.sol
│ │ │ │ ├── OVM_ProxySequencerEntrypoint.sol
│ │ │ │ └── OVM_SequencerEntrypoint.sol
│ │ │ └── verification/
│ │ │ ├── Abs_FraudContributor.sol
│ │ │ ├── OVM_BondManager.sol
│ │ │ ├── OVM_FraudVerifier.sol
│ │ │ ├── OVM_StateTransitioner.sol
│ │ │ └── OVM_StateTransitionerFactory.sol
│ │ ├── iOVM/
│ │ │ ├── accounts/
│ │ │ │ └── iOVM_ECDSAContractAccount.sol
│ │ │ ├── bridge/
│ │ │ │ ├── messaging/
│ │ │ │ │ ├── iAbs_BaseCrossDomainMessenger.sol
│ │ │ │ │ ├── iOVM_L1CrossDomainMessenger.sol
│ │ │ │ │ ├── iOVM_L1MultiMessageRelayer.sol
│ │ │ │ │ └── iOVM_L2CrossDomainMessenger.sol
│ │ │ │ └── tokens/
│ │ │ │ ├── iOVM_L1ETHGateway.sol
│ │ │ │ ├── iOVM_L1TokenGateway.sol
│ │ │ │ └── iOVM_L2DepositedToken.sol
│ │ │ ├── chain/
│ │ │ │ ├── iOVM_CanonicalTransactionChain.sol
│ │ │ │ ├── iOVM_ChainStorageContainer.sol
│ │ │ │ └── iOVM_StateCommitmentChain.sol
│ │ │ ├── execution/
│ │ │ │ ├── iOVM_ExecutionManager.sol
│ │ │ │ ├── iOVM_SafetyChecker.sol
│ │ │ │ ├── iOVM_StateManager.sol
│ │ │ │ └── iOVM_StateManagerFactory.sol
│ │ │ ├── predeploys/
│ │ │ │ ├── iOVM_DeployerWhitelist.sol
│ │ │ │ ├── iOVM_ERC20.sol
│ │ │ │ ├── iOVM_L1MessageSender.sol
│ │ │ │ └── iOVM_L2ToL1MessagePasser.sol
│ │ │ └── verification/
│ │ │ ├── iOVM_BondManager.sol
│ │ │ ├── iOVM_FraudVerifier.sol
│ │ │ ├── iOVM_StateTransitioner.sol
│ │ │ └── iOVM_StateTransitionerFactory.sol
│ │ ├── libraries/
│ │ │ ├── bridge/
│ │ │ │ └── OVM_CrossDomainEnabled.sol
│ │ │ ├── codec/
│ │ │ │ └── Lib_OVMCodec.sol
│ │ │ ├── resolver/
│ │ │ │ ├── Lib_AddressManager.sol
│ │ │ │ ├── Lib_AddressResolver.sol
│ │ │ │ ├── Lib_Ownable.sol
│ │ │ │ └── Lib_ResolvedDelegateProxy.sol
│ │ │ ├── rlp/
│ │ │ │ ├── Lib_RLPReader.sol
│ │ │ │ └── Lib_RLPWriter.sol
│ │ │ ├── standards/
│ │ │ │ ├── IUniswapV2ERC20.sol
│ │ │ │ ├── UniSafeMath.sol
│ │ │ │ └── UniswapV2ERC20.sol
│ │ │ ├── trie/
│ │ │ │ ├── Lib_MerkleTrie.sol
│ │ │ │ └── Lib_SecureMerkleTrie.sol
│ │ │ ├── utils/
│ │ │ │ ├── Lib_Bytes32Utils.sol
│ │ │ │ ├── Lib_BytesUtils.sol
│ │ │ │ ├── Lib_ECDSAUtils.sol
│ │ │ │ ├── Lib_ErrorUtils.sol
│ │ │ │ ├── Lib_EthUtils.sol
│ │ │ │ ├── Lib_Math.sol
│ │ │ │ ├── Lib_MerkleTree.sol
│ │ │ │ ├── Lib_ReentrancyGuard.sol
│ │ │ │ └── Lib_RingBuffer.sol
│ │ │ └── wrappers/
│ │ │ ├── Lib_SafeExecutionManagerWrapper.sol
│ │ │ └── Lib_SafeMathWrapper.sol
│ │ └── mockOVM/
│ │ ├── accounts/
│ │ │ └── mockOVM_ECDSAContractAccount.sol
│ │ ├── bridge/
│ │ │ ├── mockOVM_CrossDomainMessenger.sol
│ │ │ └── mockOVM_GenericCrossDomainMessenger.sol
│ │ └── verification/
│ │ └── mockOVM_BondManager.sol
│ ├── test-helpers/
│ │ ├── Helper_GasMeasurer.sol
│ │ ├── Helper_ModifiableStorage.sol
│ │ ├── Helper_PrecompileCaller.sol
│ │ ├── Helper_SimpleProxy.sol
│ │ ├── Helper_TestRunner.sol
│ │ ├── Mock_FraudVerifier.sol
│ │ └── TestERC20.sol
│ └── test-libraries/
│ ├── codec/
│ │ └── TestLib_OVMCodec.sol
│ ├── rlp/
│ │ ├── TestLib_RLPReader.sol
│ │ └── TestLib_RLPWriter.sol
│ ├── trie/
│ │ ├── TestLib_MerkleTrie.sol
│ │ └── TestLib_SecureMerkleTrie.sol
│ └── utils/
│ ├── TestLib_Bytes32Utils.sol
│ ├── TestLib_BytesUtils.sol
│ ├── TestLib_ECDSAUtils.sol
│ ├── TestLib_EthUtils.sol
│ ├── TestLib_MerkleTree.sol
│ └── TestLib_RingBuffer.sol
├── deploy/
│ ├── 000-Lib_AddressManager.deploy.ts
│ ├── 001-OVM_ChainStorageContainer_ctc_batches.deploy.ts
│ ├── 002-OVM_ChainStorageContainer_ctc_queue.deploy.ts
│ ├── 003-OVM_ChainStorageContainer_scc_batches.deploy.ts
│ ├── 004-OVM_CanonicalTransactionChain.deploy.ts
│ ├── 005-OVM_StateCommitmentChain.deploy.ts
│ ├── 006-mockOVM_BondManager.deploy.ts
│ ├── 007-OVM_L1CrossDomainMessenger.deploy.ts
│ ├── 008-Proxy__OVM_L1CrossDomainMessenger.deploy.ts
│ ├── 009-OVM_ExecutionManager.deploy.ts
│ ├── 010-OVM_FraudVerifer.deploy.ts
│ ├── 011-OVM_StateManagerFactory.deploy.ts
│ ├── 012-OVM_StateTransitionerFactory.deploy.ts
│ ├── 013-OVM_SafetyChecker.deploy.ts
│ ├── 014-OVM_L1MultiMessageRelayer.deploy.ts
│ ├── 015-OVM_L1ETHGateway.deploy.ts
│ ├── 016-Proxy__OVM_L1ETHGateway.deploy.ts
│ └── 017-finalize.ts
├── hardhat.config.ts
├── hh/
│ ├── index.ts
│ └── tasks/
│ └── task-deploy.ts
├── package.json
├── prettier-config.json
├── src/
│ ├── contract-defs.ts
│ ├── contract-deployment/
│ │ ├── config.ts
│ │ ├── deploy.ts
│ │ └── index.ts
│ ├── contract-dumps.ts
│ ├── hardhat-deploy-ethers.ts
│ ├── index.ts
│ └── predeploys.ts
├── test/
│ ├── contracts/
│ │ ├── OVM/
│ │ │ ├── accounts/
│ │ │ │ ├── OVM_ECDSAContractAccount.spec.ts
│ │ │ │ └── OVM_ProxyEOA.spec.ts
│ │ │ ├── bridge/
│ │ │ │ ├── assets/
│ │ │ │ │ ├── OVM_L1ERC20Gateway.spec.ts
│ │ │ │ │ ├── OVM_L1ETHGateway.spec.ts
│ │ │ │ │ └── OVM_L2DepositedERC20.spec.ts
│ │ │ │ └── base/
│ │ │ │ ├── OVM_L1CrossDomainMessenger.spec.ts
│ │ │ │ ├── OVM_L1MultiMessageRelayer.ts
│ │ │ │ └── OVM_L2CrossDomainMessenger.spec.ts
│ │ │ ├── chain/
│ │ │ │ ├── OVM_CanonicalTransactionChain.gas.spec.ts
│ │ │ │ ├── OVM_CanonicalTransactionChain.spec.ts
│ │ │ │ └── OVM_StateCommitmentChain.spec.ts
│ │ │ ├── execution/
│ │ │ │ ├── OVM_ExecutionManager/
│ │ │ │ │ ├── context-opcodes.spec.ts
│ │ │ │ │ ├── nuisance-gas.spec.ts
│ │ │ │ │ ├── ovmCALL.spec.ts
│ │ │ │ │ ├── ovmCREATE.spec.ts
│ │ │ │ │ ├── ovmCREATEEOA.spec.ts
│ │ │ │ │ ├── ovmDELEGATECALL.spec.ts
│ │ │ │ │ ├── ovmREVERT.spec.ts
│ │ │ │ │ ├── ovmSLOAD.spec.ts
│ │ │ │ │ ├── ovmSTATICCALL.spec.ts
│ │ │ │ │ └── run.spec.ts
│ │ │ │ ├── OVM_ExecutionManager.gas-spec.ts
│ │ │ │ ├── OVM_SafetyChecker.spec.ts
│ │ │ │ ├── OVM_StateManager.gas-spec.ts
│ │ │ │ └── OVM_StateManager.spec.ts
│ │ │ ├── precompiles/
│ │ │ │ ├── OVM_L1MessageSender.spec.ts
│ │ │ │ ├── OVM_L2ToL1MessagePasser.spec.ts
│ │ │ │ ├── OVM_ProxySequencerEntrypoint.spec.ts
│ │ │ │ └── OVM_SequencerEntrypoint.spec.ts
│ │ │ └── verification/
│ │ │ ├── OVM_BondManager.spec.ts
│ │ │ ├── OVM_FraudVerifier.spec.ts
│ │ │ ├── OVM_StateTransitioner.spec.ts
│ │ │ └── OVM_StateTransitionerFactory.spec.ts
│ │ ├── libraries/
│ │ │ ├── codec/
│ │ │ │ └── Lib_OVMCodec.spec.ts
│ │ │ ├── rlp/
│ │ │ │ ├── Lib_RLPReader.spec.ts
│ │ │ │ └── Lib_RLPWriter.spec.ts
│ │ │ ├── trie/
│ │ │ │ ├── Lib_MerkleTrie.spec.ts
│ │ │ │ └── Lib_SecureMerkleTrie.spec.ts
│ │ │ └── utils/
│ │ │ ├── Lib_Bytes32Utils.spec.ts
│ │ │ ├── Lib_BytesUtils.spec.ts
│ │ │ ├── Lib_ECDSAUtils.spec.ts
│ │ │ ├── Lib_EthUtils.spec.ts
│ │ │ └── Lib_MerkleTree.spec.ts
│ │ └── mockOVM/
│ │ └── verification/
│ │ └── mockOVM_BondManager.spec.ts
│ ├── data/
│ │ ├── index.ts
│ │ └── json/
│ │ ├── create2.test.json
│ │ ├── libraries/
│ │ │ ├── codec/
│ │ │ │ └── Lib_OVMCodec.test.json
│ │ │ ├── rlp/
│ │ │ │ ├── Lib_RLPReader.test.json
│ │ │ │ └── Lib_RLPWriter.test.json
│ │ │ ├── trie/
│ │ │ │ └── Lib_MerkleTrie.test.json
│ │ │ └── utils/
│ │ │ ├── Lib_Bytes32Utils.test.json
│ │ │ ├── Lib_BytesUtils.test.json
│ │ │ └── Lib_ECDSAUtils.test.json
│ │ └── safety-checker.test.json
│ ├── helpers/
│ │ ├── codec/
│ │ │ ├── bridge.ts
│ │ │ ├── encoding.ts
│ │ │ ├── index.ts
│ │ │ └── revert-flags.ts
│ │ ├── constants.ts
│ │ ├── dummy/
│ │ │ ├── accounts.ts
│ │ │ ├── batches.ts
│ │ │ ├── bytecode.ts
│ │ │ ├── bytes32.ts
│ │ │ ├── context.ts
│ │ │ ├── index.ts
│ │ │ └── transactions.ts
│ │ ├── gas/
│ │ │ ├── gas.ts
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── resolver/
│ │ │ ├── address-manager.ts
│ │ │ └── index.ts
│ │ ├── test-runner/
│ │ │ ├── index.ts
│ │ │ ├── json-test-runner.ts
│ │ │ ├── test-runner.ts
│ │ │ └── test.types.ts
│ │ ├── trie/
│ │ │ ├── index.ts
│ │ │ └── trie-test-generator.ts
│ │ ├── types/
│ │ │ ├── index.ts
│ │ │ └── ovm-types.ts
│ │ └── utils/
│ │ ├── custom-deployer.ts
│ │ ├── eth-time.ts
│ │ ├── index.ts
│ │ └── sol-utils.ts
│ └── setup.ts
├── tsconfig.json
└── tslint.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
# defaults
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.sol]
indent_size = 4
================================================
FILE: .gitattributes
================================================
*.sol linguist-language=Solidity
================================================
FILE: .github/CODEOWNERS
================================================
* @smartcontracts @ben-chain @maurelian
================================================
FILE: .github/workflows/build-test-lint-contracts.yml
================================================
name: CI - contracts
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build-test-lint:
name: Run Contracts Test Suite on Node ${{matrix.node}}
runs-on: ubuntu-latest
strategy:
matrix:
node: [ '10', '12', '14' ]
steps:
- uses: actions/checkout@v2
- name: Setup node ${{ matrix.node }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
# START DEPENDENCY CACHING
- name: Cache root deps
uses: actions/cache@v1
id: cache_base
with:
path: node_modules
key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('package.json') }}
# END DEPENDENCY CACHING
- name: Install Dependencies
run: yarn install
- name: Lint
run: yarn lint:check
- name: Build
run: |
yarn clean
yarn build
- name: Test
run: yarn test
================================================
FILE: .github/workflows/dockerhub-build-push.yml
================================================
name: Build & Push to DockerHub
on:
push:
branches:
- master
- testnet
- uat
jobs:
build:
name: Build & Push to DockerHub
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: webfactory/ssh-agent@v0.4.1
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY_READ }}
- name: Login to DockerHub Registry
run: echo ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }} | docker login -u ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME}} --password-stdin
- name: Build and push Deployer image to DockerHub
run: |
git clone https://github.com/ethereum-optimism/docker.git \
$HOME/docker
cd $HOME/docker
BRANCH=${GITHUB_REF##*/}
./build.sh -s deployer -b $BRANCH
if [ $BRANCH == 'master' ]; then
docker push ethereumoptimism/deployer:latest
elif [[ $BRANCH == 'uat' || $BRANCH == 'testnet' ]]; then
docker push ethereumoptimism/deployer:$BRANCH
fi
- name: Logout of DockerHub
run: docker logout
================================================
FILE: .github/workflows/integration.yml
================================================
name: Setup & Run Integration Test Suite
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
name: Setup & Run Integration Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: |
git clone https://github.com/ethereum-optimism/optimism-integration.git \
$HOME/optimism-integration
cd $HOME/optimism-integration
sed -i -Ee's#git@github.com:([^/]*)/(.*).git#https://github.com/\1/\2.git#' .gitmodules
git submodule init
git submodule update
if [ -z $GITHUB_HEAD_REF ]; then
GITHUB_HEAD_REF=${GITHUB_REF##*/}
fi
GIT_COMMIT=$(git rev-parse HEAD | head -c 8)
REMOTE=${{ github.event.pull_request.head.repo.html_url }}
echo "optimism-integration $GIT_COMMIT"
if [ -z $REMOTE ]; then
./docker/build.sh -s deployer -b $GITHUB_HEAD_REF
else
./docker/build.sh -s deployer -b $GITHUB_HEAD_REF -r $REMOTE
fi
- name: Test
run: |
cd $HOME/optimism-integration
DEPLOYER_TAG=$GITHUB_HEAD_REF ./test.sh
================================================
FILE: .github/workflows/push-to-integration-repo.yml
================================================
name: Update submodules in integration repo
on:
push:
branches:
- master
jobs:
run:
name: Update submodules
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: webfactory/ssh-agent@v0.4.1
with:
ssh-private-key: ${{ secrets.INTEGRATION_PUSH_ACTION }}
- name: Clone repo
run: |
git clone git@github.com:ethereum-optimism/optimism-integration.git $HOME/optimism-integration
cd $HOME/optimism-integration
git submodule init && git submodule update
REPO=$(echo $GITHUB_REPOSITORY | cut -d '/' -f2)
cd $HOME/optimism-integration/$REPO
git pull origin master
- name: Commit
run: |
git config --global user.email "action@github.com"
git config --global user.name "GitHub Action"
cd $HOME/optimism-integration
REPO=$(echo $GITHUB_REPOSITORY | cut -d '/' -f2)
SHORT=$(echo $GITHUB_SHA | head -c 8)
git add $REPO
git commit -m "submodule bump: $REPO $SHORT"
git push origin master
================================================
FILE: .github/workflows/tag-release.yml
================================================
name: Auto tag-release-publish
on:
push:
branches:
- master
jobs:
tag:
name: Create tag for new version
runs-on: ubuntu-latest
outputs:
tag_name: ${{ steps.create_new_tag.outputs.tag }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- uses: salsify/action-detect-and-tag-new-version@v2
id: create_new_tag
release:
name: Create release
runs-on: ubuntu-latest
needs: tag
if: needs.tag.outputs.tag_name
steps:
- uses: actions/checkout@v2
- uses: actions/create-release@v1
id: create_release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.tag.outputs.tag_name }}
release_name: ${{ needs.tag.outputs.tag_name }}
draft: false
prerelease: false
npm-publish:
name: Build and publish
runs-on: ubuntu-latest
needs: tag
if: needs.tag.outputs.tag_name
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '14.x'
registry-url: 'https://registry.npmjs.org'
- run: yarn
- run: yarn build
- run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
docker:
name: Build & Push to DockerHub
runs-on: ubuntu-latest
needs: tag
if: needs.tag.outputs.tag_name
steps:
- uses: actions/checkout@v2
- name: Login to DockerHub Registry
run: echo ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }} | docker login -u ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME}} --password-stdin
- name: Clone the docker repo
run: |
git clone https://github.com/ethereum-optimism/docker.git \
$HOME/docker
- name: Build and push Deployer image to DockerHub
run: |
cd $HOME/docker
./build.sh -s deployer -b ${{ needs.tag.outputs.tag_name }}
docker push ethereumoptimism/deployer:${{ needs.tag.outputs.tag_name }}
- name: Extract State Dump from Deployer Image
run: docker run --rm --entrypoint cat ethereumoptimism/deployer:${{ steps.get_version.outputs.VERSION }} /opt/contracts/build/dumps/state-dump.latest.json > ${{ steps.get_version.outputs.VERSION }}.json
- name: Store state dump artifact for git job
uses: actions/upload-artifact@v2
with:
name: state-dump-artifact
path: ${{ steps.get_version.outputs.VERSION }}.json
- name: Logout of DockerHub
run: docker logout
git:
name: Commit State Dump
needs: [docker, tag]
runs-on: ubuntu-latest
if: needs.tag.outputs.tag_name
steps:
- uses: actions/checkout@v2
with:
repository: ethereum-optimism/regenesis
ssh-key: ${{ secrets.REGENESIS_DEPLOY_KEY }}
- name: Download State Dump Artifact
uses: actions/download-artifact@v2
with:
name: state-dump-artifact
path: ./tags
- name: Commit to Repository
uses: stefanzweifel/git-auto-commit-action@v4
with:
branch: master
commit_message: Add tagged state dump artfiact
commit_user_name: GitHub Action
commit_user_email: action@github.com
commit_author: Github Action <action@github.com>
================================================
FILE: .gitignore
================================================
node_modules/
artifacts/
artifacts-ovm/
cache/
cache-ovm/
yarn-error.log
build/
.DS_STORE
# Coverage output
coverage/
coverage.json
# Environment variables
.env
================================================
FILE: .solcover.js
================================================
module.exports = {
skipFiles: [
'./test-helpers',
'./test-libraries',
'./optimistic-ethereum/mockOVM'
],
mocha: {
grep: "@skip-on-coverage",
invert: true
}
};
================================================
FILE: CHANGELOG.md
================================================
# 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
================================================
FILE: LICENSE.txt
================================================
(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.
================================================
FILE: README.md
================================================
**[DEPRECATED]** This repository is now deprecated in favour of the new development [monorepo](https://github.com/ethereum-optimism/optimism-monorepo).
# 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
```
### Measuring test coverage:
```shell
yarn test-coverage
```
The output is most easily viewable by opening the html file in your browser:
```shell
open ./coverage/index.html
```
### 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 build 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.
================================================
FILE: bin/deploy.js
================================================
#!/usr/bin/env node
const path = require('path')
const { spawn } = require('child_process')
const dirtree = require('directory-tree')
const main = async () => {
const task = spawn(path.join(__dirname, 'deploy.ts'))
await new Promise((resolve) => {
task.on('exit', () => {
resolve()
})
})
// Stuff below this line is currently required for CI to work properly. We probably want to
// update our CI so this is no longer necessary. But I'm adding it for backwards compat so we can
// get the hardhat-deploy stuff merged. Woot.
const nicknames = {
'Lib_AddressManager': 'AddressManager',
'mockOVM_BondManager': 'OVM_BondManager'
}
const contracts = dirtree(
path.resolve(__dirname, `../deployments/custom`)
).children.filter((child) => {
return child.extension === '.json'
}).reduce((contracts, child) => {
const contractName = child.name.replace('.json', '')
const artifact = require(path.resolve(__dirname, `../deployments/custom/${child.name}`))
contracts[nicknames[contractName] || contractName] = artifact.address
return contracts
}, {})
// We *must* console.log here because CI will pipe the output of this script into an
// addresses.json file. Also something we should probably remove.
console.log(JSON.stringify(contracts, null, 2))
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.log(
JSON.stringify({ error: error.message, stack: error.stack }, null, 2)
)
process.exit(1)
})
================================================
FILE: bin/deploy.ts
================================================
#!/usr/bin/env ts-node-script
import { Wallet } from 'ethers'
// Ensures that all relevant environment vars are properly set. These lines *must* come before the
// hardhat import because importing will load the config (which relies on these vars). Necessary
// because CI currently uses different var names than the ones we've chosen here.
// TODO: Update CI so that we don't have to do this anymore.
process.env.HARDHAT_NETWORK = 'custom' // "custom" here is an arbitrary name. only used for CI.
process.env.CONTRACTS_TARGET_NETWORK = 'custom'
process.env.CONTRACTS_DEPLOYER_KEY = process.env.DEPLOYER_PRIVATE_KEY
process.env.CONTRACTS_RPC_URL =
process.env.L1_NODE_WEB3_URL || 'http://127.0.0.1:8545'
import hre from 'hardhat'
const main = async () => {
const sequencer = new Wallet(process.env.SEQUENCER_PRIVATE_KEY)
const deployer = new Wallet(process.env.DEPLOYER_PRIVATE_KEY)
await hre.run('deploy', {
l1BlockTimeSeconds: process.env.BLOCK_TIME_SECONDS,
ctcForceInclusionPeriodSeconds: process.env.FORCE_INCLUSION_PERIOD_SECONDS,
ctcMaxTransactionGasLimit: process.env.MAX_TRANSACTION_GAS_LIMIT,
emMinTransactionGasLimit: process.env.MIN_TRANSACTION_GAS_LIMIT,
emMaxtransactionGasLimit: process.env.MAX_TRANSACTION_GAS_LIMIT,
emMaxGasPerQueuePerEpoch: process.env.MAX_GAS_PER_QUEUE_PER_EPOCH,
emSecondsPerEpoch: process.env.SECONDS_PER_EPOCH,
emOvmChainId: process.env.CHAIN_ID,
sccFraudProofWindow: parseInt(process.env.FRAUD_PROOF_WINDOW_SECONDS, 10),
sccSequencerPublishWindow: process.env.SEQUENCER_PUBLISH_WINDOW_SECONDS,
ovmSequencerAddress: sequencer.address,
ovmProposerAddress: sequencer.address,
ovmRelayerAddress: sequencer.address,
ovmAddressManagerOwner: deployer.address,
})
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.log(
JSON.stringify({ error: error.message, stack: error.stack }, null, 2)
)
process.exit(1)
})
================================================
FILE: bin/gen_safety_checker_constants.py
================================================
#!/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)
================================================
FILE: bin/serve_dump.sh
================================================
#!/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/../build/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
================================================
FILE: bin/take-dump.ts
================================================
/* 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, '../build/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))
})()
================================================
FILE: contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol
================================================
// 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(
gasleft(),
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(
gasleft(),
decodedTx.to,
decodedTx.data
);
}
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol
================================================
// 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)
);
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/bridge/messaging/Abs_BaseCrossDomainMessenger.sol
================================================
// 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!");
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L1CrossDomainMessenger.sol
================================================
// 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
);
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L1MultiMessageRelayer.sol
================================================
// 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
);
}
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L2CrossDomainMessenger.sol
================================================
// 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."
);
// Prevent calls to OVM_L2ToL1MessagePasser, which would enable
// an attacker to maliciously craft the _message to spoof
// a call from any L2 account.
if(_target == resolve("OVM_L2ToL1MessagePasser")){
// Write to the successfulMessages mapping and return immediately.
successfulMessages[xDomainCalldataHash] = true;
return;
}
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);
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/bridge/tokens/Abs_L1TokenGateway.sol
================================================
// 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);
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/bridge/tokens/Abs_L2DepositedToken.sol
================================================
// 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);
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L1ERC20Gateway.sol
================================================
// 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);
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L1ETHGateway.sol
================================================
// 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";
import { Lib_AddressManager } from "../../../libraries/resolver/Lib_AddressManager.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 *
***************/
// This contract lives behind a proxy, so the constructor parameters will go unused.
constructor()
OVM_CrossDomainEnabled(address(0))
Lib_AddressResolver(address(0))
public
{}
/******************
* Initialization *
******************/
/**
* @param _libAddressManager Address manager for this OE deployment
* @param _ovmEth L2 OVM_ETH implementation of iOVM_DepositedToken
*/
function initialize(
address _libAddressManager,
address _ovmEth
)
public
{
require(libAddressManager == Lib_AddressManager(0), "Contract has already been initialized.");
libAddressManager = Lib_AddressManager(_libAddressManager);
ovmEth = _ovmEth;
messenger = resolve("Proxy__OVM_L1CrossDomainMessenger");
}
/**************
* 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');
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L2DepositedERC20.sol
================================================
// 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);
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/chain/OVM_CanonicalTransactionChain.sol
================================================
// SPDX-License-Identifier: MIT
// @unsupported: ovm
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_MerkleTree } from "../../libraries/utils/Lib_MerkleTree.sol";
import { Lib_Math } from "../../libraries/utils/Lib_Math.sol";
/* Interface Imports */
import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
import { iOVM_ChainStorageContainer } from "../../iOVM/chain/iOVM_ChainStorageContainer.sol";
/* Contract Imports */
import { OVM_ExecutionManager } from "../execution/OVM_ExecutionManager.sol";
/**
* @title OVM_CanonicalTransactionChain
* @dev The Canonical Transaction Chain (CTC) contract is an append-only log of transactions
* which must be applied to the rollup state. It defines the ordering of rollup transactions by
* writing them to the 'CTC:batches' instance of the Chain Storage Container.
* The CTC also allows any account to 'enqueue' an L2 transaction, which will require that the Sequencer
* will eventually append it to the rollup state.
* If the Sequencer does not include an enqueued transaction within the 'force inclusion period',
* then any account may force it to be included by calling appendQueueBatch().
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_AddressResolver {
/*************
* Constants *
*************/
// L2 tx gas-related
uint256 constant public MIN_ROLLUP_TX_GAS = 100000;
uint256 constant public MAX_ROLLUP_TX_SIZE = 50000;
uint256 constant public L2_GAS_DISCOUNT_DIVISOR = 32;
// Encoding-related (all in bytes)
uint256 constant internal BATCH_CONTEXT_SIZE = 16;
uint256 constant internal BATCH_CONTEXT_LENGTH_POS = 12;
uint256 constant internal BATCH_CONTEXT_START_POS = 15;
uint256 constant internal TX_DATA_HEADER_SIZE = 3;
uint256 constant internal BYTES_TILL_TX_DATA = 65;
/*************
* Variables *
*************/
uint256 public forceInclusionPeriodSeconds;
uint256 public forceInclusionPeriodBlocks;
uint256 public maxTransactionGasLimit;
/***************
* Constructor *
***************/
constructor(
address _libAddressManager,
uint256 _forceInclusionPeriodSeconds,
uint256 _forceInclusionPeriodBlocks,
uint256 _maxTransactionGasLimit
)
Lib_AddressResolver(_libAddressManager)
{
forceInclusionPeriodSeconds = _forceInclusionPeriodSeconds;
forceInclusionPeriodBlocks = _forceInclusionPeriodBlocks;
maxTransactionGasLimit = _maxTransactionGasLimit;
}
/********************
* Public Functions *
********************/
/**
* Accesses the batch storage container.
* @return Reference to the batch storage container.
*/
function batches()
override
public
view
returns (
iOVM_ChainStorageContainer
)
{
return iOVM_ChainStorageContainer(
resolve("OVM_ChainStorageContainer:CTC:batches")
);
}
/**
* Accesses the queue storage container.
* @return Reference to the queue storage container.
*/
function queue()
override
public
view
returns (
iOVM_ChainStorageContainer
)
{
return iOVM_ChainStorageContainer(
resolve("OVM_ChainStorageContainer:CTC:queue")
);
}
/**
* Retrieves the total number of elements submitted.
* @return _totalElements Total submitted elements.
*/
function getTotalElements()
override
public
view
returns (
uint256 _totalElements
)
{
(uint40 totalElements,,,) = _getBatchExtraData();
return uint256(totalElements);
}
/**
* Retrieves the total number of batches submitted.
* @return _totalBatches Total submitted batches.
*/
function getTotalBatches()
override
public
view
returns (
uint256 _totalBatches
)
{
return batches().length();
}
/**
* Returns the index of the next element to be enqueued.
* @return Index for the next queue element.
*/
function getNextQueueIndex()
override
public
view
returns (
uint40
)
{
(,uint40 nextQueueIndex,,) = _getBatchExtraData();
return nextQueueIndex;
}
/**
* Returns the timestamp of the last transaction.
* @return Timestamp for the last transaction.
*/
function getLastTimestamp()
override
public
view
returns (
uint40
)
{
(,,uint40 lastTimestamp,) = _getBatchExtraData();
return lastTimestamp;
}
/**
* Returns the blocknumber of the last transaction.
* @return Blocknumber for the last transaction.
*/
function getLastBlockNumber()
override
public
view
returns (
uint40
)
{
(,,,uint40 lastBlockNumber) = _getBatchExtraData();
return lastBlockNumber;
}
/**
* Gets the queue element at a particular index.
* @param _index Index of the queue element to access.
* @return _element Queue element at the given index.
*/
function getQueueElement(
uint256 _index
)
override
public
view
returns (
Lib_OVMCodec.QueueElement memory _element
)
{
return _getQueueElement(
_index,
queue()
);
}
/**
* Get the number of queue elements which have not yet been included.
* @return Number of pending queue elements.
*/
function getNumPendingQueueElements()
override
public
view
returns (
uint40
)
{
return getQueueLength() - getNextQueueIndex();
}
/**
* Retrieves the length of the queue, including
* both pending and canonical transactions.
* @return Length of the queue.
*/
function getQueueLength()
override
public
view
returns (
uint40
)
{
return _getQueueLength(
queue()
);
}
/**
* Adds a transaction to the queue.
* @param _target Target L2 contract to send the transaction to.
* @param _gasLimit Gas limit for the enqueued L2 transaction.
* @param _data Transaction data.
*/
function enqueue(
address _target,
uint256 _gasLimit,
bytes memory _data
)
override
public
{
require(
_data.length <= MAX_ROLLUP_TX_SIZE,
"Transaction data size exceeds maximum for rollup transaction."
);
require(
_gasLimit <= maxTransactionGasLimit,
"Transaction gas limit exceeds maximum for rollup transaction."
);
require(
_gasLimit >= MIN_ROLLUP_TX_GAS,
"Transaction gas limit too low to enqueue."
);
// We need to consume some amount of L1 gas in order to rate limit transactions going into
// L2. However, L2 is cheaper than L1 so we only need to burn some small proportion of the
// provided L1 gas.
uint256 gasToConsume = _gasLimit/L2_GAS_DISCOUNT_DIVISOR;
uint256 startingGas = gasleft();
// Although this check is not necessary (burn below will run out of gas if not true), it
// gives the user an explicit reason as to why the enqueue attempt failed.
require(
startingGas > gasToConsume,
"Insufficient gas for L2 rate limiting burn."
);
// Here we do some "dumb" work in order to burn gas, although we should probably replace
// this with something like minting gas token later on.
uint256 i;
while(startingGas - gasleft() < gasToConsume) {
i++;
}
bytes32 transactionHash = keccak256(
abi.encode(
msg.sender,
_target,
_gasLimit,
_data
)
);
bytes32 timestampAndBlockNumber;
assembly {
timestampAndBlockNumber := timestamp()
timestampAndBlockNumber := or(timestampAndBlockNumber, shl(40, number()))
}
iOVM_ChainStorageContainer queueRef = queue();
queueRef.push(transactionHash);
queueRef.push(timestampAndBlockNumber);
// The underlying queue data structure stores 2 elements
// per insertion, so to get the real queue length we need
// to divide by 2 and subtract 1.
uint256 queueIndex = queueRef.length() / 2 - 1;
emit TransactionEnqueued(
msg.sender,
_target,
_gasLimit,
_data,
queueIndex,
block.timestamp
);
}
/**
* Appends a given number of queued transactions as a single batch.
* param _numQueuedTransactions Number of transactions to append.
*/
function appendQueueBatch(
uint256 // _numQueuedTransactions
)
override
public
pure
{
// TEMPORARY: Disable `appendQueueBatch` for minnet
revert("appendQueueBatch is currently disabled.");
// _numQueuedTransactions = Lib_Math.min(_numQueuedTransactions, getNumPendingQueueElements());
// require(
// _numQueuedTransactions > 0,
// "Must append more than zero transactions."
// );
// bytes32[] memory leaves = new bytes32[](_numQueuedTransactions);
// uint40 nextQueueIndex = getNextQueueIndex();
// for (uint256 i = 0; i < _numQueuedTransactions; i++) {
// if (msg.sender != resolve("OVM_Sequencer")) {
// Lib_OVMCodec.QueueElement memory el = getQueueElement(nextQueueIndex);
// require(
// el.timestamp + forceInclusionPeriodSeconds < block.timestamp,
// "Queue transactions cannot be submitted during the sequencer inclusion period."
// );
// }
// leaves[i] = _getQueueLeafHash(nextQueueIndex);
// nextQueueIndex++;
// }
// Lib_OVMCodec.QueueElement memory lastElement = getQueueElement(nextQueueIndex - 1);
// _appendBatch(
// Lib_MerkleTree.getMerkleRoot(leaves),
// _numQueuedTransactions,
// _numQueuedTransactions,
// lastElement.timestamp,
// lastElement.blockNumber
// );
// emit QueueBatchAppended(
// nextQueueIndex - _numQueuedTransactions,
// _numQueuedTransactions,
// getTotalElements()
// );
}
/**
* Allows the sequencer to append a batch of transactions.
* @dev This function uses a custom encoding scheme for efficiency reasons.
* .param _shouldStartAtElement Specific batch we expect to start appending to.
* .param _totalElementsToAppend Total number of batch elements we expect to append.
* .param _contexts Array of batch contexts.
* .param _transactionDataFields Array of raw transaction data.
*/
function appendSequencerBatch()
override
public
{
uint40 shouldStartAtElement;
uint24 totalElementsToAppend;
uint24 numContexts;
assembly {
shouldStartAtElement := shr(216, calldataload(4))
totalElementsToAppend := shr(232, calldataload(9))
numContexts := shr(232, calldataload(12))
}
require(
shouldStartAtElement == getTotalElements(),
"Actual batch start index does not match expected start index."
);
require(
msg.sender == resolve("OVM_Sequencer"),
"Function can only be called by the Sequencer."
);
require(
numContexts > 0,
"Must provide at least one batch context."
);
require(
totalElementsToAppend > 0,
"Must append at least one element."
);
uint40 nextTransactionPtr = uint40(BATCH_CONTEXT_START_POS + BATCH_CONTEXT_SIZE * numContexts);
require(
msg.data.length >= nextTransactionPtr,
"Not enough BatchContexts provided."
);
// Take a reference to the queue and its length so we don't have to keep resolving it.
// Length isn't going to change during the course of execution, so it's fine to simply
// resolve this once at the start. Saves gas.
iOVM_ChainStorageContainer queueRef = queue();
uint40 queueLength = _getQueueLength(queueRef);
// Reserve some memory to save gas on hashing later on. This is a relatively safe estimate
// for the average transaction size that will prevent having to resize this chunk of memory
// later on. Saves gas.
bytes memory hashMemory = new bytes((msg.data.length / totalElementsToAppend) * 2);
// Initialize the array of canonical chain leaves that we will append.
bytes32[] memory leaves = new bytes32[](totalElementsToAppend);
// Each leaf index corresponds to a tx, either sequenced or enqueued.
uint32 leafIndex = 0;
// Counter for number of sequencer transactions appended so far.
uint32 numSequencerTransactions = 0;
// We will sequentially append leaves which are pointers to the queue.
// The initial queue index is what is currently in storage.
uint40 nextQueueIndex = getNextQueueIndex();
BatchContext memory curContext;
for (uint32 i = 0; i < numContexts; i++) {
BatchContext memory nextContext = _getBatchContext(i);
if (i == 0) {
// Execute a special check for the first batch.
_validateFirstBatchContext(nextContext);
}
// Execute this check on every single batch, including the first one.
_validateNextBatchContext(
curContext,
nextContext,
nextQueueIndex,
queueRef
);
// Now we can update our current context.
curContext = nextContext;
// Process sequencer transactions first.
for (uint32 j = 0; j < curContext.numSequencedTransactions; j++) {
uint256 txDataLength;
assembly {
txDataLength := shr(232, calldataload(nextTransactionPtr))
}
require(
txDataLength <= MAX_ROLLUP_TX_SIZE,
"Transaction data size exceeds maximum for rollup transaction."
);
leaves[leafIndex] = _getSequencerLeafHash(
curContext,
nextTransactionPtr,
txDataLength,
hashMemory
);
nextTransactionPtr += uint40(TX_DATA_HEADER_SIZE + txDataLength);
numSequencerTransactions++;
leafIndex++;
}
// Now process any subsequent queue transactions.
for (uint32 j = 0; j < curContext.numSubsequentQueueTransactions; j++) {
require(
nextQueueIndex < queueLength,
"Not enough queued transactions to append."
);
leaves[leafIndex] = _getQueueLeafHash(nextQueueIndex);
nextQueueIndex++;
leafIndex++;
}
}
_validateFinalBatchContext(
curContext,
nextQueueIndex,
queueLength,
queueRef
);
require(
msg.data.length == nextTransactionPtr,
"Not all sequencer transactions were processed."
);
require(
leafIndex == totalElementsToAppend,
"Actual transaction index does not match expected total elements to append."
);
// Generate the required metadata that we need to append this batch
uint40 numQueuedTransactions = totalElementsToAppend - numSequencerTransactions;
uint40 blockTimestamp;
uint40 blockNumber;
if (curContext.numSubsequentQueueTransactions == 0) {
// The last element is a sequencer tx, therefore pull timestamp and block number from the last context.
blockTimestamp = uint40(curContext.timestamp);
blockNumber = uint40(curContext.blockNumber);
} else {
// The last element is a queue tx, therefore pull timestamp and block number from the queue element.
// curContext.numSubsequentQueueTransactions > 0 which means that we've processed at least one queue element.
// We increment nextQueueIndex after processing each queue element,
// so the index of the last element we processed is nextQueueIndex - 1.
Lib_OVMCodec.QueueElement memory lastElement = _getQueueElement(
nextQueueIndex - 1,
queueRef
);
blockTimestamp = lastElement.timestamp;
blockNumber = lastElement.blockNumber;
}
// For efficiency reasons getMerkleRoot modifies the `leaves` argument in place
// while calculating the root hash therefore any arguments passed to it must not
// be used again afterwards
_appendBatch(
Lib_MerkleTree.getMerkleRoot(leaves),
totalElementsToAppend,
numQueuedTransactions,
blockTimestamp,
blockNumber
);
emit SequencerBatchAppended(
nextQueueIndex - numQueuedTransactions,
numQueuedTransactions,
getTotalElements()
);
}
/**
* Verifies whether a transaction is included in the chain.
* @param _transaction Transaction to verify.
* @param _txChainElement Transaction chain element corresponding to the transaction.
* @param _batchHeader Header of the batch the transaction was included in.
* @param _inclusionProof Inclusion proof for the provided transaction chain element.
* @return True if the transaction exists in the CTC, false if not.
*/
function verifyTransaction(
Lib_OVMCodec.Transaction memory _transaction,
Lib_OVMCodec.TransactionChainElement memory _txChainElement,
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
Lib_OVMCodec.ChainInclusionProof memory _inclusionProof
)
override
public
view
returns (
bool
)
{
if (_txChainElement.isSequenced == true) {
return _verifySequencerTransaction(
_transaction,
_txChainElement,
_batchHeader,
_inclusionProof
);
} else {
return _verifyQueueTransaction(
_transaction,
_txChainElement.queueIndex,
_batchHeader,
_inclusionProof
);
}
}
/**********************
* Internal Functions *
**********************/
/**
* Returns the BatchContext located at a particular index.
* @param _index The index of the BatchContext
* @return The BatchContext at the specified index.
*/
function _getBatchContext(
uint256 _index
)
internal
pure
returns (
BatchContext memory
)
{
uint256 contextPtr = 15 + _index * BATCH_CONTEXT_SIZE;
uint256 numSequencedTransactions;
uint256 numSubsequentQueueTransactions;
uint256 ctxTimestamp;
uint256 ctxBlockNumber;
assembly {
numSequencedTransactions := shr(232, calldataload(contextPtr))
numSubsequentQueueTransactions := shr(232, calldataload(add(contextPtr, 3)))
ctxTimestamp := shr(216, calldataload(add(contextPtr, 6)))
ctxBlockNumber := shr(216, calldataload(add(contextPtr, 11)))
}
return BatchContext({
numSequencedTransactions: numSequencedTransactions,
numSubsequentQueueTransactions: numSubsequentQueueTransactions,
timestamp: ctxTimestamp,
blockNumber: ctxBlockNumber
});
}
/**
* Parses the batch context from the extra data.
* @return Total number of elements submitted.
* @return Index of the next queue element.
*/
function _getBatchExtraData()
internal
view
returns (
uint40,
uint40,
uint40,
uint40
)
{
bytes27 extraData = batches().getGlobalMetadata();
uint40 totalElements;
uint40 nextQueueIndex;
uint40 lastTimestamp;
uint40 lastBlockNumber;
assembly {
extraData := shr(40, extraData)
totalElements := and(extraData, 0x000000000000000000000000000000000000000000000000000000FFFFFFFFFF)
nextQueueIndex := shr(40, and(extraData, 0x00000000000000000000000000000000000000000000FFFFFFFFFF0000000000))
lastTimestamp := shr(80, and(extraData, 0x0000000000000000000000000000000000FFFFFFFFFF00000000000000000000))
lastBlockNumber := shr(120, and(extraData, 0x000000000000000000000000FFFFFFFFFF000000000000000000000000000000))
}
return (
totalElements,
nextQueueIndex,
lastTimestamp,
lastBlockNumber
);
}
/**
* Encodes the batch context for the extra data.
* @param _totalElements Total number of elements submitted.
* @param _nextQueueIndex Index of the next queue element.
* @param _timestamp Timestamp for the last batch.
* @param _blockNumber Block number of the last batch.
* @return Encoded batch context.
*/
function _makeBatchExtraData(
uint40 _totalElements,
uint40 _nextQueueIndex,
uint40 _timestamp,
uint40 _blockNumber
)
internal
pure
returns (
bytes27
)
{
bytes27 extraData;
assembly {
extraData := _totalElements
extraData := or(extraData, shl(40, _nextQueueIndex))
extraData := or(extraData, shl(80, _timestamp))
extraData := or(extraData, shl(120, _blockNumber))
extraData := shl(40, extraData)
}
return extraData;
}
/**
* Retrieves the hash of a queue element.
* @param _index Index of the queue element to retrieve a hash for.
* @return Hash of the queue element.
*/
function _getQueueLeafHash(
uint256 _index
)
internal
pure
returns (
bytes32
)
{
return _hashTransactionChainElement(
Lib_OVMCodec.TransactionChainElement({
isSequenced: false,
queueIndex: _index,
timestamp: 0,
blockNumber: 0,
txData: hex""
})
);
}
/**
* Gets the queue element at a particular index.
* @param _index Index of the queue element to access.
* @return _element Queue element at the given index.
*/
function _getQueueElement(
uint256 _index,
iOVM_ChainStorageContainer _queueRef
)
internal
view
returns (
Lib_OVMCodec.QueueElement memory _element
)
{
// The underlying queue data structure stores 2 elements
// per insertion, so to get the actual desired queue index
// we need to multiply by 2.
uint40 trueIndex = uint40(_index * 2);
bytes32 transactionHash = _queueRef.get(trueIndex);
bytes32 timestampAndBlockNumber = _queueRef.get(trueIndex + 1);
uint40 elementTimestamp;
uint40 elementBlockNumber;
assembly {
elementTimestamp := and(timestampAndBlockNumber, 0x000000000000000000000000000000000000000000000000000000FFFFFFFFFF)
elementBlockNumber := shr(40, and(timestampAndBlockNumber, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000))
}
return Lib_OVMCodec.QueueElement({
transactionHash: transactionHash,
timestamp: elementTimestamp,
blockNumber: elementBlockNumber
});
}
/**
* Retrieves the length of the queue.
* @return Length of the queue.
*/
function _getQueueLength(
iOVM_ChainStorageContainer _queueRef
)
internal
view
returns (
uint40
)
{
// The underlying queue data structure stores 2 elements
// per insertion, so to get the real queue length we need
// to divide by 2.
return uint40(_queueRef.length() / 2);
}
/**
* Retrieves the hash of a sequencer element.
* @param _context Batch context for the given element.
* @param _nextTransactionPtr Pointer to the next transaction in the calldata.
* @param _txDataLength Length of the transaction item.
* @return Hash of the sequencer element.
*/
function _getSequencerLeafHash(
BatchContext memory _context,
uint256 _nextTransactionPtr,
uint256 _txDataLength,
bytes memory _hashMemory
)
internal
pure
returns (
bytes32
)
{
// Only allocate more memory if we didn't reserve enough to begin with.
if (BYTES_TILL_TX_DATA + _txDataLength > _hashMemory.length) {
_hashMemory = new bytes(BYTES_TILL_TX_DATA + _txDataLength);
}
uint256 ctxTimestamp = _context.timestamp;
uint256 ctxBlockNumber = _context.blockNumber;
bytes32 leafHash;
assembly {
let chainElementStart := add(_hashMemory, 0x20)
// Set the first byte equal to `1` to indicate this is a sequencer chain element.
// This distinguishes sequencer ChainElements from queue ChainElements because
// all queue ChainElements are ABI encoded and the first byte of ABI encoded
// elements is always zero
mstore8(chainElementStart, 1)
mstore(add(chainElementStart, 1), ctxTimestamp)
mstore(add(chainElementStart, 33), ctxBlockNumber)
calldatacopy(add(chainElementStart, BYTES_TILL_TX_DATA), add(_nextTransactionPtr, 3), _txDataLength)
leafHash := keccak256(chainElementStart, add(BYTES_TILL_TX_DATA, _txDataLength))
}
return leafHash;
}
/**
* Retrieves the hash of a sequencer element.
* @param _txChainElement The chain element which is hashed to calculate the leaf.
* @return Hash of the sequencer element.
*/
function _getSequencerLeafHash(
Lib_OVMCodec.TransactionChainElement memory _txChainElement
)
internal
view
returns(
bytes32
)
{
bytes memory txData = _txChainElement.txData;
uint256 txDataLength = _txChainElement.txData.length;
bytes memory chainElement = new bytes(BYTES_TILL_TX_DATA + txDataLength);
uint256 ctxTimestamp = _txChainElement.timestamp;
uint256 ctxBlockNumber = _txChainElement.blockNumber;
bytes32 leafHash;
assembly {
let chainElementStart := add(chainElement, 0x20)
// Set the first byte equal to `1` to indicate this is a sequencer chain element.
// This distinguishes sequencer ChainElements from queue ChainElements because
// all queue ChainElements are ABI encoded and the first byte of ABI encoded
// elements is always zero
mstore8(chainElementStart, 1)
mstore(add(chainElementStart, 1), ctxTimestamp)
mstore(add(chainElementStart, 33), ctxBlockNumber)
pop(staticcall(gas(), 0x04, add(txData, 0x20), txDataLength, add(chainElementStart, BYTES_TILL_TX_DATA), txDataLength))
leafHash := keccak256(chainElementStart, add(BYTES_TILL_TX_DATA, txDataLength))
}
return leafHash;
}
/**
* Inserts a batch into the chain of batches.
* @param _transactionRoot Root of the transaction tree for this batch.
* @param _batchSize Number of elements in the batch.
* @param _numQueuedTransactions Number of queue transactions in the batch.
* @param _timestamp The latest batch timestamp.
* @param _blockNumber The latest batch blockNumber.
*/
function _appendBatch(
bytes32 _transactionRoot,
uint256 _batchSize,
uint256 _numQueuedTransactions,
uint40 _timestamp,
uint40 _blockNumber
)
internal
{
iOVM_ChainStorageContainer batchesRef = batches();
(uint40 totalElements, uint40 nextQueueIndex,,) = _getBatchExtraData();
Lib_OVMCodec.ChainBatchHeader memory header = Lib_OVMCodec.ChainBatchHeader({
batchIndex: batchesRef.length(),
batchRoot: _transactionRoot,
batchSize: _batchSize,
prevTotalElements: totalElements,
extraData: hex""
});
emit TransactionBatchAppended(
header.batchIndex,
header.batchRoot,
header.batchSize,
header.prevTotalElements,
header.extraData
);
bytes32 batchHeaderHash = Lib_OVMCodec.hashBatchHeader(header);
bytes27 latestBatchContext = _makeBatchExtraData(
totalElements + uint40(header.batchSize),
nextQueueIndex + uint40(_numQueuedTransactions),
_timestamp,
_blockNumber
);
batchesRef.push(batchHeaderHash, latestBatchContext);
}
/**
* Checks that the first batch context in a sequencer submission is valid
* @param _firstContext The batch context to validate.
*/
function _validateFirstBatchContext(
BatchContext memory _firstContext
)
internal
view
{
// If there are existing elements, this batch must have the same context
// or a later timestamp and block number.
if (getTotalElements() > 0) {
(,, uint40 lastTimestamp, uint40 lastBlockNumber) = _getBatchExtraData();
require(
_firstContext.blockNumber >= lastBlockNumber,
"Context block number is lower than last submitted."
);
require(
_firstContext.timestamp >= lastTimestamp,
"Context timestamp is lower than last submitted."
);
}
// Sequencer cannot submit contexts which are more than the force inclusion period old.
require(
_firstContext.timestamp + forceInclusionPeriodSeconds >= block.timestamp,
"Context timestamp too far in the past."
);
require(
_firstContext.blockNumber + forceInclusionPeriodBlocks >= block.number,
"Context block number too far in the past."
);
}
/**
* Checks that a given batch context has a time context which is below a given que element
* @param _context The batch context to validate has values lower.
* @param _queueIndex Index of the queue element we are validating came later than the context.
* @param _queueRef The storage container for the queue.
*/
function _validateContextBeforeEnqueue(
BatchContext memory _context,
uint40 _queueIndex,
iOVM_ChainStorageContainer _queueRef
)
internal
view
{
Lib_OVMCodec.QueueElement memory nextQueueElement = _getQueueElement(
_queueIndex,
_queueRef
);
// If the force inclusion period has passed for an enqueued transaction, it MUST be the next chain element.
require(
block.timestamp < nextQueueElement.timestamp + forceInclusionPeriodSeconds,
"Previously enqueued batches have expired and must be appended before a new sequencer batch."
);
// Just like sequencer transaction times must be increasing relative to each other,
// We also require that they be increasing relative to any interspersed queue elements.
require(
_context.timestamp <= nextQueueElement.timestamp,
"Sequencer transaction timestamp exceeds that of next queue element."
);
require(
_context.blockNumber <= nextQueueElement.blockNumber,
"Sequencer transaction blockNumber exceeds that of next queue element."
);
}
/**
* Checks that a given batch context is valid based on its previous context, and the next queue elemtent.
* @param _prevContext The previously validated batch context.
* @param _nextContext The batch context to validate with this call.
* @param _nextQueueIndex Index of the next queue element to process for the _nextContext's subsequentQueueElements.
* @param _queueRef The storage container for the queue.
*/
function _validateNextBatchContext(
BatchContext memory _prevContext,
BatchContext memory _nextContext,
uint40 _nextQueueIndex,
iOVM_ChainStorageContainer _queueRef
)
internal
view
{
// All sequencer transactions' times must be greater than or equal to the previous ones.
require(
_nextContext.timestamp >= _prevContext.timestamp,
"Context timestamp values must monotonically increase."
);
require(
_nextContext.blockNumber >= _prevContext.blockNumber,
"Context blockNumber values must monotonically increase."
);
// If there is going to be a queue element pulled in from this context:
if (_nextContext.numSubsequentQueueTransactions > 0) {
_validateContextBeforeEnqueue(
_nextContext,
_nextQueueIndex,
_queueRef
);
}
}
/**
* Checks that the final batch context in a sequencer submission is valid.
* @param _finalContext The batch context to validate.
* @param _queueLength The length of the queue at the start of the batchAppend call.
* @param _nextQueueIndex The next element in the queue that will be pulled into the CTC.
* @param _queueRef The storage container for the queue.
*/
function _validateFinalBatchContext(
BatchContext memory _finalContext,
uint40 _nextQueueIndex,
uint40 _queueLength,
iOVM_ChainStorageContainer _queueRef
)
internal
view
{
// If the queue is not now empty, check the mononoticity of whatever the next batch that will come in is.
if (_queueLength - _nextQueueIndex > 0 && _finalContext.numSubsequentQueueTransactions == 0) {
_validateContextBeforeEnqueue(
_finalContext,
_nextQueueIndex,
_queueRef
);
}
// Batches cannot be added from the future, or subsequent enqueue() contexts would violate monotonicity.
require(_finalContext.timestamp <= block.timestamp, "Context timestamp is from the future.");
require(_finalContext.blockNumber <= block.number, "Context block number is from the future.");
}
/**
* Hashes a transaction chain element.
* @param _element Chain element to hash.
* @return Hash of the chain element.
*/
function _hashTransactionChainElement(
Lib_OVMCodec.TransactionChainElement memory _element
)
internal
pure
returns (
bytes32
)
{
return keccak256(
abi.encode(
_element.isSequenced,
_element.queueIndex,
_element.timestamp,
_element.blockNumber,
_element.txData
)
);
}
/**
* Verifies a sequencer transaction, returning true if it was indeed included in the CTC
* @param _transaction The transaction we are verifying inclusion of.
* @param _txChainElement The chain element that the transaction is claimed to be a part of.
* @param _batchHeader Header of the batch the transaction was included in.
* @param _inclusionProof An inclusion proof into the CTC at a particular index.
* @return True if the transaction was included in the specified location, else false.
*/
function _verifySequencerTransaction(
Lib_OVMCodec.Transaction memory _transaction,
Lib_OVMCodec.TransactionChainElement memory _txChainElement,
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
Lib_OVMCodec.ChainInclusionProof memory _inclusionProof
)
internal
view
returns (
bool
)
{
OVM_ExecutionManager ovmExecutionManager = OVM_ExecutionManager(resolve("OVM_ExecutionManager"));
uint256 gasLimit = ovmExecutionManager.getMaxTransactionGasLimit();
bytes32 leafHash = _getSequencerLeafHash(_txChainElement);
require(
_verifyElement(
leafHash,
_batchHeader,
_inclusionProof
),
"Invalid Sequencer transaction inclusion proof."
);
require(
_transaction.blockNumber == _txChainElement.blockNumber
&& _transaction.timestamp == _txChainElement.timestamp
&& _transaction.entrypoint == resolve("OVM_DecompressionPrecompileAddress")
&& _transaction.gasLimit == gasLimit
&& _transaction.l1TxOrigin == address(0)
&& _transaction.l1QueueOrigin == Lib_OVMCodec.QueueOrigin.SEQUENCER_QUEUE
&& keccak256(_transaction.data) == keccak256(_txChainElement.txData),
"Invalid Sequencer transaction."
);
return true;
}
/**
* Verifies a queue transaction, returning true if it was indeed included in the CTC
* @param _transaction The transaction we are verifying inclusion of.
* @param _queueIndex The queueIndex of the queued transaction.
* @param _batchHeader Header of the batch the transaction was included in.
* @param _inclusionProof An inclusion proof into the CTC at a particular index (should point to queue tx).
* @return True if the transaction was included in the specified location, else false.
*/
function _verifyQueueTransaction(
Lib_OVMCodec.Transaction memory _transaction,
uint256 _queueIndex,
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
Lib_OVMCodec.ChainInclusionProof memory _inclusionProof
)
internal
view
returns (
bool
)
{
bytes32 leafHash = _getQueueLeafHash(_queueIndex);
require(
_verifyElement(
leafHash,
_batchHeader,
_inclusionProof
),
"Invalid Queue transaction inclusion proof."
);
bytes32 transactionHash = keccak256(
abi.encode(
_transaction.l1TxOrigin,
_transaction.entrypoint,
_transaction.gasLimit,
_transaction.data
)
);
Lib_OVMCodec.QueueElement memory el = getQueueElement(_queueIndex);
require(
el.transactionHash == transactionHash
&& el.timestamp == _transaction.timestamp
&& el.blockNumber == _transaction.blockNumber,
"Invalid Queue transaction."
);
return true;
}
/**
* Verifies a batch inclusion proof.
* @param _element Hash of the element to verify a proof for.
* @param _batchHeader Header of the batch in which the element was included.
* @param _proof Merkle inclusion proof for the element.
*/
function _verifyElement(
bytes32 _element,
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
Lib_OVMCodec.ChainInclusionProof memory _proof
)
internal
view
returns (
bool
)
{
require(
Lib_OVMCodec.hashBatchHeader(_batchHeader) == batches().get(uint32(_batchHeader.batchIndex)),
"Invalid batch header."
);
require(
Lib_MerkleTree.verify(
_batchHeader.batchRoot,
_element,
_proof.index,
_proof.siblings,
_batchHeader.batchSize
),
"Invalid inclusion proof."
);
return true;
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/chain/OVM_ChainStorageContainer.sol
================================================
// 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;
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/chain/OVM_StateCommitmentChain.sol
================================================
// 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_MerkleTree } from "../../libraries/utils/Lib_MerkleTree.sol";
/* Interface Imports */
import { iOVM_FraudVerifier } from "../../iOVM/verification/iOVM_FraudVerifier.sol";
import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitmentChain.sol";
import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
import { iOVM_BondManager } from "../../iOVM/verification/iOVM_BondManager.sol";
import { iOVM_ChainStorageContainer } from "../../iOVM/chain/iOVM_ChainStorageContainer.sol";
/* External Imports */
import '@openzeppelin/contracts/math/SafeMath.sol';
/**
* @title OVM_StateCommitmentChain
* @dev The State Commitment Chain (SCC) contract contains a list of proposed state roots which
* Proposers assert to be a result of each transaction in the Canonical Transaction Chain (CTC).
* Elements here have a 1:1 correspondence with transactions in the CTC, and should be the unique
* state root calculated off-chain by applying the canonical transactions one by one.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, Lib_AddressResolver {
/*************
* Constants *
*************/
uint256 public FRAUD_PROOF_WINDOW;
uint256 public SEQUENCER_PUBLISH_WINDOW;
/***************
* Constructor *
***************/
/**
* @param _libAddressManager Address of the Address Manager.
*/
constructor(
address _libAddressManager,
uint256 _fraudProofWindow,
uint256 _sequencerPublishWindow
)
Lib_AddressResolver(_libAddressManager)
{
FRAUD_PROOF_WINDOW = _fraudProofWindow;
SEQUENCER_PUBLISH_WINDOW = _sequencerPublishWindow;
}
/********************
* Public Functions *
********************/
/**
* Accesses the batch storage container.
* @return Reference to the batch storage container.
*/
function batches()
public
view
returns (
iOVM_ChainStorageContainer
)
{
return iOVM_ChainStorageContainer(
resolve("OVM_ChainStorageContainer:SCC:batches")
);
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function getTotalElements()
override
public
view
returns (
uint256 _totalElements
)
{
(uint40 totalElements, ) = _getBatchExtraData();
return uint256(totalElements);
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function getTotalBatches()
override
public
view
returns (
uint256 _totalBatches
)
{
return batches().length();
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function getLastSequencerTimestamp()
override
public
view
returns (
uint256 _lastSequencerTimestamp
)
{
(, uint40 lastSequencerTimestamp) = _getBatchExtraData();
return uint256(lastSequencerTimestamp);
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function appendStateBatch(
bytes32[] memory _batch,
uint256 _shouldStartAtElement
)
override
public
{
// Fail fast in to make sure our batch roots aren't accidentally made fraudulent by the
// publication of batches by some other user.
require(
_shouldStartAtElement == getTotalElements(),
"Actual batch start index does not match expected start index."
);
// Proposers must have previously staked at the BondManager
require(
iOVM_BondManager(resolve("OVM_BondManager")).isCollateralized(msg.sender),
"Proposer does not have enough collateral posted"
);
require(
_batch.length > 0,
"Cannot submit an empty state batch."
);
require(
getTotalElements() + _batch.length <= iOVM_CanonicalTransactionChain(resolve("OVM_CanonicalTransactionChain")).getTotalElements(),
"Number of state roots cannot exceed the number of canonical transactions."
);
// Pass the block's timestamp and the publisher of the data
// to be used in the fraud proofs
_appendBatch(
_batch,
abi.encode(block.timestamp, msg.sender)
);
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function deleteStateBatch(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
override
public
{
require(
msg.sender == resolve("OVM_FraudVerifier"),
"State batches can only be deleted by the OVM_FraudVerifier."
);
require(
_isValidBatchHeader(_batchHeader),
"Invalid batch header."
);
require(
insideFraudProofWindow(_batchHeader),
"State batches can only be deleted within the fraud proof window."
);
_deleteBatch(_batchHeader);
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function verifyStateCommitment(
bytes32 _element,
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
Lib_OVMCodec.ChainInclusionProof memory _proof
)
override
public
view
returns (
bool
)
{
require(
_isValidBatchHeader(_batchHeader),
"Invalid batch header."
);
require(
Lib_MerkleTree.verify(
_batchHeader.batchRoot,
_element,
_proof.index,
_proof.siblings,
_batchHeader.batchSize
),
"Invalid inclusion proof."
);
return true;
}
/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function insideFraudProofWindow(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
override
public
view
returns (
bool _inside
)
{
(uint256 timestamp,) = abi.decode(
_batchHeader.extraData,
(uint256, address)
);
require(
timestamp != 0,
"Batch header timestamp cannot be zero"
);
return SafeMath.add(timestamp, FRAUD_PROOF_WINDOW) > block.timestamp;
}
/**********************
* Internal Functions *
**********************/
/**
* Parses the batch context from the extra data.
* @return Total number of elements submitted.
* @return Timestamp of the last batch submitted by the sequencer.
*/
function _getBatchExtraData()
internal
view
returns (
uint40,
uint40
)
{
bytes27 extraData = batches().getGlobalMetadata();
uint40 totalElements;
uint40 lastSequencerTimestamp;
assembly {
extraData := shr(40, extraData)
totalElements := and(extraData, 0x000000000000000000000000000000000000000000000000000000FFFFFFFFFF)
lastSequencerTimestamp := shr(40, and(extraData, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000))
}
return (
totalElements,
lastSequencerTimestamp
);
}
/**
* Encodes the batch context for the extra data.
* @param _totalElements Total number of elements submitted.
* @param _lastSequencerTimestamp Timestamp of the last batch submitted by the sequencer.
* @return Encoded batch context.
*/
function _makeBatchExtraData(
uint40 _totalElements,
uint40 _lastSequencerTimestamp
)
internal
pure
returns (
bytes27
)
{
bytes27 extraData;
assembly {
extraData := _totalElements
extraData := or(extraData, shl(40, _lastSequencerTimestamp))
extraData := shl(40, extraData)
}
return extraData;
}
/**
* Appends a batch to the chain.
* @param _batch Elements within the batch.
* @param _extraData Any extra data to append to the batch.
*/
function _appendBatch(
bytes32[] memory _batch,
bytes memory _extraData
)
internal
{
address sequencer = resolve("OVM_Proposer");
(uint40 totalElements, uint40 lastSequencerTimestamp) = _getBatchExtraData();
if (msg.sender == sequencer) {
lastSequencerTimestamp = uint40(block.timestamp);
} else {
// We keep track of the last batch submitted by the sequencer so there's a window in
// which only the sequencer can publish state roots. A window like this just reduces
// the chance of "system breaking" state roots being published while we're still in
// testing mode. This window should be removed or significantly reduced in the future.
require(
lastSequencerTimestamp + SEQUENCER_PUBLISH_WINDOW < block.timestamp,
"Cannot publish state roots within the sequencer publication window."
);
}
// For efficiency reasons getMerkleRoot modifies the `_batch` argument in place
// while calculating the root hash therefore any arguments passed to it must not
// be used again afterwards
Lib_OVMCodec.ChainBatchHeader memory batchHeader = Lib_OVMCodec.ChainBatchHeader({
batchIndex: getTotalBatches(),
batchRoot: Lib_MerkleTree.getMerkleRoot(_batch),
batchSize: _batch.length,
prevTotalElements: totalElements,
extraData: _extraData
});
emit StateBatchAppended(
batchHeader.batchIndex,
batchHeader.batchRoot,
batchHeader.batchSize,
batchHeader.prevTotalElements,
batchHeader.extraData
);
batches().push(
Lib_OVMCodec.hashBatchHeader(batchHeader),
_makeBatchExtraData(
uint40(batchHeader.prevTotalElements + batchHeader.batchSize),
lastSequencerTimestamp
)
);
}
/**
* Removes a batch and all subsequent batches from the chain.
* @param _batchHeader Header of the batch to remove.
*/
function _deleteBatch(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
internal
{
require(
_batchHeader.batchIndex < batches().length(),
"Invalid batch index."
);
require(
_isValidBatchHeader(_batchHeader),
"Invalid batch header."
);
batches().deleteElementsAfterInclusive(
_batchHeader.batchIndex,
_makeBatchExtraData(
uint40(_batchHeader.prevTotalElements),
0
)
);
emit StateBatchDeleted(
_batchHeader.batchIndex,
_batchHeader.batchRoot
);
}
/**
* Checks that a batch header matches the stored hash for the given index.
* @param _batchHeader Batch header to validate.
* @return Whether or not the header matches the stored one.
*/
function _isValidBatchHeader(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
)
internal
view
returns (
bool
)
{
return Lib_OVMCodec.hashBatchHeader(_batchHeader) == batches().get(_batchHeader.batchIndex);
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol
================================================
// SPDX-License-Identifier: MIT
// @unsupported: ovm
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_EthUtils } from "../../libraries/utils/Lib_EthUtils.sol";
import { Lib_ErrorUtils } from "../../libraries/utils/Lib_ErrorUtils.sol";
/* Interface Imports */
import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol";
import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol";
/* Contract Imports */
import { OVM_ECDSAContractAccount } from "../accounts/OVM_ECDSAContractAccount.sol";
import { OVM_ProxyEOA } from "../accounts/OVM_ProxyEOA.sol";
import { OVM_DeployerWhitelist } from "../predeploys/OVM_DeployerWhitelist.sol";
/**
* @title OVM_ExecutionManager
* @dev The Execution Manager (EM) is the core of our OVM implementation, and provides a sandboxed
* environment allowing us to execute OVM transactions deterministically on either Layer 1 or
* Layer 2.
* The EM's run() function is the first function called during the execution of any
* transaction on L2.
* For each context-dependent EVM operation the EM has a function which implements a corresponding
* OVM operation, which will read state from the State Manager contract.
* The EM relies on the Safety Checker to verify that code deployed to Layer 2 does not contain any
* context-dependent operations.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
/********************************
* External Contract References *
********************************/
iOVM_SafetyChecker internal ovmSafetyChecker;
iOVM_StateManager internal ovmStateManager;
/*******************************
* Execution Context Variables *
*******************************/
GasMeterConfig internal gasMeterConfig;
GlobalContext internal globalContext;
TransactionContext internal transactionContext;
MessageContext internal messageContext;
TransactionRecord internal transactionRecord;
MessageRecord internal messageRecord;
/**************************
* Gas Metering Constants *
**************************/
address constant GAS_METADATA_ADDRESS = 0x06a506A506a506A506a506a506A506A506A506A5;
uint256 constant NUISANCE_GAS_SLOAD = 20000;
uint256 constant NUISANCE_GAS_SSTORE = 20000;
uint256 constant MIN_NUISANCE_GAS_PER_CONTRACT = 30000;
uint256 constant NUISANCE_GAS_PER_CONTRACT_BYTE = 100;
uint256 constant MIN_GAS_FOR_INVALID_STATE_ACCESS = 30000;
/**************************
* Default Context Values *
**************************/
uint256 constant DEFAULT_UINT256 = 0xdefa017defa017defa017defa017defa017defa017defa017defa017defa017d;
address constant DEFAULT_ADDRESS = 0xdEfa017defA017DeFA017DEfa017DeFA017DeFa0;
/***************
* Constructor *
***************/
/**
* @param _libAddressManager Address of the Address Manager.
*/
constructor(
address _libAddressManager,
GasMeterConfig memory _gasMeterConfig,
GlobalContext memory _globalContext
)
Lib_AddressResolver(_libAddressManager)
{
ovmSafetyChecker = iOVM_SafetyChecker(resolve("OVM_SafetyChecker"));
gasMeterConfig = _gasMeterConfig;
globalContext = _globalContext;
_resetContext();
}
/**********************
* Function Modifiers *
**********************/
/**
* Applies dynamically-sized refund to a transaction to account for the difference in execution
* between L1 and L2, so that the overall cost of the ovmOPCODE is fixed.
* @param _cost Desired gas cost for the function after the refund.
*/
modifier netGasCost(
uint256 _cost
) {
uint256 gasProvided = gasleft();
_;
uint256 gasUsed = gasProvided - gasleft();
// We want to refund everything *except* the specified cost.
if (_cost < gasUsed) {
transactionRecord.ovmGasRefund += gasUsed - _cost;
}
}
/**
* Applies a fixed-size gas refund to a transaction to account for the difference in execution
* between L1 and L2, so that the overall cost of an ovmOPCODE can be lowered.
* @param _discount Amount of gas cost to refund for the ovmOPCODE.
*/
modifier fixedGasDiscount(
uint256 _discount
) {
uint256 gasProvided = gasleft();
_;
uint256 gasUsed = gasProvided - gasleft();
// We want to refund the specified _discount, unless this risks underflow.
if (_discount < gasUsed) {
transactionRecord.ovmGasRefund += _discount;
} else {
// refund all we can without risking underflow.
transactionRecord.ovmGasRefund += gasUsed;
}
}
/**
* Makes sure we're not inside a static context.
*/
modifier notStatic() {
if (messageContext.isStatic == true) {
_revertWithFlag(RevertFlag.STATIC_VIOLATION);
}
_;
}
/************************************
* Transaction Execution Entrypoint *
************************************/
/**
* Starts the execution of a transaction via the OVM_ExecutionManager.
* @param _transaction Transaction data to be executed.
* @param _ovmStateManager iOVM_StateManager implementation providing account state.
*/
function run(
Lib_OVMCodec.Transaction memory _transaction,
address _ovmStateManager
)
override
public
{
// Make sure that run() is not re-enterable. This condition should awlways be satisfied
// Once run has been called once, due to the behvaior of _isValidInput().
if (transactionContext.ovmNUMBER != DEFAULT_UINT256) {
return;
}
// Store our OVM_StateManager instance (significantly easier than attempting to pass the
// address around in calldata).
ovmStateManager = iOVM_StateManager(_ovmStateManager);
// Make sure this function can't be called by anyone except the owner of the
// OVM_StateManager (expected to be an OVM_StateTransitioner). We can revert here because
// this would make the `run` itself invalid.
require(
// This method may return false during fraud proofs, but always returns true in L2 nodes' State Manager precompile.
ovmStateManager.isAuthenticated(msg.sender),
"Only authenticated addresses in ovmStateManager can call this function"
);
// Initialize the execution context, must be initialized before we perform any gas metering
// or we'll throw a nuisance gas error.
_initContext(_transaction);
// TEMPORARY: Gas metering is disabled for minnet.
// // Check whether we need to start a new epoch, do so if necessary.
// _checkNeedsNewEpoch(_transaction.timestamp);
// Make sure the transaction's gas limit is valid. We don't revert here because we reserve
// reverts for INVALID_STATE_ACCESS.
if (_isValidInput(_transaction) == false) {
_resetContext();
return;
}
// TEMPORARY: Gas metering is disabled for minnet.
// // Check gas right before the call to get total gas consumed by OVM transaction.
// uint256 gasProvided = gasleft();
// Run the transaction, make sure to meter the gas usage.
ovmCALL(
_transaction.gasLimit - gasMeterConfig.minTransactionGasLimit,
_transaction.entrypoint,
_transaction.data
);
// TEMPORARY: Gas metering is disabled for minnet.
// // Update the cumulative gas based on the amount of gas used.
// uint256 gasUsed = gasProvided - gasleft();
// _updateCumulativeGas(gasUsed, _transaction.l1QueueOrigin);
// Wipe the execution context.
_resetContext();
}
/******************************
* Opcodes: Execution Context *
******************************/
/**
* @notice Overrides CALLER.
* @return _CALLER Address of the CALLER within the current message context.
*/
function ovmCALLER()
override
public
view
returns (
address _CALLER
)
{
return messageContext.ovmCALLER;
}
/**
* @notice Overrides ADDRESS.
* @return _ADDRESS Active ADDRESS within the current message context.
*/
function ovmADDRESS()
override
public
view
returns (
address _ADDRESS
)
{
return messageContext.ovmADDRESS;
}
/**
* @notice Overrides TIMESTAMP.
* @return _TIMESTAMP Value of the TIMESTAMP within the transaction context.
*/
function ovmTIMESTAMP()
override
public
view
returns (
uint256 _TIMESTAMP
)
{
return transactionContext.ovmTIMESTAMP;
}
/**
* @notice Overrides NUMBER.
* @return _NUMBER Value of the NUMBER within the transaction context.
*/
function ovmNUMBER()
override
public
view
returns (
uint256 _NUMBER
)
{
return transactionContext.ovmNUMBER;
}
/**
* @notice Overrides GASLIMIT.
* @return _GASLIMIT Value of the block's GASLIMIT within the transaction context.
*/
function ovmGASLIMIT()
override
public
view
returns (
uint256 _GASLIMIT
)
{
return transactionContext.ovmGASLIMIT;
}
/**
* @notice Overrides CHAINID.
* @return _CHAINID Value of the chain's CHAINID within the global context.
*/
function ovmCHAINID()
override
public
view
returns (
uint256 _CHAINID
)
{
return globalContext.ovmCHAINID;
}
/*********************************
* Opcodes: L2 Execution Context *
*********************************/
/**
* @notice Specifies from which L1 rollup queue this transaction originated from.
* @return _queueOrigin Address of the ovmL1QUEUEORIGIN within the current message context.
*/
function ovmL1QUEUEORIGIN()
override
public
view
returns (
Lib_OVMCodec.QueueOrigin _queueOrigin
)
{
return transactionContext.ovmL1QUEUEORIGIN;
}
/**
* @notice Specifies which L1 account, if any, sent this transaction by calling enqueue().
* @return _l1TxOrigin Address of the account which sent the tx into L2 from L1.
*/
function ovmL1TXORIGIN()
override
public
view
returns (
address _l1TxOrigin
)
{
return transactionContext.ovmL1TXORIGIN;
}
/********************
* Opcodes: Halting *
********************/
/**
* @notice Overrides REVERT.
* @param _data Bytes data to pass along with the REVERT.
*/
function ovmREVERT(
bytes memory _data
)
override
public
{
_revertWithFlag(RevertFlag.INTENTIONAL_REVERT, _data);
}
/******************************
* Opcodes: Contract Creation *
******************************/
/**
* @notice Overrides CREATE.
* @param _bytecode Code to be used to CREATE a new contract.
* @return Address of the created contract.
* @return Revert data, if and only if the creation threw an exception.
*/
function ovmCREATE(
bytes memory _bytecode
)
override
public
notStatic
fixedGasDiscount(40000)
returns (
address,
bytes memory
)
{
// Creator is always the current ADDRESS.
address creator = ovmADDRESS();
// Check that the deployer is whitelisted, or
// that arbitrary contract deployment has been enabled.
_checkDeployerAllowed(creator);
// Generate the correct CREATE address.
address contractAddress = Lib_EthUtils.getAddressForCREATE(
creator,
_getAccountNonce(creator)
);
return _createContract(
contractAddress,
_bytecode
);
}
/**
* @notice Overrides CREATE2.
* @param _bytecode Code to be used to CREATE2 a new contract.
* @param _salt Value used to determine the contract's address.
* @return Address of the created contract.
* @return Revert data, if and only if the creation threw an exception.
*/
function ovmCREATE2(
bytes memory _bytecode,
bytes32 _salt
)
override
public
notStatic
fixedGasDiscount(40000)
returns (
address,
bytes memory
)
{
// Creator is always the current ADDRESS.
address creator = ovmADDRESS();
// Check that the deployer is whitelisted, or
// that arbitrary contract deployment has been enabled.
_checkDeployerAllowed(creator);
// Generate the correct CREATE2 address.
address contractAddress = Lib_EthUtils.getAddressForCREATE2(
creator,
_bytecode,
_salt
);
return _createContract(
contractAddress,
_bytecode
);
}
/*******************************
* Account Abstraction Opcodes *
******************************/
/**
* Retrieves the nonce of the current ovmADDRESS.
* @return _nonce Nonce of the current contract.
*/
function ovmGETNONCE()
override
public
returns (
uint256 _nonce
)
{
return _getAccountNonce(ovmADDRESS());
}
/**
* Bumps the nonce of the current ovmADDRESS by one.
*/
function ovmINCREMENTNONCE()
override
public
notStatic
{
address account = ovmADDRESS();
uint256 nonce = _getAccountNonce(account);
// Prevent overflow.
if (nonce + 1 > nonce) {
_setAccountNonce(account, nonce + 1);
}
}
/**
* Creates a new EOA contract account, for account abstraction.
* @dev Essentially functions like ovmCREATE or ovmCREATE2, but we can bypass a lot of checks
* because the contract we're creating is trusted (no need to do safety checking or to
* handle unexpected reverts). Doesn't need to return an address because the address is
* assumed to be the user's actual address.
* @param _messageHash Hash of a message signed by some user, for verification.
* @param _v Signature `v` parameter.
* @param _r Signature `r` parameter.
* @param _s Signature `s` parameter.
*/
function ovmCREATEEOA(
bytes32 _messageHash,
uint8 _v,
bytes32 _r,
bytes32 _s
)
override
public
notStatic
{
// Recover the EOA address from the message hash and signature parameters. Since we do the
// hashing in advance, we don't have handle different message hashing schemes. Even if this
// function were to return the wrong address (rather than explicitly returning the zero
// address), the rest of the transaction would simply fail (since there's no EOA account to
// actually execute the transaction).
address eoa = ecrecover(
_messageHash,
_v + 27,
_r,
_s
);
// Invalid signature is a case we proactively handle with a revert. We could alternatively
// have this function return a `success` boolean, but this is just easier.
if (eoa == address(0)) {
ovmREVERT(bytes("Signature provided for EOA contract creation is invalid."));
}
// If the user already has an EOA account, then there's no need to perform this operation.
if (_hasEmptyAccount(eoa) == false) {
return;
}
// We always need to initialize the contract with the default account values.
_initPendingAccount(eoa);
// Temporarily set the current address so it's easier to access on L2.
address prevADDRESS = messageContext.ovmADDRESS;
messageContext.ovmADDRESS = eoa;
// Now actually create the account and get its bytecode. We're not worried about reverts
// (other than out of gas, which we can't capture anyway) because this contract is trusted.
OVM_ProxyEOA proxyEOA = new OVM_ProxyEOA(0x4200000000000000000000000000000000000003);
// Reset the address now that we're done deploying.
messageContext.ovmADDRESS = prevADDRESS;
// Commit the account with its final values.
_commitPendingAccount(
eoa,
address(proxyEOA),
keccak256(Lib_EthUtils.getCode(address(proxyEOA)))
);
_setAccountNonce(eoa, 0);
}
/*********************************
* Opcodes: Contract Interaction *
*********************************/
/**
* @notice Overrides CALL.
* @param _gasLimit Amount of gas to be passed into this call.
* @param _address Address of the contract to call.
* @param _calldata Data to send along with the call.
* @return _success Whether or not the call returned (rather than reverted).
* @return _returndata Data returned by the call.
*/
function ovmCALL(
uint256 _gasLimit,
address _address,
bytes memory _calldata
)
override
public
fixedGasDiscount(100000)
returns (
bool _success,
bytes memory _returndata
)
{
// CALL updates the CALLER and ADDRESS.
MessageContext memory nextMessageContext = messageContext;
nextMessageContext.ovmCALLER = nextMessageContext.ovmADDRESS;
nextMessageContext.ovmADDRESS = _address;
return _callContract(
nextMessageContext,
_gasLimit,
_address,
_calldata
);
}
/**
* @notice Overrides STATICCALL.
* @param _gasLimit Amount of gas to be passed into this call.
* @param _address Address of the contract to call.
* @param _calldata Data to send along with the call.
* @return _success Whether or not the call returned (rather than reverted).
* @return _returndata Data returned by the call.
*/
function ovmSTATICCALL(
uint256 _gasLimit,
address _address,
bytes memory _calldata
)
override
public
fixedGasDiscount(80000)
returns (
bool _success,
bytes memory _returndata
)
{
// STATICCALL updates the CALLER, updates the ADDRESS, and runs in a static context.
MessageContext memory nextMessageContext = messageContext;
nextMessageContext.ovmCALLER = nextMessageContext.ovmADDRESS;
nextMessageContext.ovmADDRESS = _address;
nextMessageContext.isStatic = true;
return _callContract(
nextMessageContext,
_gasLimit,
_address,
_calldata
);
}
/**
* @notice Overrides DELEGATECALL.
* @param _gasLimit Amount of gas to be passed into this call.
* @param _address Address of the contract to call.
* @param _calldata Data to send along with the call.
* @return _success Whether or not the call returned (rather than reverted).
* @return _returndata Data returned by the call.
*/
function ovmDELEGATECALL(
uint256 _gasLimit,
address _address,
bytes memory _calldata
)
override
public
fixedGasDiscount(40000)
returns (
bool _success,
bytes memory _returndata
)
{
// DELEGATECALL does not change anything about the message context.
MessageContext memory nextMessageContext = messageContext;
return _callContract(
nextMessageContext,
_gasLimit,
_address,
_calldata
);
}
/************************************
* Opcodes: Contract Storage Access *
************************************/
/**
* @notice Overrides SLOAD.
* @param _key 32 byte key of the storage slot to load.
* @return _value 32 byte value of the requested storage slot.
*/
function ovmSLOAD(
bytes32 _key
)
override
public
netGasCost(40000)
returns (
bytes32 _value
)
{
// We always SLOAD from the storage of ADDRESS.
address contractAddress = ovmADDRESS();
return _getContractStorage(
contractAddress,
_key
);
}
/**
* @notice Overrides SSTORE.
* @param _key 32 byte key of the storage slot to set.
* @param _value 32 byte value for the storage slot.
*/
function ovmSSTORE(
bytes32 _key,
bytes32 _value
)
override
public
notStatic
netGasCost(60000)
{
// We always SSTORE to the storage of ADDRESS.
address contractAddress = ovmADDRESS();
_putContractStorage(
contractAddress,
_key,
_value
);
}
/*********************************
* Opcodes: Contract Code Access *
*********************************/
/**
* @notice Overrides EXTCODECOPY.
* @param _contract Address of the contract to copy code from.
* @param _offset Offset in bytes from the start of contract code to copy beyond.
* @param _length Total number of bytes to copy from the contract's code.
* @return _code Bytes of code copied from the requested contract.
*/
function ovmEXTCODECOPY(
address _contract,
uint256 _offset,
uint256 _length
)
override
public
returns (
bytes memory _code
)
{
// `ovmEXTCODECOPY` is the only overridden opcode capable of producing exactly one byte of
// return data. By blocking reads of one byte, we're able to use the condition that an
// OVM_ExecutionManager function return value having a length of exactly one byte indicates
// an error without an explicit revert. If users were able to read a single byte, they
// could forcibly trigger behavior that should only be available to this contract.
uint256 length = _length == 1 ? 2 : _length;
return Lib_EthUtils.getCode(
_getAccountEthAddress(_contract),
_offset,
length
);
}
/**
* @notice Overrides EXTCODESIZE.
* @param _contract Address of the contract to query the size of.
* @return _EXTCODESIZE Size of the requested contract in bytes.
*/
function ovmEXTCODESIZE(
address _contract
)
override
public
returns (
uint256 _EXTCODESIZE
)
{
return Lib_EthUtils.getCodeSize(
_getAccountEthAddress(_contract)
);
}
/**
* @notice Overrides EXTCODEHASH.
* @param _contract Address of the contract to query the hash of.
* @return _EXTCODEHASH Hash of the requested contract.
*/
function ovmEXTCODEHASH(
address _contract
)
override
public
returns (
bytes32 _EXTCODEHASH
)
{
return Lib_EthUtils.getCodeHash(
_getAccountEthAddress(_contract)
);
}
/***************************************
* Public Functions: Execution Context *
***************************************/
function getMaxTransactionGasLimit()
external
view
override
returns (
uint256 _maxTransactionGasLimit
)
{
return gasMeterConfig.maxTransactionGasLimit;
}
/********************************************
* Public Functions: Deployment Whitelisting *
********************************************/
/**
* Checks whether the given address is on the whitelist to ovmCREATE/ovmCREATE2, and reverts if not.
* @param _deployerAddress Address attempting to deploy a contract.
*/
function _checkDeployerAllowed(
address _deployerAddress
)
internal
{
// From an OVM semantics perspective, this will appear identical to
// the deployer ovmCALLing the whitelist. This is fine--in a sense, we are forcing them to.
(bool success, bytes memory data) = ovmCALL(
gasleft(),
0x4200000000000000000000000000000000000002,
abi.encodeWithSignature("isDeployerAllowed(address)", _deployerAddress)
);
bool isAllowed = abi.decode(data, (bool));
if (!isAllowed || !success) {
_revertWithFlag(RevertFlag.CREATOR_NOT_ALLOWED);
}
}
/********************************************
* Internal Functions: Contract Interaction *
********************************************/
/**
* Creates a new contract and associates it with some contract address.
* @param _contractAddress Address to associate the created contract with.
* @param _bytecode Bytecode to be used to create the contract.
* @return Final OVM contract address.
* @return Revertdata, if and only if the creation threw an exception.
*/
function _createContract(
address _contractAddress,
bytes memory _bytecode
)
internal
returns (
address,
bytes memory
)
{
// We always update the nonce of the creating account, even if the creation fails.
_setAccountNonce(ovmADDRESS(), _getAccountNonce(ovmADDRESS()) + 1);
// We're stepping into a CREATE or CREATE2, so we need to update ADDRESS to point
// to the contract's associated address and CALLER to point to the previous ADDRESS.
MessageContext memory nextMessageContext = messageContext;
nextMessageContext.ovmCALLER = messageContext.ovmADDRESS;
nextMessageContext.ovmADDRESS = _contractAddress;
// Run the common logic which occurs between call-type and create-type messages,
// passing in the creation bytecode and `true` to trigger create-specific logic.
(bool success, bytes memory data) = _handleExternalMessage(
nextMessageContext,
gasleft(),
_contractAddress,
_bytecode,
true
);
// Yellow paper requires that address returned is zero if the contract deployment fails.
return (
success ? _contractAddress : address(0),
data
);
}
/**
* Calls the deployed contract associated with a given address.
* @param _nextMessageContext Message context to be used for the call.
* @param _gasLimit Amount of gas to be passed into this call.
* @param _contract OVM address to be called.
* @param _calldata Data to send along with the call.
* @return _success Whether or not the call returned (rather than reverted).
* @return _returndata Data returned by the call.
*/
function _callContract(
MessageContext memory _nextMessageContext,
uint256 _gasLimit,
address _contract,
bytes memory _calldata
)
internal
returns (
bool _success,
bytes memory _returndata
)
{
// We reserve addresses of the form 0xdeaddeaddead...NNNN for the container contracts in L2 geth.
// So, we block calls to these addresses since they are not safe to run as an OVM contract itself.
if (
(uint256(_contract) & uint256(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000))
== uint256(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000)
) {
// EVM does not return data in the success case, see: https://github.com/ethereum/go-ethereum/blob/aae7660410f0ef90279e14afaaf2f429fdc2a186/core/vm/instructions.go#L600-L604
return (true, hex'');
}
// Both 0x0000... and the EVM precompiles have the same address on L1 and L2 --> no trie lookup needed.
address codeContractAddress =
uint(_contract) < 100
? _contract
: _getAccountEthAddress(_contract);
return _handleExternalMessage(
_nextMessageContext,
_gasLimit,
codeContractAddress,
_calldata,
false
);
}
/**
* Handles all interactions which involve the execution manager calling out to untrusted code (both calls and creates).
* Ensures that OVM-related measures are enforced, including L2 gas refunds, nuisance gas, and flagged reversions.
*
* @param _nextMessageContext Message context to be used for the external message.
* @param _gasLimit Amount of gas to be passed into this message.
* @param _contract OVM address being called or deployed to
* @param _data Data for the message (either calldata or creation code)
* @param _isCreate Whether this is a create-type message.
* @return Whether or not the message (either a call or deployment) succeeded.
* @return Data returned by the message.
*/
function _handleExternalMessage(
MessageContext memory _nextMessageContext,
uint256 _gasLimit,
address _contract,
bytes memory _data,
bool _isCreate
)
internal
returns (
bool,
bytes memory
)
{
// We need to switch over to our next message context for the duration of this call.
MessageContext memory prevMessageContext = messageContext;
_switchMessageContext(prevMessageContext, _nextMessageContext);
// Nuisance gas is a system used to bound the ability for an attacker to make fraud proofs
// expensive by touching a lot of different accounts or storage slots. Since most contracts
// only use a few storage slots during any given transaction, this shouldn't be a limiting
// factor.
uint256 prevNuisanceGasLeft = messageRecord.nuisanceGasLeft;
uint256 nuisanceGasLimit = _getNuisanceGasLimit(_gasLimit);
messageRecord.nuisanceGasLeft = nuisanceGasLimit;
// Make the call and make sure to pass in the gas limit. Another instance of hidden
// complexity. `_contract` is guaranteed to be a safe contract, meaning its return/revert
// behavior can be controlled. In particular, we enforce that flags are passed through
// revert data as to retrieve execution metadata that would normally be reverted out of
// existence.
bool success;
bytes memory returndata;
if (_isCreate) {
// safeCREATE() is a function which replicates a CREATE message, but uses return values
// Which match that of CALL (i.e. bool, bytes). This allows many security checks to be
// to be shared between untrusted call and create call frames.
(success, returndata) = address(this).call(
abi.encodeWithSelector(
this.safeCREATE.selector,
_gasLimit,
_data,
_contract
)
);
} else {
(success, returndata) = _contract.call{gas: _gasLimit}(_data);
}
// Switch back to the original message context now that we're out of the call.
_switchMessageContext(_nextMessageContext, prevMessageContext);
// Assuming there were no reverts, the message record should be accurate here. We'll update
// this value in the case of a revert.
uint256 nuisanceGasLeft = messageRecord.nuisanceGasLeft;
// Reverts at this point are completely OK, but we need to make a few updates based on the
// information passed through the revert.
if (success == false) {
(
RevertFlag flag,
uint256 nuisanceGasLeftPostRevert,
uint256 ovmGasRefund,
bytes memory returndataFromFlag
) = _decodeRevertData(returndata);
// INVALID_STATE_ACCESS is the only flag that triggers an immediate abort of the
// parent EVM message. This behavior is necessary because INVALID_STATE_ACCESS must
// halt any further transaction execution that could impact the execution result.
if (flag == RevertFlag.INVALID_STATE_ACCESS) {
_revertWithFlag(flag);
}
// INTENTIONAL_REVERT, UNSAFE_BYTECODE, STATIC_VIOLATION, and CREATOR_NOT_ALLOWED aren't
// dependent on the input state, so we can just handle them like standard reverts. Our only change here
// is to record the gas refund reported by the call (enforced by safety checking).
if (
flag == RevertFlag.INTENTIONAL_REVERT
|| flag == RevertFlag.UNSAFE_BYTECODE
|| flag == RevertFlag.STATIC_VIOLATION
|| flag == RevertFlag.CREATOR_NOT_ALLOWED
) {
transactionRecord.ovmGasRefund = ovmGasRefund;
}
// INTENTIONAL_REVERT needs to pass up the user-provided return data encoded into the
// flag, *not* the full encoded flag. All other revert types return no data.
if (
flag == RevertFlag.INTENTIONAL_REVERT
|| _isCreate
) {
returndata = returndataFromFlag;
} else {
returndata = hex'';
}
// Reverts mean we need to use up whatever "nuisance gas" was used by the call.
// EXCEEDS_NUISANCE_GAS explicitly reduces the remaining nuisance gas for this message
// to zero. OUT_OF_GAS is a "pseudo" flag given that messages return no data when they
// run out of gas, so we have to treat this like EXCEEDS_NUISANCE_GAS. All other flags
// will simply pass up the remaining nuisance gas.
nuisanceGasLeft = nuisanceGasLeftPostRevert;
}
// We need to reset the nuisance gas back to its original value minus the amount used here.
messageRecord.nuisanceGasLeft = prevNuisanceGasLeft - (nuisanceGasLimit - nuisanceGasLeft);
return (
success,
returndata
);
}
/**
* Handles the creation-specific safety measures required for OVM contract deployment.
* This function sanitizes the return types for creation messages to match calls (bool, bytes),
* by being an external function which the EM can call, that mimics the success/fail case of the CREATE.
* This allows for consistent handling of both types of messages in _handleExternalMessage().
* Having this step occur as a separate call frame also allows us to easily revert the
* contract deployment in the event that the code is unsafe.
*
* @param _gasLimit Amount of gas to be passed into this creation.
* @param _creationCode Code to pass into CREATE for deployment.
* @param _address OVM address being deployed to.
*/
function safeCREATE(
uint _gasLimit,
bytes memory _creationCode,
address _address
)
external
{
// The only way this should callable is from within _createContract(),
// and it should DEFINITELY not be callable by a non-EM code contract.
if (msg.sender != address(this)) {
return;
}
// Check that there is not already code at this address.
if (_hasEmptyAccount(_address) == false) {
// Note: in the EVM, this case burns all allotted gas. For improved
// developer experience, we do return the remaining gas.
_revertWithFlag(
RevertFlag.CREATE_COLLISION,
Lib_ErrorUtils.encodeRevertString("A contract has already been deployed to this address")
);
}
// Check the creation bytecode against the OVM_SafetyChecker.
if (ovmSafetyChecker.isBytecodeSafe(_creationCode) == false) {
_revertWithFlag(
RevertFlag.UNSAFE_BYTECODE,
Lib_ErrorUtils.encodeRevertString("Contract creation code contains unsafe opcodes. Did you use the right compiler or pass an unsafe constructor argument?")
);
}
// We always need to initialize the contract with the default account values.
_initPendingAccount(_address);
// Actually execute the EVM create message.
// NOTE: The inline assembly below means we can NOT make any evm calls between here and then.
address ethAddress = Lib_EthUtils.createContract(_creationCode);
if (ethAddress == address(0)) {
// If the creation fails, the EVM lets us grab its revert data. This may contain a revert flag
// to be used above in _handleExternalMessage, so we pass the revert data back up unmodified.
assembly {
returndatacopy(0,0,returndatasize())
revert(0, returndatasize())
}
}
// Again simply checking that the deployed code is safe too. Contracts can generate
// arbitrary deployment code, so there's no easy way to analyze this beforehand.
bytes memory deployedCode = Lib_EthUtils.getCode(ethAddress);
if (ovmSafetyChecker.isBytecodeSafe(deployedCode) == false) {
_revertWithFlag(
RevertFlag.UNSAFE_BYTECODE,
Lib_ErrorUtils.encodeRevertString("Constructor attempted to deploy unsafe bytecode.")
);
}
// Contract creation didn't need to be reverted and the bytecode is safe. We finish up by
// associating the desired address with the newly created contract's code hash and address.
_commitPendingAccount(
_address,
ethAddress,
Lib_EthUtils.getCodeHash(ethAddress)
);
}
/******************************************
* Internal Functions: State Manipulation *
******************************************/
/**
* Checks whether an account exists within the OVM_StateManager.
* @param _address Address of the account to check.
* @return _exists Whether or not the account exists.
*/
function _hasAccount(
address _address
)
internal
returns (
bool _exists
)
{
_checkAccountLoad(_address);
return ovmStateManager.hasAccount(_address);
}
/**
* Checks whether a known empty account exists within the OVM_StateManager.
* @param _address Address of the account to check.
* @return _exists Whether or not the account empty exists.
*/
function _hasEmptyAccount(
address _address
)
internal
returns (
bool _exists
)
{
_checkAccountLoad(_address);
return ovmStateManager.hasEmptyAccount(_address);
}
/**
* Sets the nonce of an account.
* @param _address Address of the account to modify.
* @param _nonce New account nonce.
*/
function _setAccountNonce(
address _address,
uint256 _nonce
)
internal
{
_checkAccountChange(_address);
ovmStateManager.setAccountNonce(_address, _nonce);
}
/**
* Gets the nonce of an account.
* @param _address Address of the account to access.
* @return _nonce Nonce of the account.
*/
function _getAccountNonce(
address _address
)
internal
returns (
uint256 _nonce
)
{
_checkAccountLoad(_address);
return ovmStateManager.getAccountNonce(_address);
}
/**
* Retrieves the Ethereum address of an account.
* @param _address Address of the account to access.
* @return _ethAddress Corresponding Ethereum address.
*/
function _getAccountEthAddress(
address _address
)
internal
returns (
address _ethAddress
)
{
_checkAccountLoad(_address);
return ovmStateManager.getAccountEthAddress(_address);
}
/**
* Creates the default account object for the given address.
* @param _address Address of the account create.
*/
function _initPendingAccount(
address _address
)
internal
{
// Although it seems like `_checkAccountChange` would be more appropriate here, we don't
// actually consider an account "changed" until it's inserted into the state (in this case
// by `_commitPendingAccount`).
_checkAccountLoad(_address);
ovmStateManager.initPendingAccount(_address);
}
/**
* Stores additional relevant data for a new account, thereby "committing" it to the state.
* This function is only called during `ovmCREATE` and `ovmCREATE2` after a successful contract
* creation.
* @param _address Address of the account to commit.
* @param _ethAddress Address of the associated deployed contract.
* @param _codeHash Hash of the code stored at the address.
*/
function _commitPendingAccount(
address _address,
address _ethAddress,
bytes32 _codeHash
)
internal
{
_checkAccountChange(_address);
ovmStateManager.commitPendingAccount(
_address,
_ethAddress,
_codeHash
);
}
/**
* Retrieves the value of a storage slot.
* @param _contract Address of the contract to query.
* @param _key 32 byte key of the storage slot.
* @return _value 32 byte storage slot value.
*/
function _getContractStorage(
address _contract,
bytes32 _key
)
internal
returns (
bytes32 _value
)
{
_checkContractStorageLoad(_contract, _key);
return ovmStateManager.getContractStorage(_contract, _key);
}
/**
* Sets the value of a storage slot.
* @param _contract Address of the contract to modify.
* @param _key 32 byte key of the storage slot.
* @param _value 32 byte storage slot value.
*/
function _putContractStorage(
address _contract,
bytes32 _key,
bytes32 _value
)
internal
{
// We don't set storage if the value didn't change. Although this acts as a convenient
// optimization, it's also necessary to avoid the case in which a contract with no storage
// attempts to store the value "0" at any key. Putting this value (and therefore requiring
// that the value be committed into the storage trie after execution) would incorrectly
// modify the storage root.
if (_getContractStorage(_contract, _key) == _value) {
return;
}
_checkContractStorageChange(_contract, _key);
ovmStateManager.putContractStorage(_contract, _key, _value);
}
/**
* Validation whenever a contract needs to be loaded. Checks that the account exists, charges
* nuisance gas if the account hasn't been loaded before.
* @param _address Address of the account to load.
*/
function _checkAccountLoad(
address _address
)
internal
{
// See `_checkContractStorageLoad` for more information.
if (gasleft() < MIN_GAS_FOR_INVALID_STATE_ACCESS) {
_revertWithFlag(RevertFlag.OUT_OF_GAS);
}
// See `_checkContractStorageLoad` for more information.
if (ovmStateManager.hasAccount(_address) == false) {
_revertWithFlag(RevertFlag.INVALID_STATE_ACCESS);
}
// Check whether the account has been loaded before and mark it as loaded if not. We need
// this because "nuisance gas" only applies to the first time that an account is loaded.
(
bool _wasAccountAlreadyLoaded
) = ovmStateManager.testAndSetAccountLoaded(_address);
// If we hadn't already loaded the account, then we'll need to charge "nuisance gas" based
// on the size of the contract code.
if (_wasAccountAlreadyLoaded == false) {
_useNuisanceGas(
(Lib_EthUtils.getCodeSize(_getAccountEthAddress(_address)) * NUISANCE_GAS_PER_CONTRACT_BYTE) + MIN_NUISANCE_GAS_PER_CONTRACT
);
}
}
/**
* Validation whenever a contract needs to be changed. Checks that the account exists, charges
* nuisance gas if the account hasn't been changed before.
* @param _address Address of the account to change.
*/
function _checkAccountChange(
address _address
)
internal
{
// Start by checking for a load as we only want to charge nuisance gas proportional to
// contract size once.
_checkAccountLoad(_address);
// Check whether the account has been changed before and mark it as changed if not. We need
// this because "nuisance gas" only applies to the first time that an account is changed.
(
bool _wasAccountAlreadyChanged
) = ovmStateManager.testAndSetAccountChanged(_address);
// If we hadn't already loaded the account, then we'll need to charge "nuisance gas" based
// on the size of the contract code.
if (_wasAccountAlreadyChanged == false) {
ovmStateManager.incrementTotalUncommittedAccounts();
_useNuisanceGas(
(Lib_EthUtils.getCodeSize(_getAccountEthAddress(_address)) * NUISANCE_GAS_PER_CONTRACT_BYTE) + MIN_NUISANCE_GAS_PER_CONTRACT
);
}
}
/**
* Validation whenever a slot needs to be loaded. Checks that the account exists, charges
* nuisance gas if the slot hasn't been loaded before.
* @param _contract Address of the account to load from.
* @param _key 32 byte key to load.
*/
function _checkContractStorageLoad(
address _contract,
bytes32 _key
)
internal
{
// Another case of hidden complexity. If we didn't enforce this requirement, then a
// contract could pass in just enough gas to cause the INVALID_STATE_ACCESS check to fail
// on L1 but not on L2. A contract could use this behavior to prevent the
// OVM_ExecutionManager from detecting an invalid state access. Reverting with OUT_OF_GAS
// allows us to also charge for the full message nuisance gas, because you deserve that for
// trying to break the contract in this way.
if (gasleft() < MIN_GAS_FOR_INVALID_STATE_ACCESS) {
_revertWithFlag(RevertFlag.OUT_OF_GAS);
}
// We need to make sure that the transaction isn't trying to access storage that hasn't
// been provided to the OVM_StateManager. We'll immediately abort if this is the case.
// We know that we have enough gas to do this check because of the above test.
if (ovmStateManager.hasContractStorage(_contract, _key) == false) {
_revertWithFlag(RevertFlag.INVALID_STATE_ACCESS);
}
// Check whether the slot has been loaded before and mark it as loaded if not. We need
// this because "nuisance gas" only applies to the first time that a slot is loaded.
(
bool _wasContractStorageAlreadyLoaded
) = ovmStateManager.testAndSetContractStorageLoaded(_contract, _key);
// If we hadn't already loaded the account, then we'll need to charge some fixed amount of
// "nuisance gas".
if (_wasContractStorageAlreadyLoaded == false) {
_useNuisanceGas(NUISANCE_GAS_SLOAD);
}
}
/**
* Validation whenever a slot needs to be changed. Checks that the account exists, charges
* nuisance gas if the slot hasn't been changed before.
* @param _contract Address of the account to change.
* @param _key 32 byte key to change.
*/
function _checkContractStorageChange(
address _contract,
bytes32 _key
)
internal
{
// Start by checking for load to make sure we have the storage slot and that we charge the
// "nuisance gas" necessary to prove the storage slot state.
_checkContractStorageLoad(_contract, _key);
// Check whether the slot has been changed before and mark it as changed if not. We need
// this because "nuisance gas" only applies to the first time that a slot is changed.
(
bool _wasContractStorageAlreadyChanged
) = ovmStateManager.testAndSetContractStorageChanged(_contract, _key);
// If we hadn't already changed the account, then we'll need to charge some fixed amount of
// "nuisance gas".
if (_wasContractStorageAlreadyChanged == false) {
// Changing a storage slot means that we're also going to have to change the
// corresponding account, so do an account change check.
_checkAccountChange(_contract);
ovmStateManager.incrementTotalUncommittedContractStorage();
_useNuisanceGas(NUISANCE_GAS_SSTORE);
}
}
/************************************
* Internal Functions: Revert Logic *
************************************/
/**
* Simple encoding for revert data.
* @param _flag Flag to revert with.
* @param _data Additional user-provided revert data.
* @return _revertdata Encoded revert data.
*/
function _encodeRevertData(
RevertFlag _flag,
bytes memory _data
)
internal
view
returns (
bytes memory _revertdata
)
{
// Out of gas and create exceptions will fundamentally return no data, so simulating it shouldn't either.
if (
_flag == RevertFlag.OUT_OF_GAS
) {
return bytes('');
}
// INVALID_STATE_ACCESS doesn't need to return any data other than the flag.
if (_flag == RevertFlag.INVALID_STATE_ACCESS) {
return abi.encode(
_flag,
0,
0,
bytes('')
);
}
// Just ABI encode the rest of the parameters.
return abi.encode(
_flag,
messageRecord.nuisanceGasLeft,
transactionRecord.ovmGasRefund,
_data
);
}
/**
* Simple decoding for revert data.
* @param _revertdata Revert data to decode.
* @return _flag Flag used to revert.
* @return _nuisanceGasLeft Amount of nuisance gas unused by the message.
* @return _ovmGasRefund Amount of gas refunded during the message.
* @return _data Additional user-provided revert data.
*/
function _decodeRevertData(
bytes memory _revertdata
)
internal
pure
returns (
RevertFlag _flag,
uint256 _nuisanceGasLeft,
uint256 _ovmGasRefund,
bytes memory _data
)
{
// A length of zero means the call ran out of gas, just return empty data.
if (_revertdata.length == 0) {
return (
RevertFlag.OUT_OF_GAS,
0,
0,
bytes('')
);
}
// ABI decode the incoming data.
return abi.decode(_revertdata, (RevertFlag, uint256, uint256, bytes));
}
/**
* Causes a message to revert or abort.
* @param _flag Flag to revert with.
* @param _data Additional user-provided data.
*/
function _revertWithFlag(
RevertFlag _flag,
bytes memory _data
)
internal
view
{
bytes memory revertdata = _encodeRevertData(
_flag,
_data
);
assembly {
revert(add(revertdata, 0x20), mload(revertdata))
}
}
/**
* Causes a message to revert or abort.
* @param _flag Flag to revert with.
*/
function _revertWithFlag(
RevertFlag _flag
)
internal
{
_revertWithFlag(_flag, bytes(''));
}
/******************************************
* Internal Functions: Nuisance Gas Logic *
******************************************/
/**
* Computes the nuisance gas limit from the gas limit.
* @dev This function is currently using a naive implementation whereby the nuisance gas limit
* is set to exactly equal the lesser of the gas limit or remaining gas. It's likely that
* this implementation is perfectly fine, but we may change this formula later.
* @param _gasLimit Gas limit to compute from.
* @return _nuisanceGasLimit Computed nuisance gas limit.
*/
function _getNuisanceGasLimit(
uint256 _gasLimit
)
internal
view
returns (
uint256 _nuisanceGasLimit
)
{
return _gasLimit < gasleft() ? _gasLimit : gasleft();
}
/**
* Uses a certain amount of nuisance gas.
* @param _amount Amount of nuisance gas to use.
*/
function _useNuisanceGas(
uint256 _amount
)
internal
{
// Essentially the same as a standard OUT_OF_GAS, except we also retain a record of the gas
// refund to be given at the end of the transaction.
if (messageRecord.nuisanceGasLeft < _amount) {
_revertWithFlag(RevertFlag.EXCEEDS_NUISANCE_GAS);
}
messageRecord.nuisanceGasLeft -= _amount;
}
/************************************
* Internal Functions: Gas Metering *
************************************/
/**
* Checks whether a transaction needs to start a new epoch and does so if necessary.
* @param _timestamp Transaction timestamp.
*/
function _checkNeedsNewEpoch(
uint256 _timestamp
)
internal
{
if (
_timestamp >= (
_getGasMetadata(GasMetadataKey.CURRENT_EPOCH_START_TIMESTAMP)
+ gasMeterConfig.secondsPerEpoch
)
) {
_putGasMetadata(
GasMetadataKey.CURRENT_EPOCH_START_TIMESTAMP,
_timestamp
);
_putGasMetadata(
GasMetadataKey.PREV_EPOCH_SEQUENCER_QUEUE_GAS,
_getGasMetadata(
GasMetadataKey.CUMULATIVE_SEQUENCER_QUEUE_GAS
)
);
_putGasMetadata(
GasMetadataKey.PREV_EPOCH_L1TOL2_QUEUE_GAS,
_getGasMetadata(
GasMetadataKey.CUMULATIVE_L1TOL2_QUEUE_GAS
)
);
}
}
/**
* Validates the input values of a transaction.
* @return _valid Whether or not the transaction data is valid.
*/
function _isValidInput(
Lib_OVMCodec.Transaction memory _transaction
)
view
internal
returns (
bool
)
{
// Prevent reentrancy to run():
// This check prevents calling run with the default ovmNumber.
// Combined with the first check in run():
// if (transactionContext.ovmNUMBER != DEFAULT_UINT256) { return; }
// It should be impossible to re-enter since run() returns before any other call frames are created.
// Since this value is already being written to storage, we save much gas compared to
// using the standard nonReentrant pattern.
if (_transaction.blockNumber == DEFAULT_UINT256) {
return false;
}
if (_isValidGasLimit(_transaction.gasLimit, _transaction.l1QueueOrigin) == false) {
return false;
}
return true;
}
/**
* Validates the gas limit for a given transaction.
* @param _gasLimit Gas limit provided by the transaction.
* param _queueOrigin Queue from which the transaction originated.
* @return _valid Whether or not the gas limit is valid.
*/
function _isValidGasLimit(
uint256 _gasLimit,
Lib_OVMCodec.QueueOrigin // _queueOrigin
)
view
internal
returns (
bool _valid
)
{
// Always have to be below the maximum gas limit.
if (_gasLimit > gasMeterConfig.maxTransactionGasLimit) {
return false;
}
// Always have to be above the minimum gas limit.
if (_gasLimit < gasMeterConfig.minTransactionGasLimit) {
return false;
}
// TEMPORARY: Gas metering is disabled for minnet.
return true;
// GasMetadataKey cumulativeGasKey;
// GasMetadataKey prevEpochGasKey;
// if (_queueOrigin == Lib_OVMCodec.QueueOrigin.SEQUENCER_QUEUE) {
// cumulativeGasKey = GasMetadataKey.CUMULATIVE_SEQUENCER_QUEUE_GAS;
// prevEpochGasKey = GasMetadataKey.PREV_EPOCH_SEQUENCER_QUEUE_GAS;
// } else {
// cumulativeGasKey = GasMetadataKey.CUMULATIVE_L1TOL2_QUEUE_GAS;
// prevEpochGasKey = GasMetadataKey.PREV_EPOCH_L1TOL2_QUEUE_GAS;
// }
// return (
// (
// _getGasMetadata(cumulativeGasKey)
// - _getGasMetadata(prevEpochGasKey)
// + _gasLimit
// ) < gasMeterConfig.maxGasPerQueuePerEpoch
// );
}
/**
* Updates the cumulative gas after a transaction.
* @param _gasUsed Gas used by the transaction.
* @param _queueOrigin Queue from which the transaction originated.
*/
function _updateCumulativeGas(
uint256 _gasUsed,
Lib_OVMCodec.QueueOrigin _queueOrigin
)
internal
{
GasMetadataKey cumulativeGasKey;
if (_queueOrigin == Lib_OVMCodec.QueueOrigin.SEQUENCER_QUEUE) {
cumulativeGasKey = GasMetadataKey.CUMULATIVE_SEQUENCER_QUEUE_GAS;
} else {
cumulativeGasKey = GasMetadataKey.CUMULATIVE_L1TOL2_QUEUE_GAS;
}
_putGasMetadata(
cumulativeGasKey,
(
_getGasMetadata(cumulativeGasKey)
+ gasMeterConfig.minTransactionGasLimit
+ _gasUsed
- transactionRecord.ovmGasRefund
)
);
}
/**
* Retrieves the value of a gas metadata key.
* @param _key Gas metadata key to retrieve.
* @return _value Value stored at the given key.
*/
function _getGasMetadata(
GasMetadataKey _key
)
internal
returns (
uint256 _value
)
{
return uint256(_getContractStorage(
GAS_METADATA_ADDRESS,
bytes32(uint256(_key))
));
}
/**
* Sets the value of a gas metadata key.
* @param _key Gas metadata key to set.
* @param _value Value to store at the given key.
*/
function _putGasMetadata(
GasMetadataKey _key,
uint256 _value
)
internal
{
_putContractStorage(
GAS_METADATA_ADDRESS,
bytes32(uint256(_key)),
bytes32(uint256(_value))
);
}
/*****************************************
* Internal Functions: Execution Context *
*****************************************/
/**
* Swaps over to a new message context.
* @param _prevMessageContext Context we're switching from.
* @param _nextMessageContext Context we're switching to.
*/
function _switchMessageContext(
MessageContext memory _prevMessageContext,
MessageContext memory _nextMessageContext
)
internal
{
// Avoid unnecessary the SSTORE.
if (_prevMessageContext.ovmCALLER != _nextMessageContext.ovmCALLER) {
messageContext.ovmCALLER = _nextMessageContext.ovmCALLER;
}
// Avoid unnecessary the SSTORE.
if (_prevMessageContext.ovmADDRESS != _nextMessageContext.ovmADDRESS) {
messageContext.ovmADDRESS = _nextMessageContext.ovmADDRESS;
}
// Avoid unnecessary the SSTORE.
if (_prevMessageContext.isStatic != _nextMessageContext.isStatic) {
messageContext.isStatic = _nextMessageContext.isStatic;
}
}
/**
* Initializes the execution context.
* @param _transaction OVM transaction being executed.
*/
function _initContext(
Lib_OVMCodec.Transaction memory _transaction
)
internal
{
transactionContext.ovmTIMESTAMP = _transaction.timestamp;
transactionContext.ovmNUMBER = _transaction.blockNumber;
transactionContext.ovmTXGASLIMIT = _transaction.gasLimit;
transactionContext.ovmL1QUEUEORIGIN = _transaction.l1QueueOrigin;
transactionContext.ovmL1TXORIGIN = _transaction.l1TxOrigin;
transactionContext.ovmGASLIMIT = gasMeterConfig.maxGasPerQueuePerEpoch;
messageRecord.nuisanceGasLeft = _getNuisanceGasLimit(_transaction.gasLimit);
}
/**
* Resets the transaction and message context.
*/
function _resetContext()
internal
{
transactionContext.ovmL1TXORIGIN = DEFAULT_ADDRESS;
transactionContext.ovmTIMESTAMP = DEFAULT_UINT256;
transactionContext.ovmNUMBER = DEFAULT_UINT256;
transactionContext.ovmGASLIMIT = DEFAULT_UINT256;
transactionContext.ovmTXGASLIMIT = DEFAULT_UINT256;
transactionContext.ovmL1QUEUEORIGIN = Lib_OVMCodec.QueueOrigin.SEQUENCER_QUEUE;
transactionRecord.ovmGasRefund = DEFAULT_UINT256;
messageContext.ovmCALLER = DEFAULT_ADDRESS;
messageContext.ovmADDRESS = DEFAULT_ADDRESS;
messageContext.isStatic = false;
messageRecord.nuisanceGasLeft = DEFAULT_UINT256;
// Reset the ovmStateManager.
ovmStateManager = iOVM_StateManager(address(0));
}
/*****************************
* L2-only Helper Functions *
*****************************/
/**
* Unreachable helper function for simulating eth_calls with an OVM message context.
* This function will throw an exception in all cases other than when used as a custom entrypoint in L2 Geth to simulate eth_call.
* @param _transaction the message transaction to simulate.
* @param _from the OVM account the simulated call should be from.
*/
function simulateMessage(
Lib_OVMCodec.Transaction memory _transaction,
address _from,
iOVM_StateManager _ovmStateManager
)
external
returns (
bool,
bytes memory
)
{
// Prevent this call from having any effect unless in a custom-set VM frame
require(msg.sender == address(0));
ovmStateManager = _ovmStateManager;
_initContext(_transaction);
messageRecord.nuisanceGasLeft = uint(-1);
messageContext.ovmADDRESS = _from;
bool isCreate = _transaction.entrypoint == address(0);
if (isCreate) {
(address created, bytes memory revertData) = ovmCREATE(_transaction.data);
if (created == address(0)) {
return (false, revertData);
} else {
// The eth_call RPC endpoint for to = undefined will return the deployed bytecode
// in the success case, differing from standard create messages.
return (true, Lib_EthUtils.getCode(created));
}
} else {
return ovmCALL(
_transaction.gasLimit,
_transaction.entrypoint,
_transaction.data
);
}
}
}
================================================
FILE: contracts/optimistic-ethereum/OVM/execution/OVM_SafetyChecker.sol
=======================================
gitextract_p1t8o229/ ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── CODEOWNERS │ └── workflows/ │ ├── build-test-lint-contracts.yml │ ├── dockerhub-build-push.yml │ ├── integration.yml │ ├── push-to-integration-repo.yml │ └── tag-release.yml ├── .gitignore ├── .solcover.js ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── bin/ │ ├── deploy.js │ ├── deploy.ts │ ├── gen_safety_checker_constants.py │ ├── serve_dump.sh │ └── take-dump.ts ├── contracts/ │ ├── optimistic-ethereum/ │ │ ├── OVM/ │ │ │ ├── accounts/ │ │ │ │ ├── OVM_ECDSAContractAccount.sol │ │ │ │ └── OVM_ProxyEOA.sol │ │ │ ├── bridge/ │ │ │ │ ├── messaging/ │ │ │ │ │ ├── Abs_BaseCrossDomainMessenger.sol │ │ │ │ │ ├── OVM_L1CrossDomainMessenger.sol │ │ │ │ │ ├── OVM_L1MultiMessageRelayer.sol │ │ │ │ │ └── OVM_L2CrossDomainMessenger.sol │ │ │ │ └── tokens/ │ │ │ │ ├── Abs_L1TokenGateway.sol │ │ │ │ ├── Abs_L2DepositedToken.sol │ │ │ │ ├── OVM_L1ERC20Gateway.sol │ │ │ │ ├── OVM_L1ETHGateway.sol │ │ │ │ └── OVM_L2DepositedERC20.sol │ │ │ ├── chain/ │ │ │ │ ├── OVM_CanonicalTransactionChain.sol │ │ │ │ ├── OVM_ChainStorageContainer.sol │ │ │ │ └── OVM_StateCommitmentChain.sol │ │ │ ├── execution/ │ │ │ │ ├── OVM_ExecutionManager.sol │ │ │ │ ├── OVM_SafetyChecker.sol │ │ │ │ ├── OVM_StateManager.sol │ │ │ │ └── OVM_StateManagerFactory.sol │ │ │ ├── predeploys/ │ │ │ │ ├── ERC1820Registry.sol │ │ │ │ ├── OVM_DeployerWhitelist.sol │ │ │ │ ├── OVM_ETH.sol │ │ │ │ ├── OVM_L1MessageSender.sol │ │ │ │ ├── OVM_L2ToL1MessagePasser.sol │ │ │ │ ├── OVM_ProxySequencerEntrypoint.sol │ │ │ │ └── OVM_SequencerEntrypoint.sol │ │ │ └── verification/ │ │ │ ├── Abs_FraudContributor.sol │ │ │ ├── OVM_BondManager.sol │ │ │ ├── OVM_FraudVerifier.sol │ │ │ ├── OVM_StateTransitioner.sol │ │ │ └── OVM_StateTransitionerFactory.sol │ │ ├── iOVM/ │ │ │ ├── accounts/ │ │ │ │ └── iOVM_ECDSAContractAccount.sol │ │ │ ├── bridge/ │ │ │ │ ├── messaging/ │ │ │ │ │ ├── iAbs_BaseCrossDomainMessenger.sol │ │ │ │ │ ├── iOVM_L1CrossDomainMessenger.sol │ │ │ │ │ ├── iOVM_L1MultiMessageRelayer.sol │ │ │ │ │ └── iOVM_L2CrossDomainMessenger.sol │ │ │ │ └── tokens/ │ │ │ │ ├── iOVM_L1ETHGateway.sol │ │ │ │ ├── iOVM_L1TokenGateway.sol │ │ │ │ └── iOVM_L2DepositedToken.sol │ │ │ ├── chain/ │ │ │ │ ├── iOVM_CanonicalTransactionChain.sol │ │ │ │ ├── iOVM_ChainStorageContainer.sol │ │ │ │ └── iOVM_StateCommitmentChain.sol │ │ │ ├── execution/ │ │ │ │ ├── iOVM_ExecutionManager.sol │ │ │ │ ├── iOVM_SafetyChecker.sol │ │ │ │ ├── iOVM_StateManager.sol │ │ │ │ └── iOVM_StateManagerFactory.sol │ │ │ ├── predeploys/ │ │ │ │ ├── iOVM_DeployerWhitelist.sol │ │ │ │ ├── iOVM_ERC20.sol │ │ │ │ ├── iOVM_L1MessageSender.sol │ │ │ │ └── iOVM_L2ToL1MessagePasser.sol │ │ │ └── verification/ │ │ │ ├── iOVM_BondManager.sol │ │ │ ├── iOVM_FraudVerifier.sol │ │ │ ├── iOVM_StateTransitioner.sol │ │ │ └── iOVM_StateTransitionerFactory.sol │ │ ├── libraries/ │ │ │ ├── bridge/ │ │ │ │ └── OVM_CrossDomainEnabled.sol │ │ │ ├── codec/ │ │ │ │ └── Lib_OVMCodec.sol │ │ │ ├── resolver/ │ │ │ │ ├── Lib_AddressManager.sol │ │ │ │ ├── Lib_AddressResolver.sol │ │ │ │ ├── Lib_Ownable.sol │ │ │ │ └── Lib_ResolvedDelegateProxy.sol │ │ │ ├── rlp/ │ │ │ │ ├── Lib_RLPReader.sol │ │ │ │ └── Lib_RLPWriter.sol │ │ │ ├── standards/ │ │ │ │ ├── IUniswapV2ERC20.sol │ │ │ │ ├── UniSafeMath.sol │ │ │ │ └── UniswapV2ERC20.sol │ │ │ ├── trie/ │ │ │ │ ├── Lib_MerkleTrie.sol │ │ │ │ └── Lib_SecureMerkleTrie.sol │ │ │ ├── utils/ │ │ │ │ ├── Lib_Bytes32Utils.sol │ │ │ │ ├── Lib_BytesUtils.sol │ │ │ │ ├── Lib_ECDSAUtils.sol │ │ │ │ ├── Lib_ErrorUtils.sol │ │ │ │ ├── Lib_EthUtils.sol │ │ │ │ ├── Lib_Math.sol │ │ │ │ ├── Lib_MerkleTree.sol │ │ │ │ ├── Lib_ReentrancyGuard.sol │ │ │ │ └── Lib_RingBuffer.sol │ │ │ └── wrappers/ │ │ │ ├── Lib_SafeExecutionManagerWrapper.sol │ │ │ └── Lib_SafeMathWrapper.sol │ │ └── mockOVM/ │ │ ├── accounts/ │ │ │ └── mockOVM_ECDSAContractAccount.sol │ │ ├── bridge/ │ │ │ ├── mockOVM_CrossDomainMessenger.sol │ │ │ └── mockOVM_GenericCrossDomainMessenger.sol │ │ └── verification/ │ │ └── mockOVM_BondManager.sol │ ├── test-helpers/ │ │ ├── Helper_GasMeasurer.sol │ │ ├── Helper_ModifiableStorage.sol │ │ ├── Helper_PrecompileCaller.sol │ │ ├── Helper_SimpleProxy.sol │ │ ├── Helper_TestRunner.sol │ │ ├── Mock_FraudVerifier.sol │ │ └── TestERC20.sol │ └── test-libraries/ │ ├── codec/ │ │ └── TestLib_OVMCodec.sol │ ├── rlp/ │ │ ├── TestLib_RLPReader.sol │ │ └── TestLib_RLPWriter.sol │ ├── trie/ │ │ ├── TestLib_MerkleTrie.sol │ │ └── TestLib_SecureMerkleTrie.sol │ └── utils/ │ ├── TestLib_Bytes32Utils.sol │ ├── TestLib_BytesUtils.sol │ ├── TestLib_ECDSAUtils.sol │ ├── TestLib_EthUtils.sol │ ├── TestLib_MerkleTree.sol │ └── TestLib_RingBuffer.sol ├── deploy/ │ ├── 000-Lib_AddressManager.deploy.ts │ ├── 001-OVM_ChainStorageContainer_ctc_batches.deploy.ts │ ├── 002-OVM_ChainStorageContainer_ctc_queue.deploy.ts │ ├── 003-OVM_ChainStorageContainer_scc_batches.deploy.ts │ ├── 004-OVM_CanonicalTransactionChain.deploy.ts │ ├── 005-OVM_StateCommitmentChain.deploy.ts │ ├── 006-mockOVM_BondManager.deploy.ts │ ├── 007-OVM_L1CrossDomainMessenger.deploy.ts │ ├── 008-Proxy__OVM_L1CrossDomainMessenger.deploy.ts │ ├── 009-OVM_ExecutionManager.deploy.ts │ ├── 010-OVM_FraudVerifer.deploy.ts │ ├── 011-OVM_StateManagerFactory.deploy.ts │ ├── 012-OVM_StateTransitionerFactory.deploy.ts │ ├── 013-OVM_SafetyChecker.deploy.ts │ ├── 014-OVM_L1MultiMessageRelayer.deploy.ts │ ├── 015-OVM_L1ETHGateway.deploy.ts │ ├── 016-Proxy__OVM_L1ETHGateway.deploy.ts │ └── 017-finalize.ts ├── hardhat.config.ts ├── hh/ │ ├── index.ts │ └── tasks/ │ └── task-deploy.ts ├── package.json ├── prettier-config.json ├── src/ │ ├── contract-defs.ts │ ├── contract-deployment/ │ │ ├── config.ts │ │ ├── deploy.ts │ │ └── index.ts │ ├── contract-dumps.ts │ ├── hardhat-deploy-ethers.ts │ ├── index.ts │ └── predeploys.ts ├── test/ │ ├── contracts/ │ │ ├── OVM/ │ │ │ ├── accounts/ │ │ │ │ ├── OVM_ECDSAContractAccount.spec.ts │ │ │ │ └── OVM_ProxyEOA.spec.ts │ │ │ ├── bridge/ │ │ │ │ ├── assets/ │ │ │ │ │ ├── OVM_L1ERC20Gateway.spec.ts │ │ │ │ │ ├── OVM_L1ETHGateway.spec.ts │ │ │ │ │ └── OVM_L2DepositedERC20.spec.ts │ │ │ │ └── base/ │ │ │ │ ├── OVM_L1CrossDomainMessenger.spec.ts │ │ │ │ ├── OVM_L1MultiMessageRelayer.ts │ │ │ │ └── OVM_L2CrossDomainMessenger.spec.ts │ │ │ ├── chain/ │ │ │ │ ├── OVM_CanonicalTransactionChain.gas.spec.ts │ │ │ │ ├── OVM_CanonicalTransactionChain.spec.ts │ │ │ │ └── OVM_StateCommitmentChain.spec.ts │ │ │ ├── execution/ │ │ │ │ ├── OVM_ExecutionManager/ │ │ │ │ │ ├── context-opcodes.spec.ts │ │ │ │ │ ├── nuisance-gas.spec.ts │ │ │ │ │ ├── ovmCALL.spec.ts │ │ │ │ │ ├── ovmCREATE.spec.ts │ │ │ │ │ ├── ovmCREATEEOA.spec.ts │ │ │ │ │ ├── ovmDELEGATECALL.spec.ts │ │ │ │ │ ├── ovmREVERT.spec.ts │ │ │ │ │ ├── ovmSLOAD.spec.ts │ │ │ │ │ ├── ovmSTATICCALL.spec.ts │ │ │ │ │ └── run.spec.ts │ │ │ │ ├── OVM_ExecutionManager.gas-spec.ts │ │ │ │ ├── OVM_SafetyChecker.spec.ts │ │ │ │ ├── OVM_StateManager.gas-spec.ts │ │ │ │ └── OVM_StateManager.spec.ts │ │ │ ├── precompiles/ │ │ │ │ ├── OVM_L1MessageSender.spec.ts │ │ │ │ ├── OVM_L2ToL1MessagePasser.spec.ts │ │ │ │ ├── OVM_ProxySequencerEntrypoint.spec.ts │ │ │ │ └── OVM_SequencerEntrypoint.spec.ts │ │ │ └── verification/ │ │ │ ├── OVM_BondManager.spec.ts │ │ │ ├── OVM_FraudVerifier.spec.ts │ │ │ ├── OVM_StateTransitioner.spec.ts │ │ │ └── OVM_StateTransitionerFactory.spec.ts │ │ ├── libraries/ │ │ │ ├── codec/ │ │ │ │ └── Lib_OVMCodec.spec.ts │ │ │ ├── rlp/ │ │ │ │ ├── Lib_RLPReader.spec.ts │ │ │ │ └── Lib_RLPWriter.spec.ts │ │ │ ├── trie/ │ │ │ │ ├── Lib_MerkleTrie.spec.ts │ │ │ │ └── Lib_SecureMerkleTrie.spec.ts │ │ │ └── utils/ │ │ │ ├── Lib_Bytes32Utils.spec.ts │ │ │ ├── Lib_BytesUtils.spec.ts │ │ │ ├── Lib_ECDSAUtils.spec.ts │ │ │ ├── Lib_EthUtils.spec.ts │ │ │ └── Lib_MerkleTree.spec.ts │ │ └── mockOVM/ │ │ └── verification/ │ │ └── mockOVM_BondManager.spec.ts │ ├── data/ │ │ ├── index.ts │ │ └── json/ │ │ ├── create2.test.json │ │ ├── libraries/ │ │ │ ├── codec/ │ │ │ │ └── Lib_OVMCodec.test.json │ │ │ ├── rlp/ │ │ │ │ ├── Lib_RLPReader.test.json │ │ │ │ └── Lib_RLPWriter.test.json │ │ │ ├── trie/ │ │ │ │ └── Lib_MerkleTrie.test.json │ │ │ └── utils/ │ │ │ ├── Lib_Bytes32Utils.test.json │ │ │ ├── Lib_BytesUtils.test.json │ │ │ └── Lib_ECDSAUtils.test.json │ │ └── safety-checker.test.json │ ├── helpers/ │ │ ├── codec/ │ │ │ ├── bridge.ts │ │ │ ├── encoding.ts │ │ │ ├── index.ts │ │ │ └── revert-flags.ts │ │ ├── constants.ts │ │ ├── dummy/ │ │ │ ├── accounts.ts │ │ │ ├── batches.ts │ │ │ ├── bytecode.ts │ │ │ ├── bytes32.ts │ │ │ ├── context.ts │ │ │ ├── index.ts │ │ │ └── transactions.ts │ │ ├── gas/ │ │ │ ├── gas.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── resolver/ │ │ │ ├── address-manager.ts │ │ │ └── index.ts │ │ ├── test-runner/ │ │ │ ├── index.ts │ │ │ ├── json-test-runner.ts │ │ │ ├── test-runner.ts │ │ │ └── test.types.ts │ │ ├── trie/ │ │ │ ├── index.ts │ │ │ └── trie-test-generator.ts │ │ ├── types/ │ │ │ ├── index.ts │ │ │ └── ovm-types.ts │ │ └── utils/ │ │ ├── custom-deployer.ts │ │ ├── eth-time.ts │ │ ├── index.ts │ │ └── sol-utils.ts │ └── setup.ts ├── tsconfig.json └── tslint.json
SYMBOL INDEX (154 symbols across 39 files)
FILE: bin/gen_safety_checker_constants.py
function asm (line 7) | def asm(x):
FILE: bin/take-dump.ts
constant CHAIN_ID (line 7) | const CHAIN_ID = env.CHAIN_ID || '420'
FILE: hh/tasks/task-deploy.ts
constant DEFAULT_L1_BLOCK_TIME_SECONDS (line 6) | const DEFAULT_L1_BLOCK_TIME_SECONDS = 15
constant DEFAULT_CTC_FORCE_INCLUSION_PERIOD_SECONDS (line 7) | const DEFAULT_CTC_FORCE_INCLUSION_PERIOD_SECONDS = 60 * 60 * 24 * 30 // ...
constant DEFAULT_CTC_MAX_TRANSACTION_GAS_LIMIT (line 8) | const DEFAULT_CTC_MAX_TRANSACTION_GAS_LIMIT = 9_000_000
constant DEFAULT_EM_MIN_TRANSACTION_GAS_LIMIT (line 9) | const DEFAULT_EM_MIN_TRANSACTION_GAS_LIMIT = 50_000
constant DEFAULT_EM_MAX_TRANSACTION_GAS_LIMIT (line 10) | const DEFAULT_EM_MAX_TRANSACTION_GAS_LIMIT = 9_000_000
constant DEFAULT_EM_MAX_GAS_PER_QUEUE_PER_EPOCH (line 11) | const DEFAULT_EM_MAX_GAS_PER_QUEUE_PER_EPOCH = 250_000_000
constant DEFAULT_EM_SECONDS_PER_EPOCH (line 12) | const DEFAULT_EM_SECONDS_PER_EPOCH = 0
constant DEFAULT_EM_OVM_CHAIN_ID (line 13) | const DEFAULT_EM_OVM_CHAIN_ID = 420
constant DEFAULT_SCC_FRAUD_PROOF_WINDOW (line 14) | const DEFAULT_SCC_FRAUD_PROOF_WINDOW = 60 * 60 * 24 * 7 // 7 days
constant DEFAULT_SCC_SEQUENCER_PUBLISH_WINDOW (line 15) | const DEFAULT_SCC_SEQUENCER_PUBLISH_WINDOW = 60 * 30 // 30 minutes
FILE: src/contract-deployment/config.ts
type RollupDeployConfig (line 9) | interface RollupDeployConfig {
type ContractDeployParameters (line 43) | interface ContractDeployParameters {
type ContractDeployConfig (line 49) | interface ContractDeployConfig {
FILE: src/contract-deployment/deploy.ts
type DeployResult (line 8) | interface DeployResult {
FILE: src/contract-dumps.ts
type StorageDump (line 13) | interface StorageDump {
type StateDump (line 17) | interface StateDump {
FILE: test/contracts/OVM/bridge/assets/OVM_L1ERC20Gateway.spec.ts
constant INITIAL_TOTAL_L1_SUPPLY (line 11) | const INITIAL_TOTAL_L1_SUPPLY = 3000
constant ERR_INVALID_MESSENGER (line 13) | const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenti...
constant ERR_INVALID_X_DOMAIN_MSG_SENDER (line 14) | const ERR_INVALID_X_DOMAIN_MSG_SENDER =
FILE: test/contracts/OVM/bridge/assets/OVM_L1ETHGateway.spec.ts
constant L1_ETH_GATEWAY_NAME (line 11) | const L1_ETH_GATEWAY_NAME = 'Proxy__OVM_L1CrossDomainMessenger'
constant ERR_INVALID_MESSENGER (line 13) | const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenti...
constant ERR_INVALID_X_DOMAIN_MSG_SENDER (line 14) | const ERR_INVALID_X_DOMAIN_MSG_SENDER =
constant ERR_ALREADY_INITIALIZED (line 16) | const ERR_ALREADY_INITIALIZED = 'Contract has already been initialized.'
FILE: test/contracts/OVM/bridge/assets/OVM_L2DepositedERC20.spec.ts
constant ERR_INVALID_MESSENGER (line 16) | const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenti...
constant ERR_INVALID_X_DOMAIN_MSG_SENDER (line 17) | const ERR_INVALID_X_DOMAIN_MSG_SENDER =
constant MOCK_L1GATEWAY_ADDRESS (line 19) | const MOCK_L1GATEWAY_ADDRESS: string =
FILE: test/contracts/OVM/chain/OVM_CanonicalTransactionChain.gas.spec.ts
constant DECOMPRESSION_ADDRESS (line 26) | const DECOMPRESSION_ADDRESS = '0x4200000000000000000000000000000000000008'
constant MAX_GAS_LIMIT (line 27) | const MAX_GAS_LIMIT = 8_000_000
FILE: test/contracts/OVM/chain/OVM_CanonicalTransactionChain.spec.ts
constant ELEMENT_TEST_SIZES (line 31) | const ELEMENT_TEST_SIZES = [1, 2, 4, 8, 16]
constant DECOMPRESSION_ADDRESS (line 32) | const DECOMPRESSION_ADDRESS = '0x4200000000000000000000000000000000000008'
constant MAX_GAS_LIMIT (line 33) | const MAX_GAS_LIMIT = 8_000_000
FILE: test/contracts/OVM/execution/OVM_ExecutionManager.gas-spec.ts
constant DUMMY_GASMETERCONFIG (line 17) | const DUMMY_GASMETERCONFIG = {
constant DUMMY_GLOBALCONTEXT (line 24) | const DUMMY_GLOBALCONTEXT = {
constant QUEUE_ORIGIN (line 28) | const QUEUE_ORIGIN = {
constant DUMMY_TRANSACTION (line 33) | const DUMMY_TRANSACTION = {
FILE: test/contracts/OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts
constant CREATED_CONTRACT_1 (line 13) | const CREATED_CONTRACT_1 = '0x2bda4a99d5be88609d23b1e4ab5d1d34fb1c2feb'
constant FRESH_CALL_NUISANCE_GAS_COST (line 15) | const FRESH_CALL_NUISANCE_GAS_COST =
FILE: test/contracts/OVM/execution/OVM_ExecutionManager/ovmCALL.spec.ts
constant DUMMY_REVERT_DATA (line 11) | const DUMMY_REVERT_DATA =
constant DEAD_ADDRESS (line 14) | const DEAD_ADDRESS = '0xdeaddeaddeaddeaddeaddeaddeaddeaddead1234'
FILE: test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATE.spec.ts
constant CREATED_CONTRACT_1 (line 18) | const CREATED_CONTRACT_1 = '0x2bda4a99d5be88609d23b1e4ab5d1d34fb1c2feb'
constant CREATED_CONTRACT_2 (line 19) | const CREATED_CONTRACT_2 = '0x2bda4a99d5be88609d23b1e4ab5d1d34fb1c2feb'
constant CREATED_CONTRACT_BY_2_1 (line 20) | const CREATED_CONTRACT_BY_2_1 = '0xe0d8be8101f36ebe6b01abacec884422c39a1...
constant CREATED_CONTRACT_BY_2_2 (line 21) | const CREATED_CONTRACT_BY_2_2 = '0x15ac629e1a3866b17179ee4ae86de5cbda744...
constant NESTED_CREATED_CONTRACT (line 22) | const NESTED_CREATED_CONTRACT = '0xcb964b3f4162a0d4f5c997b40e19da5a546bc...
constant DUMMY_REVERT_DATA (line 23) | const DUMMY_REVERT_DATA =
constant NON_WHITELISTED_DEPLOYER (line 26) | const NON_WHITELISTED_DEPLOYER = '0x123412341234123412341234123412341234...
constant NON_WHITELISTED_DEPLOYER_KEY (line 27) | const NON_WHITELISTED_DEPLOYER_KEY =
constant CREATED_BY_NON_WHITELISTED_DEPLOYER (line 29) | const CREATED_BY_NON_WHITELISTED_DEPLOYER =
constant WHITELISTED_DEPLOYER (line 32) | const WHITELISTED_DEPLOYER = '0x3456345634563456345634563456345634563456'
constant WHITELISTED_DEPLOYER_KEY (line 33) | const WHITELISTED_DEPLOYER_KEY =
constant CREATED_BY_WHITELISTED_DEPLOYER (line 35) | const CREATED_BY_WHITELISTED_DEPLOYER =
FILE: test/contracts/OVM/execution/OVM_ExecutionManager/ovmDELEGATECALL.spec.ts
constant CREATED_CONTRACT_1 (line 11) | const CREATED_CONTRACT_1 = '0x2bda4a99d5be88609d23b1e4ab5d1d34fb1c2feb'
constant CREATED_CONTRACT_2 (line 12) | const CREATED_CONTRACT_2 = '0xe0d8be8101f36ebe6b01abacec884422c39a1f62'
FILE: test/contracts/OVM/execution/OVM_ExecutionManager/run.spec.ts
constant GAS_METADATA_ADDRESS (line 11) | const GAS_METADATA_ADDRESS = '0x06a506a506a506a506a506a506a506a506a506a5'
type GasMetadataKey (line 13) | enum GasMetadataKey {
FILE: test/contracts/OVM/execution/OVM_StateManager.gas-spec.ts
constant DUMMY_ACCOUNT (line 19) | const DUMMY_ACCOUNT = DUMMY_ACCOUNTS[0]
constant DUMMY_KEY (line 20) | const DUMMY_KEY = DUMMY_BYTES32[0]
constant DUMMY_VALUE_1 (line 21) | const DUMMY_VALUE_1 = DUMMY_BYTES32[1]
constant DUMMY_VALUE_2 (line 22) | const DUMMY_VALUE_2 = DUMMY_BYTES32[2]
FILE: test/contracts/OVM/precompiles/OVM_L2ToL1MessagePasser.spec.ts
constant ELEMENT_TEST_SIZES (line 13) | const ELEMENT_TEST_SIZES = [1, 2, 4, 8, 16]
FILE: test/contracts/OVM/verification/OVM_BondManager.spec.ts
type State (line 386) | enum State {
type Errors (line 396) | enum Errors {
FILE: test/contracts/OVM/verification/OVM_FraudVerifier.spec.ts
constant DUMMY_TX_CHAIN_ELEMENTS (line 19) | const DUMMY_TX_CHAIN_ELEMENTS = [...Array(10).keys()].map((i) => {
constant DUMMY_HASH (line 29) | const DUMMY_HASH = hashTransaction(DUMMY_OVM_TRANSACTIONS[0])
constant DUMMY_BATCH_PROOFS_WITH_INDEX (line 31) | const DUMMY_BATCH_PROOFS_WITH_INDEX = [
FILE: test/contracts/OVM/verification/OVM_StateTransitionerFactory.spec.ts
constant DUMMY_HASH (line 15) | const DUMMY_HASH = hashTransaction(DUMMY_OVM_TRANSACTIONS[0])
FILE: test/contracts/libraries/trie/Lib_MerkleTrie.spec.ts
constant NODE_COUNTS (line 12) | const NODE_COUNTS = [1, 2, 128]
FILE: test/contracts/libraries/trie/Lib_SecureMerkleTrie.spec.ts
constant NODE_COUNTS (line 10) | const NODE_COUNTS = [1, 2, 128]
FILE: test/contracts/libraries/utils/Lib_MerkleTree.spec.ts
constant NODE_COUNTS (line 12) | const NODE_COUNTS = [
FILE: test/helpers/codec/encoding.ts
type EIP155Transaction (line 8) | interface EIP155Transaction {
type SignatureParameters (line 17) | interface SignatureParameters {
constant DEFAULT_EIP155_TX (line 24) | const DEFAULT_EIP155_TX: EIP155Transaction = {
FILE: test/helpers/codec/revert-flags.ts
constant REVERT_FLAGS (line 36) | const REVERT_FLAGS = {
FILE: test/helpers/constants.ts
constant DEFAULT_ACCOUNTS (line 10) | const DEFAULT_ACCOUNTS = defaultAccounts
constant DEFAULT_ACCOUNTS_HARDHAT (line 11) | const DEFAULT_ACCOUNTS_HARDHAT = defaultAccounts.map((account) => {
constant OVM_TX_GAS_LIMIT (line 18) | const OVM_TX_GAS_LIMIT = 10_000_000
constant RUN_OVM_TEST_GAS (line 19) | const RUN_OVM_TEST_GAS = 20_000_000
constant FORCE_INCLUSION_PERIOD_SECONDS (line 20) | const FORCE_INCLUSION_PERIOD_SECONDS = 600
constant FORCE_INCLUSION_PERIOD_BLOCKS (line 21) | const FORCE_INCLUSION_PERIOD_BLOCKS = 600 / 12
constant NON_NULL_BYTES32 (line 23) | const NON_NULL_BYTES32 =
constant NON_ZERO_ADDRESS (line 25) | const NON_ZERO_ADDRESS = '0x1111111111111111111111111111111111111111'
constant VERIFIED_EMPTY_CONTRACT_HASH (line 27) | const VERIFIED_EMPTY_CONTRACT_HASH =
constant STORAGE_XOR_VALUE (line 30) | const STORAGE_XOR_VALUE =
constant NUISANCE_GAS_COSTS (line 33) | const NUISANCE_GAS_COSTS = {
constant STORAGE_XOR (line 53) | const STORAGE_XOR =
constant EMPTY_ACCOUNT_CODE_HASH (line 59) | const EMPTY_ACCOUNT_CODE_HASH =
constant KECCAK_256_NULL (line 61) | const KECCAK_256_NULL =
FILE: test/helpers/dummy/accounts.ts
constant DUMMY_ACCOUNTS (line 9) | const DUMMY_ACCOUNTS: Array<{
FILE: test/helpers/dummy/batches.ts
constant DUMMY_BATCH_HEADERS (line 4) | const DUMMY_BATCH_HEADERS = [
constant DUMMY_BATCH_PROOFS (line 27) | const DUMMY_BATCH_PROOFS = [
FILE: test/helpers/dummy/bytecode.ts
constant DUMMY_BYTECODE (line 4) | const DUMMY_BYTECODE = '0x123412341234'
constant DUMMY_BYTECODE_BYTELEN (line 5) | const DUMMY_BYTECODE_BYTELEN = 6
constant UNSAFE_BYTECODE (line 6) | const UNSAFE_BYTECODE = '0x6069606955'
constant DUMMY_BYTECODE_HASH (line 7) | const DUMMY_BYTECODE_HASH = keccak256(DUMMY_BYTECODE)
FILE: test/helpers/dummy/bytes32.ts
constant DUMMY_BYTES32 (line 4) | const DUMMY_BYTES32: string[] = Array.from(
FILE: test/helpers/dummy/context.ts
constant DUMMY_CONTEXT (line 4) | const DUMMY_CONTEXT = {
FILE: test/helpers/dummy/transactions.ts
type Transaction (line 3) | interface Transaction {
constant DUMMY_OVM_TRANSACTIONS (line 13) | const DUMMY_OVM_TRANSACTIONS: Array<Transaction> = [
FILE: test/helpers/gas/gas.ts
class GasMeasurement (line 4) | class GasMeasurement {
method init (line 7) | public async init(wallet: Signer) {
method getGasCost (line 13) | public async getGasCost(
FILE: test/helpers/test-runner/test-runner.ts
class ExecutionManagerTestRunner (line 41) | class ExecutionManagerTestRunner {
method run (line 89) | public run(test: TestDefinition) {
method initContracts (line 185) | private async initContracts() {
method getDummyAddress (line 253) | public static getDummyAddress(placeholder: string): string {
method setPlaceholderStrings (line 257) | private setPlaceholderStrings(obj: any) {
method runTestStep (line 299) | private async runTestStep(step: TestStep | TestStep_Run) {
method parseTestStep (line 351) | private parseTestStep(step: TestStep): ParsedTestStep {
method shouldStepOnlyValidateFlag (line 361) | private shouldStepOnlyValidateFlag(step: TestStep): boolean {
method getReturnStatus (line 370) | private getReturnStatus(step: TestStep): boolean {
method encodeFunctionData (line 391) | private encodeFunctionData(step: TestStep): string {
method encodeExpectedReturnData (line 458) | private encodeExpectedReturnData(step: TestStep): string {
FILE: test/helpers/test-runner/test.types.ts
type ContextOpcode (line 4) | type ContextOpcode =
type CallOpcode (line 15) | type CallOpcode = 'ovmCALL' | 'ovmSTATICCALL' | 'ovmDELEGATECALL'
type RevertFlagError (line 17) | type RevertFlagError = {
type TestStep_evm (line 25) | interface TestStep_evm {
type TestStep_Context (line 30) | interface TestStep_Context {
type TestStep_REVERT (line 35) | interface TestStep_REVERT {
type TestStep_EXTCODESIZE (line 42) | interface TestStep_EXTCODESIZE {
type TestStep_EXTCODEHASH (line 51) | interface TestStep_EXTCODEHASH {
type TestStep_EXTCODECOPY (line 60) | interface TestStep_EXTCODECOPY {
type TestStep_SSTORE (line 71) | interface TestStep_SSTORE {
type TestStep_SLOAD (line 81) | interface TestStep_SLOAD {
type TestStep_INCREMENTNONCE (line 90) | interface TestStep_INCREMENTNONCE {
type TestStep_CALL (line 96) | interface TestStep_CALL {
type TestStep_CREATE (line 111) | interface TestStep_CREATE {
type TestStep_CREATE2 (line 127) | interface TestStep_CREATE2 {
type TestStep_CREATEEOA (line 144) | interface TestStep_CREATEEOA {
type TestStep_Run (line 156) | interface TestStep_Run {
type TestStep (line 172) | type TestStep =
type ParsedTestStep (line 187) | interface ParsedTestStep {
type TestState (line 290) | interface TestState {
type TestParameter (line 295) | interface TestParameter {
type TestDefinition (line 303) | interface TestDefinition {
FILE: test/helpers/trie/trie-test-generator.ts
type TrieNode (line 8) | interface TrieNode {
type InclusionProofTest (line 13) | interface InclusionProofTest {
type NodeUpdateTest (line 20) | interface NodeUpdateTest extends InclusionProofTest {
type EthereumAccount (line 24) | interface EthereumAccount {
type AccountProofTest (line 33) | interface AccountProofTest {
type AccountUpdateTest (line 40) | interface AccountUpdateTest extends AccountProofTest {
class TrieTestGenerator (line 89) | class TrieTestGenerator {
method constructor (line 90) | constructor(
method fromNodes (line 97) | static async fromNodes(opts: {
method fromRandom (line 106) | static async fromRandom(opts: {
method fromAccounts (line 127) | static async fromAccounts(opts: {
method makeInclusionProofTest (line 157) | public async makeInclusionProofTest(
method makeAllInclusionProofTests (line 177) | public async makeAllInclusionProofTests(): Promise<InclusionProofTest[...
method makeNodeUpdateTest (line 185) | public async makeNodeUpdateTest(
method makeAccountProofTest (line 210) | public async makeAccountProofTest(
method makeAccountUpdateTest (line 230) | public async makeAccountUpdateTest(
method prove (line 258) | private async prove(key: string): Promise<any> {
FILE: test/helpers/types/ovm-types.ts
type OVMAccount (line 4) | interface OVMAccount {
Condensed preview — 234 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,248K chars).
[
{
"path": ".editorconfig",
"chars": 183,
"preview": "root = true\n\n# defaults\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_newline ="
},
{
"path": ".gitattributes",
"chars": 33,
"preview": "*.sol linguist-language=Solidity\n"
},
{
"path": ".github/CODEOWNERS",
"chars": 46,
"preview": "* @smartcontracts @ben-chain @maurelian\n"
},
{
"path": ".github/workflows/build-test-lint-contracts.yml",
"chars": 978,
"preview": "name: CI - contracts\n\non:\n push:\n branches:\n - master\n pull_request:\n branches:\n - master\n\njobs:\n bui"
},
{
"path": ".github/workflows/dockerhub-build-push.yml",
"chars": 1113,
"preview": "name: Build & Push to DockerHub\n\non:\n push:\n branches:\n - master\n - testnet\n - uat\n\njobs:\n build:\n "
},
{
"path": ".github/workflows/integration.yml",
"chars": 1216,
"preview": "name: Setup & Run Integration Test Suite\n\non:\n push:\n branches:\n - master\n pull_request:\n branches:\n -"
},
{
"path": ".github/workflows/push-to-integration-repo.yml",
"chars": 1114,
"preview": "name: Update submodules in integration repo\n\non:\n push:\n branches:\n - master\n\njobs:\n run:\n name: Update sub"
},
{
"path": ".github/workflows/tag-release.yml",
"chars": 3377,
"preview": "name: Auto tag-release-publish\n\non:\n push:\n branches:\n - master\n\njobs:\n tag:\n name: Create tag for new vers"
},
{
"path": ".gitignore",
"chars": 163,
"preview": "node_modules/\nartifacts/\nartifacts-ovm/\ncache/\ncache-ovm/\nyarn-error.log\nbuild/\n.DS_STORE\n\n# Coverage output\ncoverage/\nc"
},
{
"path": ".solcover.js",
"chars": 187,
"preview": "module.exports = {\n skipFiles: [\n './test-helpers',\n './test-libraries',\n './optimistic-ethereum/mockOVM'\n ],"
},
{
"path": "CHANGELOG.md",
"chars": 2233,
"preview": "# Changelog\n\n## v0.1.11\n- cleanup: ECDSAContractAccount\n- cleanup: Proxy_EOA\n- cleanup: StateManagerFactory\n- cleanup: B"
},
{
"path": "LICENSE.txt",
"chars": 1066,
"preview": "(The MIT License)\n\nCopyright 2020 Optimism\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy"
},
{
"path": "README.md",
"chars": 2732,
"preview": "**[DEPRECATED]** This repository is now deprecated in favour of the new development [monorepo](https://github.com/ethere"
},
{
"path": "bin/deploy.js",
"chars": 1507,
"preview": "#!/usr/bin/env node\n\nconst path = require('path')\nconst { spawn } = require('child_process')\nconst dirtree = require('di"
},
{
"path": "bin/deploy.ts",
"chars": 1953,
"preview": "#!/usr/bin/env ts-node-script\n\nimport { Wallet } from 'ethers'\n\n// Ensures that all relevant environment vars are proper"
},
{
"path": "bin/gen_safety_checker_constants.py",
"chars": 1811,
"preview": "#!/usr/bin/env python3\n# pip3 install pyevmasm\nfrom pyevmasm import instruction_tables\n\n#print(instruction_tables.keys()"
},
{
"path": "bin/serve_dump.sh",
"chars": 1004,
"preview": "#!/bin/bash\n\n# Run this script to serve the latest state dump from\n# an http server. This is useful to serve the state d"
},
{
"path": "bin/take-dump.ts",
"chars": 702,
"preview": "/* External Imports */\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport * as mkdirp from 'mkdirp'\n\nconst env"
},
{
"path": "contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol",
"chars": 5736,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Interface Imports *"
},
{
"path": "contracts/optimistic-ethereum/OVM/accounts/OVM_ProxyEOA.sol",
"chars": 3099,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_Bytes32Utils } from \""
},
{
"path": "contracts/optimistic-ethereum/OVM/bridge/messaging/Abs_BaseCrossDomainMessenger.sol",
"chars": 3903,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Interface Imports *"
},
{
"path": "contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L1CrossDomainMessenger.sol",
"chars": 8816,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L1MultiMessageRelayer.sol",
"chars": 2244,
"preview": "// SPDX-License-Identifier: MIT\n// @unsupported: ovm\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n/*"
},
{
"path": "contracts/optimistic-ethereum/OVM/bridge/messaging/OVM_L2CrossDomainMessenger.sol",
"chars": 4458,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/OVM/bridge/tokens/Abs_L1TokenGateway.sol",
"chars": 6063,
"preview": "// SPDX-License-Identifier: MIT\n// @unsupported: ovm \npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n"
},
{
"path": "contracts/optimistic-ethereum/OVM/bridge/tokens/Abs_L2DepositedToken.sol",
"chars": 6864,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Interface Imports *"
},
{
"path": "contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L1ERC20Gateway.sol",
"chars": 2845,
"preview": "// SPDX-License-Identifier: MIT\n// @unsupported: ovm \npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n"
},
{
"path": "contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L1ETHGateway.sol",
"chars": 4909,
"preview": "// SPDX-License-Identifier: MIT\n// @unsupported: ovm\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/"
},
{
"path": "contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L2DepositedERC20.sol",
"chars": 2059,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Interface Imports *"
},
{
"path": "contracts/optimistic-ethereum/OVM/chain/OVM_CanonicalTransactionChain.sol",
"chars": 41491,
"preview": "// SPDX-License-Identifier: MIT\n// @unsupported: ovm\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/"
},
{
"path": "contracts/optimistic-ethereum/OVM/chain/OVM_ChainStorageContainer.sol",
"chars": 4498,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_RingBuffer } from \".."
},
{
"path": "contracts/optimistic-ethereum/OVM/chain/OVM_StateCommitmentChain.sol",
"chars": 11980,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol",
"chars": 64447,
"preview": "// SPDX-License-Identifier: MIT\n// @unsupported: ovm\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/"
},
{
"path": "contracts/optimistic-ethereum/OVM/execution/OVM_SafetyChecker.sol",
"chars": 7479,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Interface Imports */\nimport { iOVM_SafetyChecker } fr"
},
{
"path": "contracts/optimistic-ethereum/OVM/execution/OVM_StateManager.sol",
"chars": 19385,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/OVM/execution/OVM_StateManagerFactory.sol",
"chars": 1090,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Interface Imports */\nimport { iOVM_StateManager } fro"
},
{
"path": "contracts/optimistic-ethereum/OVM/predeploys/ERC1820Registry.sol",
"chars": 10510,
"preview": "// SPDX-License-Identifier: CC0-1.0\n/* ERC1820 Pseudo-introspection Registry Contract\n * This standard defines a univers"
},
{
"path": "contracts/optimistic-ethereum/OVM/predeploys/OVM_DeployerWhitelist.sol",
"chars": 6077,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_Bytes32Utils } from \""
},
{
"path": "contracts/optimistic-ethereum/OVM/predeploys/OVM_ETH.sol",
"chars": 962,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_AddressResolver } fro"
},
{
"path": "contracts/optimistic-ethereum/OVM/predeploys/OVM_L1MessageSender.sol",
"chars": 1484,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Interface Imports */\nimport { iOVM_L1MessageSender } "
},
{
"path": "contracts/optimistic-ethereum/OVM/predeploys/OVM_L2ToL1MessagePasser.sol",
"chars": 1482,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Interface Imports */\nimport { iOVM_L2ToL1MessagePasse"
},
{
"path": "contracts/optimistic-ethereum/OVM/predeploys/OVM_ProxySequencerEntrypoint.sol",
"chars": 2689,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_SafeExecutionManagerW"
},
{
"path": "contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol",
"chars": 4312,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_BytesUtils } from \".."
},
{
"path": "contracts/optimistic-ethereum/OVM/verification/Abs_FraudContributor.sol",
"chars": 839,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\nimport { iOVM_BondManager } from \"../../iOVM/verificatio"
},
{
"path": "contracts/optimistic-ethereum/OVM/verification/OVM_BondManager.sol",
"chars": 7973,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_AddressResolver } fro"
},
{
"path": "contracts/optimistic-ethereum/OVM/verification/OVM_FraudVerifier.sol",
"chars": 10874,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/OVM/verification/OVM_StateTransitioner.sol",
"chars": 16509,
"preview": "// SPDX-License-Identifier: MIT\n// @unsupported: ovm\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/"
},
{
"path": "contracts/optimistic-ethereum/OVM/verification/OVM_StateTransitionerFactory.sol",
"chars": 2200,
"preview": "// SPDX-License-Identifier: MIT\n// @unsupported: ovm\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_"
},
{
"path": "contracts/optimistic-ethereum/iOVM/accounts/iOVM_ECDSAContractAccount.sol",
"chars": 591,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/iOVM/bridge/messaging/iAbs_BaseCrossDomainMessenger.sol",
"chars": 920,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/**\n * @title iAbs_Bas"
},
{
"path": "contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_L1CrossDomainMessenger.sol",
"chars": 1904,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_L1MultiMessageRelayer.sol",
"chars": 555,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Interface Imports *"
},
{
"path": "contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_L2CrossDomainMessenger.sol",
"chars": 839,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Interface Imports *"
},
{
"path": "contracts/optimistic-ethereum/iOVM/bridge/tokens/iOVM_L1ETHGateway.sol",
"chars": 948,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0;\npragma experimental ABIEncoderV2;\n\n/**\n * @title iOVM_L1ETHGatew"
},
{
"path": "contracts/optimistic-ethereum/iOVM/bridge/tokens/iOVM_L1TokenGateway.sol",
"chars": 855,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0;\npragma experimental ABIEncoderV2;\n\n/**\n * @title iOVM_L1TokenGat"
},
{
"path": "contracts/optimistic-ethereum/iOVM/bridge/tokens/iOVM_L2DepositedToken.sol",
"chars": 860,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0;\npragma experimental ABIEncoderV2;\n\n/**\n * @title iOVM_L2Deposite"
},
{
"path": "contracts/optimistic-ethereum/iOVM/chain/iOVM_CanonicalTransactionChain.sol",
"chars": 6105,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/iOVM/chain/iOVM_ChainStorageContainer.sol",
"chars": 2912,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title iOVM_ChainStorageContainer\n */\ninterface i"
},
{
"path": "contracts/optimistic-ethereum/iOVM/chain/iOVM_StateCommitmentChain.sol",
"chars": 3068,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/iOVM/execution/iOVM_ExecutionManager.sol",
"chars": 4718,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/iOVM/execution/iOVM_SafetyChecker.sol",
"chars": 299,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title iOVM_SafetyChecker\n */\ninterface iOVM_Safe"
},
{
"path": "contracts/optimistic-ethereum/iOVM/execution/iOVM_StateManager.sol",
"chars": 3814,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/iOVM/execution/iOVM_StateManagerFactory.sol",
"chars": 512,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Contract Imports */\nimport { iOVM_StateManager } from"
},
{
"path": "contracts/optimistic-ethereum/iOVM/predeploys/iOVM_DeployerWhitelist.sol",
"chars": 727,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title iOVM_DeployerWhitelist\n */\ninterface iOVM_"
},
{
"path": "contracts/optimistic-ethereum/iOVM/predeploys/iOVM_ERC20.sol",
"chars": 2618,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title iOVM_ERC20\n */\ninterface iOVM_ERC20 {\n "
},
{
"path": "contracts/optimistic-ethereum/iOVM/predeploys/iOVM_L1MessageSender.sol",
"chars": 303,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title iOVM_L1MessageSender\n */\ninterface iOVM_L1"
},
{
"path": "contracts/optimistic-ethereum/iOVM/predeploys/iOVM_L2ToL1MessagePasser.sol",
"chars": 444,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title iOVM_L2ToL1MessagePasser\n */\ninterface iOV"
},
{
"path": "contracts/optimistic-ethereum/iOVM/verification/iOVM_BondManager.sol",
"chars": 3734,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\ninterface ERC20 {\n function transfer(address, uint256"
},
{
"path": "contracts/optimistic-ethereum/iOVM/verification/iOVM_FraudVerifier.sol",
"chars": 2080,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/iOVM/verification/iOVM_StateTransitioner.sol",
"chars": 2055,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/iOVM/verification/iOVM_StateTransitionerFactory.sol",
"chars": 653,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Contract Imports */\nimport { iOVM_StateTransitioner }"
},
{
"path": "contracts/optimistic-ethereum/libraries/bridge/OVM_CrossDomainEnabled.sol",
"chars": 2630,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n/* Interface Imports */\nimport { iAbs_BaseCrossDomainMess"
},
{
"path": "contracts/optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol",
"chars": 10291,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/libraries/resolver/Lib_AddressManager.sol",
"chars": 1802,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Contract Imports */\nimport { Ownable } from \"./Lib_Ow"
},
{
"path": "contracts/optimistic-ethereum/libraries/resolver/Lib_AddressResolver.sol",
"chars": 1083,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_AddressManager } from"
},
{
"path": "contracts/optimistic-ethereum/libraries/resolver/Lib_Ownable.sol",
"chars": 1879,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title Ownable\n * @dev Adapted from https://githu"
},
{
"path": "contracts/optimistic-ethereum/libraries/resolver/Lib_ResolvedDelegateProxy.sol",
"chars": 2257,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_AddressManager } from"
},
{
"path": "contracts/optimistic-ethereum/libraries/rlp/Lib_RLPReader.sol",
"chars": 13458,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title Lib_RLPReader\n * @dev Adapted from \"RLPRea"
},
{
"path": "contracts/optimistic-ethereum/libraries/rlp/Lib_RLPWriter.sol",
"chars": 6700,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/libraries/standards/IUniswapV2ERC20.sol",
"chars": 1188,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.5.16 <0.8.0;\n\ninterface IUniswapV2ERC20 {\n event Approval(address"
},
{
"path": "contracts/optimistic-ethereum/libraries/standards/UniSafeMath.sol",
"chars": 606,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.5.16 <0.8.0;\n\n// a library for performing overflow-safe math, courte"
},
{
"path": "contracts/optimistic-ethereum/libraries/standards/UniswapV2ERC20.sol",
"chars": 3481,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.5.16 <0.8.0;\n\nimport './IUniswapV2ERC20.sol';\nimport './UniSafeMath."
},
{
"path": "contracts/optimistic-ethereum/libraries/trie/Lib_MerkleTrie.sol",
"chars": 33719,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_BytesUtils } from \".."
},
{
"path": "contracts/optimistic-ethereum/libraries/trie/Lib_SecureMerkleTrie.sol",
"chars": 4886,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/optimistic-ethereum/libraries/utils/Lib_Bytes32Utils.sol",
"chars": 2630,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title Lib_Byte32Utils\n */\nlibrary Lib_Bytes32Uti"
},
{
"path": "contracts/optimistic-ethereum/libraries/utils/Lib_BytesUtils.sol",
"chars": 6378,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title Lib_BytesUtils\n */\nlibrary Lib_BytesUtils "
},
{
"path": "contracts/optimistic-ethereum/libraries/utils/Lib_ECDSAUtils.sol",
"chars": 2473,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title Lib_ECDSAUtils\n */\nlibrary Lib_ECDSAUtils "
},
{
"path": "contracts/optimistic-ethereum/libraries/utils/Lib_ErrorUtils.sol",
"chars": 920,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/**\n * @title Lib_Erro"
},
{
"path": "contracts/optimistic-ethereum/libraries/utils/Lib_EthUtils.sol",
"chars": 4561,
"preview": "// SPDX-License-Identifier: MIT\n// @unsupported: ovm\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/"
},
{
"path": "contracts/optimistic-ethereum/libraries/utils/Lib_Math.sol",
"chars": 617,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title Lib_Math\n */\nlibrary Lib_Math {\n\n /****"
},
{
"path": "contracts/optimistic-ethereum/libraries/utils/Lib_MerkleTree.sol",
"chars": 7278,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @title Lib_MerkleTree\n * @author River Keefer\n */"
},
{
"path": "contracts/optimistic-ethereum/libraries/utils/Lib_ReentrancyGuard.sol",
"chars": 2605,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant"
},
{
"path": "contracts/optimistic-ethereum/libraries/utils/Lib_RingBuffer.sol",
"chars": 10758,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\nlibrary Lib_RingBuffer {\n using Lib_RingBuffer for Ri"
},
{
"path": "contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol",
"chars": 9248,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_ErrorUtils } from \".."
},
{
"path": "contracts/optimistic-ethereum/libraries/wrappers/Lib_SafeMathWrapper.sol",
"chars": 5653,
"preview": "// SPDX-License-Identifier: MIT\n// Pulled from @openzeppelin/contracts/math/SafeMath.sol\n// SPDX-License-Identifier: MIT"
},
{
"path": "contracts/optimistic-ethereum/mockOVM/accounts/mockOVM_ECDSAContractAccount.sol",
"chars": 3334,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Interface Imports *"
},
{
"path": "contracts/optimistic-ethereum/mockOVM/bridge/mockOVM_CrossDomainMessenger.sol",
"chars": 3962,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Contract Imports */"
},
{
"path": "contracts/optimistic-ethereum/mockOVM/bridge/mockOVM_GenericCrossDomainMessenger.sol",
"chars": 1123,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/**\n * @title mockOVM_"
},
{
"path": "contracts/optimistic-ethereum/mockOVM/verification/mockOVM_BondManager.sol",
"chars": 1630,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Interface Imports */\nimport { iOVM_BondManager } from"
},
{
"path": "contracts/test-helpers/Helper_GasMeasurer.sol",
"chars": 841,
"preview": "// SPDX-License-Identifier: UNLICENSED\n// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\ncontract Helper_G"
},
{
"path": "contracts/test-helpers/Helper_ModifiableStorage.sol",
"chars": 1081,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\ncontract Helper_ModifiableStorage {\n mapping (address"
},
{
"path": "contracts/test-helpers/Helper_PrecompileCaller.sol",
"chars": 1218,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\nimport { Helper_SimpleProxy } from \"./Helper_SimpleProxy"
},
{
"path": "contracts/test-helpers/Helper_SimpleProxy.sol",
"chars": 976,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\ncontract Helper_SimpleProxy {\n address internal owner"
},
{
"path": "contracts/test-helpers/Helper_TestRunner.sol",
"chars": 6384,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Logging */\nimport {"
},
{
"path": "contracts/test-helpers/Mock_FraudVerifier.sol",
"chars": 1003,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\nimport { OVM_BondManager } from \"./../optimistic-ethereu"
},
{
"path": "contracts/test-helpers/TestERC20.sol",
"chars": 2286,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n// a test ERC20 token with an open mint function\ncontrac"
},
{
"path": "contracts/test-libraries/codec/TestLib_OVMCodec.sol",
"chars": 1376,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/test-libraries/rlp/TestLib_RLPReader.sol",
"chars": 1861,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/test-libraries/rlp/TestLib_RLPWriter.sol",
"chars": 1761,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/test-libraries/trie/TestLib_MerkleTrie.sol",
"chars": 1898,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_MerkleTrie } from \".."
},
{
"path": "contracts/test-libraries/trie/TestLib_SecureMerkleTrie.sol",
"chars": 1986,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/test-libraries/utils/TestLib_Bytes32Utils.sol",
"chars": 1016,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_Bytes32Utils } from \""
},
{
"path": "contracts/test-libraries/utils/TestLib_BytesUtils.sol",
"chars": 2227,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/test-libraries/utils/TestLib_ECDSAUtils.sol",
"chars": 650,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\n\n/* Library Imports */\nimport { Lib_ECDSAUtils } from \".."
},
{
"path": "contracts/test-libraries/utils/TestLib_EthUtils.sol",
"chars": 2121,
"preview": "// SPDX-License-Identifier: MIT\n// @unsupported: ovm\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/"
},
{
"path": "contracts/test-libraries/utils/TestLib_MerkleTree.sol",
"chars": 924,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "contracts/test-libraries/utils/TestLib_RingBuffer.sol",
"chars": 1271,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.8.0;\npragma experimental ABIEncoderV2;\n\n/* Library Imports */\n"
},
{
"path": "deploy/000-Lib_AddressManager.deploy.ts",
"chars": 1194,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport { reg"
},
{
"path": "deploy/001-OVM_ChainStorageContainer_ctc_batches.deploy.ts",
"chars": 687,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport {\n d"
},
{
"path": "deploy/002-OVM_ChainStorageContainer_ctc_queue.deploy.ts",
"chars": 683,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport {\n d"
},
{
"path": "deploy/003-OVM_ChainStorageContainer_scc_batches.deploy.ts",
"chars": 682,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport {\n d"
},
{
"path": "deploy/004-OVM_CanonicalTransactionChain.deploy.ts",
"chars": 794,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport {\n d"
},
{
"path": "deploy/005-OVM_StateCommitmentChain.deploy.ts",
"chars": 710,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport {\n d"
},
{
"path": "deploy/006-mockOVM_BondManager.deploy.ts",
"chars": 829,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport { get"
},
{
"path": "deploy/007-OVM_L1CrossDomainMessenger.deploy.ts",
"chars": 1833,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport { get"
},
{
"path": "deploy/008-Proxy__OVM_L1CrossDomainMessenger.deploy.ts",
"chars": 1844,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport { get"
},
{
"path": "deploy/009-OVM_ExecutionManager.deploy.ts",
"chars": 1039,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport {\n d"
},
{
"path": "deploy/010-OVM_FraudVerifer.deploy.ts",
"chars": 571,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport {\n d"
},
{
"path": "deploy/011-OVM_StateManagerFactory.deploy.ts",
"chars": 383,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport { dep"
},
{
"path": "deploy/012-OVM_StateTransitionerFactory.deploy.ts",
"chars": 593,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport {\n d"
},
{
"path": "deploy/013-OVM_SafetyChecker.deploy.ts",
"chars": 377,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport { dep"
},
{
"path": "deploy/014-OVM_L1MultiMessageRelayer.deploy.ts",
"chars": 587,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport {\n d"
},
{
"path": "deploy/015-OVM_L1ETHGateway.deploy.ts",
"chars": 1800,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport { get"
},
{
"path": "deploy/016-Proxy__OVM_L1ETHGateway.deploy.ts",
"chars": 1801,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport { get"
},
{
"path": "deploy/017-finalize.ts",
"chars": 1486,
"preview": "/* Imports: External */\nimport { DeployFunction } from 'hardhat-deploy/dist/types'\n\n/* Imports: Internal */\nimport { get"
},
{
"path": "hardhat.config.ts",
"chars": 1607,
"preview": "import { HardhatUserConfig } from 'hardhat/types'\nimport 'solidity-coverage'\nimport * as dotenv from 'dotenv'\n\nimport {\n"
},
{
"path": "hh/index.ts",
"chars": 29,
"preview": "import './tasks/task-deploy'\n"
},
{
"path": "hh/tasks/task-deploy.ts",
"chars": 4017,
"preview": "/* Imports: External */\nimport { ethers } from 'ethers'\nimport { task } from 'hardhat/config'\nimport * as types from 'ha"
},
{
"path": "package.json",
"chars": 3545,
"preview": "{\n \"name\": \"@eth-optimism/contracts\",\n \"version\": \"0.2.0\",\n \"main\": \"build/src/index.js\",\n \"files\": [\n \"build/**/"
},
{
"path": "prettier-config.json",
"chars": 168,
"preview": "{\n \"$schema\": \"http://json.schemastore.org/prettierrc\",\n \"trailingComma\": \"es5\",\n \"tabWidth\": 2,\n \"semi\": false,\n \""
},
{
"path": "src/contract-defs.ts",
"chars": 1004,
"preview": "import * as path from 'path'\nimport * as glob from 'glob'\nimport { ethers, ContractFactory, Signer } from 'ethers'\nimpor"
},
{
"path": "src/contract-deployment/config.ts",
"chars": 8565,
"preview": "/* External Imports */\nimport { Signer, ContractFactory, Contract } from 'ethers'\nimport { TransactionResponse } from '@"
},
{
"path": "src/contract-deployment/deploy.ts",
"chars": 2487,
"preview": "/* External Imports */\nimport { Contract } from 'ethers'\n\n/* Internal Imports */\nimport { RollupDeployConfig, makeContra"
},
{
"path": "src/contract-deployment/index.ts",
"chars": 80,
"preview": "export { RollupDeployConfig } from './config'\nexport { deploy } from './deploy'\n"
},
{
"path": "src/contract-dumps.ts",
"chars": 6975,
"preview": "/* External Imports */\nimport * as path from 'path'\nimport { ethers } from 'ethers'\nimport * as Ganache from 'ganache-co"
},
{
"path": "src/hardhat-deploy-ethers.ts",
"chars": 3737,
"preview": "/* Imports: External */\nimport { Contract } from 'ethers'\nimport { Provider } from '@ethersproject/abstract-provider'\nim"
},
{
"path": "src/index.ts",
"chars": 135,
"preview": "export * from './contract-defs'\nexport { getLatestStateDump, StateDump } from './contract-dumps'\nexport * from './contra"
},
{
"path": "src/predeploys.ts",
"chars": 734,
"preview": "export const predeploys = {\n OVM_L2ToL1MessagePasser: '0x4200000000000000000000000000000000000000',\n OVM_L1MessageSend"
},
{
"path": "test/contracts/OVM/accounts/OVM_ECDSAContractAccount.spec.ts",
"chars": 8908,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers, waffle } from 'hardhat'\nimport { Contra"
},
{
"path": "test/contracts/OVM/accounts/OVM_ProxyEOA.spec.ts",
"chars": 4978,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers, waffle } from 'hardhat'\nimport { Contra"
},
{
"path": "test/contracts/OVM/bridge/assets/OVM_L1ERC20Gateway.spec.ts",
"chars": 8870,
"preview": "import { expect } from '../../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Signer, Con"
},
{
"path": "test/contracts/OVM/bridge/assets/OVM_L1ETHGateway.spec.ts",
"chars": 9108,
"preview": "import { expect } from '../../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Signer, Con"
},
{
"path": "test/contracts/OVM/bridge/assets/OVM_L2DepositedERC20.spec.ts",
"chars": 7788,
"preview": "import { expect } from '../../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Signer, Con"
},
{
"path": "test/contracts/OVM/bridge/base/OVM_L1CrossDomainMessenger.spec.ts",
"chars": 10855,
"preview": "import { expect } from '../../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Signer, Con"
},
{
"path": "test/contracts/OVM/bridge/base/OVM_L1MultiMessageRelayer.ts",
"chars": 4521,
"preview": "import { expect } from '../../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Signer, Con"
},
{
"path": "test/contracts/OVM/bridge/base/OVM_L2CrossDomainMessenger.spec.ts",
"chars": 6300,
"preview": "import { expect } from '../../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Signer, Con"
},
{
"path": "test/contracts/OVM/chain/OVM_CanonicalTransactionChain.gas.spec.ts",
"chars": 6793,
"preview": "/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Signer, ContractFactory, Contract } from 'ethers'\nimpor"
},
{
"path": "test/contracts/OVM/chain/OVM_CanonicalTransactionChain.spec.ts",
"chars": 50906,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Signer, Contra"
},
{
"path": "test/contracts/OVM/chain/OVM_StateCommitmentChain.spec.ts",
"chars": 11599,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Signer, Contra"
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager/context-opcodes.spec.ts",
"chars": 2965,
"preview": "/* Internal Imports */\nimport {\n ExecutionManagerTestRunner,\n TestDefinition,\n NON_NULL_BYTES32,\n OVM_TX_GAS_LIMIT,\n"
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager/nuisance-gas.spec.ts",
"chars": 6774,
"preview": "/* Internal Imports */\nimport { constants } from 'ethers'\nimport {\n ExecutionManagerTestRunner,\n TestDefinition,\n OVM"
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager/ovmCALL.spec.ts",
"chars": 7236,
"preview": "/* Internal Imports */\nimport {\n ExecutionManagerTestRunner,\n TestDefinition,\n OVM_TX_GAS_LIMIT,\n NON_NULL_BYTES32,\n"
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATE.spec.ts",
"chars": 29499,
"preview": "/* Internal Imports */\nimport { constants, ethers } from 'ethers'\nimport {\n ExecutionManagerTestRunner,\n TestDefinitio"
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATEEOA.spec.ts",
"chars": 3713,
"preview": "/* External Imports */\nimport { fromHexString } from '@eth-optimism/core-utils'\n\n/* Internal Imports */\nimport {\n Execu"
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager/ovmDELEGATECALL.spec.ts",
"chars": 11791,
"preview": "/* Internal Imports */\nimport {\n ExecutionManagerTestRunner,\n TestDefinition,\n OVM_TX_GAS_LIMIT,\n NON_NULL_BYTES32,\n"
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager/ovmREVERT.spec.ts",
"chars": 3071,
"preview": "/* Internal Imports */\nimport {\n ExecutionManagerTestRunner,\n TestDefinition,\n OVM_TX_GAS_LIMIT,\n NON_NULL_BYTES32,\n"
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager/ovmSLOAD.spec.ts",
"chars": 1830,
"preview": "/* External Imports */\nimport { ethers } from 'ethers'\n\n/* Internal Imports */\nimport {\n ExecutionManagerTestRunner,\n "
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager/ovmSTATICCALL.spec.ts",
"chars": 10280,
"preview": "/* External Imports */\nimport { ethers } from 'ethers'\n\n/* Internal Imports */\nimport {\n ExecutionManagerTestRunner,\n "
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager/run.spec.ts",
"chars": 4154,
"preview": "/* Internal Imports */\nimport { constants } from 'ethers'\nimport {\n ExecutionManagerTestRunner,\n TestDefinition,\n OVM"
},
{
"path": "test/contracts/OVM/execution/OVM_ExecutionManager.gas-spec.ts",
"chars": 3439,
"preview": "import { expect } from '../../../setup'\nimport { deployContractCode } from '../../../helpers/utils'\n\n/* External Imports"
},
{
"path": "test/contracts/OVM/execution/OVM_SafetyChecker.spec.ts",
"chars": 837,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Contract } fro"
},
{
"path": "test/contracts/OVM/execution/OVM_StateManager.gas-spec.ts",
"chars": 13698,
"preview": "import '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { constants, Contract, ContractF"
},
{
"path": "test/contracts/OVM/execution/OVM_StateManager.spec.ts",
"chars": 27473,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Contract, Cont"
},
{
"path": "test/contracts/OVM/precompiles/OVM_L1MessageSender.spec.ts",
"chars": 1860,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { ContractFactor"
},
{
"path": "test/contracts/OVM/precompiles/OVM_L2ToL1MessagePasser.spec.ts",
"chars": 2367,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { ContractFactor"
},
{
"path": "test/contracts/OVM/precompiles/OVM_ProxySequencerEntrypoint.spec.ts",
"chars": 5394,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers, waffle } from 'hardhat'\nimport { Contra"
},
{
"path": "test/contracts/OVM/precompiles/OVM_SequencerEntrypoint.spec.ts",
"chars": 5910,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { waffle, ethers } from 'hardhat'\nimport { Contra"
},
{
"path": "test/contracts/OVM/verification/OVM_BondManager.spec.ts",
"chars": 15050,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { waffle, ethers as deployer } from 'hardhat'\nimp"
},
{
"path": "test/contracts/OVM/verification/OVM_FraudVerifier.spec.ts",
"chars": 18394,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { ContractFactor"
},
{
"path": "test/contracts/OVM/verification/OVM_StateTransitioner.spec.ts",
"chars": 16795,
"preview": "/* tslint:disable:no-empty */\nimport { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'ha"
},
{
"path": "test/contracts/OVM/verification/OVM_StateTransitionerFactory.spec.ts",
"chars": 2622,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { ContractFactor"
},
{
"path": "test/contracts/libraries/codec/Lib_OVMCodec.spec.ts",
"chars": 320,
"preview": "/* tslint:disable:no-empty */\nimport '../../../setup'\n\n/* Internal Imports */\nimport { Lib_OVMCodec_TEST_JSON } from '.."
},
{
"path": "test/contracts/libraries/rlp/Lib_RLPReader.spec.ts",
"chars": 264,
"preview": "/* Internal Imports */\nimport { Lib_RLPReader_TEST_JSON } from '../../../data'\nimport { runJsonTest } from '../../../hel"
},
{
"path": "test/contracts/libraries/rlp/Lib_RLPWriter.spec.ts",
"chars": 1647,
"preview": "/* tslint:disable:no-empty */\nimport { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'ha"
},
{
"path": "test/contracts/libraries/trie/Lib_MerkleTrie.spec.ts",
"chars": 5516,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport * as rlp from 'rlp'\nimport { ethers } from 'hardh"
},
{
"path": "test/contracts/libraries/trie/Lib_SecureMerkleTrie.spec.ts",
"chars": 3221,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Contract } fro"
},
{
"path": "test/contracts/libraries/utils/Lib_Bytes32Utils.spec.ts",
"chars": 276,
"preview": "/* Internal Imports */\nimport { Lib_Bytes32Utils_TEST_JSON } from '../../../data'\nimport { runJsonTest } from '../../../"
},
{
"path": "test/contracts/libraries/utils/Lib_BytesUtils.spec.ts",
"chars": 925,
"preview": "/* Internal Imports */\nimport { Lib_BytesUtils_TEST_JSON } from '../../../data'\nimport { runJsonTest } from '../../../he"
},
{
"path": "test/contracts/libraries/utils/Lib_ECDSAUtils.spec.ts",
"chars": 268,
"preview": "/* Internal Imports */\nimport { Lib_ECDSAUtils_TEST_JSON } from '../../../data'\nimport { runJsonTest } from '../../../he"
},
{
"path": "test/contracts/libraries/utils/Lib_EthUtils.spec.ts",
"chars": 9968,
"preview": "/* tslint:disable:no-empty */\nimport { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'ha"
},
{
"path": "test/contracts/libraries/utils/Lib_MerkleTree.spec.ts",
"chars": 5384,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Contract, BigN"
},
{
"path": "test/contracts/mockOVM/verification/mockOVM_BondManager.spec.ts",
"chars": 1223,
"preview": "import { expect } from '../../../setup'\n\n/* External Imports */\nimport { ethers } from 'hardhat'\nimport { Signer, Contra"
},
{
"path": "test/data/index.ts",
"chars": 845,
"preview": "export { tests as Lib_RLPWriter_TEST_JSON } from './json/libraries/rlp/Lib_RLPWriter.test.json'\nexport { tests as Lib_RL"
},
{
"path": "test/data/json/create2.test.json",
"chars": 78832,
"preview": "{\n \"source\": \"https://eips.ethereum.org/EIPS/eip-1014\",\n \"notes\": \"added additional tests with more bytecode\",\n \"date"
},
{
"path": "test/data/json/libraries/codec/Lib_OVMCodec.test.json",
"chars": 622,
"preview": "{\n \"tests\": {\n \"decompressEIP155Transaction\": {\n \"decompression\": {\n \"in\": [\n "
},
{
"path": "test/data/json/libraries/rlp/Lib_RLPReader.test.json",
"chars": 13788,
"preview": "{\n \"tests\": {\n \"readBool\": {\n \"true\": {\n \"in\": [\n \"0x01\"\n "
},
{
"path": "test/data/json/libraries/rlp/Lib_RLPWriter.test.json",
"chars": 8216,
"preview": "{\n \"source\": \"https://github.com/ethereum/tests/blob/develop/RLPTests/rlptest.json\",\n \"notes\": \"Removed BigInt test, s"
},
{
"path": "test/data/json/libraries/trie/Lib_MerkleTrie.test.json",
"chars": 38487,
"preview": "{\n \"tests\": {\n \"update\": {\n \"basic leaf value updates\": {\n \"in\": [\n "
},
{
"path": "test/data/json/libraries/utils/Lib_Bytes32Utils.test.json",
"chars": 1845,
"preview": "{\n \"tests\": {\n \"toBool\": {\n \"input bytes32 of 0\": {\n \"in\": [\"0x000000000000000000000"
},
{
"path": "test/data/json/libraries/utils/Lib_BytesUtils.test.json",
"chars": 3912,
"preview": "{\n \"tests\": {\n \"slice\": {\n \"start zero, length = 0\": {\n \"in\": [\"0x12345678\", 0, 0],\n"
}
]
// ... and 34 more files (download for full content)
About this extraction
This page contains the full source code of the ethereum-optimism/contracts GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 234 files (1.1 MB), approximately 315.9k tokens, and a symbol index with 154 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.