Commit 21621133 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #2664 from ethereum-optimism/develop

Develop -> Master PR
parents 65b06a39 31727208
---
'@eth-optimism/contracts-periphery': patch
---
Introduce the Drippie peripheral contract for managing ETH drips
---
'@eth-optimism/l2geth': patch
---
Rerelease the previous version
---
'@eth-optimism/core-utils': patch
---
Update geth genesis type
---
'@eth-optimism/contracts-bedrock': patch
---
Initial release
......@@ -63,7 +63,7 @@ jobs:
yarn-monorepo:
docker:
- image: ethereumoptimism/js-builder:latest
- image: ethereumoptimism/js-builder:nightly
steps:
- restore_cache:
keys:
......@@ -87,6 +87,7 @@ jobs:
- node_modules
- packages/common-ts/node_modules
- packages/contracts/node_modules
- packages/contracts-bedrock/node_modules
- packages/contracts-periphery/node_modules
- packages/core-utils/node_modules
- packages/data-transport-layer/node_modules
......@@ -97,7 +98,8 @@ jobs:
- integration-tests/node_modules
- run:
name: Build monorepo
command: yarn build
command: |
yarn build
- save_cache:
key: v2-cache-yarn-build-{{ .Revision }}
paths:
......@@ -116,6 +118,19 @@ jobs:
command: yarn test:slither
working_directory: packages/contracts
contracts-periphery-slither:
docker:
- image: ethereumoptimism/js-builder:latest
steps:
- restore_cache:
keys:
- v2-cache-yarn-build-{{ .Revision }}
- checkout
- run:
name: Run Slither
command: yarn test:slither
working_directory: packages/contracts-periphery
contracts-tests:
docker:
- image: ethereumoptimism/js-builder:latest
......@@ -155,6 +170,10 @@ jobs:
name: Lint
command: yarn lint:check
working_directory: packages/contracts-periphery
- run:
name: Slither
command: yarn test:slither
working_directory: packages/contracts
- run:
name: Test
command: yarn test:coverage
......@@ -349,46 +368,36 @@ jobs:
bedrock-solidity:
docker:
- image: ethereumoptimism/js-builder:0.0.4
- image: ethereumoptimism/js-builder:nightly
steps:
- checkout
- run:
name: init submodules
command: |
git submodule sync --recursive
git submodule update --recursive --init
- run:
name: install
command: yarn install
working_directory: contracts-bedrock
working_directory: packages/contracts-bedrock
- run:
name: lint
command: |
# remove prettierrc in root of repo since it doesn't work with non-Lerna packages
mv ../.eslintrc.js ../.eslintrc.bak
yarn lint:check
mv ../.eslintrc.bak ../.eslintrc.js
working_directory: contracts-bedrock
command: yarn lint:check
working_directory: packages/contracts-bedrock
- run:
name: slither
command: yarn slither || exit 0
working_directory: contracts-bedrock
working_directory: packages/contracts-bedrock
- run:
name: build forge
command: yarn build:forge
working_directory: contracts-bedrock
name: build
command: yarn build
working_directory: packages/contracts-bedrock
- run:
name: test forge
command: yarn test:forge
working_directory: contracts-bedrock
name: test
command: yarn test
working_directory: packages/contracts-bedrock
- run:
name: gas snapshot
command: forge snapshot
working_directory: contracts-bedrock
command: forge snapshot && git diff --exit-code
working_directory: packages/contracts-bedrock
- run:
name: check go bindings
command: |
make && git diff --exit-code
command: make && git diff --exit-code
working_directory: op-bindings
bedrock-go-tests:
......@@ -459,24 +468,13 @@ jobs:
bedrock-integration-tests:
machine:
image: ubuntu-2004:202111-02
image: ethereumoptimism/js-builder:nightly
docker_layer_caching: true
steps:
- checkout
- run:
name: init submodules
command: |
git submodule sync --recursive
git submodule update --recursive --init
- node/install:
install-yarn: true
node-version: '16.13'
- run:
name: install Foundry
command: |
curl -L https://foundry.paradigm.xyz | bash
source /home/circleci/.bashrc
foundryup
- run:
name: build typescript
command: make build-ts
......
......@@ -6,11 +6,12 @@ module.exports = {
},
ignorePatterns: ['dist', 'coverage', 'packages/contracts/hardhat'],
extends: ['plugin:prettier/recommended'],
parser: 'babel-eslint',
parser: '@babel/eslint-parser',
parserOptions: {
es6: true,
ecmaVersion: 6,
sourceType: 'module',
requireConfigFile: false,
},
plugins: [
'eslint-plugin-import',
......@@ -25,7 +26,7 @@ module.exports = {
files: ['**/*.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
project: './packages/**/tsconfig.json',
sourceType: 'module',
allowAutomaticSingleRunInference: true,
},
......
......@@ -58,6 +58,11 @@ jobs:
- name: Install Dependencies
run: yarn
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Build
run: yarn build
......
......@@ -55,6 +55,11 @@ jobs:
- name: Install Dependencies
run: yarn
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Publish To NPM or Create Release Pull Request
uses: changesets/action@v1
id: changesets
......@@ -94,7 +99,7 @@ jobs:
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile
file: ./l2geth/Dockerfile
push: true
tags: ethereumoptimism/l2geth:${{ needs.release.outputs.l2geth }},ethereumoptimism/l2geth:latest
......
......@@ -27,6 +27,9 @@ packages/data-transport-layer/db
packages/integration-tests-bedrock/cache
packages/integration-tests-bedrock/artifacts
packages/contracts-bedrock/deployments/devnetL1
packages/contracts-bedrock/deployments/anvil
# vim
*.sw*
......
[submodule "tests"]
path = l2geth/tests/testdata
url = https://github.com/ethereum/tests
[submodule "packages/contracts-bedrock/lib/forge-std"]
path = contracts-bedrock/lib/forge-std
url = https://github.com/foundry-rs/forge-std.git
[submodule "packages/contracts-bedrock/lib/solmate"]
path = contracts-bedrock/lib/solmate
url = https://github.com/rari-capital/solmate.git
[submodule "packages/contracts-bedrock/lib/ds-test"]
path = contracts-bedrock/lib/ds-test
url = https://github.com/dapphub/ds-test.git
......@@ -17,7 +17,7 @@ module.exports = {
bracketSpacing: true,
// These options are specific to the Solidity Plugin
explicitTypes: 'always',
compiler: '0.8.9',
compiler: '>=0.8.10',
},
},
],
......
{
"$schema": "http://json.schemastore.org/prettierrc",
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"arrowParens": "always"
}
module.exports = {
env: {
browser: false,
es2021: true,
mocha: true,
node: true,
},
plugins: ['@typescript-eslint'],
extends: [
'standard',
'plugin:prettier/recommended',
'plugin:node/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 12,
},
rules: {
'node/no-unpublished-import': 'off',
'node/no-unsupported-features/es-syntax': [
'error',
{ ignores: ['modules'] },
],
},
}
module.exports = {
$schema: 'http://json.schemastore.org/prettierrc',
trailingComma: 'es5',
tabWidth: 2,
semi: false,
singleQuote: true,
arrowParens: 'always',
overrides: [
{
files: '*.sol',
options: {
// These options are native to Prettier.
printWidth: 100,
tabWidth: 4,
useTabs: false,
singleQuote: false,
bracketSpacing: true,
// These options are specific to the Solidity Plugin
explicitTypes: 'always',
compiler: '0.8.10',
},
},
],
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_BedrockPredeployAddresses
* TODO: just merge this value into the monorepo
*/
library Lib_BedrockPredeployAddresses {
address internal constant L1_BLOCK_ATTRIBUTES = 0x4200000000000000000000000000000000000015;
}
Subproject commit c7a36fb236f298e04edf28e2fee385b80f53945f
Subproject commit 1680d7fb3e00b7b197a7336e7c88e838c7e6a3ec
Subproject commit 851ea3baa4327f453da723df75b1093b58b964dc
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "dist",
"declaration": true,
"resolveJsonModule": true
},
"include": ["./scripts", "./test", "./typechain"],
"files": ["./hardhat.config.ts"]
}
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d h1:t5Wuyh53qYyg9eqn4BbnlIT+vmhyww0TatL+zT3uWgI=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220512193241-32ef0bba48ce h1:Wa0BVNdeyzIoJkrZtI7o2NEw8F98vVIzkPpiFACbdCA=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220512193241-32ef0bba48ce/go.mod h1:zwRwhzbX7GhQgG12DdrLr9aRGGLObKwmZxYrCLICIRc=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea h1:xGKKbowc5Q2d4VEYMkJg6E3h5ki2Kgi2r+qxaTHCnxc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea/go.mod h1:zwRwhzbX7GhQgG12DdrLr9aRGGLObKwmZxYrCLICIRc=
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5 h1:2U0HzY8BJ8hVwDKIzp7y4voR9CX/nvcfymLmg2UiOio=
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI=
......@@ -28,6 +28,7 @@
"url": "https://github.com/ethereum-optimism/optimism.git"
},
"devDependencies": {
"@babel/eslint-parser": "^7.5.4",
"@eth-optimism/contracts": "0.5.25",
"@eth-optimism/core-utils": "0.8.5",
"@eth-optimism/sdk": "1.1.6",
......@@ -47,7 +48,6 @@
"@uniswap/v3-periphery": "^1.0.1",
"@uniswap/v3-sdk": "^3.6.2",
"async-mutex": "^0.3.2",
"babel-eslint": "^10.1.0",
"chai": "^4.3.4",
"chai-as-promised": "^7.1.1",
"commander": "^8.3.0",
......@@ -55,12 +55,12 @@
"envalid": "^7.1.0",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"eslint-plugin-unicorn": "^42.0.0",
"ethereum-waffle": "^3.3.0",
"ethers": "^5.6.8",
"hardhat": "^2.9.6",
......
......@@ -16,7 +16,7 @@ require (
github.com/benbjohnson/clock v1.1.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcd v0.22.1 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
......@@ -160,4 +160,4 @@ replace (
github.com/ethereum-optimism/optimism/op-proposer v0.0.0 => ../op-proposer
)
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d
......@@ -124,9 +124,8 @@ github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MR
github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE=
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
......@@ -220,10 +219,11 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
......@@ -243,8 +243,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea h1:xGKKbowc5Q2d4VEYMkJg6E3h5ki2Kgi2r+qxaTHCnxc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea/go.mod h1:zwRwhzbX7GhQgG12DdrLr9aRGGLObKwmZxYrCLICIRc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d h1:Jc7YIDFx88lmiPrmS2p/mwqbETCJpdm7rj1fagbs6zc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d/go.mod h1:RD3NhcSBjZpj3k+SnQq24wBrmnmie78P5R/P62iNBD8=
github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
......@@ -1088,6 +1088,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
......@@ -1155,6 +1156,7 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
......@@ -1170,6 +1172,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
......@@ -1192,8 +1195,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
......@@ -1250,6 +1255,7 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
......@@ -1358,6 +1364,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
......@@ -1442,8 +1449,9 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
......
#/bin/bash
set -eu
CONTRACTS_PATH="../contracts-bedrock/"
CONTRACTS_PATH="../packages/contracts-bedrock/"
if [ "$#" -ne 2 ]; then
......
......@@ -6,7 +6,7 @@ require github.com/ethereum/go-ethereum v1.10.17
require (
github.com/VictoriaMetrics/fastcache v1.9.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
......@@ -27,4 +27,4 @@ require (
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
)
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d
......@@ -48,9 +48,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE=
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
......@@ -90,8 +89,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
......@@ -99,8 +98,8 @@ github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea h1:xGKKbowc5Q2d4VEYMkJg6E3h5ki2Kgi2r+qxaTHCnxc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea/go.mod h1:zwRwhzbX7GhQgG12DdrLr9aRGGLObKwmZxYrCLICIRc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d h1:Jc7YIDFx88lmiPrmS2p/mwqbETCJpdm7rj1fagbs6zc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d/go.mod h1:RD3NhcSBjZpj3k+SnQq24wBrmnmie78P5R/P62iNBD8=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
......@@ -357,6 +356,7 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
......@@ -375,6 +375,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
......@@ -387,6 +388,7 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
......@@ -405,6 +407,8 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
......@@ -430,6 +434,7 @@ golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
......@@ -481,7 +486,8 @@ golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
......@@ -528,6 +534,7 @@ golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
......@@ -583,7 +590,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
......@@ -596,7 +602,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
......
......@@ -19,7 +19,7 @@ require (
github.com/benbjohnson/clock v1.1.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcd v0.22.1 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
......@@ -167,4 +167,4 @@ replace (
github.com/ethereum-optimism/optimism/op-proposer v0.0.0 => ../op-proposer
)
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d
......@@ -124,9 +124,8 @@ github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MR
github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE=
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
......@@ -220,10 +219,11 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
......@@ -244,8 +244,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea h1:xGKKbowc5Q2d4VEYMkJg6E3h5ki2Kgi2r+qxaTHCnxc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea/go.mod h1:zwRwhzbX7GhQgG12DdrLr9aRGGLObKwmZxYrCLICIRc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d h1:Jc7YIDFx88lmiPrmS2p/mwqbETCJpdm7rj1fagbs6zc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d/go.mod h1:RD3NhcSBjZpj3k+SnQq24wBrmnmie78P5R/P62iNBD8=
github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
......@@ -1091,6 +1091,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
......@@ -1158,6 +1159,7 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
......@@ -1173,6 +1175,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
......@@ -1195,8 +1198,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
......@@ -1253,6 +1258,7 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
......@@ -1361,6 +1367,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
......@@ -1446,8 +1453,9 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
......
......@@ -36,7 +36,7 @@ require (
github.com/benbjohnson/clock v1.1.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcd v0.22.1 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327 // indirect
......@@ -155,12 +155,12 @@ require (
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.19.1 // indirect
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
golang.org/x/tools v0.1.5 // indirect
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/grpc v1.40.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
......@@ -172,7 +172,7 @@ require (
replace github.com/ethereum-optimism/optimism/op-bindings v0.0.0 => ../op-bindings
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d
replace github.com/ethereum-optimism/optimism/op-proposer v0.0.0 => ../op-proposer
......
......@@ -111,9 +111,8 @@ github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MR
github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE=
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
......@@ -200,13 +199,15 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E=
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ=
github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
......@@ -226,8 +227,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea h1:xGKKbowc5Q2d4VEYMkJg6E3h5ki2Kgi2r+qxaTHCnxc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea/go.mod h1:zwRwhzbX7GhQgG12DdrLr9aRGGLObKwmZxYrCLICIRc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d h1:Jc7YIDFx88lmiPrmS2p/mwqbETCJpdm7rj1fagbs6zc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d/go.mod h1:RD3NhcSBjZpj3k+SnQq24wBrmnmie78P5R/P62iNBD8=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
......@@ -273,6 +274,7 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
......@@ -1060,6 +1062,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
......@@ -1127,6 +1130,7 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
......@@ -1142,6 +1146,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
......@@ -1164,8 +1169,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
......@@ -1222,6 +1229,7 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
......@@ -1330,6 +1338,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
......@@ -1415,8 +1424,9 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
......@@ -1545,8 +1555,6 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8=
gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=
......@@ -1568,7 +1576,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
......
......@@ -226,32 +226,33 @@ func UserDeposits(receipts []*types.Receipt, depositContractAddr common.Address)
return out, errs
}
func BatchesFromEVMTransactions(config *rollup.Config, txLists []types.Transactions) ([]*BatchData, error) {
func BatchesFromEVMTransactions(config *rollup.Config, txLists []types.Transactions) ([]*BatchData, []error) {
var out []*BatchData
var errs []error
l1Signer := config.L1Signer()
for _, txs := range txLists {
for _, tx := range txs {
for i, txs := range txLists {
for j, tx := range txs {
if to := tx.To(); to != nil && *to == config.BatchInboxAddress {
seqDataSubmitter, err := l1Signer.Sender(tx) // optimization: only derive sender if To is correct
if err != nil {
// TODO: log error
errs = append(errs, fmt.Errorf("invalid signature: tx list: %d, tx: %d, err: %w", i, j, err))
continue // bad signature, ignore
}
// some random L1 user might have sent a transaction to our batch inbox, ignore them
if seqDataSubmitter != config.BatchSenderAddress {
// TODO: log/record metric
errs = append(errs, fmt.Errorf("unauthorized batch submitter: tx list: %d, tx: %d", i, j))
continue // not an authorized batch submitter, ignore
}
batches, err := DecodeBatches(config, bytes.NewReader(tx.Data()))
if err != nil {
// TODO: log/record metric
errs = append(errs, fmt.Errorf("invalid batch: tx list: %d, tx: %d, err: %w", i, j, err))
continue
}
out = append(out, batches...)
}
}
}
return out, nil
return out, errs
}
func FilterBatches(config *rollup.Config, epoch rollup.Epoch, minL2Time uint64, maxL2Time uint64, batches []*BatchData) (out []*BatchData) {
......
......@@ -198,10 +198,14 @@ func (d *outputImpl) insertEpoch(ctx context.Context, l2Head eth.L2BlockRef, l2S
if err != nil {
return l2Head, l2SafeHead, false, fmt.Errorf("failed to fetch transactions from %s: %v", l1Input, err)
}
batches, err := derive.BatchesFromEVMTransactions(&d.Config, transactions)
if err != nil {
return l2Head, l2SafeHead, false, fmt.Errorf("failed to fetch create batches from transactions: %w", err)
batches, errs := derive.BatchesFromEVMTransactions(&d.Config, transactions)
// Some input to derive.BatchesFromEVMTransactions may be invalid and produce errors.
// We log the errors, but keep going as this process is designed to be resilient to these errors
// and we have defaults in case no valid (or partial) batches were submitted.
for i, err := range errs {
d.log.Error("Failed to decode batch", "err_idx", i, "err", err)
}
// Make batches contiguous
minL2Time := uint64(l2Info.Timestamp) + d.Config.BlockTime
maxL2Time := l1Info.Time() + d.Config.MaxSequencerDrift
......
......@@ -16,7 +16,7 @@ require (
github.com/benbjohnson/clock v1.1.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcd v0.22.1 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
......@@ -158,4 +158,4 @@ replace github.com/ethereum-optimism/optimism/op-node v0.0.0 => ../op-node
replace github.com/ethereum-optimism/optimism/op-bindings v0.0.0 => ../op-bindings
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea
replace github.com/ethereum/go-ethereum v1.10.17 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d
......@@ -124,9 +124,8 @@ github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MR
github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE=
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
......@@ -220,10 +219,11 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
......@@ -243,8 +243,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea h1:xGKKbowc5Q2d4VEYMkJg6E3h5ki2Kgi2r+qxaTHCnxc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220518163235-a32d414959ea/go.mod h1:zwRwhzbX7GhQgG12DdrLr9aRGGLObKwmZxYrCLICIRc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d h1:Jc7YIDFx88lmiPrmS2p/mwqbETCJpdm7rj1fagbs6zc=
github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220602143715-bea96bb3e75d/go.mod h1:RD3NhcSBjZpj3k+SnQq24wBrmnmie78P5R/P62iNBD8=
github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
......@@ -1089,6 +1089,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
......@@ -1156,6 +1157,7 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
......@@ -1171,6 +1173,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
......@@ -1193,8 +1196,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
......@@ -1251,6 +1256,7 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
......@@ -1359,6 +1365,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
......@@ -1443,8 +1450,9 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
......
......@@ -32,6 +32,8 @@ set -eu
L1_URL="http://localhost:8545"
L2_URL="http://localhost:9545"
CONTRACTS_BEDROCK=./packages/contracts-bedrock
# Helper method that waits for a given URL to be up. Can't use
# cURL's built-in retry logic because connection reset errors
# are ignored unless you're using a very recent version of cURL
......@@ -64,25 +66,27 @@ else
fi
# Bring up L1.
cd ops-bedrock
echo "Bringing up L1..."
DOCKER_BUILDKIT=1 docker-compose build
docker-compose up -d l1
wait_up $L1_URL
cd ../
(
cd ops-bedrock
echo "Bringing up L1..."
DOCKER_BUILDKIT=1 docker-compose build
docker-compose up -d l1
wait_up $L1_URL
)
# Deploy contracts using Hardhat.
if [ ! -f ./contracts-bedrock/deployments/devnetL1/OptimismPortal.json ]; then
if [ ! -f $CONTRACTS_BEDROCK/deployments/devnetL1/OptimismPortal.json ]; then
echo "Deploying contracts."
cd ./contracts-bedrock
L2OO_STARTING_BLOCK_TIMESTAMP=$GENESIS_TIMESTAMP yarn hardhat --network devnetL1 deploy
cd ../
(
cd $CONTRACTS_BEDROCK
L2OO_STARTING_BLOCK_TIMESTAMP=$GENESIS_TIMESTAMP yarn hardhat --network devnetL1 deploy
)
else
echo "Contracts already deployed, skipping."
fi
function get_deployed_bytecode() {
echo $(jq -r .deployedBytecode ./contracts-bedrock/artifacts/contracts/$1)
echo $(jq -r .deployedBytecode $CONTRACTS_BEDROCK/artifacts/contracts/$1)
}
# Pull out the necessary bytecode/addresses from the artifacts/deployments.
......@@ -92,8 +96,8 @@ OPTIMISM_MINTABLE_TOKEN_FACTORY_BYTECODE=$(get_deployed_bytecode universal/Optim
L2_STANDARD_BRIDGE_BYTECODE=$(get_deployed_bytecode L2/L2StandardBridge.sol/L2StandardBridge.json)
L1_BLOCK_INFO_BYTECODE=$(get_deployed_bytecode L2/L1Block.sol/L1Block.json)
DEPOSIT_CONTRACT_ADDRESS=$(jq -r .address < ./contracts-bedrock/deployments/devnetL1/OptimismPortal.json)
L2OO_ADDRESS=$(jq -r .address < ./contracts-bedrock/deployments/devnetL1/L2OutputOracle.json)
DEPOSIT_CONTRACT_ADDRESS=$(jq -r .address < $CONTRACTS_BEDROCK/deployments/devnetL1/OptimismPortal.json)
L2OO_ADDRESS=$(jq -r .address < $CONTRACTS_BEDROCK/deployments/devnetL1/L2OutputOracle.json)
# Replace values in the L2 genesis file. It doesn't matter if this gets run every time,
# since the replaced values will be the same.
......@@ -110,11 +114,12 @@ jq ". | .alloc.\"4200000000000000000000000000000000000015\".code = \"$L1_BLOCK_I
jq ". | .timestamp = \"$GENESIS_TIMESTAMP\" " > ./.devnet/genesis-l2.json
# Bring up L2.
cd ops-bedrock
echo "Bringing up L2..."
docker-compose up -d l2
wait_up $L2_URL
cd ../
(
cd ops-bedrock
echo "Bringing up L2..."
docker-compose up -d l2
wait_up $L2_URL
)
# Start putting together the rollup config.
echo "Building rollup config..."
......@@ -154,16 +159,16 @@ SEQUENCER_GENESIS_HASH="$(echo $L2_GENESIS | jq -r '.result.hash')"
SEQUENCER_BATCH_INBOX_ADDRESS="$(cat ./ops-bedrock/rollup.json | jq -r '.batch_inbox_address')"
# Bring up everything else.
cd ops-bedrock
echo "Bringing up devnet..."
L2OO_ADDRESS="$L2OO_ADDRESS" \
SEQUENCER_GENESIS_HASH="$SEQUENCER_GENESIS_HASH" \
SEQUENCER_BATCH_INBOX_ADDRESS="$SEQUENCER_BATCH_INBOX_ADDRESS" \
docker-compose up -d op-proposer op-batcher
echo "Bringin up stateviz webserver..."
docker-compose up -d stateviz
cd ../
(
cd ops-bedrock
echo "Bringing up devnet..."
L2OO_ADDRESS="$L2OO_ADDRESS" \
SEQUENCER_GENESIS_HASH="$SEQUENCER_GENESIS_HASH" \
SEQUENCER_BATCH_INBOX_ADDRESS="$SEQUENCER_BATCH_INBOX_ADDRESS" \
docker-compose up -d op-proposer op-batcher
echo "Bringin up stateviz webserver..."
docker-compose up -d stateviz
)
echo "Devnet ready."
......@@ -2,10 +2,15 @@
# be used to build any of the follow-on services
#
# ### BASE: Install deps
FROM ghcr.io/foundry-rs/foundry:latest as foundry
FROM node:16-alpine3.14 as base
RUN apk --no-cache add curl jq python3 ca-certificates git make gcc musl-dev linux-headers bash build-base
COPY --from=foundry /usr/local/bin/forge /usr/local/bin/forge
COPY --from=foundry /usr/local/bin/cast /usr/local/bin/cast
# copy over the needed configs to run the dep installation
# note: this approach can be a bit unhandy to maintain, but it allows
# us to cache the installation steps
......@@ -15,6 +20,7 @@ COPY packages/sdk/package.json ./packages/sdk/package.json
COPY packages/core-utils/package.json ./packages/core-utils/package.json
COPY packages/common-ts/package.json ./packages/common-ts/package.json
COPY packages/contracts/package.json ./packages/contracts/package.json
COPY packages/contracts-bedrock/package.json ./packages/contracts-bedrock/package.json
COPY packages/contracts-periphery/package.json ./packages/contracts-periphery/package.json
COPY packages/data-transport-layer/package.json ./packages/data-transport-layer/package.json
COPY packages/message-relayer/package.json ./packages/message-relayer/package.json
......
......@@ -21,8 +21,11 @@
"teleportr"
],
"nohoist": [
"**/typechain",
"**/@typechain/*"
"**/typechain/*",
"**/@typechain/*",
"@eth-optimism/contracts-bedrock/ds-test",
"@eth-optimism/contracts-bedrock/forge-std",
"@eth-optimism/contracts-bedrock/@rari-capital/solmate"
]
},
"private": true,
......@@ -41,25 +44,39 @@
"release": "yarn build && yarn changeset publish"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@babel/eslint-parser": "^7.18.2",
"@types/chai": "^4.2.18",
"@types/chai-as-promised": "^7.1.4",
"@types/mocha": "^8.2.2",
"@types/node": "^12.0.0",
"@typescript-eslint/eslint-plugin": "^5.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"chai": "^4.2.0",
"copyfiles": "^2.3.0",
"depcheck": "^1.4.3",
"doctoc": "2.1.0",
"eslint": "^7.27.0",
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"eslint-plugin-unicorn": "^42.0.0",
"husky": "^6.0.0",
"lerna": "^4.0.0",
"lint-staged": "11.0.0",
"markdownlint": "^0.24.0",
"markdownlint-cli2": "^0.3.2",
"mocha": "^8.4.0",
"nyc": "^15.1.0",
"patch-package": "^6.4.7",
"prettier": "^2.3.1",
"prettier-plugin-solidity": "^1.0.0-beta.13",
"ts-mocha": "^8.0.0",
"typescript": "^4.6.2"
},
"dependencies": {
......
......@@ -9,8 +9,8 @@
],
"scripts": {
"all": "yarn clean && yarn build && yarn test && yarn lint:fix && yarn lint",
"build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"build": "tsc -p tsconfig.json",
"clean": "rimraf dist/ ./tsconfig.tsbuildinfo",
"lint:check": "eslint . --max-warnings=0",
"lint:fix": "yarn lint:check --fix",
"lint": "yarn lint:fix && yarn lint:check",
......@@ -48,28 +48,10 @@
"devDependencies": {
"@ethersproject/abstract-provider": "^5.6.1",
"@ethersproject/abstract-signer": "^5.6.2",
"@types/chai": "^4.2.18",
"@types/express": "^4.17.12",
"@types/mocha": "^8.2.2",
"@types/pino": "^6.3.6",
"@types/pino-multi-stream": "^5.1.1",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"chai": "^4.3.4",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"lint-staged": "11.0.0",
"mocha": "^8.4.0",
"prettier": "^2.3.1",
"supertest": "^6.1.4",
"ts-mocha": "^8.0.0",
"typescript": "^4.6.2"
"supertest": "^6.1.4"
}
}
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
{
"extends": "../../tsconfig.json"
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
module.exports = {
extends: '../../.eslintrc.js',
}
......@@ -88,14 +88,14 @@ OVM_ETH_Test:test_metadata() (gas: 15608)
OVM_ETH_Test:test_mint() (gas: 10621)
OVM_ETH_Test:test_transfer() (gas: 10726)
OVM_ETH_Test:test_transferFrom() (gas: 13008)
OptimismMintableTokenFactory_Test:test_bridge() (gas: 9850)
OptimismMintableTokenFactory_Test:test_burn() (gas: 52791)
OptimismMintableTokenFactory_Test:test_burnRevertsFromNotBridge() (gas: 13211)
OptimismMintableTokenFactory_Test:test_l1Token() (gas: 9779)
OptimismMintableTokenFactory_Test:test_l2Bridge() (gas: 9768)
OptimismMintableTokenFactory_Test:test_mint() (gas: 65732)
OptimismMintableTokenFactory_Test:test_mintRevertsFromNotBridge() (gas: 13213)
OptimismMintableTokenFactory_Test:test_remoteToken() (gas: 9762)
OptimismMintableERC20_Test:test_bridge() (gas: 9850)
OptimismMintableERC20_Test:test_burn() (gas: 52791)
OptimismMintableERC20_Test:test_burnRevertsFromNotBridge() (gas: 13211)
OptimismMintableERC20_Test:test_l1Token() (gas: 9779)
OptimismMintableERC20_Test:test_l2Bridge() (gas: 9768)
OptimismMintableERC20_Test:test_mint() (gas: 65732)
OptimismMintableERC20_Test:test_mintRevertsFromNotBridge() (gas: 13213)
OptimismMintableERC20_Test:test_remoteToken() (gas: 9762)
OptimismMintableTokenFactory_Test:test_bridge() (gas: 9707)
OptimismMintableTokenFactory_Test:test_createStandardL2Token() (gas: 1106538)
OptimismMintableTokenFactory_Test:test_createStandardL2TokenSameTwice() (gas: 2193987)
......
module.exports = {
...require('../../.prettierrc.js'),
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
import { OptimismPortal } from "./OptimismPortal.sol";
import { CrossDomainMessenger } from "../universal/CrossDomainMessenger.sol";
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
import { StandardBridge } from "../universal/StandardBridge.sol";
/**
......
......@@ -3,7 +3,7 @@ pragma solidity 0.8.10;
import { L2OutputOracle } from "./L2OutputOracle.sol";
import { WithdrawalVerifier } from "../libraries/Lib_WithdrawalVerifier.sol";
import { AddressAliasHelper } from "@eth-optimism/contracts/standards/AddressAliasHelper.sol";
import { AddressAliasHelper } from "../libraries/AddressAliasHelper.sol";
import { ExcessivelySafeCall } from "../libraries/ExcessivelySafeCall.sol";
/**
......
......@@ -3,7 +3,7 @@ pragma solidity ^0.8.10;
/* External Imports */
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Lib_BedrockPredeployAddresses } from "../libraries/Lib_BedrockPredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
import { L1Block } from "../L2/L1Block.sol";
/**
......@@ -68,7 +68,7 @@ contract GasPriceOracle is Ownable {
}
function l1BaseFee() public view returns (uint256) {
return L1Block(Lib_BedrockPredeployAddresses.L1_BLOCK_ATTRIBUTES).basefee();
return L1Block(Lib_PredeployAddresses.L1_BLOCK_ATTRIBUTES).basefee();
}
/**
......
......@@ -2,7 +2,7 @@
pragma solidity 0.8.10;
import { L1Block } from "./L1Block.sol";
import { Lib_BedrockPredeployAddresses } from "../libraries/Lib_BedrockPredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
/**
* @title L1BlockNumber
......@@ -30,6 +30,6 @@ contract L1BlockNumber {
}
function getL1BlockNumber() public view returns (uint256) {
return L1Block(Lib_BedrockPredeployAddresses.L1_BLOCK_ATTRIBUTES).number();
return L1Block(Lib_PredeployAddresses.L1_BLOCK_ATTRIBUTES).number();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { AddressAliasHelper } from "@eth-optimism/contracts/standards/AddressAliasHelper.sol";
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { AddressAliasHelper } from "../libraries/AddressAliasHelper.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
import { CrossDomainMessenger } from "../universal/CrossDomainMessenger.sol";
import { L2ToL1MessagePasser } from "./L2ToL1MessagePasser.sol";
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
import { StandardBridge } from "../universal/StandardBridge.sol";
import { OptimismMintableERC20 } from "../universal/OptimismMintableERC20.sol";
......
......@@ -2,9 +2,7 @@
pragma solidity ^0.8.9;
/* Library Imports */
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
/* Contract Imports */
import { OptimismMintableERC20 } from "../universal/OptimismMintableERC20.sol";
......
......@@ -2,9 +2,7 @@
pragma solidity ^0.8.9;
/* Library Imports */
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
/* Contract Imports */
import { L2StandardBridge } from "./L2StandardBridge.sol";
......
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2019-2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.7;
library AddressAliasHelper {
uint160 constant offset = uint160(0x1111000000000000000000000000000000001111);
/// @notice Utility function that converts the address in the L1 that submitted a tx to
/// the inbox to the msg.sender viewed in the L2
/// @param l1Address the address in the L1 that triggered the tx to L2
/// @return l2Address L2 address as viewed in msg.sender
function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
unchecked {
l2Address = address(uint160(l1Address) + offset);
}
}
/// @notice Utility function that converts the msg.sender viewed in the L2 to the
/// address in the L1 that submitted a tx to the inbox
/// @param l2Address L2 address as viewed in msg.sender
/// @return l1Address the address in the L1 that triggered the tx to L2
function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
unchecked {
l1Address = address(uint160(l2Address) - offset);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_BytesUtils
*/
library Lib_BytesUtils {
/**********************
* Internal Functions *
**********************/
function slice(
bytes memory _bytes,
uint256 _start,
uint256 _length
) internal pure returns (bytes memory) {
require(_length + 31 >= _length, "slice_overflow");
require(_start + _length >= _start, "slice_overflow");
require(_bytes.length >= _start + _length, "slice_outOfBounds");
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
let lengthmod := and(_length, 31)
// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
// The multiplication in the next line has the same exact purpose
// as the one above.
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)
//zero out the 32 bytes slice we are about to return
//we need to do it because Solidity does not garbage collect
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) {
if (_start >= _bytes.length) {
return bytes("");
}
return slice(_bytes, _start, _bytes.length - _start);
}
function toBytes32(bytes memory _bytes) internal pure returns (bytes32) {
if (_bytes.length < 32) {
bytes32 ret;
assembly {
ret := mload(add(_bytes, 32))
}
return ret;
}
return abi.decode(_bytes, (bytes32)); // will truncate if input length > 32 bytes
}
function toUint256(bytes memory _bytes) internal pure returns (uint256) {
return uint256(toBytes32(_bytes));
}
function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
bytes memory nibbles = new bytes(_bytes.length * 2);
for (uint256 i = 0; i < _bytes.length; i++) {
nibbles[i * 2] = _bytes[i] >> 4;
nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16);
}
return nibbles;
}
function fromNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
bytes memory ret = new bytes(_bytes.length / 2);
for (uint256 i = 0; i < ret.length; i++) {
ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]);
}
return ret;
}
function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) {
return keccak256(_bytes) == keccak256(_other);
}
}
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import {
Lib_CrossDomainUtils
} from "@eth-optimism/contracts/libraries/bridge/Lib_CrossDomainUtils.sol";
import { Lib_RLPWriter } from "@eth-optimism/contracts/libraries/rlp/Lib_RLPWriter.sol";
import { Lib_CrossDomainUtils } from "./Lib_CrossDomainUtils.sol";
import { Lib_RLPWriter } from "./rlp/Lib_RLPWriter.sol";
/**
* @title CrossDomainHashing
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_CrossDomainUtils
*/
library Lib_CrossDomainUtils {
/**
* 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 encodeXDomainCalldata(
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
);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_DefaultValues
*/
library Lib_DefaultValues {
// 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;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_PredeployAddresses
*/
library Lib_PredeployAddresses {
address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;
address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;
address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;
address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000);
address internal constant L2_CROSS_DOMAIN_MESSENGER =
0x4200000000000000000000000000000000000007;
address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;
address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;
address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;
address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;
address internal constant L2_STANDARD_TOKEN_FACTORY =
0x4200000000000000000000000000000000000012;
address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;
address internal constant L1_BLOCK_ATTRIBUTES = 0x4200000000000000000000000000000000000015;
}
......@@ -2,12 +2,8 @@
pragma solidity 0.8.10;
/* Library Imports */
import {
Lib_SecureMerkleTrie
} from "@eth-optimism/contracts/libraries/trie/Lib_SecureMerkleTrie.sol";
import {
Lib_CrossDomainUtils
} from "@eth-optimism/contracts/libraries/bridge/Lib_CrossDomainUtils.sol";
import { Lib_SecureMerkleTrie } from "./trie/Lib_SecureMerkleTrie.sol";
import { Lib_CrossDomainUtils } from "./Lib_CrossDomainUtils.sol";
/**
* @title WithdrawalVerifier
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_RLPReader
* @dev Adapted from "RLPReader" by Hamdi Allam (hamdi.allam97@gmail.com).
*/
library Lib_RLPReader {
/*************
* Constants *
*************/
uint256 internal constant MAX_LIST_LENGTH = 32;
/*********
* Enums *
*********/
enum RLPItemType {
DATA_ITEM,
LIST_ITEM
}
/***********
* Structs *
***********/
struct RLPItem {
uint256 length;
uint256 ptr;
}
/**********************
* Internal Functions *
**********************/
/**
* Converts bytes to a reference to memory position and length.
* @param _in Input bytes to convert.
* @return Output memory reference.
*/
function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory) {
uint256 ptr;
assembly {
ptr := add(_in, 32)
}
return RLPItem({ length: _in.length, ptr: ptr });
}
/**
* Reads an RLP list value into a list of RLP items.
* @param _in RLP list value.
* @return Decoded RLP list items.
*/
function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory) {
(uint256 listOffset, , RLPItemType itemType) = _decodeLength(_in);
require(itemType == RLPItemType.LIST_ITEM, "Invalid RLP list value.");
// Solidity in-memory arrays can't be increased in size, but *can* be decreased in size by
// writing to the length. Since we can't know the number of RLP items without looping over
// the entire input, we'd have to loop twice to accurately size this array. It's easier to
// simply set a reasonable maximum list length and decrease the size before we finish.
RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH);
uint256 itemCount = 0;
uint256 offset = listOffset;
while (offset < _in.length) {
require(itemCount < MAX_LIST_LENGTH, "Provided RLP list exceeds max list length.");
(uint256 itemOffset, uint256 itemLength, ) = _decodeLength(
RLPItem({ length: _in.length - offset, ptr: _in.ptr + offset })
);
out[itemCount] = RLPItem({ length: itemLength + itemOffset, ptr: _in.ptr + offset });
itemCount += 1;
offset += itemOffset + itemLength;
}
// Decrease the array size to match the actual item count.
assembly {
mstore(out, itemCount)
}
return out;
}
/**
* Reads an RLP list value into a list of RLP items.
* @param _in RLP list value.
* @return Decoded RLP list items.
*/
function readList(bytes memory _in) internal pure returns (RLPItem[] memory) {
return readList(toRLPItem(_in));
}
/**
* Reads an RLP bytes value into bytes.
* @param _in RLP bytes value.
* @return Decoded bytes.
*/
function readBytes(RLPItem memory _in) internal pure returns (bytes memory) {
(uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in);
require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes value.");
return _copy(_in.ptr, itemOffset, itemLength);
}
/**
* Reads an RLP bytes value into bytes.
* @param _in RLP bytes value.
* @return Decoded bytes.
*/
function readBytes(bytes memory _in) internal pure returns (bytes memory) {
return readBytes(toRLPItem(_in));
}
/**
* Reads an RLP string value into a string.
* @param _in RLP string value.
* @return Decoded string.
*/
function readString(RLPItem memory _in) internal pure returns (string memory) {
return string(readBytes(_in));
}
/**
* Reads an RLP string value into a string.
* @param _in RLP string value.
* @return Decoded string.
*/
function readString(bytes memory _in) internal pure returns (string memory) {
return readString(toRLPItem(_in));
}
/**
* Reads an RLP bytes32 value into a bytes32.
* @param _in RLP bytes32 value.
* @return Decoded bytes32.
*/
function readBytes32(RLPItem memory _in) internal pure returns (bytes32) {
require(_in.length <= 33, "Invalid RLP bytes32 value.");
(uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in);
require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes32 value.");
uint256 ptr = _in.ptr + itemOffset;
bytes32 out;
assembly {
out := mload(ptr)
// Shift the bytes over to match the item size.
if lt(itemLength, 32) {
out := div(out, exp(256, sub(32, itemLength)))
}
}
return out;
}
/**
* Reads an RLP bytes32 value into a bytes32.
* @param _in RLP bytes32 value.
* @return Decoded bytes32.
*/
function readBytes32(bytes memory _in) internal pure returns (bytes32) {
return readBytes32(toRLPItem(_in));
}
/**
* Reads an RLP uint256 value into a uint256.
* @param _in RLP uint256 value.
* @return Decoded uint256.
*/
function readUint256(RLPItem memory _in) internal pure returns (uint256) {
return uint256(readBytes32(_in));
}
/**
* Reads an RLP uint256 value into a uint256.
* @param _in RLP uint256 value.
* @return Decoded uint256.
*/
function readUint256(bytes memory _in) internal pure returns (uint256) {
return readUint256(toRLPItem(_in));
}
/**
* Reads an RLP bool value into a bool.
* @param _in RLP bool value.
* @return Decoded bool.
*/
function readBool(RLPItem memory _in) internal pure returns (bool) {
require(_in.length == 1, "Invalid RLP boolean value.");
uint256 ptr = _in.ptr;
uint256 out;
assembly {
out := byte(0, mload(ptr))
}
require(out == 0 || out == 1, "Lib_RLPReader: Invalid RLP boolean value, must be 0 or 1");
return out != 0;
}
/**
* Reads an RLP bool value into a bool.
* @param _in RLP bool value.
* @return Decoded bool.
*/
function readBool(bytes memory _in) internal pure returns (bool) {
return readBool(toRLPItem(_in));
}
/**
* Reads an RLP address value into a address.
* @param _in RLP address value.
* @return Decoded address.
*/
function readAddress(RLPItem memory _in) internal pure returns (address) {
if (_in.length == 1) {
return address(0);
}
require(_in.length == 21, "Invalid RLP address value.");
return address(uint160(readUint256(_in)));
}
/**
* Reads an RLP address value into a address.
* @param _in RLP address value.
* @return Decoded address.
*/
function readAddress(bytes memory _in) internal pure returns (address) {
return readAddress(toRLPItem(_in));
}
/**
* Reads the raw bytes of an RLP item.
* @param _in RLP item to read.
* @return Raw RLP bytes.
*/
function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory) {
return _copy(_in);
}
/*********************
* Private Functions *
*********************/
/**
* Decodes the length of an RLP item.
* @param _in RLP item to decode.
* @return Offset of the encoded data.
* @return Length of the encoded data.
* @return RLP item type (LIST_ITEM or DATA_ITEM).
*/
function _decodeLength(RLPItem memory _in)
private
pure
returns (
uint256,
uint256,
RLPItemType
)
{
require(_in.length > 0, "RLP item cannot be null.");
uint256 ptr = _in.ptr;
uint256 prefix;
assembly {
prefix := byte(0, mload(ptr))
}
if (prefix <= 0x7f) {
// Single byte.
return (0, 1, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xb7) {
// Short string.
// slither-disable-next-line variable-scope
uint256 strLen = prefix - 0x80;
require(_in.length > strLen, "Invalid RLP short string.");
return (1, strLen, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xbf) {
// Long string.
uint256 lenOfStrLen = prefix - 0xb7;
require(_in.length > lenOfStrLen, "Invalid RLP long string length.");
uint256 strLen;
assembly {
// Pick out the string length.
strLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfStrLen)))
}
require(_in.length > lenOfStrLen + strLen, "Invalid RLP long string.");
return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xf7) {
// Short list.
// slither-disable-next-line variable-scope
uint256 listLen = prefix - 0xc0;
require(_in.length > listLen, "Invalid RLP short list.");
return (1, listLen, RLPItemType.LIST_ITEM);
} else {
// Long list.
uint256 lenOfListLen = prefix - 0xf7;
require(_in.length > lenOfListLen, "Invalid RLP long list length.");
uint256 listLen;
assembly {
// Pick out the list length.
listLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfListLen)))
}
require(_in.length > lenOfListLen + listLen, "Invalid RLP long list.");
return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM);
}
}
/**
* Copies the bytes from a memory location.
* @param _src Pointer to the location to read from.
* @param _offset Offset to start reading from.
* @param _length Number of bytes to read.
* @return Copied bytes.
*/
function _copy(
uint256 _src,
uint256 _offset,
uint256 _length
) private pure returns (bytes memory) {
bytes memory out = new bytes(_length);
if (out.length == 0) {
return out;
}
uint256 src = _src + _offset;
uint256 dest;
assembly {
dest := add(out, 32)
}
// Copy over as many complete words as we can.
for (uint256 i = 0; i < _length / 32; i++) {
assembly {
mstore(dest, mload(src))
}
src += 32;
dest += 32;
}
// Pick out the remaining bytes.
uint256 mask;
unchecked {
mask = 256**(32 - (_length % 32)) - 1;
}
assembly {
mstore(dest, or(and(mload(src), not(mask)), and(mload(dest), mask)))
}
return out;
}
/**
* Copies an RLP item into bytes.
* @param _in RLP item to copy.
* @return Copied bytes.
*/
function _copy(RLPItem memory _in) private pure returns (bytes memory) {
return _copy(_in.ptr, 0, _in.length);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_RLPWriter
* @author Bakaoh (with modifications)
*/
library Lib_RLPWriter {
/**********************
* Internal Functions *
**********************/
/**
* RLP encodes a byte string.
* @param _in The byte string to encode.
* @return The RLP encoded string in bytes.
*/
function writeBytes(bytes memory _in) internal pure returns (bytes memory) {
bytes memory encoded;
if (_in.length == 1 && uint8(_in[0]) < 128) {
encoded = _in;
} else {
encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);
}
return encoded;
}
/**
* RLP encodes a list of RLP encoded byte byte strings.
* @param _in The list of RLP encoded byte strings.
* @return The RLP encoded list of items in bytes.
*/
function writeList(bytes[] memory _in) internal pure returns (bytes memory) {
bytes memory list = _flatten(_in);
return abi.encodePacked(_writeLength(list.length, 192), list);
}
/**
* RLP encodes a string.
* @param _in The string to encode.
* @return The RLP encoded string in bytes.
*/
function writeString(string memory _in) internal pure returns (bytes memory) {
return writeBytes(bytes(_in));
}
/**
* RLP encodes an address.
* @param _in The address to encode.
* @return The RLP encoded address in bytes.
*/
function writeAddress(address _in) internal pure returns (bytes memory) {
return writeBytes(abi.encodePacked(_in));
}
/**
* RLP encodes a uint.
* @param _in The uint256 to encode.
* @return The RLP encoded uint256 in bytes.
*/
function writeUint(uint256 _in) internal pure returns (bytes memory) {
return writeBytes(_toBinary(_in));
}
/**
* RLP encodes a bool.
* @param _in The bool to encode.
* @return The RLP encoded bool in bytes.
*/
function writeBool(bool _in) internal pure returns (bytes memory) {
bytes memory encoded = new bytes(1);
encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));
return encoded;
}
/*********************
* Private Functions *
*********************/
/**
* Encode the first byte, followed by the `len` in binary form if `length` is more than 55.
* @param _len The length of the string or the payload.
* @param _offset 128 if item is string, 192 if item is list.
* @return RLP encoded bytes.
*/
function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {
bytes memory encoded;
if (_len < 56) {
encoded = new bytes(1);
encoded[0] = bytes1(uint8(_len) + uint8(_offset));
} else {
uint256 lenLen;
uint256 i = 1;
while (_len / i != 0) {
lenLen++;
i *= 256;
}
encoded = new bytes(lenLen + 1);
encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);
for (i = 1; i <= lenLen; i++) {
encoded[i] = bytes1(uint8((_len / (256**(lenLen - i))) % 256));
}
}
return encoded;
}
/**
* Encode integer in big endian binary form with no leading zeroes.
* @notice TODO: This should be optimized with assembly to save gas costs.
* @param _x The integer to encode.
* @return RLP encoded bytes.
*/
function _toBinary(uint256 _x) private pure returns (bytes memory) {
bytes memory b = abi.encodePacked(_x);
uint256 i = 0;
for (; i < 32; i++) {
if (b[i] != 0) {
break;
}
}
bytes memory res = new bytes(32 - i);
for (uint256 j = 0; j < res.length; j++) {
res[j] = b[i++];
}
return res;
}
/**
* Copies a piece of memory to another location.
* @notice From: https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol.
* @param _dest Destination location.
* @param _src Source location.
* @param _len Length of memory to copy.
*/
function _memcpy(
uint256 _dest,
uint256 _src,
uint256 _len
) private pure {
uint256 dest = _dest;
uint256 src = _src;
uint256 len = _len;
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
uint256 mask;
unchecked {
mask = 256**(32 - len) - 1;
}
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
/**
* Flattens a list of byte strings into one byte string.
* @notice From: https://github.com/sammayo/solidity-rlp-encoder/blob/master/RLPEncode.sol.
* @param _list List of byte strings to flatten.
* @return The flattened byte string.
*/
function _flatten(bytes[] memory _list) private pure returns (bytes memory) {
if (_list.length == 0) {
return new bytes(0);
}
uint256 len;
uint256 i = 0;
for (; i < _list.length; i++) {
len += _list[i].length;
}
bytes memory flattened = new bytes(len);
uint256 flattenedPtr;
assembly {
flattenedPtr := add(flattened, 0x20)
}
for (i = 0; i < _list.length; i++) {
bytes memory item = _list[i];
uint256 listPtr;
assembly {
listPtr := add(item, 0x20)
}
_memcpy(flattenedPtr, listPtr, item.length);
flattenedPtr += _list[i].length;
}
return flattened;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import { Lib_BytesUtils } from "../Lib_BytesUtils.sol";
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
/**
* @title Lib_MerkleTrie
*/
library Lib_MerkleTrie {
/*******************
* Data Structures *
*******************/
enum NodeType {
BranchNode,
ExtensionNode,
LeafNode
}
struct TrieNode {
bytes encoded;
Lib_RLPReader.RLPItem[] decoded;
}
/**********************
* Contract Constants *
**********************/
// TREE_RADIX determines the number of elements per branch node.
uint256 constant TREE_RADIX = 16;
// Branch nodes have TREE_RADIX elements plus an additional `value` slot.
uint256 constant BRANCH_NODE_LENGTH = TREE_RADIX + 1;
// Leaf nodes and extension nodes always have two elements, a `path` and a `value`.
uint256 constant LEAF_OR_EXTENSION_NODE_LENGTH = 2;
// Prefixes are prepended to the `path` within a leaf or extension node and
// allow us to differentiate between the two node types. `ODD` or `EVEN` is
// determined by the number of nibbles within the unprefixed `path`. If the
// number of nibbles if even, we need to insert an extra padding nibble so
// the resulting prefixed `path` has an even number of nibbles.
uint8 constant PREFIX_EXTENSION_EVEN = 0;
uint8 constant PREFIX_EXTENSION_ODD = 1;
uint8 constant PREFIX_LEAF_EVEN = 2;
uint8 constant PREFIX_LEAF_ODD = 3;
// Just a utility constant. RLP represents `NULL` as 0x80.
bytes1 constant RLP_NULL = bytes1(0x80);
/**********************
* Internal Functions *
**********************/
/**
* @notice Verifies a proof that a given key/value pair is present in the
* Merkle trie.
* @param _key Key of the node to search for, as a hex string.
* @param _value Value of the node to search for, as a hex string.
* @param _proof Merkle trie inclusion proof for the desired node. Unlike
* traditional Merkle trees, this proof is executed top-down and consists
* of a list of RLP-encoded nodes that make a path down to the target node.
* @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed.
* @return _verified `true` if the k/v pair exists in the trie, `false` otherwise.
*/
function verifyInclusionProof(
bytes memory _key,
bytes memory _value,
bytes memory _proof,
bytes32 _root
) internal pure returns (bool _verified) {
(bool exists, bytes memory value) = get(_key, _proof, _root);
return (exists && Lib_BytesUtils.equal(_value, value));
}
/**
* @notice Retrieves the value associated with a given key.
* @param _key Key to search for, as hex bytes.
* @param _proof Merkle trie inclusion proof for the key.
* @param _root Known root of the Merkle trie.
* @return _exists Whether or not the key exists.
* @return _value Value of the key if it exists.
*/
function get(
bytes memory _key,
bytes memory _proof,
bytes32 _root
) internal pure returns (bool _exists, bytes memory _value) {
TrieNode[] memory proof = _parseProof(_proof);
(uint256 pathLength, bytes memory keyRemainder, bool isFinalNode) = _walkNodePath(
proof,
_key,
_root
);
bool exists = keyRemainder.length == 0;
require(exists || isFinalNode, "Provided proof is invalid.");
bytes memory value = exists ? _getNodeValue(proof[pathLength - 1]) : bytes("");
return (exists, value);
}
/*********************
* Private Functions *
*********************/
/**
* @notice Walks through a proof using a provided key.
* @param _proof Inclusion proof to walk through.
* @param _key Key to use for the walk.
* @param _root Known root of the trie.
* @return _pathLength Length of the final path
* @return _keyRemainder Portion of the key remaining after the walk.
* @return _isFinalNode Whether or not we've hit a dead end.
*/
function _walkNodePath(
TrieNode[] memory _proof,
bytes memory _key,
bytes32 _root
)
private
pure
returns (
uint256 _pathLength,
bytes memory _keyRemainder,
bool _isFinalNode
)
{
uint256 pathLength = 0;
bytes memory key = Lib_BytesUtils.toNibbles(_key);
bytes32 currentNodeID = _root;
uint256 currentKeyIndex = 0;
uint256 currentKeyIncrement = 0;
TrieNode memory currentNode;
// Proof is top-down, so we start at the first element (root).
for (uint256 i = 0; i < _proof.length; i++) {
currentNode = _proof[i];
currentKeyIndex += currentKeyIncrement;
// Keep track of the proof elements we actually need.
// It's expensive to resize arrays, so this simply reduces gas costs.
pathLength += 1;
if (currentKeyIndex == 0) {
// First proof element is always the root node.
require(keccak256(currentNode.encoded) == currentNodeID, "Invalid root hash");
} else if (currentNode.encoded.length >= 32) {
// Nodes 32 bytes or larger are hashed inside branch nodes.
require(
keccak256(currentNode.encoded) == currentNodeID,
"Invalid large internal hash"
);
} else {
// Nodes smaller than 31 bytes aren't hashed.
require(
Lib_BytesUtils.toBytes32(currentNode.encoded) == currentNodeID,
"Invalid internal node hash"
);
}
if (currentNode.decoded.length == BRANCH_NODE_LENGTH) {
if (currentKeyIndex == key.length) {
// We've hit the end of the key
// meaning the value should be within this branch node.
break;
} else {
// We're not at the end of the key yet.
// Figure out what the next node ID should be and continue.
uint8 branchKey = uint8(key[currentKeyIndex]);
Lib_RLPReader.RLPItem memory nextNode = currentNode.decoded[branchKey];
currentNodeID = _getNodeID(nextNode);
currentKeyIncrement = 1;
continue;
}
} else if (currentNode.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) {
bytes memory path = _getNodePath(currentNode);
uint8 prefix = uint8(path[0]);
uint8 offset = 2 - (prefix % 2);
bytes memory pathRemainder = Lib_BytesUtils.slice(path, offset);
bytes memory keyRemainder = Lib_BytesUtils.slice(key, currentKeyIndex);
uint256 sharedNibbleLength = _getSharedNibbleLength(pathRemainder, keyRemainder);
if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) {
if (
pathRemainder.length == sharedNibbleLength &&
keyRemainder.length == sharedNibbleLength
) {
// The key within this leaf matches our key exactly.
// Increment the key index to reflect that we have no remainder.
currentKeyIndex += sharedNibbleLength;
}
// We've hit a leaf node, so our next node should be NULL.
currentNodeID = bytes32(RLP_NULL);
break;
} else if (prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD) {
if (sharedNibbleLength != pathRemainder.length) {
// Our extension node is not identical to the remainder.
// We've hit the end of this path
// updates will need to modify this extension.
currentNodeID = bytes32(RLP_NULL);
break;
} else {
// Our extension shares some nibbles.
// Carry on to the next node.
currentNodeID = _getNodeID(currentNode.decoded[1]);
currentKeyIncrement = sharedNibbleLength;
continue;
}
} else {
revert("Received a node with an unknown prefix");
}
} else {
revert("Received an unparseable node.");
}
}
// If our node ID is NULL, then we're at a dead end.
bool isFinalNode = currentNodeID == bytes32(RLP_NULL);
return (pathLength, Lib_BytesUtils.slice(key, currentKeyIndex), isFinalNode);
}
/**
* @notice Parses an RLP-encoded proof into something more useful.
* @param _proof RLP-encoded proof to parse.
* @return _parsed Proof parsed into easily accessible structs.
*/
function _parseProof(bytes memory _proof) private pure returns (TrieNode[] memory _parsed) {
Lib_RLPReader.RLPItem[] memory nodes = Lib_RLPReader.readList(_proof);
TrieNode[] memory proof = new TrieNode[](nodes.length);
for (uint256 i = 0; i < nodes.length; i++) {
bytes memory encoded = Lib_RLPReader.readBytes(nodes[i]);
proof[i] = TrieNode({ encoded: encoded, decoded: Lib_RLPReader.readList(encoded) });
}
return proof;
}
/**
* @notice Picks out the ID for a node. Node ID is referred to as the
* "hash" within the specification, but nodes < 32 bytes are not actually
* hashed.
* @param _node Node to pull an ID for.
* @return _nodeID ID for the node, depending on the size of its contents.
*/
function _getNodeID(Lib_RLPReader.RLPItem memory _node) private pure returns (bytes32 _nodeID) {
bytes memory nodeID;
if (_node.length < 32) {
// Nodes smaller than 32 bytes are RLP encoded.
nodeID = Lib_RLPReader.readRawBytes(_node);
} else {
// Nodes 32 bytes or larger are hashed.
nodeID = Lib_RLPReader.readBytes(_node);
}
return Lib_BytesUtils.toBytes32(nodeID);
}
/**
* @notice Gets the path for a leaf or extension node.
* @param _node Node to get a path for.
* @return _path Node path, converted to an array of nibbles.
*/
function _getNodePath(TrieNode memory _node) private pure returns (bytes memory _path) {
return Lib_BytesUtils.toNibbles(Lib_RLPReader.readBytes(_node.decoded[0]));
}
/**
* @notice Gets the path for a node.
* @param _node Node to get a value for.
* @return _value Node value, as hex bytes.
*/
function _getNodeValue(TrieNode memory _node) private pure returns (bytes memory _value) {
return Lib_RLPReader.readBytes(_node.decoded[_node.decoded.length - 1]);
}
/**
* @notice Utility; determines the number of nibbles shared between two
* nibble arrays.
* @param _a First nibble array.
* @param _b Second nibble array.
* @return _shared Number of shared nibbles.
*/
function _getSharedNibbleLength(bytes memory _a, bytes memory _b)
private
pure
returns (uint256 _shared)
{
uint256 i = 0;
while (_a.length > i && _b.length > i && _a[i] == _b[i]) {
i++;
}
return i;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import { Lib_MerkleTrie } from "./Lib_MerkleTrie.sol";
/**
* @title Lib_SecureMerkleTrie
*/
library Lib_SecureMerkleTrie {
/**********************
* Internal Functions *
**********************/
/**
* @notice Verifies a proof that a given key/value pair is present in the
* Merkle trie.
* @param _key Key of the node to search for, as a hex string.
* @param _value Value of the node to search for, as a hex string.
* @param _proof Merkle trie inclusion proof for the desired node. Unlike
* traditional Merkle trees, this proof is executed top-down and consists
* of a list of RLP-encoded nodes that make a path down to the target node.
* @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed.
* @return _verified `true` if the k/v pair exists in the trie, `false` otherwise.
*/
function verifyInclusionProof(
bytes memory _key,
bytes memory _value,
bytes memory _proof,
bytes32 _root
) internal pure returns (bool _verified) {
bytes memory key = _getSecureKey(_key);
return Lib_MerkleTrie.verifyInclusionProof(key, _value, _proof, _root);
}
/**
* @notice Retrieves the value associated with a given key.
* @param _key Key to search for, as hex bytes.
* @param _proof Merkle trie inclusion proof for the key.
* @param _root Known root of the Merkle trie.
* @return _exists Whether or not the key exists.
* @return _value Value of the key if it exists.
*/
function get(
bytes memory _key,
bytes memory _proof,
bytes32 _root
) internal pure returns (bool _exists, bytes memory _value) {
bytes memory key = _getSecureKey(_key);
return Lib_MerkleTrie.get(key, _proof, _root);
}
/*********************
* Private Functions *
*********************/
/**
* Computes the secure counterpart to a key.
* @param _key Key to get a secure key from.
* @return _secureKey Secure version of the key.
*/
function _getSecureKey(bytes memory _key) private pure returns (bytes memory _secureKey) {
return abi.encodePacked(keccak256(_key));
}
}
......@@ -13,13 +13,9 @@ import { OptimismPortal } from "../L1/OptimismPortal.sol";
import { L2ToL1MessagePasser } from "../L2/L2ToL1MessagePasser.sol";
import { L1CrossDomainMessenger } from "../L1/L1CrossDomainMessenger.sol";
import { L2CrossDomainMessenger } from "../L2/L2CrossDomainMessenger.sol";
import { AddressAliasHelper } from "@eth-optimism/contracts/standards/AddressAliasHelper.sol";
import { AddressAliasHelper } from "../libraries/AddressAliasHelper.sol";
import { OVM_ETH } from "../L2/OVM_ETH.sol";
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract CommonTest is Test {
......
......@@ -4,7 +4,7 @@ pragma solidity 0.8.10;
import { CommonTest } from "./CommonTest.t.sol";
import { GasPriceOracle } from "../L2/GasPriceOracle.sol";
import { L1Block } from "../L2/L1Block.sol";
import { Lib_BedrockPredeployAddresses } from "../libraries/Lib_BedrockPredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
contract GasPriceOracle_Test is CommonTest {
......@@ -19,11 +19,11 @@ contract GasPriceOracle_Test is CommonTest {
function setUp() external {
// place the L1Block contract at the predeploy address
vm.etch(
Lib_BedrockPredeployAddresses.L1_BLOCK_ATTRIBUTES,
Lib_PredeployAddresses.L1_BLOCK_ATTRIBUTES,
address(new L1Block()).code
);
l1Block = L1Block(Lib_BedrockPredeployAddresses.L1_BLOCK_ATTRIBUTES);
l1Block = L1Block(Lib_PredeployAddresses.L1_BLOCK_ATTRIBUTES);
depositor = l1Block.DEPOSITOR_ACCOUNT();
// We are not setting the gas oracle at its predeploy
......
......@@ -4,15 +4,15 @@ pragma solidity 0.8.10;
import { Test } from "forge-std/Test.sol";
import { L1Block } from "../L2/L1Block.sol";
import { L1BlockNumber } from "../L2/L1BlockNumber.sol";
import { Lib_BedrockPredeployAddresses } from "../libraries/Lib_BedrockPredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
contract L1BlockNumberTest is Test {
L1Block lb;
L1BlockNumber bn;
function setUp() external {
vm.etch(Lib_BedrockPredeployAddresses.L1_BLOCK_ATTRIBUTES, address(new L1Block()).code);
lb = L1Block(Lib_BedrockPredeployAddresses.L1_BLOCK_ATTRIBUTES);
vm.etch(Lib_PredeployAddresses.L1_BLOCK_ATTRIBUTES, address(new L1Block()).code);
lb = L1Block(Lib_PredeployAddresses.L1_BLOCK_ATTRIBUTES);
bn = new L1BlockNumber();
vm.prank(lb.DEPOSITOR_ACCOUNT());
lb.setL1BlockValues(uint64(999), uint64(2), 3, keccak256(abi.encode(1)), uint64(4));
......
......@@ -6,18 +6,10 @@ import { Messenger_Initializer } from "./CommonTest.t.sol";
import { L2OutputOracle_Initializer } from "./L2OutputOracle.t.sol";
/* Libraries */
import {
AddressAliasHelper
} from "@eth-optimism/contracts/standards/AddressAliasHelper.sol";
import {
Lib_DefaultValues
} from "@eth-optimism/contracts/libraries/constants/Lib_DefaultValues.sol";
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import {
Lib_CrossDomainUtils
} from "@eth-optimism/contracts/libraries/bridge/Lib_CrossDomainUtils.sol";
import { AddressAliasHelper } from "../libraries/AddressAliasHelper.sol";
import { Lib_DefaultValues } from "../libraries/Lib_DefaultValues.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
import { Lib_CrossDomainUtils } from "../libraries/Lib_CrossDomainUtils.sol";
import { WithdrawalVerifier } from "../libraries/Lib_WithdrawalVerifier.sol";
/* Target contract dependencies */
......@@ -29,10 +21,6 @@ import { CrossDomainHashing } from "../libraries/Lib_CrossDomainHashing.sol";
/* Target contract */
import { L1CrossDomainMessenger } from "../L1/L1CrossDomainMessenger.sol";
import {
ICrossDomainMessenger
} from "@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol";
contract L1CrossDomainMessenger_Test is Messenger_Initializer {
// Receiver address for testing
address recipient = address(0xabbaacdc);
......
......@@ -5,10 +5,8 @@ import { Bridge_Initializer } from "./CommonTest.t.sol";
import { StandardBridge } from "../universal/StandardBridge.sol";
import { L2StandardBridge } from "../L2/L2StandardBridge.sol";
import { CrossDomainMessenger } from "../universal/CrossDomainMessenger.sol";
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { AddressAliasHelper } from "@eth-optimism/contracts/standards/AddressAliasHelper.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
import { AddressAliasHelper } from "../libraries/AddressAliasHelper.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { stdStorage, StdStorage } from "forge-std/Test.sol";
......
......@@ -3,26 +3,14 @@ pragma solidity 0.8.10;
import { Messenger_Initializer } from "./CommonTest.t.sol";
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import {
Lib_CrossDomainUtils
} from "@eth-optimism/contracts/libraries/bridge/Lib_CrossDomainUtils.sol";
import { AddressAliasHelper } from "@eth-optimism/contracts/standards/AddressAliasHelper.sol";
import { Lib_CrossDomainUtils } from "../libraries/Lib_CrossDomainUtils.sol";
import { AddressAliasHelper } from "../libraries/AddressAliasHelper.sol";
import { L2ToL1MessagePasser } from "../L2/L2ToL1MessagePasser.sol";
import { L2OutputOracle } from "../L1/L2OutputOracle.sol";
import { L2CrossDomainMessenger } from "../L2/L2CrossDomainMessenger.sol";
import { L1CrossDomainMessenger } from "../L1/L1CrossDomainMessenger.sol";
import { Lib_BedrockPredeployAddresses } from "../libraries/Lib_BedrockPredeployAddresses.sol";
import { CrossDomainHashing } from "../libraries/Lib_CrossDomainHashing.sol";
import {
Lib_DefaultValues
} from "@eth-optimism/contracts/libraries/constants/Lib_DefaultValues.sol";
import { console } from "forge-std/console.sol";
import { Lib_DefaultValues } from "../libraries/Lib_DefaultValues.sol";
contract L2CrossDomainMessenger_Test is Messenger_Initializer {
// Receiver address for testing
......
......@@ -3,10 +3,7 @@ pragma solidity ^0.8.9;
import { CommonTest } from "./CommonTest.t.sol";
import { OVM_ETH } from "../L2/OVM_ETH.sol";
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
contract OVM_ETH_Test is CommonTest {
OVM_ETH eth;
......
......@@ -4,7 +4,7 @@ pragma solidity 0.8.10;
import { Bridge_Initializer } from "./CommonTest.t.sol";
import { LibRLP } from "./Lib_RLP.t.sol";
contract OptimismMintableTokenFactory_Test is Bridge_Initializer {
contract OptimismMintableERC20_Test is Bridge_Initializer {
event Mint(address indexed _account, uint256 _amount);
event Burn(address indexed _account, uint256 _amount);
......
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import { AddressAliasHelper } from "@eth-optimism/contracts/standards/AddressAliasHelper.sol";
import { CommonTest } from "./CommonTest.t.sol";
import { AddressAliasHelper } from "../libraries/AddressAliasHelper.sol";
import { L2OutputOracle } from "../L1/L2OutputOracle.sol";
import { OptimismPortal } from "../L1/OptimismPortal.sol";
import { WithdrawalVerifier } from "../libraries/Lib_WithdrawalVerifier.sol";
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { Bridge_Initializer } from "./CommonTest.t.sol";
import { SequencerFeeVault } from "../L2/SequencerFeeVault.sol";
import { L2StandardBridge } from "../L2/L2StandardBridge.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
contract SequencerFeeVault_Test is Bridge_Initializer {
SequencerFeeVault vault =
......
......@@ -4,9 +4,7 @@ pragma solidity ^0.8.9;
// solhint-disable max-line-length
/* Library Imports */
import {
Lib_DefaultValues
} from "@eth-optimism/contracts/libraries/constants/Lib_DefaultValues.sol";
import { Lib_DefaultValues } from "../libraries/Lib_DefaultValues.sol";
import { CrossDomainHashing } from "../libraries/Lib_CrossDomainHashing.sol";
/* External Imports */
......
......@@ -3,9 +3,7 @@ pragma solidity ^0.8.9;
/* Contract Imports */
import { OptimismMintableERC20 } from "../universal/OptimismMintableERC20.sol";
import {
Lib_PredeployAddresses
} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.sol";
import { Lib_PredeployAddresses } from "../libraries/Lib_PredeployAddresses.sol";
/**
* @title OptimismMintableTokenFactory
......
[default]
src = 'contracts'
# We need to build seperate artifacts for forge and hh, because they each expect a different
# structure for the artifacts directory.
out = 'forge-artifacts'
optimizer = true
optimizer_runs = 999999
remappings = [
'@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/',
'@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/',
'@eth-optimism/contracts/=node_modules/@eth-optimism/contracts/',
'excessively-safe-call/=node_modules/excessively-safe-call/src/',
'solmate/=node_modules/@rari-capital/solmate/src',
'forge-std/=node_modules/forge-std/src',
'ds-test/=node_modules/ds-test/src'
]
extra_output = ['devdoc', 'userdoc', 'metadata', 'storageLayout']
bytecode_hash = "none"
......@@ -2,9 +2,9 @@ import { HardhatUserConfig, task, subtask } from 'hardhat/config'
import { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } from 'hardhat/builtin-tasks/task-names'
import '@nomiclabs/hardhat-waffle'
import '@typechain/hardhat'
import 'hardhat-gas-reporter'
import 'solidity-coverage'
import 'hardhat-deploy'
import '@foundry-rs/hardhat-forge'
import './tasks/deposits'
......@@ -33,9 +33,9 @@ const config: HardhatUserConfig = {
],
},
},
gasReporter: {
enabled: process.env.REPORT_GAS !== undefined,
currency: 'USD',
typechain: {
outDir: 'dist/types',
target: 'ethers-v5',
},
namedAccounts: {
deployer: {
......
{
"name": "@eth-optimism/specs-contracts",
"name": "@eth-optimism/contracts-bedrock",
"version": "0.1.0",
"description": "Contracts for Optimism Specs",
"main": "index.js",
"main": "dist/index",
"types": "dist/index",
"license": "MIT",
"files": [
"dist/**/*.js",
"dist/**/*.d.ts",
"dist/types/*.ts",
"artifacts/src/**/*.json",
"deployments/**/*.json"
],
"dependencies": {
"@eth-optimism/contracts": "^0.5.21",
"@openzeppelin/contracts": "^4.5.0",
"@openzeppelin/contracts-upgradeable": "^4.5.2",
"ethers": "^5.6.8",
"hardhat": "^2.9.6",
"@rari-capital/solmate": "7.0.0-alpha.1",
"ds-test": "https://github.com/dapphub/ds-test.git#9310e879db8ba3ea6d5c6489a579118fd264a3f5",
"forge-std": "https://github.com/foundry-rs/forge-std.git#1680d7fb3e00b7b197a7336e7c88e838c7e6a3ec",
"merkle-patricia-tree": "^4.2.4",
"rlp": "^2.2.7"
},
"scripts": {
"build:forge": "forge build",
"build:hh": "yarn hardhat compile",
"build": "yarn build:forge && yarn build:hh",
"test:hh": "yarn hardhat test",
"test": "yarn test:forge",
"test:forge": "forge test",
"build": "hardhat compile && tsc && hardhat typechain",
"build:ts": "tsc",
"test": "forge test",
"gas-snapshot": "forge snapshot",
"slither": "slither .",
"clean": "rm -rf ./artifacts ./forge-artifacts ./cache ./coverage ./tsconfig.build.tsbuildinfo",
"clean": "rm -rf ./dist ./artifacts ./forge-artifacts ./cache ./coverage ./tsconfig.tsbuildinfo",
"lint:ts:check": "eslint .",
"lint:contracts:check": "yarn solhint -f table 'contracts/**/*.sol'",
"lint:check": "yarn lint:contracts:check && yarn lint:ts:check",
......@@ -33,36 +41,24 @@
},
"devDependencies": {
"@eth-optimism/core-utils": "^0.7.3",
"@foundry-rs/hardhat-forge": "^0.1.5",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^2.1.3",
"@nomiclabs/hardhat-waffle": "^2.0.0",
"@typechain/ethers-v5": "^7.0.1",
"@typechain/hardhat": "^2.3.0",
"@types/chai": "^4.2.21",
"@types/mocha": "^9.0.0",
"@types/node": "^12.0.0",
"@typescript-eslint/eslint-plugin": "^4.29.1",
"@typescript-eslint/eslint-plugin": "^5.26.0",
"@typescript-eslint/parser": "^4.29.1",
"chai": "^4.2.0",
"dotenv": "^16.0.0",
"eslint": "^7.29.0",
"eslint-config-prettier": "^8.3.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^5.1.0",
"ethereum-waffle": "^3.0.0",
"ethers": "^5.6.8",
"hardhat-deploy": "^0.11.4",
"hardhat-gas-reporter": "^1.0.4",
"prettier": "^2.3.2",
"prettier-plugin-solidity": "^1.0.0-beta.13",
"solhint": "^3.3.6",
"solhint-plugin-prettier": "^0.0.5",
"solidity-coverage": "^0.7.16",
"ts-node": "^10.1.0",
"typechain": "^5.1.2",
"typescript": "^4.5.2"
"typescript": "^4.6.2"
}
}
export * from './utils'
export * from './generateProofs'
export * from './constants'
import { BigNumber, BigNumberish, BytesLike, ContractReceipt, ethers, Event } from 'ethers'
function formatNumber(value: BigNumberish, name: string): Uint8Array {
import {
BigNumber,
BigNumberish,
BytesLike,
ContractReceipt,
ethers,
Event,
} from 'ethers'
const formatNumber = (value: BigNumberish, name: string): Uint8Array => {
const result = ethers.utils.stripZeros(BigNumber.from(value).toHexString())
if (result.length > 32) {
throw new Error(`invalid length for ${name}`)
......@@ -8,14 +15,14 @@ function formatNumber(value: BigNumberish, name: string): Uint8Array {
return result
}
function handleNumber(value: string): BigNumber {
const handleNumber = (value: string): BigNumber => {
if (value === '0x') {
return ethers.constants.Zero
}
return BigNumber.from(value)
}
function handleAddress(value: string): string {
const handleAddress = (value: string): string => {
if (value === '0x') {
// @ts-ignore
return null
......@@ -102,10 +109,16 @@ export class DepositTx {
}
const l1BlockHash = this.l1BlockHash
const input = ethers.utils.hexConcat([l1BlockHash, ethers.utils.zeroPad(marker, 32)])
const input = ethers.utils.hexConcat([
l1BlockHash,
ethers.utils.zeroPad(marker, 32),
])
const depositIDHash = ethers.utils.keccak256(input)
const domain = BigNumber.from(this.domain).toHexString()
const domainInput = ethers.utils.hexConcat([ethers.utils.zeroPad(domain, 32), depositIDHash])
const domainInput = ethers.utils.hexConcat([
ethers.utils.zeroPad(domain, 32),
depositIDHash,
])
this._sourceHash = ethers.utils.keccak256(domainInput)
}
return this._sourceHash
......@@ -157,7 +170,9 @@ export class DepositTx {
}
fromL1Receipt(receipt: ContractReceipt, index: number): DepositTx {
if (!receipt.events) throw new Error('cannot parse receipt')
if (!receipt.events) {
throw new Error('cannot parse receipt')
}
const event = receipt.events[index]
if (!event) {
throw new Error(`event index ${index} does not exist`)
......@@ -170,27 +185,38 @@ export class DepositTx {
}
fromL1Event(event: Event): DepositTx {
if (event.event !== 'TransactionDeposited')
if (event.event !== 'TransactionDeposited') {
throw new Error(`incorrect event type: ${event.event}`)
if (typeof event.args === 'undefined') throw new Error('no event args')
if (typeof event.args.from === 'undefined')
}
if (typeof event.args === 'undefined') {
throw new Error('no event args')
}
if (typeof event.args.from === 'undefined') {
throw new Error('"from" undefined')
}
this.from = event.args.from
if (typeof event.args.isCreation === 'undefined')
if (typeof event.args.isCreation === 'undefined') {
throw new Error('"isCreation" undefined')
if (typeof event.args.to === 'undefined') throw new Error('"to" undefined')
}
if (typeof event.args.to === 'undefined') {
throw new Error('"to" undefined')
}
this.to = event.args.isCreation ? null : event.args.to
if (typeof event.args.mint === 'undefined')
if (typeof event.args.mint === 'undefined') {
throw new Error('"mint" undefined')
}
this.mint = event.args.mint
if (typeof event.args.value === 'undefined')
if (typeof event.args.value === 'undefined') {
throw new Error('"value" undefined')
}
this.value = event.args.value
if (typeof event.args.gasLimit === 'undefined')
if (typeof event.args.gasLimit === 'undefined') {
throw new Error('"gasLimit" undefined')
}
this.gas = event.args.gasLimit
if (typeof event.args.data === 'undefined')
if (typeof event.args.data === 'undefined') {
throw new Error('"data" undefined')
}
this.data = event.args.data
this.domain = SourceHashDomain.UserDeposit
this.l1BlockHash = event.blockHash
......
import { task, types } from 'hardhat/config'
import { Contract, providers, utils, Wallet } from 'ethers'
import { Event } from '@ethersproject/contracts'
import { Contract, providers, utils, Wallet, Event } from 'ethers'
import dotenv from 'dotenv'
import { DepositTx, SourceHashDomain } from '../helpers/index'
import { DepositTx } from '../src'
dotenv.config()
async function sleep(ms: number) {
const sleep = async (ms: number) => {
return new Promise((resolve) => setTimeout(resolve, ms))
}
......@@ -37,7 +37,7 @@ task('deposit', 'Deposits funds onto L2.')
'deaddeaddeaddeaddeaddeaddeaddeaddead0001',
types.string
)
.setAction(async (args) => {
.setAction(async (args, hre) => {
const {
l1ProviderUrl,
l2ProviderUrl,
......@@ -46,7 +46,7 @@ task('deposit', 'Deposits funds onto L2.')
depositContractAddr,
privateKey,
} = args
const depositFeedArtifact = require('../artifacts/contracts/L1/OptimismPortal.sol/OptimismPortal.json')
const depositFeedArtifact = await hre.deployments.get('OptimismPortal')
const l1Provider = new providers.JsonRpcProvider(l1ProviderUrl)
const l2Provider = new providers.JsonRpcProvider(l2ProviderUrl)
......@@ -95,8 +95,8 @@ task('deposit', 'Deposits funds onto L2.')
console.log(`Waiting for L2 TX hash ${hash}`)
while (true) {
const tx = await l2Provider.send('eth_getTransactionByHash', [hash])
if (tx) {
const expected = await l2Provider.send('eth_getTransactionByHash', [hash])
if (expected) {
console.log('Deposit success')
break
}
......
import { expect } from 'chai'
import { DepositTx, SourceHashDomain } from '../helpers'
import { BigNumber } from '@ethersproject/bignumber'
import { BigNumber } from 'ethers'
import { DepositTx, SourceHashDomain } from '../src'
describe('Helpers', () => {
describe('DepositTx', () => {
// TODO(tynes): this is out of date now that the subversion
// byte has been added
it('should serialize/deserialize and hash', () => {
// constants serialized using optimistic-geth
// TODO(tynes): more tests
......
{
"extends": "../../tsconfig.build.json",
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"exclude": ["hardhat.config.ts", "deploy", "tasks", "test"],
"include": [
"src/**/*"
]
......
......@@ -7,4 +7,16 @@ ignores: [
"typescript",
"prettier-plugin-solidity",
"solhint-plugin-prettier",
"@babel/eslint-parser",
"@typescript-eslint/parser",
"eslint-plugin-import",
"eslint-plugin-unicorn",
"eslint-plugin-jsdoc",
"eslint-plugin-prefer-arrow",
"eslint-plugin-react",
"@typescript-eslint/eslint-plugin",
"eslint-config-prettier",
"eslint-plugin-prettier",
"chai",
"babel-eslint"
]
# Etherscan API key for Ethereum and Ethereum testnets
ETHERSCAN_API_KEY=
ETHEREUM_ETHERSCAN_API_KEY=
# Etherscan API key for Optimism and Optimism testnets
OPTIMISTIC_ETHERSCAN_API_KEY=
# Ledger required to deploy stuff, insert address here
LEDGER_ADDRESS=
# Required to deploy to Ethereum or Ethereum testnets
INFURA_PROJECT_ID=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract CallRecorder {
struct CallInfo {
address sender;
bytes data;
uint256 gas;
uint256 value;
}
CallInfo public lastCall;
function record() public payable {
lastCall.sender = msg.sender;
lastCall.data = msg.data;
lastCall.gas = gasleft();
lastCall.value = msg.value;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract Reverter {
function doRevert() public pure {
revert("Reverter reverted");
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract SimpleStorage {
mapping(bytes32 => bytes32) public db;
function set(bytes32 _key, bytes32 _value) public payable {
db[_key] = _value;
}
function get(bytes32 _key) public view returns (bytes32) {
return db[_key];
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { Owned } from "@rari-capital/solmate/src/auth/Owned.sol";
import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
import { ERC721 } from "@rari-capital/solmate/src/tokens/ERC721.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { Transactor } from "./Transactor.sol";
/**
* @title RetroReceiver
* @notice RetroReceiver is a minimal contract for receiving funds, meant to be deployed at the
* same address on every chain that supports EIP-2470.
* @title AssetReceiver
* @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either
* ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.
*/
contract RetroReceiver is Owned {
contract AssetReceiver is Transactor {
/**
* Emitted when ETH is received by this address.
*/
......@@ -42,9 +42,9 @@ contract RetroReceiver is Owned {
);
/**
* @param _owner Address to initially own the contract.
* @param _owner Initial contract owner.
*/
constructor(address _owner) Owned(_owner) {}
constructor(address _owner) Transactor(_owner) {}
/**
* Make sure we can receive ETH.
......@@ -58,7 +58,7 @@ contract RetroReceiver is Owned {
*
* @param _to Address to receive the ETH balance.
*/
function withdrawETH(address payable _to) public onlyOwner {
function withdrawETH(address payable _to) external onlyOwner {
withdrawETH(_to, address(this).balance);
}
......@@ -69,6 +69,7 @@ contract RetroReceiver is Owned {
* @param _amount Amount of ETH to withdraw.
*/
function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {
// slither-disable-next-line reentrancy-unlimited-gas
_to.transfer(_amount);
emit WithdrewETH(msg.sender, _to, _amount);
}
......@@ -79,7 +80,7 @@ contract RetroReceiver is Owned {
* @param _asset ERC20 token to withdraw.
* @param _to Address to receive the ERC20 balance.
*/
function withdrawERC20(ERC20 _asset, address _to) public onlyOwner {
function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {
withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));
}
......@@ -95,7 +96,9 @@ contract RetroReceiver is Owned {
address _to,
uint256 _amount
) public onlyOwner {
// slither-disable-next-line unchecked-transfer
_asset.transfer(_to, _amount);
// slither-disable-next-line reentrancy-events
emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);
}
......@@ -110,8 +113,9 @@ contract RetroReceiver is Owned {
ERC721 _asset,
address _to,
uint256 _id
) public onlyOwner {
) external onlyOwner {
_asset.transferFrom(address(this), _to, _id);
// slither-disable-next-line reentrancy-events
emit WithdrewERC721(msg.sender, _to, address(_asset), _id);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title Transactor
* @notice Transactor is a minimal contract that can send transactions.
*/
contract Transactor is Ownable {
/**
* @param _owner Initial contract owner.
*/
constructor(address _owner) Ownable() {
transferOwnership(_owner);
}
/**
* Sends a CALL to a target address.
*
* @param _target Address to call.
* @param _data Data to send with the call.
* @param _gas Amount of gas to send with the call.
* @param _value ETH value to send with the call.
* @return Boolean success value.
* @return Bytes data returned by the call.
*/
function CALL(
address _target,
bytes memory _data,
uint256 _gas,
uint256 _value
) external payable onlyOwner returns (bool, bytes memory) {
return _target.call{ gas: _gas, value: _value }(_data);
}
/**
* Sends a DELEGATECALL to a target address.
*
* @param _target Address to call.
* @param _data Data to send with the call.
* @param _gas Amount of gas to send with the call.
* @return Boolean success value.
* @return Bytes data returned by the call.
*/
function DELEGATECALL(
address _target,
bytes memory _data,
uint256 _gas
) external payable onlyOwner returns (bool, bytes memory) {
// slither-disable-next-line controlled-delegatecall
return _target.delegatecall{ gas: _gas }(_data);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { AssetReceiver } from "../AssetReceiver.sol";
import { IDripCheck } from "./IDripCheck.sol";
/**
* @title Drippie
* @notice Drippie is a system for managing automated contract interactions. A specific interaction
* is called a "drip" and can be executed according to some condition (called a dripcheck) and an
* execution interval. Drips cannot be executed faster than the execution interval. Drips can
* trigger arbitrary contract calls where the calling contract is this contract address. Drips can
* also send ETH value, which makes them ideal for keeping addresses sufficiently funded with ETH.
* Drippie is designed to be connected with smart contract automation services so that drips can be
* executed automatically. However, Drippie is specifically designed to be separated from these
* services so that trust assumptions are better compartmentalized.
*/
contract Drippie is AssetReceiver {
/**
* Enum representing different status options for a given drip.
*/
enum DripStatus {
NONE,
ACTIVE,
PAUSED,
ARCHIVED
}
/**
* Represents a drip action.
*/
struct DripAction {
address payable target;
bytes data;
uint256 value;
}
/**
* Represents the configuration for a given drip.
*/
struct DripConfig {
uint256 interval;
IDripCheck dripcheck;
bytes checkparams;
DripAction[] actions;
}
/**
* Represents the state of an active drip.
*/
struct DripState {
DripStatus status;
DripConfig config;
uint256 last;
}
/**
* Emitted when a new drip is created.
*/
event DripCreated(string indexed name, DripConfig config);
/**
* Emitted when a drip status is updated.
*/
event DripStatusUpdated(string indexed name, DripStatus status);
/**
* Emitted when a drip is executed.
*/
event DripExecuted(string indexed name, address indexed executor, uint256 timestamp);
/**
* Maps from drip names to drip states.
*/
mapping(string => DripState) public drips;
/**
* @param _owner Initial contract owner.
*/
constructor(address _owner) AssetReceiver(_owner) {}
/**
* Creates a new drip with the given name and configuration. Once created, drips cannot be
* modified in any way (this is a security measure). If you want to update a drip, simply pause
* (and potentially archive) the existing drip and create a new one.
*
* @param _name Name of the drip.
* @param _config Configuration for the drip.
*/
function create(string memory _name, DripConfig memory _config) external onlyOwner {
// Make sure this drip doesn't already exist. We *must* guarantee that no other function
// will ever set the status of a drip back to NONE after it's been created. This is why
// archival is a separate status.
require(
drips[_name].status == DripStatus.NONE,
"Drippie: drip with that name already exists"
);
// We initialize this way because Solidity won't let us copy arrays into storage yet.
DripState storage state = drips[_name];
state.status = DripStatus.PAUSED;
state.config.interval = _config.interval;
state.config.dripcheck = _config.dripcheck;
state.config.checkparams = _config.checkparams;
// Solidity doesn't let us copy arrays into storage, so we push each array one by one.
for (uint256 i = 0; i < _config.actions.length; i++) {
state.config.actions.push(_config.actions[i]);
}
// Tell the world!
emit DripCreated(_name, _config);
}
/**
* Sets the status for a given drip. The behavior of this function depends on the status that
* the user is trying to set. A drip can always move between ACTIVE and PAUSED, but it can
* never move back to NONE and once ARCHIVED, it can never move back to ACTIVE or PAUSED.
*
* @param _name Name of the drip to update.
* @param _status New drip status.
*/
function status(string memory _name, DripStatus _status) external onlyOwner {
// Make sure we can never set drip status back to NONE. A simple security measure to
// prevent accidental overwrites if this code is ever updated down the line.
require(
_status != DripStatus.NONE,
"Drippie: drip status can never be set back to NONE after creation"
);
// Make sure the drip in question actually exists. Not strictly necessary but there doesn't
// seem to be any clear reason why you would want to do this, and it may save some gas in
// the case of a front-end bug.
require(
drips[_name].status != DripStatus.NONE,
"Drippie: drip with that name does not exist"
);
// Once a drip has been archived, it cannot be un-archived. This is, after all, the entire
// point of archiving a drip.
require(
drips[_name].status != DripStatus.ARCHIVED,
"Drippie: drip with that name has been archived"
);
// Although not strictly necessary, we make sure that the status here is actually changing.
// This may save the client some gas if there's a front-end bug and the user accidentally
// tries to "change" the status to the same value as before.
require(
drips[_name].status != _status,
"Drippie: cannot set drip status to same status as before"
);
// If the user is trying to archive this drip, make sure the drip has been paused. We do
// not allow users to archive active drips so that the effects of this action are more
// abundantly clear.
if (_status == DripStatus.ARCHIVED) {
require(
drips[_name].status == DripStatus.PAUSED,
"Drippie: drip must be paused to be archived"
);
}
// If we made it here then we can safely update the status.
drips[_name].status = _status;
emit DripStatusUpdated(_name, drips[_name].status);
}
/**
* Triggers a drip. This function is deliberately left as a public function because the
* assumption being made here is that setting the drip to ACTIVE is an affirmative signal that
* the drip should be executable according to the drip parameters, drip check, and drip
* interval. Note that drip parameters are read entirely from the state and are not supplied as
* user input, so there should not be any way for a non-authorized user to influence the
* behavior of the drip.
*
* @param _name Name of the drip to trigger.
*/
function drip(string memory _name) external {
DripState storage state = drips[_name];
// Only allow active drips to be executed, an obvious security measure.
require(
state.status == DripStatus.ACTIVE,
"Drippie: selected drip does not exist or is not currently active"
);
// Don't drip if the drip interval has not yet elapsed since the last time we dripped. This
// is a safety measure that prevents a malicious recipient from, e.g., spending all of
// their funds and repeatedly requesting new drips. Limits the potential impact of a
// compromised recipient to just a single drip interval, after which the drip can be paused
// by the owner address.
require(
state.last + state.config.interval <= block.timestamp,
"Drippie: drip interval has not elapsed since last drip"
);
// Make sure we're allowed to execute this drip.
require(
state.config.dripcheck.check(state.config.checkparams),
"Drippie: dripcheck failed so drip is not yet ready to be triggered"
);
// Update the last execution time for this drip before the call. Note that it's entirely
// possible for a drip to be executed multiple times per block or even multiple times
// within the same transaction (via re-entrancy) if the drip interval is set to zero. Users
// should set a drip interval of 1 if they'd like the drip to be executed only once per
// block (since this will then prevent re-entrancy).
state.last = block.timestamp;
// Execute each action in the drip. We allow drips to have multiple actions because there
// are scenarios in which a contract must do multiple things atomically. For example, the
// contract may need to withdraw ETH from one account and then deposit that ETH into
// another account within the same transaction.
uint256 len = state.config.actions.length;
for (uint256 i = 0; i < len; i++) {
// Must be marked as "storage" because copying structs into memory is not yet supported
// by Solidity. Won't significantly reduce gas costs but at least makes it easier to
// read what the rest of this section is doing.
DripAction storage action = state.config.actions[i];
// Actually execute the action. We could use ExcessivelySafeCall here but not strictly
// necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this
// will ever happen in practice). Could save a marginal amount of gas to ignore the
// returndata.
// slither-disable-next-line calls-loop
(bool success, ) = action.target.call{ value: action.value }(action.data);
// Generally should not happen, but could if there's a misconfiguration (e.g., passing
// the wrong data to the target contract), the recipient is not payable, or
// insufficient gas was supplied to this transaction. We revert so the drip can be
// fixed and triggered again later. Means we cannot emit an event to alert of the
// failure, but can reasonably be detected by off-chain services even without an event.
// Note that this forces the drip executor to supply sufficient gas to the call
// (assuming there is some sufficient gas limit that exists, otherwise the drip will
// not execute).
require(
success,
"Drippie: drip was unsuccessful, please check your configuration for mistakes"
);
}
emit DripExecuted(_name, msg.sender, block.timestamp);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
interface IDripCheck {
// DripCheck contracts that want to take parameters as inputs MUST expose a struct called
// Params and an event _EventForExposingParamsStructInABI(Params params). This makes it
// possible to easily encode parameters on the client side. Solidity does not support generics
// so it's not possible to do this with explicit typing.
function check(bytes memory _params) external view returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { IDripCheck } from "../IDripCheck.sol";
/**
* @title CheckBalanceHigh
* @notice DripCheck for checking if an account's balance is above a given threshold.
*/
contract CheckBalanceHigh is IDripCheck {
event _EventToExposeStructInABI__Params(Params params);
struct Params {
address target;
uint256 threshold;
}
function check(bytes memory _params) external view returns (bool) {
Params memory params = abi.decode(_params, (Params));
// Check target balance is above threshold.
return params.target.balance > params.threshold;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { IDripCheck } from "../IDripCheck.sol";
/**
* @title CheckBalanceLow
* @notice DripCheck for checking if an account's balance is below a given threshold.
*/
contract CheckBalanceLow is IDripCheck {
event _EventToExposeStructInABI__Params(Params params);
struct Params {
address target;
uint256 threshold;
}
function check(bytes memory _params) external view returns (bool) {
Params memory params = abi.decode(_params, (Params));
// Check target ETH balance is below threshold.
return params.target.balance < params.threshold;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { IDripCheck } from "../IDripCheck.sol";
interface IGelatoTreasury {
function userTokenBalance(address _user, address _token) external view returns (uint256);
}
/**
* @title CheckGelatoLow
* @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.
*/
contract CheckGelatoLow is IDripCheck {
event _EventToExposeStructInABI__Params(Params params);
struct Params {
address treasury;
uint256 threshold;
address recipient;
}
function check(bytes memory _params) external view returns (bool) {
Params memory params = abi.decode(_params, (Params));
// Check GelatoTreasury ETH balance is below threshold.
return
IGelatoTreasury(params.treasury).userTokenBalance(
params.recipient,
// Gelato represents ETH as 0xeeeee....eeeee
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
) < params.threshold;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { IDripCheck } from "../IDripCheck.sol";
/**
* @title CheckTrue
* @notice DripCheck that always returns true.
*/
contract CheckTrue is IDripCheck {
function check(bytes memory) external pure returns (bool) {
return true;
}
}
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { getDeployConfig } from '../src'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const config = getDeployConfig(hre.network.name)
const { deploy } = await hre.deployments.deterministic('AssetReceiver', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['RetroReceiver']),
from: deployer,
args: [config.retroReceiverOwner],
log: true,
})
await deploy()
}
deployFn.tags = ['RetroReceiver']
deployFn.dependencies = ['OptimismAuthority']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { getDeployConfig } from '../../src'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const config = getDeployConfig(hre.network.name)
const { deploy } = await hre.deployments.deterministic('Drippie', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['Drippie']),
from: deployer,
args: [config.drippieOwner],
log: true,
})
await deploy()
}
deployFn.tags = ['Drippie']
deployFn.dependencies = ['OptimismAuthority']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic('CheckBalanceHigh', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['CheckBalanceHigh']),
from: deployer,
log: true,
})
await deploy()
}
deployFn.tags = ['CheckBalanceHigh']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic('CheckBalanceLow', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['CheckBalanceLow']),
from: deployer,
log: true,
})
await deploy()
}
deployFn.tags = ['CheckBalanceLow']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic('CheckGelatoLow', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['CheckGelatoLow']),
from: deployer,
log: true,
})
await deploy()
}
deployFn.tags = ['CheckGelatoLow']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic('CheckTrue', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['CheckTrue']),
from: deployer,
log: true,
})
await deploy()
}
deployFn.tags = ['CheckTrue']
export default deployFn
......@@ -7,6 +7,8 @@ import '@nomiclabs/hardhat-ethers'
import '@nomiclabs/hardhat-waffle'
import '@nomiclabs/hardhat-etherscan'
import 'solidity-coverage'
import 'hardhat-gas-reporter'
import 'hardhat-deploy'
// Hardhat tasks
import './tasks'
......@@ -18,15 +20,57 @@ const config: HardhatUserConfig = {
networks: {
optimism: {
chainId: 10,
url: 'https://mainnet.optimsim.io',
url: 'https://mainnet.optimism.io',
verify: {
etherscan: {
apiKey: getenv('OPTIMISTIC_ETHERSCAN_API_KEY'),
},
},
},
opkovan: {
chainId: 69,
url: 'https://kovan.optimism.io',
verify: {
etherscan: {
apiKey: getenv('OPTIMISTIC_ETHERSCAN_API_KEY'),
},
},
},
mainnet: {
ethereum: {
chainId: 1,
url: 'https://rpc.ankr.com/eth',
url: `https://mainnet.infura.io/v3/${getenv('INFURA_PROJECT_ID')}`,
verify: {
etherscan: {
apiKey: getenv('ETHEREUM_ETHERSCAN_API_KEY'),
},
},
},
goerli: {
chainId: 5,
url: `https://goerli.infura.io/v3/${getenv('INFURA_PROJECT_ID')}`,
verify: {
etherscan: {
apiKey: getenv('ETHEREUM_ETHERSCAN_API_KEY'),
},
},
},
ropsten: {
chainId: 3,
url: `https://ropsten.infura.io/v3/${getenv('INFURA_PROJECT_ID')}`,
verify: {
etherscan: {
apiKey: getenv('ETHEREUM_ETHERSCAN_API_KEY'),
},
},
},
kovan: {
chainId: 42,
url: `https://kovan.infura.io/v3/${getenv('INFURA_PROJECT_ID')}`,
verify: {
etherscan: {
apiKey: getenv('ETHEREUM_ETHERSCAN_API_KEY'),
},
},
},
},
mocha: {
......@@ -52,12 +96,8 @@ const config: HardhatUserConfig = {
},
},
},
etherscan: {
apiKey: {
mainnet: getenv('ETHERSCAN_API_KEY'),
optimisticEthereum: getenv('OPTIMISTIC_ETHERSCAN_API_KEY'),
optimisticKovan: getenv('OPTIMISTIC_ETHERSCAN_API_KEY'),
},
namedAccounts: {
deployer: `ledger://${getenv('LEDGER_ADDRESS')}`,
},
}
......
......@@ -21,6 +21,9 @@
"test": "yarn test:contracts",
"test:contracts": "hardhat test --show-stack-traces",
"test:coverage": "NODE_OPTIONS=--max_old_space_size=8192 hardhat coverage && istanbul check-coverage --statements 90 --branches 84 --functions 88 --lines 90",
"test:slither": "slither .",
"pretest:slither": "rm -f @openzeppelin && rm -f hardhat && ln -s node_modules/@openzeppelin @openzeppelin && ln -s ../../node_modules/hardhat hardhat",
"posttest:slither": "rm -f @openzeppelin && rm -f hardhat",
"lint:ts:check": "eslint . --max-warnings=0",
"lint:contracts:check": "yarn solhint -f table 'contracts/**/*.sol'",
"lint:check": "yarn lint:contracts:check && yarn lint:ts:check",
......@@ -28,7 +31,7 @@
"lint:contracts:fix": "yarn prettier --write 'contracts/**/*.sol'",
"lint:fix": "yarn lint:contracts:fix && yarn lint:ts:fix",
"lint": "yarn lint:fix && yarn lint:check",
"clean": "rm -rf ./dist ./artifacts ./cache ./coverage ./tsconfig.build.tsbuildinfo",
"clean": "rm -rf ./dist ./artifacts ./cache ./coverage ./tsconfig.tsbuildinfo",
"prepublishOnly": "yarn copyfiles -u 1 -e \"**/test-*/**/*\" \"contracts/**/*\" ./",
"postpublish": "rimraf chugsplash L1 L2 libraries standards",
"prepack": "yarn prepublishOnly",
......@@ -49,46 +52,37 @@
"type": "git",
"url": "https://github.com/ethereum-optimism/optimism.git"
},
"dependencies": {
"@eth-optimism/core-utils": "^0.8.5",
"@openzeppelin/contracts": "4.3.2"
},
"devDependencies": {
"@defi-wonderland/smock": "^2.0.7",
"@eth-optimism/core-utils": "^0.8.5",
"@ethersproject/hardware-wallets": "^5.6.1",
"@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-etherscan": "^3.0.3",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@rari-capital/solmate": "^6.3.0",
"@openzeppelin/contracts": "4.6.0",
"@types/chai": "^4.2.18",
"@types/mocha": "^8.2.2",
"@types/node": "^17.0.21",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"chai": "^4.3.4",
"copyfiles": "^2.3.0",
"dotenv": "^10.0.0",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"ethereum-waffle": "^3.3.0",
"ethers": "^5.6.8",
"hardhat": "^2.9.6",
"hardhat-deploy": "^0.11.10",
"hardhat-gas-reporter": "^1.0.8",
"istanbul": "^0.4.5",
"lint-staged": "11.0.0",
"mocha": "^8.4.0",
"node-fetch": "^2.6.7",
"prettier": "^2.3.1",
"prettier-plugin-solidity": "^1.0.0-beta.18",
"solhint": "^3.3.6",
"solhint-plugin-prettier": "^0.0.5",
"solidity-coverage": "^0.7.17",
"ts-node": "^10.0.0",
"typescript": "^4.6.2"
"mocha": "^10.0.0"
}
}
......@@ -8,5 +8,5 @@
"hardhat_ignore_compile": false,
"disable_color": false,
"exclude_dependencies": false,
"filter_paths": "@openzeppelin|hardhat|contracts/test-helpers|contracts/test-libraries|contracts/L2/predeploys/WETH9.sol"
"filter_paths": "@openzeppelin|hardhat|contracts/testing"
}
import { ethers } from 'ethers'
/**
* Defines the configuration for a deployment.
*/
export interface DeployConfig {
/**
* Initial RetroReceiver owner.
*/
retroReceiverOwner: string
/**
* Initial Drippie owner.
*/
drippieOwner: string
}
/**
* Specification for each of the configuration options.
*/
const configSpec: {
[K in keyof DeployConfig]: {
type: string
default?: any
}
} = {
retroReceiverOwner: {
type: 'address',
},
drippieOwner: {
type: 'address',
},
}
/**
* Gets the deploy config for the given network.
*
* @param network Network name.
* @returns Deploy config for the given network.
*/
export const getDeployConfig = (network: string): Required<DeployConfig> => {
let config: DeployConfig
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
config = require(`../../config/deploy/${network}.ts`).default
} catch (err) {
throw new Error(
`error while loading deploy config for network: ${network}, ${err}`
)
}
return parseDeployConfig(config)
}
/**
* Parses and validates the given deploy config, replacing any missing values with defaults.
*
* @param config Deploy config to parse.
* @returns Parsed deploy config.
*/
export const parseDeployConfig = (
config: DeployConfig
): Required<DeployConfig> => {
// Create a clone of the config object. Shallow clone is fine because none of the input options
// are expected to be objects or functions etc.
const parsed = { ...config }
for (const [key, spec] of Object.entries(configSpec)) {
// Make sure the value is defined, or use a default.
if (parsed[key] === undefined) {
if ('default' in spec) {
parsed[key] = spec.default
} else {
throw new Error(
`deploy config is missing required field: ${key} (${spec.type})`
)
}
} else {
// Make sure the default has the correct type.
if (spec.type === 'address') {
if (!ethers.utils.isAddress(parsed[key])) {
throw new Error(
`deploy config field: ${key} is not of type ${spec.type}: ${parsed[key]}`
)
}
} else if (typeof parsed[key] !== spec.type) {
throw new Error(
`deploy config field: ${key} is not of type ${spec.type}: ${parsed[key]}`
)
}
}
}
return parsed as Required<DeployConfig>
}
import assert from 'assert'
import { BigNumberish, ethers } from 'ethers'
import { Interface } from 'ethers/lib/utils'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import { Etherscan } from '../etherscan'
export interface DripConfig {
interval: BigNumberish
dripcheck: string
checkparams?: any
actions: Array<{
target: string
value?: BigNumberish
data?:
| string
| {
fn: string
args: any[]
}
}>
}
export interface DrippieConfig {
[name: string]: DripConfig
}
export const getDrippieConfig = async (
hre: HardhatRuntimeEnvironment
): Promise<Required<DrippieConfig>> => {
let config: DrippieConfig
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
config = require(`../../config/drippie/${hre.network.name}.ts`).default
} catch (err) {
throw new Error(
`error while loading drippie config for network: ${hre.network.name}, ${err}`
)
}
return parseDrippieConfig(hre, config)
}
export const encodeDripCheckParams = (
iface: Interface,
params: any
): string => {
return ethers.utils.defaultAbiCoder.encode(
[iface.getEvent('_EventToExposeStructInABI__Params').inputs[0]],
[params]
)
}
export const parseDrippieConfig = async (
hre: HardhatRuntimeEnvironment,
config: DrippieConfig
): Promise<Required<DrippieConfig>> => {
// Create a clone of the config object. Shallow clone is fine because none of the input options
// are expected to be objects or functions etc.
const parsed = { ...config }
const etherscan = new Etherscan(
hre.network.config.verify.etherscan.apiKey,
hre.network.config.chainId
)
for (const dripConfig of Object.values(parsed)) {
for (const action of dripConfig.actions) {
assert(ethers.utils.isAddress(action.target), 'target is not an address')
if (action.data === undefined) {
action.data = '0x'
} else if (typeof action.data === 'string') {
assert(
ethers.utils.isHexString(action.data),
'action is not a hex string'
)
} else {
const abi = await etherscan.getContractABI(action.target)
const iface = new ethers.utils.Interface(abi)
action.data = iface.encodeFunctionData(action.data.fn, action.data.args)
}
if (action.value === undefined) {
action.value = ethers.BigNumber.from(0)
} else {
action.value = ethers.BigNumber.from(action.value)
}
}
const dripcheck = await hre.deployments.get(dripConfig.dripcheck)
dripConfig.dripcheck = dripcheck.address
if (dripConfig.checkparams === undefined) {
dripConfig.checkparams = '0x'
} else {
dripConfig.checkparams = encodeDripCheckParams(
new ethers.utils.Interface(dripcheck.abi),
dripConfig.checkparams
)
}
dripConfig.interval = ethers.BigNumber.from(dripConfig.interval)
}
return parsed as Required<DrippieConfig>
}
export * from './deploy'
export * from './drippie'
import fetch from 'node-fetch'
interface NetworkData {
chainId: number
names: string[]
etherscanApiUrl: string
}
const networks: {
[id: number]: NetworkData
} = {
1: {
chainId: 1,
names: ['mainnet', 'main', 'eth', 'ethereum'],
etherscanApiUrl: 'https://api.etherscan.io',
},
3: {
chainId: 3,
names: ['ropsten'],
etherscanApiUrl: 'https://api-ropsten.etherscan.io',
},
4: {
chainId: 4,
names: ['rinkeby'],
etherscanApiUrl: 'https://api-rinkeby.etherscan.io',
},
5: {
chainId: 5,
names: ['goerli'],
etherscanApiUrl: 'https://api-goerli.etherscan.io',
},
10: {
chainId: 10,
names: ['optimism'],
etherscanApiUrl: 'https://api-optimistic.etherscan.io',
},
42: {
chainId: 42,
names: ['kovan'],
etherscanApiUrl: 'https://api-kovan.etherscan.io',
},
69: {
chainId: 69,
names: ['opkovan', 'kovan-optimism', 'optimistic-kovan'],
etherscanApiUrl: 'https://api-kovan-optimistic.etherscan.io',
},
}
export class Etherscan {
net: NetworkData
constructor(
private readonly apiKey: string,
private readonly network: string | number
) {
if (typeof network === 'string') {
this.net = Object.values(networks).find((net) => {
return net.names.includes(network)
})
} else {
this.net = networks[this.network]
}
}
public async getContractSource(address: string): Promise<any> {
const url = new URL(`${this.net.etherscanApiUrl}/api`)
url.searchParams.append('module', 'contract')
url.searchParams.append('action', 'getsourcecode')
url.searchParams.append('address', address)
url.searchParams.append('apikey', this.apiKey)
const response = await fetch(url)
const result = await response.json()
return result.result[0]
}
public async getContractABI(address: string): Promise<any> {
const source = await this.getContractSource(address)
if (source.Proxy === '1') {
const impl = await this.getContractSource(source.Implementation)
return impl.ABI
} else {
return source.ABI
}
}
}
export * from './config'
export * from './etherscan'
import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes'
import { LedgerSigner } from '@ethersproject/hardware-wallets'
task('deploy-receiver')
.addParam('creator', 'Creator address', undefined, types.string)
.addParam('owner', 'Owner address', undefined, types.string)
.setAction(async (args, hre) => {
console.log(`connecting to ledger...`)
const signer = new LedgerSigner(
hre.ethers.provider,
'default',
hre.ethers.utils.defaultPath
)
const addr = await signer.getAddress()
if (args.creator !== addr) {
throw new Error(`Incorrect key. Creator ${args.creator}, Signer ${addr}`)
}
const singleton = new hre.ethers.Contract(
'0xce0042B868300000d44A59004Da54A005ffdcf9f',
[
{
constant: false,
inputs: [
{
internalType: 'bytes',
name: '_initCode',
type: 'bytes',
},
{
internalType: 'bytes32',
name: '_salt',
type: 'bytes32',
},
],
name: 'deploy',
outputs: [
{
internalType: 'address payable',
name: 'createdContract',
type: 'address',
},
],
payable: false,
stateMutability: 'nonpayable',
type: 'function',
},
],
signer
)
const salt =
'0x0000000000000000000000000000000000000000000000000000000000000001'
const code = hre.ethers.utils.hexConcat([
hre.artifacts.readArtifactSync('RetroReceiver').bytecode,
hre.ethers.utils.defaultAbiCoder.encode(['address'], [addr]),
])
// Predict and connect to the contract address
const receiver = await hre.ethers.getContractAt(
'RetroReceiver',
await singleton.callStatic.deploy(code, salt, {
gasLimit: 2_000_000,
}),
signer
)
console.log(`creating contract: ${receiver.address}...`)
const tx1 = await singleton.deploy(code, salt, {
gasLimit: 2_000_000,
})
console.log(`waiting for tx: ${tx1.hash}...`)
await tx1.wait()
console.log(`transferring ownership to: ${args.owner}...`)
const tx2 = await receiver.setOwner(args.owner)
console.log(`waiting for tx: ${tx2.hash}...`)
await tx2.wait()
console.log(`verifying contract: ${receiver.address}...`)
await hre.run('verify:verify', {
address: receiver.address,
constructorArguments: [addr],
})
console.log(`all done`)
})
export * from './deploy-receiver'
export * from './install-drippie-config'
import { task } from 'hardhat/config'
import { LedgerSigner } from '@ethersproject/hardware-wallets'
import { PopulatedTransaction } from 'ethers'
import { DripConfig, getDrippieConfig } from '../src'
task('install-drippie-config').setAction(async (args, hre) => {
console.log(`connecting to ledger...`)
const signer = new LedgerSigner(
hre.ethers.provider,
'default',
hre.ethers.utils.defaultPath
)
console.log(`connecting to Drippie...`)
const Drippie = await hre.ethers.getContractAt(
'Drippie',
(
await hre.deployments.get('Drippie')
).address,
signer
)
console.log(`loading local version of Drippie config for network...`)
const config = await getDrippieConfig(hre)
// Need this to deal with annoying Ethers/Ledger 1559 issue.
const sendtx = async (tx: PopulatedTransaction): Promise<void> => {
const gas = await signer.estimateGas(tx)
tx.type = 1
tx.gasLimit = gas
const ret = await signer.sendTransaction(tx)
console.log(`sent tx: ${ret.hash}`)
console.log(`waiting for tx to be confirmed...`)
await ret.wait()
console.log(`tx confirmed`)
}
const isSameConfig = (a: DripConfig, b: DripConfig): boolean => {
return (
a.dripcheck.toLowerCase() === b.dripcheck.toLowerCase() &&
a.checkparams === b.checkparams &&
hre.ethers.BigNumber.from(a.interval).eq(b.interval) &&
a.actions.length === b.actions.length &&
a.actions.every((ax, i) => {
return (
ax.target === b.actions[i].target &&
ax.data === b.actions[i].data &&
hre.ethers.BigNumber.from(ax.value).eq(b.actions[i].value)
)
})
)
}
console.log(`installing Drippie config file...`)
for (const [dripName, dripConfig] of Object.entries(config)) {
console.log(`checking config for drip: ${dripName}`)
const drip = await Drippie.drips(dripName)
if (drip.status === 0) {
console.log(`drip does not exist yet: ${dripName}`)
console.log(`creating drip...`)
const tx = await Drippie.populateTransaction.create(dripName, dripConfig)
await sendtx(tx)
} else if (!isSameConfig(dripConfig, drip.config)) {
console.log(`drip exists but local config is different: ${dripName}`)
console.log(`drips cannot be modified for security reasons`)
console.log(`please do not modify the local config for existing drips`)
console.log(`you can archive the old drip and create another`)
} else {
console.log(`drip is already installed`)
}
}
console.log(`config is fully installed`)
})
......@@ -5,7 +5,7 @@ import { Contract } from 'ethers'
import { expect } from '../../setup'
import { deploy } from '../../helpers'
describe('RetroReceiver', () => {
describe('AssetReceiver', () => {
const DEFAULT_TOKEN_ID = 0
const DEFAULT_AMOUNT = hre.ethers.constants.WeiPerEther
const DEFAULT_RECIPIENT = '0x' + '11'.repeat(20)
......@@ -18,11 +18,11 @@ describe('RetroReceiver', () => {
let TestERC20: Contract
let TestERC721: Contract
let RetroReceiver: Contract
let AssetReceiver: Contract
beforeEach('deploy contracts', async () => {
TestERC20 = await deploy('TestERC20', { signer: signer1 })
TestERC721 = await deploy('TestERC721', { signer: signer1 })
RetroReceiver = await deploy('RetroReceiver', {
AssetReceiver = await deploy('AssetReceiver', {
signer: signer1,
args: [signer1.address],
})
......@@ -37,41 +37,35 @@ describe('RetroReceiver', () => {
])
})
describe('constructor', () => {
it('should set the owner', async () => {
expect(await RetroReceiver.owner()).to.equal(signer1.address)
})
})
describe('receive', () => {
it('should be able to receive ETH', async () => {
await expect(
signer1.sendTransaction({
to: RetroReceiver.address,
to: AssetReceiver.address,
value: DEFAULT_AMOUNT,
})
).to.not.be.reverted
expect(
await hre.ethers.provider.getBalance(RetroReceiver.address)
await hre.ethers.provider.getBalance(AssetReceiver.address)
).to.equal(DEFAULT_AMOUNT)
})
})
describe('withdrawETH(address)', () => {
describe('when called by the owner', () => {
describe('when called by authorized address', () => {
it('should withdraw all ETH in the contract', async () => {
await signer1.sendTransaction({
to: RetroReceiver.address,
to: AssetReceiver.address,
value: DEFAULT_AMOUNT,
})
await expect(RetroReceiver['withdrawETH(address)'](DEFAULT_RECIPIENT))
.to.emit(RetroReceiver, 'WithdrewETH')
await expect(AssetReceiver['withdrawETH(address)'](DEFAULT_RECIPIENT))
.to.emit(AssetReceiver, 'WithdrewETH')
.withArgs(signer1.address, DEFAULT_RECIPIENT, DEFAULT_AMOUNT)
expect(
await hre.ethers.provider.getBalance(RetroReceiver.address)
await hre.ethers.provider.getBalance(AssetReceiver.address)
).to.equal(0)
expect(
......@@ -80,36 +74,36 @@ describe('RetroReceiver', () => {
})
})
describe('when called by not the owner', () => {
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
RetroReceiver.connect(signer2)['withdrawETH(address)'](
AssetReceiver.connect(signer2)['withdrawETH(address)'](
signer2.address
)
).to.be.revertedWith('UNAUTHORIZED')
).to.be.revertedWith('Ownable: caller is not the owner')
})
})
})
describe('withdrawETH(address,uint256)', () => {
describe('when called by the owner', () => {
describe('when called by authorized address', () => {
it('should withdraw the given amount of ETH', async () => {
await signer1.sendTransaction({
to: RetroReceiver.address,
to: AssetReceiver.address,
value: DEFAULT_AMOUNT.mul(2),
})
await expect(
RetroReceiver['withdrawETH(address,uint256)'](
AssetReceiver['withdrawETH(address,uint256)'](
DEFAULT_RECIPIENT,
DEFAULT_AMOUNT
)
)
.to.emit(RetroReceiver, 'WithdrewETH')
.to.emit(AssetReceiver, 'WithdrewETH')
.withArgs(signer1.address, DEFAULT_RECIPIENT, DEFAULT_AMOUNT)
expect(
await hre.ethers.provider.getBalance(RetroReceiver.address)
await hre.ethers.provider.getBalance(AssetReceiver.address)
).to.equal(DEFAULT_AMOUNT)
expect(
......@@ -118,30 +112,30 @@ describe('RetroReceiver', () => {
})
})
describe('when called by not the owner', () => {
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
RetroReceiver.connect(signer2)['withdrawETH(address,uint256)'](
AssetReceiver.connect(signer2)['withdrawETH(address,uint256)'](
DEFAULT_RECIPIENT,
DEFAULT_AMOUNT
)
).to.be.revertedWith('UNAUTHORIZED')
).to.be.revertedWith('Ownable: caller is not the owner')
})
})
})
describe('withdrawERC20(address,address)', () => {
describe('when called by the owner', () => {
describe('when called by authorized address', () => {
it('should withdraw all ERC20 balance held by the contract', async () => {
await TestERC20.transfer(RetroReceiver.address, DEFAULT_AMOUNT)
await TestERC20.transfer(AssetReceiver.address, DEFAULT_AMOUNT)
await expect(
RetroReceiver['withdrawERC20(address,address)'](
AssetReceiver['withdrawERC20(address,address)'](
TestERC20.address,
DEFAULT_RECIPIENT
)
)
.to.emit(RetroReceiver, 'WithdrewERC20')
.to.emit(AssetReceiver, 'WithdrewERC20')
.withArgs(
signer1.address,
DEFAULT_RECIPIENT,
......@@ -155,31 +149,31 @@ describe('RetroReceiver', () => {
})
})
describe('when called by not the owner', () => {
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
RetroReceiver.connect(signer2)['withdrawERC20(address,address)'](
AssetReceiver.connect(signer2)['withdrawERC20(address,address)'](
TestERC20.address,
DEFAULT_RECIPIENT
)
).to.be.revertedWith('UNAUTHORIZED')
).to.be.revertedWith('Ownable: caller is not the owner')
})
})
})
describe('withdrawERC20(address,address,uint256)', () => {
describe('when called by the owner', () => {
describe('when called by authorized address', () => {
it('should withdraw the given ERC20 amount', async () => {
await TestERC20.transfer(RetroReceiver.address, DEFAULT_AMOUNT.mul(2))
await TestERC20.transfer(AssetReceiver.address, DEFAULT_AMOUNT.mul(2))
await expect(
RetroReceiver['withdrawERC20(address,address,uint256)'](
AssetReceiver['withdrawERC20(address,address,uint256)'](
TestERC20.address,
DEFAULT_RECIPIENT,
DEFAULT_AMOUNT
)
)
.to.emit(RetroReceiver, 'WithdrewERC20')
.to.emit(AssetReceiver, 'WithdrewERC20')
.withArgs(
signer1.address,
DEFAULT_RECIPIENT,
......@@ -193,34 +187,34 @@ describe('RetroReceiver', () => {
})
})
describe('when called by not the owner', () => {
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
RetroReceiver.connect(signer2)[
AssetReceiver.connect(signer2)[
'withdrawERC20(address,address,uint256)'
](TestERC20.address, DEFAULT_RECIPIENT, DEFAULT_AMOUNT)
).to.be.revertedWith('UNAUTHORIZED')
).to.be.revertedWith('Ownable: caller is not the owner')
})
})
})
describe('withdrawERC721', () => {
describe('when called by the owner', () => {
describe('when called by authorized address', () => {
it('should withdraw the token', async () => {
await TestERC721.transferFrom(
signer1.address,
RetroReceiver.address,
AssetReceiver.address,
DEFAULT_TOKEN_ID
)
await expect(
RetroReceiver.withdrawERC721(
AssetReceiver.withdrawERC721(
TestERC721.address,
DEFAULT_RECIPIENT,
DEFAULT_TOKEN_ID
)
)
.to.emit(RetroReceiver, 'WithdrewERC721')
.to.emit(AssetReceiver, 'WithdrewERC721')
.withArgs(
signer1.address,
DEFAULT_RECIPIENT,
......@@ -234,15 +228,15 @@ describe('RetroReceiver', () => {
})
})
describe('when called by not the owner', () => {
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
RetroReceiver.connect(signer2).withdrawERC721(
AssetReceiver.connect(signer2).withdrawERC721(
TestERC721.address,
DEFAULT_RECIPIENT,
DEFAULT_TOKEN_ID
)
).to.be.revertedWith('UNAUTHORIZED')
).to.be.revertedWith('Ownable: caller is not the owner')
})
})
})
......
import hre from 'hardhat'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { Contract } from 'ethers'
import { expect } from '../../setup'
import { decodeSolidityRevert, deploy } from '../../helpers'
describe('AssetReceiver', () => {
let signer1: SignerWithAddress
let signer2: SignerWithAddress
before('signer setup', async () => {
;[signer1, signer2] = await hre.ethers.getSigners()
})
let CallRecorder: Contract
let Reverter: Contract
let Transactor: Contract
beforeEach('deploy contracts', async () => {
CallRecorder = await deploy('CallRecorder')
Reverter = await deploy('Reverter')
Transactor = await deploy('Transactor', {
signer: signer1,
args: [signer1.address],
})
})
describe('CALL', () => {
describe('when called by authorized address', () => {
it('should do a call to the target contract', async () => {
const data = CallRecorder.interface.encodeFunctionData('record')
await Transactor.CALL(CallRecorder.address, data, 1_000_000, 0, {
gasLimit: 2_000_000,
})
const call = await CallRecorder.lastCall()
expect(call.data).to.equal(data)
expect(call.sender).to.equal(Transactor.address)
})
it('should be able to call with value', async () => {
const data = CallRecorder.interface.encodeFunctionData('record')
const value = 69
await Transactor.CALL(CallRecorder.address, data, 1_000_000, value, {
gasLimit: 2_000_000,
value,
})
const call = await CallRecorder.lastCall()
expect(call.value).to.equal(value)
})
it('should be able to set gas limit', async () => {
const data = CallRecorder.interface.encodeFunctionData('record')
const gas = 100_000
await Transactor.CALL(CallRecorder.address, data, gas, 0, {
gasLimit: 2_000_000,
})
const call = await CallRecorder.lastCall()
expect(call.gas.toNumber()).to.be.lessThan(gas)
})
})
describe('when called by not authorized address', () => {
it('should be reverted', async () => {
const data = CallRecorder.interface.encodeFunctionData('record')
await expect(
Transactor.connect(signer2).CALL(
CallRecorder.address,
data,
1_000_000,
0,
{
gasLimit: 2_000_000,
}
)
).to.be.revertedWith('Ownable: caller is not the owner')
})
})
})
describe('DELEGATECALL', () => {
describe('when called by authorized address', () => {
it('should do a delegatecall to the target contract', async () => {
const data = Reverter.interface.encodeFunctionData('doRevert')
const ret = await Transactor.callStatic.DELEGATECALL(
Reverter.address,
data,
1_000_000,
{
gasLimit: 2_000_000,
}
)
expect(ret[0]).to.equal(false)
expect(decodeSolidityRevert(ret[1])).to.deep.equal('Reverter reverted')
})
})
describe('when called by not authorized address', () => {
it('should be reverted', async () => {
const data = Reverter.interface.encodeFunctionData('doRevert')
await expect(
Transactor.connect(signer2).DELEGATECALL(
Reverter.address,
data,
1_000_000,
{
gasLimit: 2_000_000,
}
)
).to.be.revertedWith('Ownable: caller is not the owner')
})
})
})
})
import hre from 'hardhat'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { Contract } from 'ethers'
import { toRpcHexString } from '@eth-optimism/core-utils'
import { expect } from '../../../setup'
import { deploy } from '../../../helpers'
describe('Drippie', () => {
const DEFAULT_DRIP_NAME = 'drippity drip drip'
const DEFAULT_DRIP_CONFIG = {
interval: hre.ethers.BigNumber.from(100),
dripcheck: '', // Gets added in setup
checkparams: '0x',
actions: [
{
target: '0x' + '11'.repeat(20),
data: '0x',
value: hre.ethers.BigNumber.from(1),
},
],
}
let signer1: SignerWithAddress
let signer2: SignerWithAddress
before('signer setup', async () => {
;[signer1, signer2] = await hre.ethers.getSigners()
})
before('deploy default dripcheck', async () => {
DEFAULT_DRIP_CONFIG.dripcheck = (await deploy('CheckTrue')).address
})
let SimpleStorage: Contract
let Drippie: Contract
beforeEach('deploy contracts', async () => {
SimpleStorage = await deploy('SimpleStorage')
Drippie = await deploy('Drippie', {
signer: signer1,
args: [signer1.address],
})
})
beforeEach('balance setup', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
Drippie.address,
toRpcHexString(DEFAULT_DRIP_CONFIG.actions[0].value.mul(100000)),
])
await hre.ethers.provider.send('hardhat_setBalance', [
DEFAULT_DRIP_CONFIG.actions[0].target,
'0x0',
])
})
describe('create', () => {
describe('when called by authorized address', () => {
it('should create a drip with the given name', async () => {
await expect(
Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
).to.emit(Drippie, 'DripCreated')
const drip = await Drippie.drips(DEFAULT_DRIP_NAME)
expect(drip.status).to.equal(2) // PAUSED
expect(drip.last).to.deep.equal(hre.ethers.BigNumber.from(0))
expect(drip.config.interval).to.deep.equal(DEFAULT_DRIP_CONFIG.interval)
expect(drip.config.dripcheck).to.deep.equal(
DEFAULT_DRIP_CONFIG.dripcheck
)
expect(drip.config.checkparams).to.deep.equal(
DEFAULT_DRIP_CONFIG.checkparams
)
expect(drip.config.actions[0][0]).to.deep.equal(
DEFAULT_DRIP_CONFIG.actions[0].target
)
expect(drip.config.actions[0][1]).to.deep.equal(
DEFAULT_DRIP_CONFIG.actions[0].data
)
expect(drip.config.actions[0][2]).to.deep.equal(
DEFAULT_DRIP_CONFIG.actions[0].value
)
})
it('should not be able to create the same drip twice', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await expect(
Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
).to.be.revertedWith('Drippie: drip with that name already exists')
})
})
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
Drippie.connect(signer2).create(
DEFAULT_DRIP_NAME,
DEFAULT_DRIP_CONFIG
)
).to.be.revertedWith('Ownable: caller is not the owner')
})
})
})
describe('status', () => {
describe('when called by authorized address', () => {
it('should allow setting between PAUSED and ACTIVE', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
expect((await Drippie.drips(DEFAULT_DRIP_NAME)).status).to.equal(2) // PAUSED
await Drippie.status(DEFAULT_DRIP_NAME, 1) // ACTIVE
expect((await Drippie.drips(DEFAULT_DRIP_NAME)).status).to.equal(1) // ACTIVE
await Drippie.status(DEFAULT_DRIP_NAME, 2) // PAUSED
expect((await Drippie.drips(DEFAULT_DRIP_NAME)).status).to.equal(2) // PAUSED
})
it('should not allow setting status to NONE', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await expect(Drippie.status(DEFAULT_DRIP_NAME, 0)).to.be.revertedWith(
'Drippie: drip status can never be set back to NONE after creation'
)
})
it('should not allow setting status to same status as before', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await expect(Drippie.status(DEFAULT_DRIP_NAME, 2)).to.be.revertedWith(
'Drippie: cannot set drip status to same status as before'
)
})
it('should allow setting status to ARCHIVED if PAUSED', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 3) // ARCHIVED
expect((await Drippie.drips(DEFAULT_DRIP_NAME)).status).to.equal(3) // ARCHIVED
})
it('should not allow setting status to ARCHIVED if ACTIVE', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 1) // ACTIVE
await expect(Drippie.status(DEFAULT_DRIP_NAME, 3)).to.be.revertedWith(
'Drippie: drip must be paused to be archived'
)
})
it('should not allow setting status to PAUSED if ARCHIVED', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 3) // ARCHIVED
await expect(Drippie.status(DEFAULT_DRIP_NAME, 2)).to.be.revertedWith(
'Drippie: drip with that name has been archived'
)
})
it('should not allow setting status to ACTIVE if ARCHIVED', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 3) // ARCHIVED
await expect(Drippie.status(DEFAULT_DRIP_NAME, 1)).to.be.revertedWith(
'Drippie: drip with that name has been archived'
)
})
it('should revert if the drip does not exist yet', async () => {
await expect(Drippie.status(DEFAULT_DRIP_NAME, 1)).to.be.revertedWith(
'Drippie: drip with that name does not exist'
)
})
})
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
Drippie.connect(signer2).status(DEFAULT_DRIP_NAME, 1)
).to.be.revertedWith('Ownable: caller is not the owner')
})
})
})
describe('drip', () => {
it('should drip the amount', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 1) // ACTIVE
await expect(Drippie.drip(DEFAULT_DRIP_NAME)).to.emit(
Drippie,
'DripExecuted'
)
expect(
await signer1.provider.getBalance(DEFAULT_DRIP_CONFIG.actions[0].target)
).to.equal(DEFAULT_DRIP_CONFIG.actions[0].value)
})
it('should be able to trigger one function', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, {
...DEFAULT_DRIP_CONFIG,
actions: [
{
target: SimpleStorage.address,
data: SimpleStorage.interface.encodeFunctionData('set', [
'0x' + '33'.repeat(32),
'0x' + '44'.repeat(32),
]),
value: hre.ethers.BigNumber.from(0),
},
],
})
await Drippie.status(DEFAULT_DRIP_NAME, 1) // ACTIVE
await Drippie.drip(DEFAULT_DRIP_NAME)
expect(await SimpleStorage.get('0x' + '33'.repeat(32))).to.equal(
'0x' + '44'.repeat(32)
)
})
it('should be able to trigger two functions', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, {
...DEFAULT_DRIP_CONFIG,
actions: [
{
target: SimpleStorage.address,
data: SimpleStorage.interface.encodeFunctionData('set', [
'0x' + '33'.repeat(32),
'0x' + '44'.repeat(32),
]),
value: hre.ethers.BigNumber.from(0),
},
{
target: SimpleStorage.address,
data: SimpleStorage.interface.encodeFunctionData('set', [
'0x' + '44'.repeat(32),
'0x' + '55'.repeat(32),
]),
value: hre.ethers.BigNumber.from(0),
},
],
})
await Drippie.status(DEFAULT_DRIP_NAME, 1) // ACTIVE
await Drippie.drip(DEFAULT_DRIP_NAME)
expect(await SimpleStorage.get('0x' + '33'.repeat(32))).to.equal(
'0x' + '44'.repeat(32)
)
expect(await SimpleStorage.get('0x' + '44'.repeat(32))).to.equal(
'0x' + '55'.repeat(32)
)
})
it('should revert if dripping twice in one interval', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 1) // ACTIVE
await Drippie.drip(DEFAULT_DRIP_NAME)
await expect(Drippie.drip(DEFAULT_DRIP_NAME)).to.be.revertedWith(
'Drippie: drip interval has not elapsed'
)
await hre.ethers.provider.send('evm_increaseTime', [
DEFAULT_DRIP_CONFIG.interval.add(1).toHexString(),
])
await expect(Drippie.drip(DEFAULT_DRIP_NAME)).to.not.be.reverted
})
it('should revert when the drip does not exist', async () => {
await expect(Drippie.drip(DEFAULT_DRIP_NAME)).to.be.revertedWith(
'Drippie: selected drip does not exist or is not currently active'
)
})
it('should revert when the drip is not active', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await expect(Drippie.drip(DEFAULT_DRIP_NAME)).to.be.revertedWith(
'Drippie: selected drip does not exist or is not currently active'
)
})
})
})
import hre from 'hardhat'
import { Contract } from 'ethers'
import { toRpcHexString } from '@eth-optimism/core-utils'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
import { encodeDripCheckParams } from '../../../../../src'
describe('CheckBalanceHigh', () => {
const RECIPIENT = '0x' + '11'.repeat(20)
const THRESHOLD = 100
let CheckBalanceHigh: Contract
before(async () => {
CheckBalanceHigh = await deploy('CheckBalanceHigh')
})
describe('check', () => {
it('should return true when balance is above threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD + 1),
])
expect(
await CheckBalanceHigh.check(
encodeDripCheckParams(CheckBalanceHigh.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(true)
})
it('should return false when balance is below threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD - 1),
])
expect(
await CheckBalanceHigh.check(
encodeDripCheckParams(CheckBalanceHigh.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(false)
})
})
})
import hre from 'hardhat'
import { Contract } from 'ethers'
import { toRpcHexString } from '@eth-optimism/core-utils'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
import { encodeDripCheckParams } from '../../../../../src'
describe('CheckBalanceLow', () => {
const RECIPIENT = '0x' + '11'.repeat(20)
const THRESHOLD = 100
let CheckBalanceLow: Contract
before(async () => {
CheckBalanceLow = await deploy('CheckBalanceLow')
})
describe('check', () => {
it('should return true when balance is below threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD - 1),
])
expect(
await CheckBalanceLow.check(
encodeDripCheckParams(CheckBalanceLow.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(true)
})
it('should return false when balance is above threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD + 1),
])
expect(
await CheckBalanceLow.check(
encodeDripCheckParams(CheckBalanceLow.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(false)
})
})
})
import { Contract } from 'ethers'
import { smock, FakeContract } from '@defi-wonderland/smock'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
import { encodeDripCheckParams } from '../../../../../src'
describe('CheckGelatoLow', () => {
const RECIPIENT = '0x' + '11'.repeat(20)
const THRESHOLD = 100
let CheckGelatoLow: Contract
let FakeGelatoTresury: FakeContract<Contract>
before(async () => {
CheckGelatoLow = await deploy('CheckGelatoLow')
FakeGelatoTresury = await smock.fake('IGelatoTreasury')
})
describe('check', () => {
it('should return true when balance is below threshold', async () => {
FakeGelatoTresury.userTokenBalance.returns(THRESHOLD - 1)
expect(
await CheckGelatoLow.check(
encodeDripCheckParams(CheckGelatoLow.interface, {
treasury: FakeGelatoTresury.address,
threshold: THRESHOLD,
recipient: RECIPIENT,
})
)
).to.equal(true)
})
it('should return false when balance is above threshold', async () => {
FakeGelatoTresury.userTokenBalance.returns(THRESHOLD + 1)
expect(
await CheckGelatoLow.check(
encodeDripCheckParams(CheckGelatoLow.interface, {
treasury: FakeGelatoTresury.address,
threshold: THRESHOLD,
recipient: RECIPIENT,
})
)
).to.equal(false)
})
})
})
import { Contract } from 'ethers'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
describe('CheckTrue', () => {
let CheckTrue: Contract
before(async () => {
CheckTrue = await deploy('CheckTrue')
})
describe('check', () => {
it('should return true', async () => {
expect(await CheckTrue.check('0x')).to.equal(true)
})
})
})
export * from './deploy'
export * from './solidity'
import { ethers } from 'ethers'
export const decodeSolidityRevert = (revert: string) => {
const iface = new ethers.utils.Interface([
{
inputs: [
{
internalType: 'string',
name: 'message',
type: 'string',
},
],
name: 'Error',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
])
return iface.decodeFunctionData('Error', revert)[0]
}
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"resolveJsonModule": true,
}
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
......@@ -7,4 +7,14 @@ ignores: [
"prettier-plugin-solidity",
"solhint-plugin-prettier",
"ts-generator",
"@babel/eslint-parser",
"@typescript-eslint/parser",
"eslint-plugin-import",
"eslint-plugin-unicorn",
"eslint-plugin-jsdoc",
"eslint-plugin-prefer-arrow",
"eslint-plugin-react",
"@typescript-eslint/eslint-plugin",
"eslint-config-prettier",
"eslint-plugin-prettier"
]
......@@ -22,7 +22,7 @@ const enableGasReport = !!process.env.ENABLE_GAS_REPORT
const privateKey = process.env.PRIVATE_KEY || '0x' + '11'.repeat(32) // this is to avoid hardhat error
const deploy = process.env.DEPLOY_DIRECTORY || 'deploy'
const config: HardhatUserConfig = {
const config: HardhatUserConfig | any = {
networks: {
hardhat: {
live: false,
......
......@@ -18,7 +18,7 @@
],
"scripts": {
"build": "yarn build:contracts && yarn autogen:artifacts && yarn build:typescript",
"build:typescript": "tsc -p ./tsconfig.build.json",
"build:typescript": "tsc -p ./tsconfig.json",
"build:contracts": "hardhat compile --show-stack-traces",
"autogen:markdown": "ts-node scripts/generate-markdown.ts",
"autogen:artifacts": "ts-node scripts/generate-artifacts.ts && ts-node scripts/generate-deployed-artifacts.ts",
......@@ -35,7 +35,7 @@
"lint:contracts:fix": "yarn prettier --write 'contracts/**/*.sol'",
"lint:fix": "yarn lint:contracts:fix && yarn lint:ts:fix",
"lint": "yarn lint:fix && yarn lint:check",
"clean": "rm -rf ./dist ./artifacts ./cache ./coverage ./tsconfig.build.tsbuildinfo",
"clean": "rm -rf ./dist ./artifacts ./cache ./coverage ./tsconfig.tsbuildinfo",
"prepublishOnly": "yarn copyfiles -u 1 -e \"**/test-*/**/*\" \"contracts/**/*\" ./",
"postpublish": "rimraf chugsplash L1 L2 libraries standards",
"prepack": "yarn prepublishOnly",
......@@ -82,21 +82,10 @@
"@types/mkdirp": "^1.0.1",
"@types/mocha": "^8.2.2",
"@types/node": "^17.0.21",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"chai": "^4.3.4",
"copyfiles": "^2.3.0",
"directory-tree": "^2.2.7",
"dotenv": "^10.0.0",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"ethereum-waffle": "^3.3.0",
"ethers": "^5.6.8",
"glob": "^7.1.6",
......
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"resolveJsonModule": true,
}
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
ignores: [
"@babel/eslint-parser",
"@typescript-eslint/parser",
"eslint-plugin-import",
"eslint-plugin-unicorn",
"eslint-plugin-jsdoc",
"eslint-plugin-prefer-arrow",
"eslint-plugin-react",
"@typescript-eslint/eslint-plugin",
"eslint-config-prettier",
"eslint-plugin-prettier",
"chai"
]
......@@ -9,8 +9,8 @@
],
"scripts": {
"all": "yarn clean && yarn build && yarn test && yarn lint:fix && yarn lint",
"build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"build": "tsc -p tsconfig.json",
"clean": "rimraf dist/ ./tsconfig.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check",
"lint:check": "eslint . --max-warnings=0",
"lint:fix": "yarn lint:check --fix",
......@@ -40,24 +40,6 @@
"ethers": "^5.6.8"
},
"devDependencies": {
"@types/chai": "^4.2.18",
"@types/mocha": "^8.2.2",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"lint-staged": "11.0.0",
"mocha": "^8.4.0",
"nyc": "^15.1.0",
"prettier": "^2.3.1",
"ts-mocha": "^8.0.0",
"typescript": "^4.6.2"
"mocha": "^10.0.0"
}
}
......@@ -7,36 +7,52 @@ export interface State {
[address: string]: {
nonce: number
balance: string
codeHash: string
root: string
codeHash?: string
root?: string
code?: string
storage?: {
[key: string]: string
}
secretKey?: string
}
}
/**
* Represents Geth's ChainConfig
*/
export interface ChainConfig {
chainId: number
homesteadBlock: number
eip150Block: number
eip155Block: number
eip158Block: number
byzantiumBlock: number
constantinopleBlock: number
petersburgBlock: number
istanbulBlock: number
muirGlacierBlock: number
berlinBlock: number
londonBlock?: number
arrowGlacierBlock?: number
mergeForkBlock?: number
terminalTotalDifficulty?: number
clique?: {
period: number
epoch: number
}
ethash?: {}
}
/**
* Represents Geth's genesis file format.
*/
export interface Genesis {
config: {
chainId: number
homesteadBlock: number
eip150Block: number
eip155Block: number
eip158Block: number
byzantiumBlock: number
constantinopleBlock: number
petersburgBlock: number
istanbulBlock: number
muirGlacierBlock: number
clique: {
period: number
epoch: number
}
}
config: ChainConfig
nonce?: number
timestamp?: number
difficulty: string
mixHash?: string
coinbase?: string
gasLimit: string
extraData: string
alloc: State
......
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"typeRoots": ["node_modules/@types", "src/@types"]
}
"rootDir": "./src",
"outDir": "./dist"
},
"compilerOptions": {
"typeRoots": ["node_modules/@types"]
},
"include": [
"src/**/*"
]
}
ignores: [
"@babel/eslint-parser",
"@typescript-eslint/parser",
"eslint-plugin-import",
"eslint-plugin-unicorn",
"eslint-plugin-jsdoc",
"eslint-plugin-prefer-arrow",
"eslint-plugin-react",
"@typescript-eslint/eslint-plugin",
"eslint-config-prettier",
"eslint-plugin-prettier",
"chai"
]
......@@ -9,7 +9,7 @@
"dist/index"
],
"scripts": {
"clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo",
"clean": "rimraf ./dist ./tsconfig.tsbuildinfo",
"clean:db": "rimraf ./db",
"lint": "yarn run lint:fix && yarn run lint:check",
"lint:fix": "yarn lint:check --fix",
......@@ -18,7 +18,7 @@
"start:local": "ts-node ./src/services/run.ts | pino-pretty",
"test": "hardhat --config test/config/hardhat.config.ts test",
"test:coverage": "nyc hardhat --config test/config/hardhat.config.ts test && nyc merge .nyc_output coverage.json",
"build": "tsc -p tsconfig.build.json",
"build": "tsc -p tsconfig.json",
"pre-commit": "lint-staged"
},
"keywords": [
......@@ -56,33 +56,16 @@
"levelup": "^4.4.0"
},
"devDependencies": {
"@types/chai": "^4.2.18",
"@types/chai-as-promised": "^7.1.4",
"@types/cors": "^2.8.9",
"@types/levelup": "^4.3.0",
"@types/mocha": "^8.2.2",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"bfj": "^7.0.2",
"chai": "^4.3.4",
"chai-as-promised": "^7.1.1",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"hardhat": "^2.9.6",
"lint-staged": "11.0.0",
"mocha": "^8.4.0",
"pino-pretty": "^4.7.1",
"prettier": "^2.3.1",
"prom-client": "^13.1.0",
"rimraf": "^3.0.2",
"ts-node": "^10.0.0",
"typescript": "^4.6.2"
"ts-node": "^10.0.0"
}
}
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"typeRoots": ["node_modules/@types", "src/@types"]
}
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
ignores: [
"@babel/eslint-parser",
"@typescript-eslint/parser",
"eslint-plugin-import",
"eslint-plugin-unicorn",
"eslint-plugin-jsdoc",
"eslint-plugin-prefer-arrow",
"eslint-plugin-react",
"@typescript-eslint/eslint-plugin",
"eslint-config-prettier",
"eslint-plugin-prettier",
"chai"
]
......@@ -11,8 +11,8 @@
"scripts": {
"start": "ts-node ./src/service.ts",
"test:coverage": "echo 'No tests defined.'",
"build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"build": "tsc -p tsconfig.json",
"clean": "rimraf dist/ ./tsconfig.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check",
"pre-commit": "lint-staged",
"lint:fix": "yarn lint:check --fix",
......@@ -33,11 +33,9 @@
},
"devDependencies": {
"@types/dateformat": "^5.0.0",
"@types/node": "^17.0.23",
"dateformat": "^4.5.1",
"ethers": "^5.6.8",
"ts-node": "^10.7.0",
"typescript": "^4.6.3"
"ts-node": "^10.7.0"
},
"dependencies": {
"@eth-optimism/common-ts": "^0.2.8",
......
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"resolveJsonModule": true
}
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
......@@ -8,7 +8,7 @@
"lint:fix": "yarn lint:check --fix",
"lint:check": "eslint . --max-warnings=0",
"build:contracts": "forge build --root . -c contracts -o artifacts",
"test": "ts-mocha --timeout 30000 test/**/*.spec.ts",
"test": "echo 'no unit tests'",
"test:actor": "IS_LIVE_NETWORK=true ts-node actor-tests/lib/runner.ts",
"test:integration:live": "NO_NETWORK=true IS_LIVE_NETWORK=true hardhat --network optimism test",
"clean": "rimraf cache artifacts"
......@@ -31,40 +31,17 @@
"@eth-optimism/core-utils": "0.8.5",
"@eth-optimism/sdk": "1.1.6",
"@ethersproject/abstract-provider": "^5.6.1",
"@ethersproject/providers": "^5.6.8",
"@ethersproject/transactions": "^5.6.2",
"@types/chai": "^4.2.18",
"@types/chai-as-promised": "^7.1.4",
"@types/mocha": "^8.2.2",
"@types/rimraf": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"async-mutex": "^0.3.2",
"babel-eslint": "^10.1.0",
"chai": "^4.3.4",
"chai-as-promised": "^7.1.1",
"commander": "^8.3.0",
"chai": "^4.3.4",
"dotenv": "^10.0.0",
"envalid": "^7.1.0",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"ethereum-waffle": "^3.3.0",
"ethers": "^5.6.8",
"mocha": "^8.4.0",
"node-fetch": "^2.6.7",
"prom-client": "^14.0.1",
"rimraf": "^3.0.2",
"ts-node": "^10.7.0",
"typescript": "^4.3.5"
"ts-node": "^10.7.0"
},
"dependencies": {
"ts-mocha": "^9.0.2",
"rlp": "^3.0.0",
"winston": "^3.7.2"
}
}
......@@ -2,30 +2,41 @@
// can fall behind.
/* Imports: External */
import { BigNumber, constants, Contract, ContractReceipt, utils, Wallet } from 'ethers'
import {
BigNumber,
constants,
Contract,
ContractReceipt,
utils,
Wallet,
} from 'ethers'
import { awaitCondition } from '@eth-optimism/core-utils'
import * as rlp from 'rlp'
import { Block } from '@ethersproject/abstract-provider'
/* Imports: Internal */
import env from './shared/env'
import { expect } from './shared/setup'
import winston from 'winston'
import { predeploys } from '@eth-optimism/contracts'
const l2ToL1MessagePasserArtifact = require('../../contracts/artifacts/contracts/L2/L2ToL1MessagePasser.sol/L2ToL1MessagePasser.json')
const l2OOracleArtifact = require('../../contracts/artifacts/contracts/L1/L2OutputOracle.sol/L2OutputOracle.json')
import env from './shared/env'
import { expect } from './shared/setup'
import l2ToL1MessagePasserArtifact from '../../contracts-bedrock/artifacts/contracts/L2/L2ToL1MessagePasser.sol/L2ToL1MessagePasser.json'
import l2OOracleArtifact from '../../contracts-bedrock/artifacts/contracts/L1/L2OutputOracle.sol/L2OutputOracle.json'
/**
* Calculates the target output timestamp to make the withdrawal proof against. ie. the first
* output with a timestamp greater than the burn block timestamp.
*
* @param {Contract} oracle Address of the L2 Output Oracle.
* @param {number} withdrawalTimestamp L2 timestamp of the block the withdrawal was made in.
*/
const getTargetOutput = async (oracle: Contract, withdrawalTimestamp: number) => {
const getTargetOutput = async (
oracle: Contract,
withdrawalTimestamp: number
) => {
const submissionInterval = (await oracle.SUBMISSION_INTERVAL()).toNumber()
const startingBlockTimestamp = (await oracle.STARTING_BLOCK_TIMESTAMP()).toNumber()
let nextTimestamp = (await oracle.nextTimestamp()).toNumber()
const startingBlockTimestamp = (
await oracle.STARTING_BLOCK_TIMESTAMP()
).toNumber()
const nextTimestamp = (await oracle.nextTimestamp()).toNumber()
let targetOutputTimestamp
if (withdrawalTimestamp < nextTimestamp) {
// Just use the next timestamp
......@@ -33,18 +44,16 @@ const getTargetOutput = async (oracle: Contract, withdrawalTimestamp: number) =>
} else {
// Calculate the first timestamp greater than the burnBlock which will be appended.
targetOutputTimestamp =
Math.ceil(
(withdrawalTimestamp - startingBlockTimestamp)
/ submissionInterval
)
* submissionInterval
+ startingBlockTimestamp
Math.ceil(
(withdrawalTimestamp - startingBlockTimestamp) / submissionInterval
) *
submissionInterval +
startingBlockTimestamp
}
return targetOutputTimestamp
}
describe('Withdrawals', () => {
let logger: winston.Logger
let portal: Contract
......@@ -58,7 +67,7 @@ describe('Withdrawals', () => {
withdrawer = new Contract(
predeploys.OVM_L2ToL1MessagePasser,
l2ToL1MessagePasserArtifact.abi,
l2ToL1MessagePasserArtifact.abi
)
})
......@@ -78,16 +87,18 @@ describe('Withdrawals', () => {
recipient: recipient.address,
})
logger.info('Depositing to new address on L2')
let tx = await portal.connect(env.l1Wallet).depositTransaction(
recipient.address,
utils.parseEther('1.337'),
gasLimit,
false,
[],
{
value: utils.parseEther('1.337'),
},
)
let tx = await portal
.connect(env.l1Wallet)
.depositTransaction(
recipient.address,
utils.parseEther('1.337'),
gasLimit,
false,
[],
{
value: utils.parseEther('1.337'),
}
)
await tx.wait()
await awaitCondition(async () => {
......@@ -111,7 +122,7 @@ describe('Withdrawals', () => {
[],
{
value,
},
}
)
const receipt: ContractReceipt = await tx.wait()
expect(receipt.events!.length).to.eq(1)
......@@ -135,8 +146,8 @@ describe('Withdrawals', () => {
value,
gasLimit,
'0x',
],
),
]
)
)
const included = await withdrawer.sentMessages(withdrawalHash)
......@@ -150,39 +161,52 @@ describe('Withdrawals', () => {
portal = portal.connect(recipient)
const oracle = new Contract(
await portal.L2_ORACLE(),
l2OOracleArtifact.abi,
l2OOracleArtifact.abi
).connect(recipient)
const targetOutputTimestamp = await getTargetOutput(oracle, burnBlock.timestamp)
const targetOutputTimestamp = await getTargetOutput(
oracle,
burnBlock.timestamp
)
// Set the timeout based on the diff between latest output and target output timestamp.
let latestBlockTimestamp = (await oracle.latestBlockTimestamp()).toNumber()
let latestBlockTimestamp = (
await oracle.latestBlockTimestamp()
).toNumber()
let difference = targetOutputTimestamp - latestBlockTimestamp
this.timeout(difference * 5000)
let output: string
await awaitCondition(async () => {
const proposal = await oracle.getL2Output(targetOutputTimestamp)
output = proposal.outputRoot
latestBlockTimestamp = (await oracle.latestBlockTimestamp()).toNumber()
if(targetOutputTimestamp - latestBlockTimestamp < difference){
// Only log when a new output has been appended
difference = targetOutputTimestamp - latestBlockTimestamp
logger.info('Waiting for output submission', {
targetTimestamp: targetOutputTimestamp,
latestOracleTS: latestBlockTimestamp,
difference,
output,
})
}
return output != constants.HashZero
}, 2000, 2*difference)
await awaitCondition(
async () => {
const proposal = await oracle.getL2Output(targetOutputTimestamp)
output = proposal.outputRoot
latestBlockTimestamp = (
await oracle.latestBlockTimestamp()
).toNumber()
if (targetOutputTimestamp - latestBlockTimestamp < difference) {
// Only log when a new output has been appended
difference = targetOutputTimestamp - latestBlockTimestamp
logger.info('Waiting for output submission', {
targetTimestamp: targetOutputTimestamp,
latestOracleTS: latestBlockTimestamp,
difference,
output,
})
}
return output !== constants.HashZero
},
2000,
2 * difference
)
// suppress compilation errors since Typescript cannot detect
// that awaitCondition above will throw if it times out.
output = output!
const blocksSinceBurn = Math.floor((targetOutputTimestamp - burnBlock.timestamp) / 2)
const blocksSinceBurn = Math.floor(
(targetOutputTimestamp - burnBlock.timestamp) / 2
)
const targetBlockNum = burnBlock.number + blocksSinceBurn + 1
const targetBlockNumHex = utils.hexValue(targetBlockNum)
const storageSlot = '00'.repeat(31) + '01' // i.e the second variable declared in the contract
......@@ -192,19 +216,19 @@ describe('Withdrawals', () => {
targetBlockNumHex,
])
const {stateRoot: targetStateRoot, hash: targetHash} = await env.l2Provider.send(
'eth_getBlockByNumber',
[
const { stateRoot: targetStateRoot, hash: targetHash } =
await env.l2Provider.send('eth_getBlockByNumber', [
targetBlockNumHex,
false,
],
)
])
const finalizationPeriod = (await portal.FINALIZATION_PERIOD()).toNumber()
logger.info('Waiting finalization period', {
seconds: finalizationPeriod,
})
await new Promise((resolve) => setTimeout(resolve, finalizationPeriod * 1000))
await new Promise((resolve) =>
setTimeout(resolve, finalizationPeriod * 1000)
)
logger.info('Finalizing withdrawal')
const initialBal = await recipient.getBalance()
......@@ -225,7 +249,7 @@ describe('Withdrawals', () => {
rlp.encode(proof.storageProof[0].proof),
{
gasLimit,
},
}
)
await tx.wait()
const finalBal = await recipient.getBalance()
......
......@@ -5,9 +5,8 @@ import { awaitCondition } from '@eth-optimism/core-utils'
/* Imports: Internal */
import { defaultTransactionFactory } from './shared/utils'
import env from './shared/env'
const counterArtifact = require('../artifacts/Counter.sol/Counter.json')
const multiDepositorArtifact = require('../artifacts/MultiDepositor.sol/MultiDepositor.json')
import counterArtifact from '../artifacts/Counter.sol/Counter.json'
import multiDepositorArtifact from '../artifacts/MultiDepositor.sol/MultiDepositor.json'
describe('Deposits', () => {
let portal: Contract
......@@ -29,7 +28,7 @@ describe('Deposits', () => {
[],
{
value: tx.value,
},
}
)
await result.wait()
......@@ -44,7 +43,7 @@ describe('Deposits', () => {
const value = utils.parseEther('0.1')
const factory = new ContractFactory(
multiDepositorArtifact.abi,
multiDepositorArtifact.bytecode.object,
multiDepositorArtifact.bytecode.object
).connect(env.l1Wallet)
const contract = await factory.deploy(portal.address)
await contract.deployed()
......@@ -63,7 +62,7 @@ describe('Deposits', () => {
const value = utils.parseEther('0.1')
const factory = new ContractFactory(
counterArtifact.abi,
counterArtifact.bytecode.object,
counterArtifact.bytecode.object
)
const tx = await factory.getDeployTransaction()
const result = await portal.depositTransaction(
......@@ -73,8 +72,8 @@ describe('Deposits', () => {
true,
tx.data,
{
value: value,
},
value,
}
)
await result.wait()
const l2Nonce = await env.l2Wallet.getTransactionCount()
......
......@@ -5,8 +5,7 @@ import { ContractFactory, Wallet } from 'ethers'
import { expect } from './shared/setup'
import { defaultTransactionFactory } from './shared/utils'
import env from './shared/env'
const counterArtifact = require('../artifacts/Counter.sol/Counter.json')
import counterArtifact from '../artifacts/Counter.sol/Counter.json'
describe('RPCs', () => {
let wallet: Wallet
......@@ -38,10 +37,10 @@ describe('RPCs', () => {
it('should correctly process a contract creation', async () => {
const factory = new ContractFactory(
counterArtifact.abi,
counterArtifact.bytecode.object,
counterArtifact.bytecode.object
).connect(wallet)
const counter = await factory.deploy({
gasLimit: 1_000_000
gasLimit: 1_000_000,
})
await counter.deployed()
expect(await env.l2Provider.getCode(counter.address)).not.to.equal('0x')
......
......@@ -2,27 +2,26 @@
import { Wallet, providers, Contract } from 'ethers'
import { bool, cleanEnv, num, str } from 'envalid'
import dotenv from 'dotenv'
import winston, { info } from 'winston'
import winston from 'winston'
const {combine, timestamp, printf, colorize, align} = winston.format
const { combine, timestamp, printf, colorize, align } = winston.format
/* Imports: Internal */
const portalArtifact = require('../../../contracts/artifacts/contracts/L1/OptimismPortal.sol/OptimismPortal.json')
import portalArtifact from '../../../contracts-bedrock/artifacts/contracts/L1/OptimismPortal.sol/OptimismPortal.json'
dotenv.config()
const procEnv = cleanEnv(process.env, {
L1_URL: str({default: 'http://localhost:8545'}),
L1_POLLING_INTERVAL: num({default: 10}),
L1_URL: str({ default: 'http://localhost:8545' }),
L1_POLLING_INTERVAL: num({ default: 10 }),
L2_URL: str({default: 'http://localhost:9545'}),
L2_POLLING_INTERVAL: num({default: 1}),
L2_URL: str({ default: 'http://localhost:9545' }),
L2_POLLING_INTERVAL: num({ default: 1 }),
OPTIMISM_PORTAL_ADDRESS: str(),
PRIVATE_KEY: str({
default:
'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
default: 'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
}),
MOCHA_TIMEOUT: num({
......@@ -72,13 +71,13 @@ export class OptimismEnv {
this.l2Provider = l2Provider
this.optimismPortal = new Contract(
procEnv.OPTIMISM_PORTAL_ADDRESS,
portalArtifact.abi,
portalArtifact.abi
)
this.logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: combine(
{
transform(info) {
transform: (info) => {
// @ts-ignore
const args = info[Symbol.for('splat')]
const meta = args ? args[0] : null
......@@ -87,16 +86,18 @@ export class OptimismEnv {
return info
},
},
colorize({all: true}),
colorize({ all: true }),
timestamp({
format: 'YYYY-MM-DD hh:mm:ss.SSS A',
}),
align(),
printf((info) => `[${info.timestamp}] ${info.level}: ${info.message}`),
printf((info) => `[${info.timestamp}] ${info.level}: ${info.message}`)
),
transports: [new winston.transports.Stream({
stream: process.stderr,
})],
transports: [
new winston.transports.Stream({
stream: process.stderr,
}),
],
})
}
}
......
......@@ -7,4 +7,4 @@ chai.use(solidity)
chai.use(chaiAsPromised)
const expect = chai.expect
export { expect }
\ No newline at end of file
export { expect }
......@@ -8,4 +8,3 @@ export const defaultTransactionFactory = () => {
value: BigNumber.from(0),
}
}
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "dist",
"declaration": true,
"resolveJsonModule": true
"outDir": "./dist"
},
"include": [
"src/**/*",
"./test",
"./artifacts/**/*.json",
"./tasks/**/*.ts",
......
ignores: [
"@babel/eslint-parser",
"@typescript-eslint/parser",
"eslint-plugin-import",
"eslint-plugin-unicorn",
"eslint-plugin-jsdoc",
"eslint-plugin-prefer-arrow",
"eslint-plugin-react",
"@typescript-eslint/eslint-plugin",
"eslint-config-prettier",
"eslint-plugin-prettier",
"chai"
]
......@@ -11,8 +11,8 @@
"scripts": {
"start": "ts-node ./src/service.ts",
"test:coverage": "echo 'No tests defined.'",
"build": "tsc -p ./tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"build": "tsc -p ./tsconfig.json",
"clean": "rimraf dist/ ./tsconfig.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check",
"pre-commit": "lint-staged",
"lint:fix": "yarn lint:check --fix",
......@@ -40,22 +40,8 @@
"@ethersproject/abstract-provider": "^5.6.1",
"@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"ethereum-waffle": "^3.3.0",
"hardhat": "^2.9.6",
"lint-staged": "11.0.0",
"prettier": "^2.3.1",
"ts-node": "^10.0.0",
"typescript": "^4.6.2"
"ts-node": "^10.0.0"
}
}
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
\ No newline at end of file
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"resolveJsonModule": true
}
}
\ No newline at end of file
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
......@@ -11,8 +11,8 @@
"scripts": {
"start": "ts-node ./src/service",
"test:coverage": "echo 'No tests defined.'",
"build": "tsc -p tsconfig.build.json",
"clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo",
"build": "tsc -p tsconfig.json",
"clean": "rimraf ./dist ./tsconfig.tsbuildinfo",
"lint": "yarn run lint:fix && yarn run lint:check",
"pre-commit": "lint-staged",
"lint:fix": "yarn lint:check --fix",
......@@ -37,19 +37,6 @@
"@ethersproject/abstract-provider": "^5.6.1"
},
"devDependencies": {
"@types/node": "^15.12.2",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"lint-staged": "11.0.0",
"ts-node": "^10.0.0",
"typescript": "^4.6.2"
"ts-node": "^10.0.0"
}
}
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
{
"extends": "../../tsconfig.json"
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
ignores: [
"@eth-optimism/core-utils",
"ts-mocha",
"typedoc",
"@babel/eslint-parser",
"@typescript-eslint/parser",
"eslint-plugin-import",
"eslint-plugin-unicorn",
"eslint-plugin-jsdoc",
"eslint-plugin-prefer-arrow",
"eslint-plugin-react",
"@typescript-eslint/eslint-plugin",
"eslint-config-prettier",
"eslint-plugin-prettier",
"chai",
"typedoc"
]
......@@ -9,8 +9,8 @@
],
"scripts": {
"all": "yarn clean && yarn build && yarn test && yarn lint:fix && yarn lint",
"build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"build": "tsc -p tsconfig.json",
"clean": "rimraf dist/ ./tsconfig.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check",
"lint:check": "eslint . --max-warnings=0",
"lint:fix": "yarn lint:check --fix",
......@@ -37,32 +37,13 @@
"@ethersproject/transactions": "^5.6.2",
"@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@types/chai": "^4.2.18",
"@types/chai-as-promised": "^7.1.4",
"@types/mocha": "^8.2.2",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"chai": "^4.3.4",
"chai-as-promised": "^7.1.1",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"ethereum-waffle": "^3.4.0",
"ethers": "^5.6.8",
"hardhat": "^2.9.6",
"lint-staged": "11.0.0",
"mocha": "^8.4.0",
"nyc": "^15.1.0",
"prettier": "^2.3.1",
"ts-mocha": "^8.0.0",
"typedoc": "^0.22.13",
"typescript": "^4.6.2"
"mocha": "^10.0.0"
},
"dependencies": {
"@eth-optimism/contracts": "0.5.25",
......
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
{
"extends": "../../tsconfig.json"
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
{
"compilerOptions": {
"module": "commonjs",
"target": "es2017",
"sourceMap": true,
"esModuleInterop": true,
"composite": true,
"resolveJsonModule": true,
"declaration": true,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"typeRoots": [
"node_modules/@types"
]
},
"exclude": [
"node_modules",
"dist"
]
}
{
"extends": "./tsconfig.build.json"
"compilerOptions": {
"module": "commonjs",
"target": "es2022",
"sourceMap": true,
"esModuleInterop": true,
"composite": true,
"resolveJsonModule": true,
"declaration": true,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"typeRoots": [
"node_modules/@types"
]
},
"exclude": [
"node_modules",
"dist"
]
}
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment