Commit 3bc8c737 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into jm/monitoring/package

parents 2b931bc3 bd907f6c
...@@ -513,8 +513,9 @@ jobs: ...@@ -513,8 +513,9 @@ jobs:
command: | command: |
# Note: We don't use circle CI test splits because we need to split by test name, not by package. There is an additional # Note: We don't use circle CI test splits because we need to split by test name, not by package. There is an additional
# constraint that gotestsum does not currently (nor likely will) accept files from different pacakges when building. # constraint that gotestsum does not currently (nor likely will) accept files from different pacakges when building.
OP_TESTLOG_DISABLE_COLOR=true OP_E2E_DISABLE_PARALLEL=true OP_E2E_USE_HTTP=<<parameters.use_http>> gotestsum \ OP_TESTLOG_DISABLE_COLOR=true OP_E2E_DISABLE_PARALLEL=false OP_E2E_USE_HTTP=<<parameters.use_http>> gotestsum \
--format=standard-verbose --junitfile=/tmp/test-results/<<parameters.module>>_http_<<parameters.use_http>>.xml ./... --format=standard-verbose --junitfile=/tmp/test-results/<<parameters.module>>_http_<<parameters.use_http>>.xml \
-- -timeout=20m
working_directory: <<parameters.module>> working_directory: <<parameters.module>>
- store_test_results: - store_test_results:
path: /tmp/test-results path: /tmp/test-results
...@@ -830,45 +831,6 @@ workflows: ...@@ -830,45 +831,6 @@ workflows:
- contracts-bedrock-tests: - contracts-bedrock-tests:
requires: requires:
- yarn-monorepo - yarn-monorepo
- bedrock-echidna-build:
requires:
- yarn-monorepo
- bedrock-echidna-run:
name: Bedrock Echidna Alias Test
echidna_target: aliasing
requires:
- bedrock-echidna-build
- bedrock-echidna-run:
name: Bedrock Echidna Eth Burn Test
echidna_target: "burn:eth"
requires:
- bedrock-echidna-build
- bedrock-echidna-run:
name: Bedrock Echidna Gas Burn Test
echidna_target: "burn:gas"
size: 2xlarge
requires:
- bedrock-echidna-build
- bedrock-echidna-run:
name: Bedrock Echidna Encoding Test
echidna_target: encoding
requires:
- bedrock-echidna-build
- bedrock-echidna-run:
name: Bedrock Echidna Metering Test
echidna_target: metering
requires:
- bedrock-echidna-build
- bedrock-echidna-run:
name: Bedrock Echidna Hashing Test
echidna_target: hashing
requires:
- bedrock-echidna-build
- bedrock-echidna-run:
name: Bedrock Echidna Portal Test
echidna_target: portal
requires:
- bedrock-echidna-build
- op-bindings-build: - op-bindings-build:
requires: requires:
- yarn-monorepo - yarn-monorepo
......
queue_rules: queue_rules:
- name: default - name: default
speculative_checks: 3
conditions: [] conditions: []
pull_request_rules: pull_request_rules:
...@@ -11,6 +10,7 @@ pull_request_rules: ...@@ -11,6 +10,7 @@ pull_request_rules:
- "#approved-reviews-by>=1" - "#approved-reviews-by>=1"
- "#changes-requested-reviews-by=0" - "#changes-requested-reviews-by=0"
- "label!=do-not-merge" - "label!=do-not-merge"
- "label!=multiple-reviewers"
- "label!=mergify-ignore" - "label!=mergify-ignore"
- "base=develop" - "base=develop"
- or: - or:
......
...@@ -11,18 +11,18 @@ use ( ...@@ -11,18 +11,18 @@ use (
./op-batcher ./op-batcher
./op-bindings ./op-bindings
./op-chain-ops ./op-chain-ops
./op-wheel
./op-e2e ./op-e2e
./op-exporter ./op-exporter
./op-heartbeat ./op-heartbeat
./op-node ./op-node
./op-proposer ./op-proposer
./op-service ./op-service
./proxyd ./op-wheel
./packages/contracts-bedrock/test-case-generator ./packages/contracts-bedrock/test-case-generator
./proxyd
) )
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468
// For local debugging: // For local debugging:
//replace github.com/ethereum/go-ethereum v1.10.26 => ../go-ethereum //replace github.com/ethereum/go-ethereum v1.10.26 => ../go-ethereum
...@@ -50,7 +50,6 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV ...@@ -50,7 +50,6 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4=
github.com/Shopify/sarama v1.19.0 h1:9oksLxC6uxVPHPVYUmq6xhr1BOF/hHobWH2UzO67z1s= github.com/Shopify/sarama v1.19.0 h1:9oksLxC6uxVPHPVYUmq6xhr1BOF/hHobWH2UzO67z1s=
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
...@@ -156,6 +155,8 @@ github.com/ethereum-optimism/op-geth v0.0.0-20221028165624-03aeaf2c39a5 h1:b0ySU ...@@ -156,6 +155,8 @@ github.com/ethereum-optimism/op-geth v0.0.0-20221028165624-03aeaf2c39a5 h1:b0ySU
github.com/ethereum-optimism/op-geth v0.0.0-20221028165624-03aeaf2c39a5/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo= github.com/ethereum-optimism/op-geth v0.0.0-20221028165624-03aeaf2c39a5/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo=
github.com/ethereum-optimism/op-geth v0.0.0-20221104125741-d6c1bb9a110d h1:rDRvYVDftip53l1igBiLa3+CLPmIH2r0of2GTArMC60= github.com/ethereum-optimism/op-geth v0.0.0-20221104125741-d6c1bb9a110d h1:rDRvYVDftip53l1igBiLa3+CLPmIH2r0of2GTArMC60=
github.com/ethereum-optimism/op-geth v0.0.0-20221104125741-d6c1bb9a110d/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo= github.com/ethereum-optimism/op-geth v0.0.0-20221104125741-d6c1bb9a110d/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo=
github.com/ethereum-optimism/op-geth v0.0.0-20221215174217-c69b1f12761e h1:kdpBVWv7Rs/LbM8o8QyJlEBNiA2sw1GEhGyn4pkpesw=
github.com/ethereum-optimism/op-geth v0.0.0-20221215174217-c69b1f12761e/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
...@@ -310,7 +311,6 @@ github.com/klauspost/cpuid/v2 v2.2.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t ...@@ -310,7 +311,6 @@ github.com/klauspost/cpuid/v2 v2.2.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 h1:KAZ1BW2TCmT6PRihDPpocIy1QTtsAsrx6TneU/4+CMg= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 h1:KAZ1BW2TCmT6PRihDPpocIy1QTtsAsrx6TneU/4+CMg=
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada h1:3L+neHp83cTjegPdCiOxVOJtRIy7/8RldvMTsyPYH10= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada h1:3L+neHp83cTjegPdCiOxVOJtRIy7/8RldvMTsyPYH10=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4= github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4=
github.com/labstack/echo/v4 v4.5.0 h1:JXk6H5PAw9I3GwizqUHhYyS4f45iyGebR/c1xNCeOCY= github.com/labstack/echo/v4 v4.5.0 h1:JXk6H5PAw9I3GwizqUHhYyS4f45iyGebR/c1xNCeOCY=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity ^0.8.9; pragma solidity ^0.8.9;
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { OptimismMintableERC721 } from "@eth-optimism/contracts-periphery/contracts/universal/op-erc721/OptimismMintableERC721.sol"; import { OptimismMintableERC721 } from "@eth-optimism/contracts-bedrock/contracts/universal/OptimismMintableERC721.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
contract FakeOptimismMintableERC721 is OptimismMintableERC721 { contract FakeOptimismMintableERC721 is OptimismMintableERC721 {
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.5.4", "@babel/eslint-parser": "^7.5.4",
"@eth-optimism/contracts": "^0.5.39", "@eth-optimism/contracts": "^0.5.39",
"@eth-optimism/contracts-bedrock": "0.11.0",
"@eth-optimism/contracts-periphery": "^1.0.4", "@eth-optimism/contracts-periphery": "^1.0.4",
"@eth-optimism/core-utils": "0.12.0", "@eth-optimism/core-utils": "0.12.0",
"@eth-optimism/sdk": "1.8.0", "@eth-optimism/sdk": "1.8.0",
......
...@@ -4,10 +4,10 @@ import { ethers } from 'hardhat' ...@@ -4,10 +4,10 @@ import { ethers } from 'hardhat'
import { getChainId } from '@eth-optimism/core-utils' import { getChainId } from '@eth-optimism/core-utils'
import { predeploys } from '@eth-optimism/contracts' import { predeploys } from '@eth-optimism/contracts'
import Artifact__TestERC721 from '@eth-optimism/contracts-periphery/artifacts/contracts/testing/helpers/TestERC721.sol/TestERC721.json' import Artifact__TestERC721 from '@eth-optimism/contracts-periphery/artifacts/contracts/testing/helpers/TestERC721.sol/TestERC721.json'
import Artifact__L1ERC721Bridge from '@eth-optimism/contracts-periphery/artifacts/contracts/L1/L1ERC721Bridge.sol/L1ERC721Bridge.json' import Artifact__L1ERC721Bridge from '@eth-optimism/contracts-bedrock/artifacts/contracts/L1/L1ERC721Bridge.sol/L1ERC721Bridge.json'
import Artifact__L2ERC721Bridge from '@eth-optimism/contracts-periphery/artifacts/contracts/L2/L2ERC721Bridge.sol/L2ERC721Bridge.json' import Artifact__L2ERC721Bridge from '@eth-optimism/contracts-bedrock/artifacts/contracts/L2/L2ERC721Bridge.sol/L2ERC721Bridge.json'
import Artifact__OptimismMintableERC721Factory from '@eth-optimism/contracts-periphery/artifacts/contracts/universal/op-erc721/OptimismMintableERC721Factory.sol/OptimismMintableERC721Factory.json' import Artifact__OptimismMintableERC721Factory from '@eth-optimism/contracts-bedrock/artifacts/contracts/universal/OptimismMintableERC721Factory.sol/OptimismMintableERC721Factory.json'
import Artifact__OptimismMintableERC721 from '@eth-optimism/contracts-periphery/artifacts/contracts/universal/op-erc721/OptimismMintableERC721.sol/OptimismMintableERC721.json' import Artifact__OptimismMintableERC721 from '@eth-optimism/contracts-bedrock/artifacts/contracts/universal/OptimismMintableERC721.sol/OptimismMintableERC721.json'
/* Imports: Internal */ /* Imports: Internal */
import { expect } from './shared/setup' import { expect } from './shared/setup'
......
...@@ -93,4 +93,4 @@ require ( ...@@ -93,4 +93,4 @@ require (
lukechampine.com/blake3 v1.1.7 // indirect lukechampine.com/blake3 v1.1.7 // indirect
) )
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468
...@@ -104,8 +104,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m ...@@ -104,8 +104,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 h1:QJL/gtfxGe11tApZIPCeKERQHrLZMAG0RwGV9eTgtvE= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.4 h1:CFn4+t0FUrBG5DmkKyYrLbGmzHWLdLv8QdUnlklvozc= github.com/ethereum-optimism/optimism/op-bindings v0.10.4 h1:CFn4+t0FUrBG5DmkKyYrLbGmzHWLdLv8QdUnlklvozc=
github.com/ethereum-optimism/optimism/op-bindings v0.10.4/go.mod h1:philKV8erP02ggjk2mRIdvJd2ZjMzpmqu0+zwwzKmNw= github.com/ethereum-optimism/optimism/op-bindings v0.10.4/go.mod h1:philKV8erP02ggjk2mRIdvJd2ZjMzpmqu0+zwwzKmNw=
github.com/ethereum-optimism/optimism/op-node v0.10.4 h1:ZXqfrFKgb6W4ZLbkfO9NlgaQ1djBCCPzNGbd6TgehVI= github.com/ethereum-optimism/optimism/op-node v0.10.4 h1:ZXqfrFKgb6W4ZLbkfO9NlgaQ1djBCCPzNGbd6TgehVI=
......
This diff is collapsed.
This diff is collapsed.
...@@ -32,4 +32,4 @@ require ( ...@@ -32,4 +32,4 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468
...@@ -28,8 +28,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1 ...@@ -28,8 +28,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 h1:QJL/gtfxGe11tApZIPCeKERQHrLZMAG0RwGV9eTgtvE= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
......
package predeploys package predeploys
import ( import (
"math/big"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -12,3 +15,26 @@ func TestGethAddresses(t *testing.T) { ...@@ -12,3 +15,26 @@ func TestGethAddresses(t *testing.T) {
// we import geth in the monorepo, and do not want to import op-bindings into geth. // we import geth in the monorepo, and do not want to import op-bindings into geth.
require.Equal(t, L1BlockAddr, types.L1BlockAddr) require.Equal(t, L1BlockAddr, types.L1BlockAddr)
} }
// TestL1BlockSlots ensures that the storage layout of the L1Block
// contract matches the hardcoded values in `op-geth`.
func TestL1BlockSlots(t *testing.T) {
layout, err := bindings.GetStorageLayout("L1Block")
require.NoError(t, err)
var l1BaseFeeSlot, overHeadSlot, scalarSlot common.Hash
for _, entry := range layout.Storage {
switch entry.Label {
case "l1FeeOverhead":
overHeadSlot = common.BigToHash(big.NewInt(int64(entry.Slot)))
case "l1FeeScalar":
scalarSlot = common.BigToHash(big.NewInt(int64(entry.Slot)))
case "basefee":
l1BaseFeeSlot = common.BigToHash(big.NewInt(int64(entry.Slot)))
}
}
require.Equal(t, types.OverheadSlot, overHeadSlot)
require.Equal(t, types.ScalarSlot, scalarSlot)
require.Equal(t, types.L1BaseFeeSlot, l1BaseFeeSlot)
}
...@@ -82,9 +82,10 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) { ...@@ -82,9 +82,10 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) {
uint642Big(config.GasPriceOracleScalar), uint642Big(config.GasPriceOracleScalar),
config.BatchSenderAddress.Hash(), config.BatchSenderAddress.Hash(),
gasLimit, gasLimit,
config.P2PSequencerAddress,
) )
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("cannot abi encode initialize for SystemConfig: %w", err)
} }
if _, err := upgradeProxy( if _, err := upgradeProxy(
backend, backend,
...@@ -106,7 +107,7 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) { ...@@ -106,7 +107,7 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) {
uint642Big(uint64(config.L1GenesisBlockTimestamp)), uint642Big(uint64(config.L1GenesisBlockTimestamp)),
) )
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("cannot abi encode initialize for L2OutputOracle: %w", err)
} }
if _, err := upgradeProxy( if _, err := upgradeProxy(
backend, backend,
...@@ -124,7 +125,7 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) { ...@@ -124,7 +125,7 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) {
} }
data, err = portalABI.Pack("initialize") data, err = portalABI.Pack("initialize")
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("cannot abi encode initialize for OptimismPortal: %w", err)
} }
if _, err := upgradeProxy( if _, err := upgradeProxy(
backend, backend,
...@@ -144,7 +145,7 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) { ...@@ -144,7 +145,7 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) {
config.FinalSystemOwner, config.FinalSystemOwner,
) )
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("cannot abi encode initialize for L1CrossDomainMessenger: %w", err)
} }
if _, err := upgradeProxy( if _, err := upgradeProxy(
backend, backend,
...@@ -268,6 +269,7 @@ func deployL1Contracts(config *DeployConfig, backend *backends.SimulatedBackend) ...@@ -268,6 +269,7 @@ func deployL1Contracts(config *DeployConfig, backend *backends.SimulatedBackend)
uint642Big(config.GasPriceOracleScalar), uint642Big(config.GasPriceOracleScalar),
config.BatchSenderAddress.Hash(), // left-padded 32 bytes value, version is zero anyway config.BatchSenderAddress.Hash(), // left-padded 32 bytes value, version is zero anyway
gasLimit, gasLimit,
config.P2PSequencerAddress,
}, },
}, },
{ {
...@@ -329,6 +331,7 @@ func l1Deployer(backend *backends.SimulatedBackend, opts *bind.TransactOpts, dep ...@@ -329,6 +331,7 @@ func l1Deployer(backend *backends.SimulatedBackend, opts *bind.TransactOpts, dep
deployment.Args[2].(*big.Int), deployment.Args[2].(*big.Int),
deployment.Args[3].(common.Hash), deployment.Args[3].(common.Hash),
deployment.Args[4].(uint64), deployment.Args[4].(uint64),
deployment.Args[5].(common.Address),
) )
case "L2OutputOracle": case "L2OutputOracle":
_, tx, _, err = bindings.DeployL2OutputOracle( _, tx, _, err = bindings.DeployL2OutputOracle(
...@@ -397,6 +400,10 @@ func l1Deployer(backend *backends.SimulatedBackend, opts *bind.TransactOpts, dep ...@@ -397,6 +400,10 @@ func l1Deployer(backend *backends.SimulatedBackend, opts *bind.TransactOpts, dep
} }
} }
if err != nil {
err = fmt.Errorf("cannot deploy %s: %w", deployment.Name, err)
}
return tx, err return tx, err
} }
......
...@@ -54,4 +54,4 @@ require ( ...@@ -54,4 +54,4 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468
...@@ -75,8 +75,8 @@ github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8E ...@@ -75,8 +75,8 @@ github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8E
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 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/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 h1:QJL/gtfxGe11tApZIPCeKERQHrLZMAG0RwGV9eTgtvE= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.4 h1:CFn4+t0FUrBG5DmkKyYrLbGmzHWLdLv8QdUnlklvozc= github.com/ethereum-optimism/optimism/op-bindings v0.10.4 h1:CFn4+t0FUrBG5DmkKyYrLbGmzHWLdLv8QdUnlklvozc=
github.com/ethereum-optimism/optimism/op-bindings v0.10.4/go.mod h1:philKV8erP02ggjk2mRIdvJd2ZjMzpmqu0+zwwzKmNw= github.com/ethereum-optimism/optimism/op-bindings v0.10.4/go.mod h1:philKV8erP02ggjk2mRIdvJd2ZjMzpmqu0+zwwzKmNw=
github.com/ethereum-optimism/optimism/op-node v0.10.1 h1:kVBaOEOYLV22XEHRhB7dfdmoXepO0kx/RsZQK+Bpk1Y= github.com/ethereum-optimism/optimism/op-node v0.10.1 h1:kVBaOEOYLV22XEHRhB7dfdmoXepO0kx/RsZQK+Bpk1Y=
......
...@@ -105,6 +105,7 @@ func (m *MnemonicConfig) Secrets() (*Secrets, error) { ...@@ -105,6 +105,7 @@ func (m *MnemonicConfig) Secrets() (*Secrets, error) {
Alice: alice, Alice: alice,
Bob: bob, Bob: bob,
Mallory: mallory, Mallory: mallory,
Wallet: wallet,
}, nil }, nil
} }
...@@ -123,6 +124,9 @@ type Secrets struct { ...@@ -123,6 +124,9 @@ type Secrets struct {
Alice *ecdsa.PrivateKey Alice *ecdsa.PrivateKey
Bob *ecdsa.PrivateKey Bob *ecdsa.PrivateKey
Mallory *ecdsa.PrivateKey Mallory *ecdsa.PrivateKey
// Share the wallet to be able to generate more accounts
Wallet *hdwallet.Wallet
} }
// EncodePrivKey encodes the given private key in 32 bytes // EncodePrivKey encodes the given private key in 32 bytes
......
...@@ -8,10 +8,10 @@ import ( ...@@ -8,10 +8,10 @@ import (
"math/big" "math/big"
"time" "time"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
...@@ -21,9 +21,45 @@ import ( ...@@ -21,9 +21,45 @@ import (
"github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
) )
func waitForL1OriginOnL2(l1BlockNum uint64, client *ethclient.Client, timeout time.Duration) (*types.Block, error) {
timeoutCh := time.After(timeout)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
headChan := make(chan *types.Header, 100)
headSub, err := client.SubscribeNewHead(ctx, headChan)
if err != nil {
return nil, err
}
defer headSub.Unsubscribe()
for {
select {
case head := <-headChan:
block, err := client.BlockByNumber(ctx, head.Number)
if err != nil {
return nil, err
}
l1Info, err := derive.L1InfoDepositTxData(block.Transactions()[0].Data())
if err != nil {
return nil, err
}
if l1Info.Number >= l1BlockNum {
return block, nil
}
case err := <-headSub.Err():
return nil, fmt.Errorf("Error in head subscription: %w", err)
case <-timeoutCh:
return nil, errors.New("timeout")
}
}
}
func waitForTransaction(hash common.Hash, client *ethclient.Client, timeout time.Duration) (*types.Receipt, error) { func waitForTransaction(hash common.Hash, client *ethclient.Client, timeout time.Duration) (*types.Receipt, error) {
timeoutCh := time.After(timeout) timeoutCh := time.After(timeout)
ticker := time.NewTicker(100 * time.Millisecond) ticker := time.NewTicker(100 * time.Millisecond)
...@@ -72,7 +108,7 @@ func waitForBlock(number *big.Int, client *ethclient.Client, timeout time.Durati ...@@ -72,7 +108,7 @@ func waitForBlock(number *big.Int, client *ethclient.Client, timeout time.Durati
} }
} }
func initL1Geth(cfg *SystemConfig, genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) { func initL1Geth(cfg *SystemConfig, genesis *core.Genesis, opts ...GethOption) (*node.Node, *eth.Ethereum, error) {
ethConfig := &ethconfig.Config{ ethConfig := &ethconfig.Config{
NetworkId: cfg.DeployConfig.L1ChainID, NetworkId: cfg.DeployConfig.L1ChainID,
Genesis: genesis, Genesis: genesis,
...@@ -87,7 +123,7 @@ func initL1Geth(cfg *SystemConfig, genesis *core.Genesis) (*node.Node, *eth.Ethe ...@@ -87,7 +123,7 @@ func initL1Geth(cfg *SystemConfig, genesis *core.Genesis) (*node.Node, *eth.Ethe
HTTPModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine"}, HTTPModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine"},
} }
l1Node, l1Eth, err := createGethNode(false, nodeConfig, ethConfig, []*ecdsa.PrivateKey{cfg.Secrets.CliqueSigner}) l1Node, l1Eth, err := createGethNode(false, nodeConfig, ethConfig, []*ecdsa.PrivateKey{cfg.Secrets.CliqueSigner}, opts...)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
...@@ -158,11 +194,25 @@ func defaultNodeConfig(name string, jwtPath string) *node.Config { ...@@ -158,11 +194,25 @@ func defaultNodeConfig(name string, jwtPath string) *node.Config {
} }
} }
type GethOption func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error
// init a geth node. // init a geth node.
func initL2Geth(name string, l2ChainID *big.Int, genesis *core.Genesis, jwtPath string) (*node.Node, *eth.Ethereum, error) { func initL2Geth(name string, l2ChainID *big.Int, genesis *core.Genesis, jwtPath string, opts ...GethOption) (*node.Node, *eth.Ethereum, error) {
ethConfig := &ethconfig.Config{ ethConfig := &ethconfig.Config{
NetworkId: l2ChainID.Uint64(), NetworkId: l2ChainID.Uint64(),
Genesis: genesis, Genesis: genesis,
Miner: miner.Config{
Etherbase: common.Address{},
Notify: nil,
NotifyFull: false,
ExtraData: nil,
GasFloor: 0,
GasCeil: 0,
GasPrice: nil,
Recommit: 0,
Noverify: false,
NewPayloadTimeout: 0,
},
} }
nodeConfig := &node.Config{ nodeConfig := &node.Config{
Name: fmt.Sprintf("l2-geth-%v", name), Name: fmt.Sprintf("l2-geth-%v", name),
...@@ -176,14 +226,19 @@ func initL2Geth(name string, l2ChainID *big.Int, genesis *core.Genesis, jwtPath ...@@ -176,14 +226,19 @@ func initL2Geth(name string, l2ChainID *big.Int, genesis *core.Genesis, jwtPath
HTTPModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine"}, HTTPModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine"},
JWTSecret: jwtPath, JWTSecret: jwtPath,
} }
return createGethNode(true, nodeConfig, ethConfig, nil) return createGethNode(true, nodeConfig, ethConfig, nil, opts...)
} }
// createGethNode creates an in-memory geth node based on the configuration. // createGethNode creates an in-memory geth node based on the configuration.
// The private keys are added to the keystore and are unlocked. // The private keys are added to the keystore and are unlocked.
// If the node is l2, catalyst is enabled. // If the node is l2, catalyst is enabled.
// The node should be started and then closed when done. // The node should be started and then closed when done.
func createGethNode(l2 bool, nodeCfg *node.Config, ethCfg *ethconfig.Config, privateKeys []*ecdsa.PrivateKey) (*node.Node, *eth.Ethereum, error) { func createGethNode(l2 bool, nodeCfg *node.Config, ethCfg *ethconfig.Config, privateKeys []*ecdsa.PrivateKey, opts ...GethOption) (*node.Node, *eth.Ethereum, error) {
for i, opt := range opts {
if err := opt(ethCfg, nodeCfg); err != nil {
return nil, nil, fmt.Errorf("failed to apply geth option %d: %w", i, err)
}
}
ethCfg.NoPruning = true // force everything to be an archive node ethCfg.NoPruning = true // force everything to be an archive node
n, err := node.New(nodeCfg) n, err := node.New(nodeCfg)
if err != nil { if err != nil {
......
...@@ -2,8 +2,6 @@ module github.com/ethereum-optimism/optimism/op-e2e ...@@ -2,8 +2,6 @@ module github.com/ethereum-optimism/optimism/op-e2e
go 1.18 go 1.18
replace github.com/ethereum-optimism/optimism/op-chain-ops v0.10.0 => ../op-chain-ops
require ( require (
github.com/docker/docker v20.10.21+incompatible github.com/docker/docker v20.10.21+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
...@@ -15,6 +13,7 @@ require ( ...@@ -15,6 +13,7 @@ require (
github.com/ethereum-optimism/optimism/op-proposer v0.10.4 github.com/ethereum-optimism/optimism/op-proposer v0.10.4
github.com/ethereum-optimism/optimism/op-service v0.10.4 github.com/ethereum-optimism/optimism/op-service v0.10.4
github.com/ethereum/go-ethereum v1.10.26 github.com/ethereum/go-ethereum v1.10.26
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8
github.com/libp2p/go-libp2p v0.23.3 github.com/libp2p/go-libp2p v0.23.3
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
) )
...@@ -169,4 +168,4 @@ require ( ...@@ -169,4 +168,4 @@ require (
lukechampine.com/blake3 v1.1.7 // indirect lukechampine.com/blake3 v1.1.7 // indirect
) )
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468
...@@ -157,8 +157,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m ...@@ -157,8 +157,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 h1:QJL/gtfxGe11tApZIPCeKERQHrLZMAG0RwGV9eTgtvE= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-batcher v0.10.4 h1:qLCdvVMgVja2AGbkKKG7xNW8nm+3C5rz4xagQ3Cg0sw= github.com/ethereum-optimism/optimism/op-batcher v0.10.4 h1:qLCdvVMgVja2AGbkKKG7xNW8nm+3C5rz4xagQ3Cg0sw=
github.com/ethereum-optimism/optimism/op-batcher v0.10.4/go.mod h1:a19oViWrL7dy1pPSIa2Dgsv8o97HOzVtKx+m2J5qQqY= github.com/ethereum-optimism/optimism/op-batcher v0.10.4/go.mod h1:a19oViWrL7dy1pPSIa2Dgsv8o97HOzVtKx+m2J5qQqY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.4 h1:CFn4+t0FUrBG5DmkKyYrLbGmzHWLdLv8QdUnlklvozc= github.com/ethereum-optimism/optimism/op-bindings v0.10.4 h1:CFn4+t0FUrBG5DmkKyYrLbGmzHWLdLv8QdUnlklvozc=
...@@ -275,6 +275,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ ...@@ -275,6 +275,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8 h1:Ep/joEub9YwcjRY6ND3+Y/w0ncE540RtGatVhtZL0/Q= github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8 h1:Ep/joEub9YwcjRY6ND3+Y/w0ncE540RtGatVhtZL0/Q=
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
......
...@@ -144,6 +144,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig { ...@@ -144,6 +144,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig {
"batcher": testlog.Logger(t, log.LvlInfo).New("role", "batcher"), "batcher": testlog.Logger(t, log.LvlInfo).New("role", "batcher"),
"proposer": testlog.Logger(t, log.LvlCrit).New("role", "proposer"), "proposer": testlog.Logger(t, log.LvlCrit).New("role", "proposer"),
}, },
GethOptions: map[string][]GethOption{},
P2PTopology: nil, // no P2P connectivity by default P2PTopology: nil, // no P2P connectivity by default
NonFinalizedProposals: false, NonFinalizedProposals: false,
} }
...@@ -175,6 +176,7 @@ type SystemConfig struct { ...@@ -175,6 +176,7 @@ type SystemConfig struct {
Premine map[common.Address]*big.Int Premine map[common.Address]*big.Int
Nodes map[string]*rollupNode.Config // Per node config. Don't use populate rollup.Config Nodes map[string]*rollupNode.Config // Per node config. Don't use populate rollup.Config
Loggers map[string]log.Logger Loggers map[string]log.Logger
GethOptions map[string][]GethOption
ProposerLogger log.Logger ProposerLogger log.Logger
BatcherLogger log.Logger BatcherLogger log.Logger
...@@ -265,6 +267,21 @@ func (cfg SystemConfig) Start() (*System, error) { ...@@ -265,6 +267,21 @@ func (cfg SystemConfig) Start() (*System, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
for addr, amount := range cfg.Premine {
if existing, ok := l2Genesis.Alloc[addr]; ok {
l2Genesis.Alloc[addr] = core.GenesisAccount{
Code: existing.Code,
Storage: existing.Storage,
Balance: amount,
Nonce: existing.Nonce,
}
} else {
l2Genesis.Alloc[addr] = core.GenesisAccount{
Balance: amount,
Nonce: 0,
}
}
}
makeRollupConfig := func() rollup.Config { makeRollupConfig := func() rollup.Config {
return rollup.Config{ return rollup.Config{
...@@ -296,7 +313,7 @@ func (cfg SystemConfig) Start() (*System, error) { ...@@ -296,7 +313,7 @@ func (cfg SystemConfig) Start() (*System, error) {
sys.RollupConfig = &defaultConfig sys.RollupConfig = &defaultConfig
// Initialize nodes // Initialize nodes
l1Node, l1Backend, err := initL1Geth(&cfg, l1Genesis) l1Node, l1Backend, err := initL1Geth(&cfg, l1Genesis, cfg.GethOptions["l1"]...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -304,7 +321,7 @@ func (cfg SystemConfig) Start() (*System, error) { ...@@ -304,7 +321,7 @@ func (cfg SystemConfig) Start() (*System, error) {
sys.Backends["l1"] = l1Backend sys.Backends["l1"] = l1Backend
for name := range cfg.Nodes { for name := range cfg.Nodes {
node, backend, err := initL2Geth(name, big.NewInt(int64(cfg.DeployConfig.L2ChainID)), l2Genesis, cfg.JWTFilePath) node, backend, err := initL2Geth(name, big.NewInt(int64(cfg.DeployConfig.L2ChainID)), l2Genesis, cfg.JWTFilePath, cfg.GethOptions[name]...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -15,9 +15,11 @@ import ( ...@@ -15,9 +15,11 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient/gethclient" "github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -288,6 +290,67 @@ func TestConfirmationDepth(t *testing.T) { ...@@ -288,6 +290,67 @@ func TestConfirmationDepth(t *testing.T) {
require.LessOrEqual(t, verInfo.Number+verConfDepth, l1Head.NumberU64(), "the ver L2 head block should have an origin older than the L1 head block by at least the verifier conf depth") require.LessOrEqual(t, verInfo.Number+verConfDepth, l1Head.NumberU64(), "the ver L2 head block should have an origin older than the L1 head block by at least the verifier conf depth")
} }
// TestPendingGasLimit tests the configuration of the gas limit of the pending block,
// and if it does not conflict with the regular gas limit on the verifier or sequencer.
func TestPendingGasLimit(t *testing.T) {
parallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t)
// configure the L2 gas limit to be high, and the pending gas limits to be lower for resource saving.
cfg.DeployConfig.L2GenesisBlockGasLimit = 20_000_000
cfg.GethOptions["sequencer"] = []GethOption{
func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error {
ethCfg.Miner.GasCeil = 10_000_000
return nil
},
}
cfg.GethOptions["verifier"] = []GethOption{
func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error {
ethCfg.Miner.GasCeil = 9_000_000
return nil
},
}
sys, err := cfg.Start()
require.Nil(t, err, "Error starting up system")
defer sys.Close()
log := testlog.Logger(t, log.LvlInfo)
log.Info("genesis", "l2", sys.RollupConfig.Genesis.L2, "l1", sys.RollupConfig.Genesis.L1, "l2_time", sys.RollupConfig.Genesis.L2Time)
l2Verif := sys.Clients["verifier"]
l2Seq := sys.Clients["sequencer"]
checkGasLimit := func(client *ethclient.Client, number *big.Int, expected uint64) *types.Header {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
header, err := client.HeaderByNumber(ctx, number)
cancel()
require.NoError(t, err)
require.Equal(t, expected, header.GasLimit)
return header
}
// check if the gaslimits are matching the expected values,
// and that the verifier/sequencer can use their locally configured gas limit for the pending block.
for {
checkGasLimit(l2Seq, big.NewInt(-1), 10_000_000)
checkGasLimit(l2Verif, big.NewInt(-1), 9_000_000)
checkGasLimit(l2Seq, nil, 20_000_000)
latestVerifHeader := checkGasLimit(l2Verif, nil, 20_000_000)
// Stop once the verifier passes genesis:
// this implies we checked a new block from the sequencer, on both sequencer and verifier nodes.
if latestVerifHeader.Number.Uint64() > 0 {
break
}
time.Sleep(500 * time.Millisecond)
}
}
// TestFinalize tests if L2 finalizes after sufficient time after L1 finalizes // TestFinalize tests if L2 finalizes after sufficient time after L1 finalizes
func TestFinalize(t *testing.T) { func TestFinalize(t *testing.T) {
parallel(t) parallel(t)
......
This diff is collapsed.
...@@ -6,6 +6,7 @@ require ( ...@@ -6,6 +6,7 @@ require (
github.com/ethereum-optimism/optimism/op-node v0.10.1 github.com/ethereum-optimism/optimism/op-node v0.10.1
github.com/ethereum-optimism/optimism/op-service v0.10.1 github.com/ethereum-optimism/optimism/op-service v0.10.1
github.com/ethereum/go-ethereum v1.10.26 github.com/ethereum/go-ethereum v1.10.26
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_golang v1.14.0
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
github.com/urfave/cli v1.22.10 github.com/urfave/cli v1.22.10
......
...@@ -159,6 +159,7 @@ github.com/hashicorp/go-bexpr v0.1.11 h1:6DqdA/KBjurGby9yTY0bmkathya0lfwF2SeuubC ...@@ -159,6 +159,7 @@ github.com/hashicorp/go-bexpr v0.1.11 h1:6DqdA/KBjurGby9yTY0bmkathya0lfwF2SeuubC
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
......
...@@ -160,4 +160,4 @@ require ( ...@@ -160,4 +160,4 @@ require (
lukechampine.com/blake3 v1.1.7 // indirect lukechampine.com/blake3 v1.1.7 // indirect
) )
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468
...@@ -143,8 +143,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF ...@@ -143,8 +143,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 h1:QJL/gtfxGe11tApZIPCeKERQHrLZMAG0RwGV9eTgtvE= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.4 h1:CFn4+t0FUrBG5DmkKyYrLbGmzHWLdLv8QdUnlklvozc= github.com/ethereum-optimism/optimism/op-bindings v0.10.4 h1:CFn4+t0FUrBG5DmkKyYrLbGmzHWLdLv8QdUnlklvozc=
github.com/ethereum-optimism/optimism/op-bindings v0.10.4/go.mod h1:philKV8erP02ggjk2mRIdvJd2ZjMzpmqu0+zwwzKmNw= github.com/ethereum-optimism/optimism/op-bindings v0.10.4/go.mod h1:philKV8erP02ggjk2mRIdvJd2ZjMzpmqu0+zwwzKmNw=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.4 h1:10/BrNfcobBNuaIQQAUcDblzLCtNeGMhGvqHdzhENKk= github.com/ethereum-optimism/optimism/op-chain-ops v0.10.4 h1:10/BrNfcobBNuaIQQAUcDblzLCtNeGMhGvqHdzhENKk=
......
...@@ -73,6 +73,7 @@ func (ibc *IterativeBatchCall[K, V, O]) Reset() { ...@@ -73,6 +73,7 @@ func (ibc *IterativeBatchCall[K, V, O]) Reset() {
scheduled <- r scheduled <- r
} }
atomic.StoreUint32(&ibc.completed, 0)
ibc.requestsValues = requestsValues ibc.requestsValues = requestsValues
ibc.scheduled = scheduled ibc.scheduled = scheduled
if len(ibc.requestsKeys) == 0 { if len(ibc.requestsKeys) == 0 {
......
...@@ -99,4 +99,4 @@ require ( ...@@ -99,4 +99,4 @@ require (
lukechampine.com/blake3 v1.1.7 // indirect lukechampine.com/blake3 v1.1.7 // indirect
) )
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468
...@@ -105,8 +105,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m ...@@ -105,8 +105,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 h1:QJL/gtfxGe11tApZIPCeKERQHrLZMAG0RwGV9eTgtvE= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.4 h1:CFn4+t0FUrBG5DmkKyYrLbGmzHWLdLv8QdUnlklvozc= github.com/ethereum-optimism/optimism/op-bindings v0.10.4 h1:CFn4+t0FUrBG5DmkKyYrLbGmzHWLdLv8QdUnlklvozc=
github.com/ethereum-optimism/optimism/op-bindings v0.10.4/go.mod h1:philKV8erP02ggjk2mRIdvJd2ZjMzpmqu0+zwwzKmNw= github.com/ethereum-optimism/optimism/op-bindings v0.10.4/go.mod h1:philKV8erP02ggjk2mRIdvJd2ZjMzpmqu0+zwwzKmNw=
github.com/ethereum-optimism/optimism/op-node v0.10.4 h1:ZXqfrFKgb6W4ZLbkfO9NlgaQ1djBCCPzNGbd6TgehVI= github.com/ethereum-optimism/optimism/op-node v0.10.4 h1:ZXqfrFKgb6W4ZLbkfO9NlgaQ1djBCCPzNGbd6TgehVI=
......
...@@ -67,4 +67,4 @@ require ( ...@@ -67,4 +67,4 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468
...@@ -110,8 +110,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF ...@@ -110,8 +110,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 h1:QJL/gtfxGe11tApZIPCeKERQHrLZMAG0RwGV9eTgtvE= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
......
...@@ -85,4 +85,4 @@ require ( ...@@ -85,4 +85,4 @@ require (
lukechampine.com/blake3 v1.1.7 // indirect lukechampine.com/blake3 v1.1.7 // indirect
) )
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468
...@@ -81,8 +81,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF ...@@ -81,8 +81,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790 h1:QJL/gtfxGe11tApZIPCeKERQHrLZMAG0RwGV9eTgtvE= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221205191237-0678a130d790/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-node v0.10.3 h1:96KbEtbfJTg5GXtNqLnrDPnXMbeynIy1G8iSc47whrA= github.com/ethereum-optimism/optimism/op-node v0.10.3 h1:96KbEtbfJTg5GXtNqLnrDPnXMbeynIy1G8iSc47whrA=
github.com/ethereum-optimism/optimism/op-node v0.10.3/go.mod h1:fsRLXH68xaLhjfr67MPEtjCocCzSXGhZIre536QccIw= github.com/ethereum-optimism/optimism/op-node v0.10.3/go.mod h1:fsRLXH68xaLhjfr67MPEtjCocCzSXGhZIre536QccIw=
github.com/ethereum-optimism/optimism/op-service v0.10.3 h1:gr+eVq6CzxMFqo0/9n6EoUkpumtYZEzO84gti6ekj/s= github.com/ethereum-optimism/optimism/op-service v0.10.3 h1:gr+eVq6CzxMFqo0/9n6EoUkpumtYZEzO84gti6ekj/s=
......
...@@ -11,7 +11,7 @@ GETH_VERSION='v1.10.26' ...@@ -11,7 +11,7 @@ GETH_VERSION='v1.10.26'
def main(): def main():
for project in ('op-service', 'op-node', 'op-proposer', 'op-batcher', 'op-bindings', 'op-chain-ops', 'op-e2e'): for project in ('op-service', 'op-node', 'op-proposer', 'op-batcher', 'op-bindings', 'op-chain-ops', 'op-e2e', 'op-wheel'):
print(f'Updating {project}...') print(f'Updating {project}...')
update_mod(project) update_mod(project)
......
...@@ -230,6 +230,11 @@ OptimismMintableERC721_Test:test_constructor_succeeds() (gas: 24162) ...@@ -230,6 +230,11 @@ OptimismMintableERC721_Test:test_constructor_succeeds() (gas: 24162)
OptimismMintableERC721_Test:test_safeMint_notBridge_reverts() (gas: 11142) OptimismMintableERC721_Test:test_safeMint_notBridge_reverts() (gas: 11142)
OptimismMintableERC721_Test:test_safeMint_succeeds() (gas: 140502) OptimismMintableERC721_Test:test_safeMint_succeeds() (gas: 140502)
OptimismMintableERC721_Test:test_tokenURI_succeeds() (gas: 163420) OptimismMintableERC721_Test:test_tokenURI_succeeds() (gas: 163420)
OptimismMintableERC721Factory_Test:test_constructor_succeeds() (gas: 9983)
OptimismMintableERC721Factory_Test:test_constructor_zeroBridge_reverts() (gas: 39114)
OptimismMintableERC721Factory_Test:test_constructor_zeroRemoteChainId_reverts() (gas: 41265)
OptimismMintableERC721Factory_Test:test_createOptimismMintableERC721_succeeds() (gas: 2276418)
OptimismMintableERC721Factory_Test:test_createOptimismMintableERC721_zeroRemoteToken_reverst() (gas: 9395)
OptimismPortalUpgradeable_Test:test_initialize_cannotInitImpl_reverts() (gas: 10791) OptimismPortalUpgradeable_Test:test_initialize_cannotInitImpl_reverts() (gas: 10791)
OptimismPortalUpgradeable_Test:test_initialize_cannotInitProxy_reverts() (gas: 15833) OptimismPortalUpgradeable_Test:test_initialize_cannotInitProxy_reverts() (gas: 15833)
OptimismPortalUpgradeable_Test:test_params_initValuesOnProxy_succeeds() (gas: 16011) OptimismPortalUpgradeable_Test:test_params_initValuesOnProxy_succeeds() (gas: 16011)
...@@ -374,7 +379,8 @@ SequencerFeeVault_Test:test_minWithdrawalAmount_succeeds() (gas: 5420) ...@@ -374,7 +379,8 @@ SequencerFeeVault_Test:test_minWithdrawalAmount_succeeds() (gas: 5420)
SequencerFeeVault_Test:test_receive_succeeds() (gas: 17336) SequencerFeeVault_Test:test_receive_succeeds() (gas: 17336)
SequencerFeeVault_Test:test_withdraw_notEnough_reverts() (gas: 9309) SequencerFeeVault_Test:test_withdraw_notEnough_reverts() (gas: 9309)
SequencerFeeVault_Test:test_withdraw_succeeds() (gas: 159816) SequencerFeeVault_Test:test_withdraw_succeeds() (gas: 159816)
SystemConfig_Initialize_TestFail:test_initialize_lowGasLimit_reverts() (gas: 61707) SystemConfig_Initialize_TestFail:test_initialize_lowGasLimit_reverts() (gas: 61952)
SystemConfig_Setters_TestFail:test_setBatcherHash_notOwner_reverts() (gas: 10501) SystemConfig_Setters_TestFail:test_setBatcherHash_notOwner_reverts() (gas: 10523)
SystemConfig_Setters_TestFail:test_setGasConfig_notOwner_reverts() (gas: 10576) SystemConfig_Setters_TestFail:test_setGasConfig_notOwner_reverts() (gas: 10510)
SystemConfig_Setters_TestFail:test_setGasLimit_notOwner_reverts() (gas: 10592) SystemConfig_Setters_TestFail:test_setGasLimit_notOwner_reverts() (gas: 10614)
SystemConfig_Setters_TestFail:test_setUnsafeBlockSigner_notOwner_reverts() (gas: 10638)
...@@ -104,27 +104,29 @@ ...@@ -104,27 +104,29 @@
➡ contracts/L1/SystemConfig.sol:SystemConfig ➡ contracts/L1/SystemConfig.sol:SystemConfig
======================= =======================
+---------------+-------------+------+--------+-------+--------------------------------------------+ +-------------------+-------------+------+--------+-------+--------------------------------------------+
| Name | Type | Slot | Offset | Bytes | Contract | | Name | Type | Slot | Offset | Bytes | Contract |
+==================================================================================================+ +======================================================================================================+
| _initialized | uint8 | 0 | 0 | 1 | contracts/L1/SystemConfig.sol:SystemConfig | | _initialized | uint8 | 0 | 0 | 1 | contracts/L1/SystemConfig.sol:SystemConfig |
|---------------+-------------+------+--------+-------+--------------------------------------------| |-------------------+-------------+------+--------+-------+--------------------------------------------|
| _initializing | bool | 0 | 1 | 1 | contracts/L1/SystemConfig.sol:SystemConfig | | _initializing | bool | 0 | 1 | 1 | contracts/L1/SystemConfig.sol:SystemConfig |
|---------------+-------------+------+--------+-------+--------------------------------------------| |-------------------+-------------+------+--------+-------+--------------------------------------------|
| __gap | uint256[50] | 1 | 0 | 1600 | contracts/L1/SystemConfig.sol:SystemConfig | | __gap | uint256[50] | 1 | 0 | 1600 | contracts/L1/SystemConfig.sol:SystemConfig |
|---------------+-------------+------+--------+-------+--------------------------------------------| |-------------------+-------------+------+--------+-------+--------------------------------------------|
| _owner | address | 51 | 0 | 20 | contracts/L1/SystemConfig.sol:SystemConfig | | _owner | address | 51 | 0 | 20 | contracts/L1/SystemConfig.sol:SystemConfig |
|---------------+-------------+------+--------+-------+--------------------------------------------| |-------------------+-------------+------+--------+-------+--------------------------------------------|
| __gap | uint256[49] | 52 | 0 | 1568 | contracts/L1/SystemConfig.sol:SystemConfig | | __gap | uint256[49] | 52 | 0 | 1568 | contracts/L1/SystemConfig.sol:SystemConfig |
|---------------+-------------+------+--------+-------+--------------------------------------------| |-------------------+-------------+------+--------+-------+--------------------------------------------|
| overhead | uint256 | 101 | 0 | 32 | contracts/L1/SystemConfig.sol:SystemConfig | | overhead | uint256 | 101 | 0 | 32 | contracts/L1/SystemConfig.sol:SystemConfig |
|---------------+-------------+------+--------+-------+--------------------------------------------| |-------------------+-------------+------+--------+-------+--------------------------------------------|
| scalar | uint256 | 102 | 0 | 32 | contracts/L1/SystemConfig.sol:SystemConfig | | scalar | uint256 | 102 | 0 | 32 | contracts/L1/SystemConfig.sol:SystemConfig |
|---------------+-------------+------+--------+-------+--------------------------------------------| |-------------------+-------------+------+--------+-------+--------------------------------------------|
| batcherHash | bytes32 | 103 | 0 | 32 | contracts/L1/SystemConfig.sol:SystemConfig | | unsafeBlockSigner | address | 103 | 0 | 20 | contracts/L1/SystemConfig.sol:SystemConfig |
|---------------+-------------+------+--------+-------+--------------------------------------------| |-------------------+-------------+------+--------+-------+--------------------------------------------|
| gasLimit | uint64 | 104 | 0 | 8 | contracts/L1/SystemConfig.sol:SystemConfig | | batcherHash | bytes32 | 104 | 0 | 32 | contracts/L1/SystemConfig.sol:SystemConfig |
+---------------+-------------+------+--------+-------+--------------------------------------------+ |-------------------+-------------+------+--------+-------+--------------------------------------------|
| gasLimit | uint64 | 105 | 0 | 8 | contracts/L1/SystemConfig.sol:SystemConfig |
+-------------------+-------------+------+--------+-------+--------------------------------------------+
======================= =======================
➡ contracts/legacy/DeployerWhitelist.sol:DeployerWhitelist ➡ contracts/legacy/DeployerWhitelist.sol:DeployerWhitelist
......
...@@ -16,14 +16,17 @@ contract SystemConfig is OwnableUpgradeable, Semver { ...@@ -16,14 +16,17 @@ contract SystemConfig is OwnableUpgradeable, Semver {
/** /**
* @notice Enum representing different types of updates. * @notice Enum representing different types of updates.
* *
* @custom:value BATCHER Represents an update to the batcher hash. * @custom:value BATCHER Represents an update to the batcher hash.
* @custom:value GAS_CONFIG Represents an update to txn fee config on L2. * @custom:value GAS_CONFIG Represents an update to txn fee config on L2.
* @custom:value GAS_LIMIT Represents an update to gas limit on L2. * @custom:value GAS_LIMIT Represents an update to gas limit on L2.
* @custom:value UNSAFE_BLOCK_SIGNER Represents an update to the signer key for unsafe
* block distrubution.
*/ */
enum UpdateType { enum UpdateType {
BATCHER, BATCHER,
GAS_CONFIG, GAS_CONFIG,
GAS_LIMIT GAS_LIMIT,
UNSAFE_BLOCK_SIGNER
} }
/** /**
...@@ -48,6 +51,13 @@ contract SystemConfig is OwnableUpgradeable, Semver { ...@@ -48,6 +51,13 @@ contract SystemConfig is OwnableUpgradeable, Semver {
*/ */
uint256 public scalar; uint256 public scalar;
/**
* @notice Address corresponding to the key that can propagate unsafe blocks
* across the p2p network. This value should not be tightly packed
* into a storage slot with another value to make state proofs more simple.
*/
address public unsafeBlockSigner;
/** /**
* @notice Identifier for the batcher. For version 1 of this configuration, this is represented * @notice Identifier for the batcher. For version 1 of this configuration, this is represented
* as an address left-padded with zeros to 32 bytes. * as an address left-padded with zeros to 32 bytes.
...@@ -82,9 +92,10 @@ contract SystemConfig is OwnableUpgradeable, Semver { ...@@ -82,9 +92,10 @@ contract SystemConfig is OwnableUpgradeable, Semver {
uint256 _overhead, uint256 _overhead,
uint256 _scalar, uint256 _scalar,
bytes32 _batcherHash, bytes32 _batcherHash,
uint64 _gasLimit uint64 _gasLimit,
address _unsafeBlockSigner
) Semver(1, 0, 0) { ) Semver(1, 0, 0) {
initialize(_owner, _overhead, _scalar, _batcherHash, _gasLimit); initialize(_owner, _overhead, _scalar, _batcherHash, _gasLimit, _unsafeBlockSigner);
} }
/** /**
...@@ -101,7 +112,8 @@ contract SystemConfig is OwnableUpgradeable, Semver { ...@@ -101,7 +112,8 @@ contract SystemConfig is OwnableUpgradeable, Semver {
uint256 _overhead, uint256 _overhead,
uint256 _scalar, uint256 _scalar,
bytes32 _batcherHash, bytes32 _batcherHash,
uint64 _gasLimit uint64 _gasLimit,
address _unsafeBlockSigner
) public initializer { ) public initializer {
require(_gasLimit >= MINIMUM_GAS_LIMIT, "SystemConfig: gas limit too low"); require(_gasLimit >= MINIMUM_GAS_LIMIT, "SystemConfig: gas limit too low");
__Ownable_init(); __Ownable_init();
...@@ -110,6 +122,7 @@ contract SystemConfig is OwnableUpgradeable, Semver { ...@@ -110,6 +122,7 @@ contract SystemConfig is OwnableUpgradeable, Semver {
scalar = _scalar; scalar = _scalar;
batcherHash = _batcherHash; batcherHash = _batcherHash;
gasLimit = _gasLimit; gasLimit = _gasLimit;
unsafeBlockSigner = _unsafeBlockSigner;
} }
/** /**
...@@ -139,6 +152,13 @@ contract SystemConfig is OwnableUpgradeable, Semver { ...@@ -139,6 +152,13 @@ contract SystemConfig is OwnableUpgradeable, Semver {
emit ConfigUpdate(VERSION, UpdateType.GAS_CONFIG, data); emit ConfigUpdate(VERSION, UpdateType.GAS_CONFIG, data);
} }
function setUnsafeBlockSigner(address _unsafeBlockSigner) external onlyOwner {
unsafeBlockSigner = _unsafeBlockSigner;
bytes memory data = abi.encode(_unsafeBlockSigner);
emit ConfigUpdate(VERSION, UpdateType.UNSAFE_BLOCK_SIGNER, data);
}
/** /**
* @notice Updates the L2 gas limit. * @notice Updates the L2 gas limit.
* *
......
...@@ -78,6 +78,7 @@ contract SystemDictator is OwnableUpgradeable { ...@@ -78,6 +78,7 @@ contract SystemDictator is OwnableUpgradeable {
uint256 scalar; uint256 scalar;
bytes32 batcherHash; bytes32 batcherHash;
uint64 gasLimit; uint64 gasLimit;
address unsafeBlockSigner;
} }
/** /**
...@@ -353,7 +354,8 @@ contract SystemDictator is OwnableUpgradeable { ...@@ -353,7 +354,8 @@ contract SystemDictator is OwnableUpgradeable {
config.systemConfigConfig.overhead, config.systemConfigConfig.overhead,
config.systemConfigConfig.scalar, config.systemConfigConfig.scalar,
config.systemConfigConfig.batcherHash, config.systemConfigConfig.batcherHash,
config.systemConfigConfig.gasLimit config.systemConfigConfig.gasLimit,
config.systemConfigConfig.unsafeBlockSigner
) )
) )
); );
......
...@@ -420,31 +420,25 @@ contract Bridge_Initializer is Messenger_Initializer { ...@@ -420,31 +420,25 @@ contract Bridge_Initializer is Messenger_Initializer {
contract ERC721Bridge_Initializer is Messenger_Initializer { contract ERC721Bridge_Initializer is Messenger_Initializer {
L1ERC721Bridge L1Bridge; L1ERC721Bridge L1Bridge;
L2ERC721Bridge L2Bridge; L2ERC721Bridge L2Bridge;
OptimismMintableERC721Factory factory;
function setUp() public virtual override { function setUp() public virtual override {
super.setUp(); super.setUp();
// Deploy the L1ERC721Bridge.
L1Bridge = new L1ERC721Bridge(address(L1Messenger), Predeploys.L2_ERC721_BRIDGE); L1Bridge = new L1ERC721Bridge(address(L1Messenger), Predeploys.L2_ERC721_BRIDGE);
L2ERC721Bridge l2b = new L2ERC721Bridge( // Deploy the implementation for the L2ERC721Bridge and etch it into the predeploy address.
vm.etch(Predeploys.L2_ERC721_BRIDGE, address(new L2ERC721Bridge(
Predeploys.L2_CROSS_DOMAIN_MESSENGER, Predeploys.L2_CROSS_DOMAIN_MESSENGER,
address(L1Bridge) address(L1Bridge)
); )).code);
vm.etch(Predeploys.L2_ERC721_BRIDGE, address(l2b).code); // Set up a reference to the L2ERC721Bridge.
L2Bridge = L2ERC721Bridge(Predeploys.L2_ERC721_BRIDGE); L2Bridge = L2ERC721Bridge(Predeploys.L2_ERC721_BRIDGE);
OptimismMintableERC721Factory f = new OptimismMintableERC721Factory( // Label the L1 and L2 bridges.
Predeploys.L2_ERC721_BRIDGE,
block.chainid
);
vm.etch(Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY, address(f).code);
factory = OptimismMintableERC721Factory(Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY);
vm.label(address(L1Bridge), "L1ERC721Bridge"); vm.label(address(L1Bridge), "L1ERC721Bridge");
vm.label(Predeploys.L2_ERC721_BRIDGE, "L2ERC721Bridge"); vm.label(address(L2Bridge), "L2ERC721Bridge");
vm.label(Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY, "OptimismMintableERC721Factory");
} }
} }
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { ERC721Bridge_Initializer } from "./CommonTest.t.sol";
import { LibRLP } from "./RLP.t.sol";
import { OptimismMintableERC721 } from "../universal/OptimismMintableERC721.sol";
import { OptimismMintableERC721Factory } from "../universal/OptimismMintableERC721Factory.sol";
contract OptimismMintableERC721Factory_Test is ERC721Bridge_Initializer {
OptimismMintableERC721Factory internal factory;
event OptimismMintableERC721Created(
address indexed localToken,
address indexed remoteToken,
address deployer
);
function setUp() public override {
super.setUp();
// Set up the token pair.
factory = new OptimismMintableERC721Factory(address(L2Bridge), 1);
// Label the addresses for nice traces.
vm.label(address(factory), "OptimismMintableERC721Factory");
}
function test_constructor_succeeds() external {
assertEq(factory.bridge(), address(L2Bridge));
assertEq(factory.remoteChainId(), 1);
assertEq(factory.BRIDGE(), address(L2Bridge));
assertEq(factory.REMOTE_CHAIN_ID(), 1);
}
function test_constructor_zeroBridge_reverts() external {
vm.expectRevert("OptimismMintableERC721Factory: bridge cannot be address(0)");
new OptimismMintableERC721Factory(address(0), 1);
}
function test_constructor_zeroRemoteChainId_reverts() external {
vm.expectRevert("OptimismMintableERC721Factory: remote chain id cannot be zero");
new OptimismMintableERC721Factory(address(L2Bridge), 0);
}
function test_createOptimismMintableERC721_succeeds() external {
// Predict the address based on the factory address and nonce.
address predicted = LibRLP.computeAddress(address(factory), 1);
// Expect a token creation event.
vm.expectEmit(true, true, true, true);
emit OptimismMintableERC721Created(
predicted,
address(1234),
alice
);
// Create the token.
vm.prank(alice);
OptimismMintableERC721 created = OptimismMintableERC721(
factory.createOptimismMintableERC721(
address(1234),
"L2Token",
"L2T"
)
);
// Token address should be correct.
assertEq(address(created), predicted);
// Should be marked as created by the factory.
assertEq(factory.isOptimismMintableERC721(address(created)), true);
// Token should've been constructed correctly.
assertEq(created.name(), "L2Token");
assertEq(created.symbol(), "L2T");
assertEq(created.REMOTE_TOKEN(), address(1234));
assertEq(created.BRIDGE(), address(L2Bridge));
assertEq(created.REMOTE_CHAIN_ID(), 1);
}
function test_createOptimismMintableERC721_zeroRemoteToken_reverst() external {
// Try to create a token with a zero remote token address.
vm.expectRevert("OptimismMintableERC721Factory: L1 token address cannot be address(0)");
factory.createOptimismMintableERC721(
address(0),
"L2Token",
"L2T"
);
}
}
...@@ -13,7 +13,8 @@ contract SystemConfig_Init is CommonTest { ...@@ -13,7 +13,8 @@ contract SystemConfig_Init is CommonTest {
_overhead: 2100, _overhead: 2100,
_scalar: 1000000, _scalar: 1000000,
_batcherHash: bytes32(hex"abcd"), _batcherHash: bytes32(hex"abcd"),
_gasLimit: 9_000_000 _gasLimit: 9_000_000,
_unsafeBlockSigner: address(1)
}); });
} }
} }
...@@ -29,7 +30,8 @@ contract SystemConfig_Initialize_TestFail is CommonTest { ...@@ -29,7 +30,8 @@ contract SystemConfig_Initialize_TestFail is CommonTest {
_overhead: 0, _overhead: 0,
_scalar: 0, _scalar: 0,
_batcherHash: bytes32(hex""), _batcherHash: bytes32(hex""),
_gasLimit: MINIMUM_GAS_LIMIT - 1 _gasLimit: MINIMUM_GAS_LIMIT - 1,
_unsafeBlockSigner: address(1)
}); });
} }
} }
...@@ -49,6 +51,11 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { ...@@ -49,6 +51,11 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
sysConf.setGasLimit(0); sysConf.setGasLimit(0);
} }
function test_setUnsafeBlockSigner_notOwner_reverts() external {
vm.expectRevert("Ownable: caller is not the owner");
sysConf.setUnsafeBlockSigner(address(0x20));
}
} }
contract SystemConfig_Setters_Test is SystemConfig_Init { contract SystemConfig_Setters_Test is SystemConfig_Init {
...@@ -94,4 +101,17 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -94,4 +101,17 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
sysConf.setGasLimit(newGasLimit); sysConf.setGasLimit(newGasLimit);
assertEq(sysConf.gasLimit(), newGasLimit); assertEq(sysConf.gasLimit(), newGasLimit);
} }
function testFuzz_setUnsafeBlockSigner_succeeds(address newUnsafeSigner) external {
vm.expectEmit(true, true, true, true);
emit ConfigUpdate(
0,
SystemConfig.UpdateType.UNSAFE_BLOCK_SIGNER,
abi.encode(newUnsafeSigner)
);
vm.prank(sysConf.owner());
sysConf.setUnsafeBlockSigner(newUnsafeSigner);
assertEq(sysConf.unsafeBlockSigner(), newUnsafeSigner);
}
} }
...@@ -17,6 +17,7 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -17,6 +17,7 @@ const deployFn: DeployFunction = async (hre) => {
hre.deployConfig.gasPriceOracleScalar, hre.deployConfig.gasPriceOracleScalar,
batcherHash, batcherHash,
hre.deployConfig.l2GenesisBlockGasLimit, hre.deployConfig.l2GenesisBlockGasLimit,
hre.deployConfig.p2pSequencerAddress,
], ],
postDeployAction: async (contract) => { postDeployAction: async (contract) => {
await assertContractVariable( await assertContractVariable(
...@@ -35,6 +36,11 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -35,6 +36,11 @@ const deployFn: DeployFunction = async (hre) => {
hre.deployConfig.gasPriceOracleScalar hre.deployConfig.gasPriceOracleScalar
) )
await assertContractVariable(contract, 'batcherHash', batcherHash) await assertContractVariable(contract, 'batcherHash', batcherHash)
await assertContractVariable(
contract,
'unsafeBlockSigner',
hre.deployConfig.p2pSequencerAddress
)
}, },
}) })
} }
......
...@@ -93,12 +93,13 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -93,12 +93,13 @@ const deployFn: DeployFunction = async (hre) => {
systemConfigConfig: { systemConfigConfig: {
owner: hre.deployConfig.finalSystemOwner, owner: hre.deployConfig.finalSystemOwner,
overhead: hre.deployConfig.gasPriceOracleOverhead, overhead: hre.deployConfig.gasPriceOracleOverhead,
scalar: hre.deployConfig.gasPriceOracleDecimals, scalar: hre.deployConfig.gasPriceOracleScalar,
batcherHash: hre.ethers.utils.hexZeroPad( batcherHash: hre.ethers.utils.hexZeroPad(
hre.deployConfig.batchSenderAddress, hre.deployConfig.batchSenderAddress,
32 32
), ),
gasLimit: hre.deployConfig.l2GenesisBlockGasLimit, gasLimit: hre.deployConfig.l2GenesisBlockGasLimit,
unsafeBlockSigner: hre.deployConfig.p2pSequencerAddress,
}, },
} }
......
...@@ -31,6 +31,7 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -31,6 +31,7 @@ const deployFn: DeployFunction = async (hre) => {
L1ERC721BridgeProxy, L1ERC721BridgeProxy,
L1ERC721BridgeProxyWithSigner, L1ERC721BridgeProxyWithSigner,
L1ERC721Bridge, L1ERC721Bridge,
SystemConfigProxy,
] = await getContractsFromArtifacts(hre, [ ] = await getContractsFromArtifacts(hre, [
{ {
name: 'SystemDictatorProxy', name: 'SystemDictatorProxy',
...@@ -89,6 +90,11 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -89,6 +90,11 @@ const deployFn: DeployFunction = async (hre) => {
iface: 'L1ERC721Bridge', iface: 'L1ERC721Bridge',
signerOrProvider: deployer, signerOrProvider: deployer,
}, },
{
name: 'SystemConfigProxy',
iface: 'SystemConfig',
signerOrProvider: deployer,
},
]) ])
// If we have the key for the controller then we don't need to wait for external txns. // If we have the key for the controller then we don't need to wait for external txns.
...@@ -498,6 +504,40 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -498,6 +504,40 @@ const deployFn: DeployFunction = async (hre) => {
'messenger', 'messenger',
L1CrossDomainMessenger.address L1CrossDomainMessenger.address
) )
// Check the SystemConfig was initialized properly.
await assertContractVariable(
SystemConfigProxy,
'owner',
hre.deployConfig.finalSystemOwner
)
await assertContractVariable(
SystemConfigProxy,
'overhead',
hre.deployConfig.gasPriceOracleOverhead
)
await assertContractVariable(
SystemConfigProxy,
'scalar',
hre.deployConfig.gasPriceOracleScalar
)
await assertContractVariable(
SystemConfigProxy,
'batcherHash',
ethers.utils.hexZeroPad(
hre.deployConfig.batchSenderAddress.toLowerCase(),
32
)
)
await assertContractVariable(
SystemConfigProxy,
'gasLimit',
hre.deployConfig.l2GenesisBlockGasLimit
)
}, },
}) })
......
...@@ -155,7 +155,6 @@ interface OptionalL2DeployConfig { ...@@ -155,7 +155,6 @@ interface OptionalL2DeployConfig {
l2GenesisBlockBaseFeePerGas: string l2GenesisBlockBaseFeePerGas: string
gasPriceOracleOverhead: number gasPriceOracleOverhead: number
gasPriceOracleScalar: number gasPriceOracleScalar: number
gasPriceOracleDecimals: number
} }
/** /**
...@@ -326,10 +325,6 @@ export const deployConfigSpec: { ...@@ -326,10 +325,6 @@ export const deployConfigSpec: {
type: 'number', type: 'number',
default: 1_000_000, default: 1_000_000,
}, },
gasPriceOracleDecimals: {
type: 'number',
default: 6,
},
governanceTokenSymbol: { governanceTokenSymbol: {
type: 'string', type: 'string',
default: 'OP', default: 'OP',
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { ERC721Bridge } from "../universal/op-erc721/ERC721Bridge.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { L2ERC721Bridge } from "../L2/L2ERC721Bridge.sol";
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol";
/**
* @title L1ERC721Bridge
* @notice The L1 ERC721 bridge is a contract which works together with the L2 ERC721 bridge to
* make it possible to transfer ERC721 tokens from Ethereum to Optimism. This contract
* acts as an escrow for ERC721 tokens deposited into L2.
*/
contract L1ERC721Bridge is ERC721Bridge, Semver {
/**
* @notice Mapping of L1 token to L2 token to ID to boolean, indicating if the given L1 token
* by ID was deposited for a given L2 token.
*/
mapping(address => mapping(address => mapping(uint256 => bool))) public deposits;
/**
* @custom:semver 1.0.0
*
* @param _messenger Address of the CrossDomainMessenger on this network.
* @param _otherBridge Address of the ERC721 bridge on the other network.
*/
constructor(address _messenger, address _otherBridge)
Semver(1, 0, 0)
ERC721Bridge(_messenger, _otherBridge)
{}
/*************************
* Cross-chain Functions *
*************************/
/**
* @notice Completes an ERC721 bridge from the other domain and sends the ERC721 token to the
* recipient on this domain.
*
* @param _localToken Address of the ERC721 token on this domain.
* @param _remoteToken Address of the ERC721 token on the other domain.
* @param _from Address that triggered the bridge on the other domain.
* @param _to Address to receive the token on this domain.
* @param _tokenId ID of the token being deposited.
* @param _extraData Optional data to forward to L2. Data supplied here will not be used to
* execute any code on L2 and is only emitted as extra data for the
* convenience of off-chain tooling.
*/
function finalizeBridgeERC721(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _tokenId,
bytes calldata _extraData
) external onlyOtherBridge {
require(_localToken != address(this), "L1ERC721Bridge: local token cannot be self");
// Checks that the L1/L2 NFT pair has a token ID that is escrowed in the L1 Bridge.
require(
deposits[_localToken][_remoteToken][_tokenId] == true,
"L1ERC721Bridge: Token ID is not escrowed in the L1 Bridge"
);
// Mark that the token ID for this L1/L2 token pair is no longer escrowed in the L1
// Bridge.
deposits[_localToken][_remoteToken][_tokenId] = false;
// When a withdrawal is finalized on L1, the L1 Bridge transfers the NFT to the
// withdrawer.
IERC721(_localToken).safeTransferFrom(address(this), _to, _tokenId);
// slither-disable-next-line reentrancy-events
emit ERC721BridgeFinalized(_localToken, _remoteToken, _from, _to, _tokenId, _extraData);
}
/**
* @inheritdoc ERC721Bridge
*/
function _initiateBridgeERC721(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _tokenId,
uint32 _minGasLimit,
bytes calldata _extraData
) internal override {
require(_remoteToken != address(0), "ERC721Bridge: remote token cannot be address(0)");
// Construct calldata for _l2Token.finalizeBridgeERC721(_to, _tokenId)
bytes memory message = abi.encodeWithSelector(
L2ERC721Bridge.finalizeBridgeERC721.selector,
_remoteToken,
_localToken,
_from,
_to,
_tokenId,
_extraData
);
// Lock token into bridge
deposits[_localToken][_remoteToken][_tokenId] = true;
IERC721(_localToken).transferFrom(_from, address(this), _tokenId);
// Send calldata into L2
messenger.sendMessage(otherBridge, message, _minGasLimit);
emit ERC721BridgeInitiated(_localToken, _remoteToken, _from, _to, _tokenId, _extraData);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { ERC721Bridge } from "../universal/op-erc721/ERC721Bridge.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { L1ERC721Bridge } from "../L1/L1ERC721Bridge.sol";
import { IOptimismMintableERC721 } from "../universal/op-erc721/IOptimismMintableERC721.sol";
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol";
/**
* @title L2ERC721Bridge
* @notice The L2 ERC721 bridge is a contract which works together with the L1 ERC721 bridge to
* make it possible to transfer ERC721 tokens from Ethereum to Optimism. This contract
* acts as a minter for new tokens when it hears about deposits into the L1 ERC721 bridge.
* This contract also acts as a burner for tokens being withdrawn.
* **WARNING**: Do not bridge an ERC721 that was originally deployed on Optimism. This
* bridge ONLY supports ERC721s originally deployed on Ethereum. Users will need to
* wait for the one-week challenge period to elapse before their Optimism-native NFT
* can be refunded on L2.
*/
contract L2ERC721Bridge is ERC721Bridge, Semver {
/**
* @custom:semver 1.0.0
*
* @param _messenger Address of the CrossDomainMessenger on this network.
* @param _otherBridge Address of the ERC721 bridge on the other network.
*/
constructor(address _messenger, address _otherBridge)
Semver(1, 0, 0)
ERC721Bridge(_messenger, _otherBridge)
{}
/**
* @notice Completes an ERC721 bridge from the other domain and sends the ERC721 token to the
* recipient on this domain.
*
* @param _localToken Address of the ERC721 token on this domain.
* @param _remoteToken Address of the ERC721 token on the other domain.
* @param _from Address that triggered the bridge on the other domain.
* @param _to Address to receive the token on this domain.
* @param _tokenId ID of the token being deposited.
* @param _extraData Optional data to forward to L1. Data supplied here will not be used to
* execute any code on L1 and is only emitted as extra data for the
* convenience of off-chain tooling.
*/
function finalizeBridgeERC721(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _tokenId,
bytes calldata _extraData
) external onlyOtherBridge {
require(_localToken != address(this), "L2ERC721Bridge: local token cannot be self");
// Note that supportsInterface makes a callback to the _localToken address which is user
// provided.
require(
ERC165Checker.supportsInterface(_localToken, type(IOptimismMintableERC721).interfaceId),
"L2ERC721Bridge: local token interface is not compliant"
);
require(
_remoteToken == IOptimismMintableERC721(_localToken).remoteToken(),
"L2ERC721Bridge: wrong remote token for Optimism Mintable ERC721 local token"
);
// When a deposit is finalized, we give the NFT with the same tokenId to the account
// on L2. Note that safeMint makes a callback to the _to address which is user provided.
IOptimismMintableERC721(_localToken).safeMint(_to, _tokenId);
// slither-disable-next-line reentrancy-events
emit ERC721BridgeFinalized(_localToken, _remoteToken, _from, _to, _tokenId, _extraData);
}
/**
* @inheritdoc ERC721Bridge
*/
function _initiateBridgeERC721(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _tokenId,
uint32 _minGasLimit,
bytes calldata _extraData
) internal override {
require(_remoteToken != address(0), "ERC721Bridge: remote token cannot be address(0)");
// Check that the withdrawal is being initiated by the NFT owner
require(
_from == IOptimismMintableERC721(_localToken).ownerOf(_tokenId),
"Withdrawal is not being initiated by NFT owner"
);
// Construct calldata for l1ERC721Bridge.finalizeBridgeERC721(_to, _tokenId)
// slither-disable-next-line reentrancy-events
address remoteToken = IOptimismMintableERC721(_localToken).remoteToken();
require(
remoteToken == _remoteToken,
"L2ERC721Bridge: remote token does not match given value"
);
// When a withdrawal is initiated, we burn the withdrawer's NFT to prevent subsequent L2
// usage
// slither-disable-next-line reentrancy-events
IOptimismMintableERC721(_localToken).burn(_from, _tokenId);
bytes memory message = abi.encodeWithSelector(
L1ERC721Bridge.finalizeBridgeERC721.selector,
remoteToken,
_localToken,
_from,
_to,
_tokenId,
_extraData
);
// Send message to L1 bridge
// slither-disable-next-line reentrancy-events
messenger.sendMessage(otherBridge, message, _minGasLimit);
// slither-disable-next-line reentrancy-events
emit ERC721BridgeInitiated(_localToken, remoteToken, _from, _to, _tokenId, _extraData);
}
}
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity ^0.8.0;
contract CallRecorder { contract CallRecorder {
struct CallInfo { struct CallInfo {
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity ^0.8.0;
import { ProxyAdmin } from "@eth-optimism/contracts-bedrock/contracts/universal/ProxyAdmin.sol"; import { ProxyAdmin } from "@eth-optimism/contracts-bedrock/contracts/universal/ProxyAdmin.sol";
import { Proxy } from "@eth-optimism/contracts-bedrock/contracts/universal/Proxy.sol"; import { Proxy } from "@eth-optimism/contracts-bedrock/contracts/universal/Proxy.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity ^0.8.0;
contract FailingReceiver { contract FailingReceiver {
receive() external payable { receive() external payable {
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity ^0.8.0;
contract Reverter { contract Reverter {
function doRevert() public pure { function doRevert() public pure {
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity ^0.8.0;
contract SimpleStorage { contract SimpleStorage {
mapping(bytes32 => bytes32) public db; mapping(bytes32 => bytes32) public db;
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity ^0.8.0;
import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity ^0.8.0;
import { ERC721 } from "@rari-capital/solmate/src/tokens/ERC721.sol"; import { ERC721 } from "@rari-capital/solmate/src/tokens/ERC721.sol";
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import {
CrossDomainMessenger
} from "@eth-optimism/contracts-bedrock/contracts/universal/CrossDomainMessenger.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
/**
* @title ERC721Bridge
* @notice ERC721Bridge is a base contract for the L1 and L2 ERC721 bridges.
*/
abstract contract ERC721Bridge {
/**
* @notice Emitted when an ERC721 bridge to the other network is initiated.
*
* @param localToken Address of the token on this domain.
* @param remoteToken Address of the token on the remote domain.
* @param from Address that initiated bridging action.
* @param to Address to receive the token.
* @param tokenId ID of the specific token deposited.
* @param extraData Extra data for use on the client-side.
*/
event ERC721BridgeInitiated(
address indexed localToken,
address indexed remoteToken,
address indexed from,
address to,
uint256 tokenId,
bytes extraData
);
/**
* @notice Emitted when an ERC721 bridge from the other network is finalized.
*
* @param localToken Address of the token on this domain.
* @param remoteToken Address of the token on the remote domain.
* @param from Address that initiated bridging action.
* @param to Address to receive the token.
* @param tokenId ID of the specific token deposited.
* @param extraData Extra data for use on the client-side.
*/
event ERC721BridgeFinalized(
address indexed localToken,
address indexed remoteToken,
address indexed from,
address to,
uint256 tokenId,
bytes extraData
);
/**
* @notice Messenger contract on this domain.
*/
CrossDomainMessenger public immutable messenger;
/**
* @notice Address of the bridge on the other network.
*/
address public immutable otherBridge;
/**
* @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades.
*/
uint256[49] private __gap;
/**
* @notice Ensures that the caller is a cross-chain message from the other bridge.
*/
modifier onlyOtherBridge() {
require(
msg.sender == address(messenger) && messenger.xDomainMessageSender() == otherBridge,
"ERC721Bridge: function can only be called from the other bridge"
);
_;
}
/**
* @param _messenger Address of the CrossDomainMessenger on this network.
* @param _otherBridge Address of the ERC721 bridge on the other network.
*/
constructor(address _messenger, address _otherBridge) {
require(_messenger != address(0), "ERC721Bridge: messenger cannot be address(0)");
require(_otherBridge != address(0), "ERC721Bridge: other bridge cannot be address(0)");
messenger = CrossDomainMessenger(_messenger);
otherBridge = _otherBridge;
}
/**
* @notice Initiates a bridge of an NFT to the caller's account on the other chain. Note that
* this function can only be called by EOAs. Smart contract wallets should use the
* `bridgeERC721To` function after ensuring that the recipient address on the remote
* chain exists. Also note that the current owner of the token on this chain must
* approve this contract to operate the NFT before it can be bridged.
* **WARNING**: Do not bridge an ERC721 that was originally deployed on Optimism. This
* bridge only supports ERC721s originally deployed on Ethereum. Users will need to
* wait for the one-week challenge period to elapse before their Optimism-native NFT
* can be refunded on L2.
*
* @param _localToken Address of the ERC721 on this domain.
* @param _remoteToken Address of the ERC721 on the remote domain.
* @param _tokenId Token ID to bridge.
* @param _minGasLimit Minimum gas limit for the bridge message on the other domain.
* @param _extraData Optional data to forward to the other chain. Data supplied here will not
* be used to execute any code on the other chain and is only emitted as
* extra data for the convenience of off-chain tooling.
*/
function bridgeERC721(
address _localToken,
address _remoteToken,
uint256 _tokenId,
uint32 _minGasLimit,
bytes calldata _extraData
) external {
// Modifier requiring sender to be EOA. This prevents against a user error that would occur
// if the sender is a smart contract wallet that has a different address on the remote chain
// (or doesn't have an address on the remote chain at all). The user would fail to receive
// the NFT if they use this function because it sends the NFT to the same address as the
// caller. This check could be bypassed by a malicious contract via initcode, but it takes
// care of the user error we want to avoid.
require(!Address.isContract(msg.sender), "ERC721Bridge: account is not externally owned");
_initiateBridgeERC721(
_localToken,
_remoteToken,
msg.sender,
msg.sender,
_tokenId,
_minGasLimit,
_extraData
);
}
/**
* @notice Initiates a bridge of an NFT to some recipient's account on the other chain. Note
* that the current owner of the token on this chain must approve this contract to
* operate the NFT before it can be bridged.
* **WARNING**: Do not bridge an ERC721 that was originally deployed on Optimism. This
* bridge only supports ERC721s originally deployed on Ethereum. Users will need to
* wait for the one-week challenge period to elapse before their Optimism-native NFT
* can be refunded on L2.
*
* @param _localToken Address of the ERC721 on this domain.
* @param _remoteToken Address of the ERC721 on the remote domain.
* @param _to Address to receive the token on the other domain.
* @param _tokenId Token ID to bridge.
* @param _minGasLimit Minimum gas limit for the bridge message on the other domain.
* @param _extraData Optional data to forward to the other chain. Data supplied here will not
* be used to execute any code on the other chain and is only emitted as
* extra data for the convenience of off-chain tooling.
*/
function bridgeERC721To(
address _localToken,
address _remoteToken,
address _to,
uint256 _tokenId,
uint32 _minGasLimit,
bytes calldata _extraData
) external {
require(_to != address(0), "ERC721Bridge: nft recipient cannot be address(0)");
_initiateBridgeERC721(
_localToken,
_remoteToken,
msg.sender,
_to,
_tokenId,
_minGasLimit,
_extraData
);
}
/**
* @notice Internal function for initiating a token bridge to the other domain.
*
* @param _localToken Address of the ERC721 on this domain.
* @param _remoteToken Address of the ERC721 on the remote domain.
* @param _from Address of the sender on this domain.
* @param _to Address to receive the token on the other domain.
* @param _tokenId Token ID to bridge.
* @param _minGasLimit Minimum gas limit for the bridge message on the other domain.
* @param _extraData Optional data to forward to the other domain. Data supplied here will
* not be used to execute any code on the other domain and is only emitted
* as extra data for the convenience of off-chain tooling.
*/
function _initiateBridgeERC721(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _tokenId,
uint32 _minGasLimit,
bytes calldata _extraData
) internal virtual;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {
IERC721Enumerable
} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
/**
* @title IOptimismMintableERC721
* @notice Interface for contracts that are compatible with the OptimismMintableERC721 standard.
* Tokens that follow this standard can be easily transferred across the ERC721 bridge.
*/
interface IOptimismMintableERC721 is IERC721Enumerable {
/**
* @notice Emitted when a token is minted.
*
* @param account Address of the account the token was minted to.
* @param tokenId Token ID of the minted token.
*/
event Mint(address indexed account, uint256 tokenId);
/**
* @notice Emitted when a token is burned.
*
* @param account Address of the account the token was burned from.
* @param tokenId Token ID of the burned token.
*/
event Burn(address indexed account, uint256 tokenId);
/**
* @notice Chain ID of the chain where the remote token is deployed.
*/
function remoteChainId() external view returns (uint256);
/**
* @notice Address of the token on the remote domain.
*/
function remoteToken() external view returns (address);
/**
* @notice Address of the ERC721 bridge on this network.
*/
function bridge() external view returns (address);
/**
* @notice Mints some token ID for a user, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* @param _to Address of the user to mint the token for.
* @param _tokenId Token ID to mint.
*/
function safeMint(address _to, uint256 _tokenId) external;
/**
* @notice Burns a token ID from a user.
*
* @param _from Address of the user to burn the token from.
* @param _tokenId Token ID to burn.
*/
function burn(address _from, uint256 _tokenId) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {
ERC721Enumerable
} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { IOptimismMintableERC721 } from "./IOptimismMintableERC721.sol";
/**
* @title OptimismMintableERC721
* @notice This contract is the remote representation for some token that lives on another network,
* typically an Optimism representation of an Ethereum-based token. Standard reference
* implementation that can be extended or modified according to your needs.
*/
contract OptimismMintableERC721 is ERC721Enumerable, IOptimismMintableERC721 {
/**
* @inheritdoc IOptimismMintableERC721
*/
uint256 public immutable remoteChainId;
/**
* @inheritdoc IOptimismMintableERC721
*/
address public immutable remoteToken;
/**
* @inheritdoc IOptimismMintableERC721
*/
address public immutable bridge;
/**
* @notice Base token URI for this token.
*/
string public baseTokenURI;
/**
* @param _bridge Address of the bridge on this network.
* @param _remoteChainId Chain ID where the remote token is deployed.
* @param _remoteToken Address of the corresponding token on the other network.
* @param _name ERC721 name.
* @param _symbol ERC721 symbol.
*/
constructor(
address _bridge,
uint256 _remoteChainId,
address _remoteToken,
string memory _name,
string memory _symbol
) ERC721(_name, _symbol) {
require(_bridge != address(0), "OptimismMintableERC721: bridge cannot be address(0)");
require(_remoteChainId != 0, "OptimismMintableERC721: remote chain id cannot be zero");
require(
_remoteToken != address(0),
"OptimismMintableERC721: remote token cannot be address(0)"
);
remoteChainId = _remoteChainId;
remoteToken = _remoteToken;
bridge = _bridge;
// Creates a base URI in the format specified by EIP-681:
// https://eips.ethereum.org/EIPS/eip-681
baseTokenURI = string(
abi.encodePacked(
"ethereum:",
Strings.toHexString(uint160(_remoteToken), 20),
"@",
Strings.toString(_remoteChainId),
"/tokenURI?uint256="
)
);
}
/**
* @notice Modifier that prevents callers other than the bridge from calling the function.
*/
modifier onlyBridge() {
require(msg.sender == bridge, "OptimismMintableERC721: only bridge can call this function");
_;
}
/**
* @inheritdoc IOptimismMintableERC721
*/
function safeMint(address _to, uint256 _tokenId) external virtual onlyBridge {
_safeMint(_to, _tokenId);
emit Mint(_to, _tokenId);
}
/**
* @inheritdoc IOptimismMintableERC721
*/
function burn(address _from, uint256 _tokenId) external virtual onlyBridge {
_burn(_tokenId);
emit Burn(_from, _tokenId);
}
/**
* @notice Checks if a given interface ID is supported by this contract.
*
* @param _interfaceId The interface ID to check.
*
* @return True if the interface ID is supported, false otherwise.
*/
function supportsInterface(bytes4 _interfaceId)
public
view
override(ERC721Enumerable, IERC165)
returns (bool)
{
bytes4 iface1 = type(IERC165).interfaceId;
bytes4 iface2 = type(IOptimismMintableERC721).interfaceId;
return
_interfaceId == iface1 ||
_interfaceId == iface2 ||
super.supportsInterface(_interfaceId);
}
/**
* @notice Returns the base token URI.
*
* @return Base token URI.
*/
function _baseURI() internal view virtual override returns (string memory) {
return baseTokenURI;
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { OptimismMintableERC721 } from "./OptimismMintableERC721.sol";
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol";
/**
* @title OptimismMintableERC721Factory
* @notice Factory contract for creating OptimismMintableERC721 contracts.
*/
contract OptimismMintableERC721Factory is Semver {
/**
* @notice Emitted whenever a new OptimismMintableERC721 contract is created.
*
* @param localToken Address of the token on the this domain.
* @param remoteToken Address of the token on the remote domain.
* @param deployer Address of the initiator of the deployment
*/
event OptimismMintableERC721Created(
address indexed localToken,
address indexed remoteToken,
address deployer
);
/**
* @notice Address of the ERC721 bridge on this network.
*/
address public immutable bridge;
/**
* @notice Chain ID for the remote network.
*/
uint256 public immutable remoteChainId;
/**
* @notice Tracks addresses created by this factory.
*/
mapping(address => bool) public isOptimismMintableERC721;
/**
* @custom:semver 1.0.0
*
* @param _bridge Address of the ERC721 bridge on this network.
*/
constructor(address _bridge, uint256 _remoteChainId) Semver(1, 0, 0) {
require(
_bridge != address(0),
"OptimismMintableERC721Factory: bridge cannot be address(0)"
);
require(
_remoteChainId != 0,
"OptimismMintableERC721Factory: remote chain id cannot be zero"
);
bridge = _bridge;
remoteChainId = _remoteChainId;
}
/**
* @notice Creates an instance of the standard ERC721.
*
* @param _remoteToken Address of the corresponding token on the other domain.
* @param _name ERC721 name.
* @param _symbol ERC721 symbol.
*/
function createOptimismMintableERC721(
address _remoteToken,
string memory _name,
string memory _symbol
) external returns (address) {
require(
_remoteToken != address(0),
"OptimismMintableERC721Factory: L1 token address cannot be address(0)"
);
address localToken = address(
new OptimismMintableERC721(bridge, remoteChainId, _remoteToken, _name, _symbol)
);
isOptimismMintableERC721[localToken] = true;
emit OptimismMintableERC721Created(localToken, _remoteToken, msg.sender);
return localToken;
}
}
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import fetch from 'node-fetch'
import {
isTargetL1Network,
predeploy,
getProxyAdmin,
validateERC721Bridge,
} from '../../src/nft-bridge-deploy-helpers'
// Handle the `ops` deployment
const getL1CrossDomainMessengerProxyDeployment = async (
hre: HardhatRuntimeEnvironment
) => {
const network = hre.network.name
if (network === 'ops-l1') {
const res = await fetch(
'http://localhost:8080/deployments/local/Proxy__OVM_L1CrossDomainMessenger.json'
)
return res.json()
} else {
return hre.deployments.get('Proxy__OVM_L1CrossDomainMessenger')
}
}
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = hre.deployments
const { getAddress } = hre.ethers.utils
if (!isTargetL1Network(hre.network.name)) {
console.log(`Deploying to unsupported network ${hre.network.name}`)
return
}
console.log(`Deploying L1ERC721Bridge to ${hre.network.name}`)
console.log(`Using deployer ${deployer}`)
const Deployment__L1ERC721BridgeProxy = await hre.deployments.get(
'L1ERC721BridgeProxy'
)
const L1ERC721BridgeProxy = await hre.ethers.getContractAt(
'Proxy',
Deployment__L1ERC721BridgeProxy.address
)
const admin = await L1ERC721BridgeProxy.callStatic.admin()
if (getAddress(admin) !== getAddress(deployer)) {
throw new Error('deployer is not proxy admin')
}
// Get the address of the currently deployed L1CrossDomainMessenger.
// This should be the address of the proxy
const Deployment__L1CrossDomainMessengerProxy =
await getL1CrossDomainMessengerProxyDeployment(hre)
const L1CrossDomainMessengerProxyAddress =
Deployment__L1CrossDomainMessengerProxy.address
// Deploy the L1ERC721Bridge. The arguments are
// - messenger
// - otherBridge
// Since this is the L1ERC721Bridge, the otherBridge is the
// predeploy address
await deploy('L1ERC721Bridge', {
from: deployer,
args: [L1CrossDomainMessengerProxyAddress, predeploy],
log: true,
waitConfirmations: 1,
})
const Deployment__L1ERC721Bridge = await hre.deployments.get('L1ERC721Bridge')
console.log(
`L1ERC721Bridge deployed to ${Deployment__L1ERC721Bridge.address}`
)
await validateERC721Bridge(hre, Deployment__L1ERC721Bridge.address, {
messenger: L1CrossDomainMessengerProxyAddress,
otherBridge: predeploy,
})
{
// Upgrade the Proxy to the newly deployed implementation
const tx = await L1ERC721BridgeProxy.upgradeTo(
Deployment__L1ERC721Bridge.address
)
const receipt = await tx.wait()
console.log(`L1ERC721BridgeProxy upgraded: ${receipt.transactionHash}`)
}
{
// Set the admin correctly
const newAdmin = getProxyAdmin(hre.network.name)
const tx = await L1ERC721BridgeProxy.changeAdmin(newAdmin)
const receipt = await tx.wait()
console.log(`L1ERC721BridgeProxy admin updated: ${receipt.transactionHash}`)
}
await validateERC721Bridge(hre, L1ERC721BridgeProxy.address, {
messenger: L1CrossDomainMessengerProxyAddress,
otherBridge: predeploy,
})
}
deployFn.tags = ['L1ERC721BridgeImplementation']
deployFn.dependencies = ['L1ERC721BridgeProxy']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { isTargetL1Network } from '../../src/nft-bridge-deploy-helpers'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = hre.deployments
if (!isTargetL1Network(hre.network.name)) {
console.log(`Deploying to unsupported network ${hre.network.name}`)
return
}
console.log(`Deploying L1ERC721BridgeProxy to ${hre.network.name}`)
console.log(`Using deployer ${deployer}`)
await deploy('L1ERC721BridgeProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: 1,
})
const Deployment__L1ERC721BridgeProxy = await hre.deployments.get(
'L1ERC721BridgeProxy'
)
console.log(
`L1ERC721BridgeProxy deployed to ${Deployment__L1ERC721BridgeProxy.address}`
)
}
deployFn.tags = ['L1ERC721BridgeProxy']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { predeploys } from '@eth-optimism/contracts'
import {
isTargetL2Network,
predeploy,
validateERC721Bridge,
getProxyAdmin,
} from '../../src/nft-bridge-deploy-helpers'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { getAddress } = hre.ethers.utils
if (!isTargetL2Network(hre.network.name)) {
console.log(`Deploying to unsupported network ${hre.network.name}`)
return
}
console.log(`Deploying L2ERC721Bridge to ${hre.network.name}`)
console.log(`Using deployer ${deployer}`)
const L2ERC721BridgeProxy = await hre.ethers.getContractAt('Proxy', predeploy)
// Check to make sure that the admin of the proxy is the deployer.
// The deployer of the L2ERC721Bridge should be the same as the
// admin of the L2ERC721BridgeProxy so that it is easy to upgrade
// the implementation. The admin is then changed depending on the
// network after the L2ERC721BridgeProxy is upgraded to the implementation
const admin = await L2ERC721BridgeProxy.callStatic.admin()
if (getAddress(admin) !== getAddress(deployer)) {
throw new Error(`Unexpected admin ${admin}`)
}
const Deployment__L1ERC721Bridge = await hre.companionNetworks[
'l1'
].deployments.get('L1ERC721BridgeProxy')
const L1ERC721BridgeAddress = Deployment__L1ERC721Bridge.address
// Deploy the L2ERC721Bridge implementation
await hre.deployments.deploy('L2ERC721Bridge', {
from: deployer,
args: [predeploys.L2CrossDomainMessenger, L1ERC721BridgeAddress],
log: true,
waitConfirmations: 1,
})
const Deployment__L2ERC721Bridge = await hre.deployments.get('L2ERC721Bridge')
console.log(
`L2ERC721Bridge deployed to ${Deployment__L2ERC721Bridge.address}`
)
await validateERC721Bridge(hre, Deployment__L2ERC721Bridge.address, {
messenger: predeploys.L2CrossDomainMessenger,
otherBridge: L1ERC721BridgeAddress,
})
{
// Upgrade the implementation of the proxy to the newly deployed
// L2ERC721Bridge
const tx = await L2ERC721BridgeProxy.upgradeTo(
Deployment__L2ERC721Bridge.address
)
const receipt = await tx.wait()
console.log(
`Upgraded the implementation of the L2ERC721BridgeProxy: ${receipt.transactionhash}`
)
}
await validateERC721Bridge(hre, L2ERC721BridgeProxy.address, {
messenger: predeploys.L2CrossDomainMessenger,
otherBridge: L1ERC721BridgeAddress,
})
{
const newAdmin = getProxyAdmin(hre.network.name)
console.log(`Changing admin to ${newAdmin}`)
const tx = await L2ERC721BridgeProxy.changeAdmin(newAdmin)
const receipt = await tx.wait()
console.log(
`Changed admin of the L2ERC721BridgeProxy: ${receipt.transactionHash}`
)
}
}
deployFn.tags = ['L2ERC721BridgeImplementation']
deployFn.dependencies = ['L2ERC721BridgeProxy', 'L1ERC721BridgeProxy']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
const predeploy = '0x4200000000000000000000000000000000000014'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { getAddress } = hre.ethers.utils
console.log(`Deploying L2ERC721BridgeProxy to ${hre.network.name}`)
console.log(`Using deployer ${deployer}`)
// Check to make sure that the Proxy has not been deployed yet
const pre = await hre.ethers.provider.getCode(predeploy, 'latest')
if (pre !== '0x') {
console.log(`Code already deployed to ${predeploy}`)
return
}
// A special deployer account must be used
const mainnetDeployer = getAddress(
'0x53A6eecC2dD4795Fcc68940ddc6B4d53Bd88Bd9E'
)
const goerliDeployer = getAddress(
'0x5c679a57e018f5f146838138d3e032ef4913d551'
)
const kovanDeployer = getAddress('0xa81224490b9fa4930a2e920550cd1c9106bb6d9e')
const localDeployer = getAddress('0xdfc82d475833a50de90c642770f34a9db7deb725')
// Deploy the L2ERC721BridgeProxy as a predeploy address
if (hre.network.name === 'optimism') {
if (getAddress(deployer) !== mainnetDeployer) {
throw new Error(`Incorrect deployer: ${deployer}`)
}
} else if (hre.network.name === 'optimism-goerli') {
if (getAddress(deployer) !== goerliDeployer) {
throw new Error(`Incorrect deployer: ${deployer}`)
}
} else if (hre.network.name === 'ops-l2') {
if (getAddress(deployer) !== localDeployer) {
throw new Error(`Incorrect deployer: ${deployer}`)
}
} else if (hre.network.name === 'optimism-kovan') {
if (getAddress(deployer) !== kovanDeployer) {
throw new Error(`Incorrect deployer: ${deployer}`)
}
} else {
throw new Error(`Unknown network: ${hre.network.name}`)
}
// Set the deployer as the admin of the Proxy. This is
// temporary, the admin will be updated when deploying
// the implementation
await hre.deployments.deploy('L2ERC721BridgeProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: 1,
})
// Check that the Proxy was deployed to the correct address
const code = await hre.ethers.provider.getCode(predeploy)
if (code === '0x') {
throw new Error('Code is not set at expected predeploy address')
}
console.log(`L2ERC721BridgeProxy deployed to ${predeploy}`)
}
deployFn.tags = ['L2ERC721BridgeProxy']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { getProxyAdmin, predeploy } from '../../src/nft-bridge-deploy-helpers'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { getAddress } = hre.ethers.utils
console.log(`Deploying OptimismMintableERC721Factory to ${hre.network.name}`)
console.log(`Using deployer ${deployer}`)
const Deployment__OptimismMintableERC721FactoryProxy =
await hre.deployments.get('OptimismMintableERC721FactoryProxy')
const OptimismMintableERC721FactoryProxy = await hre.ethers.getContractAt(
'Proxy',
Deployment__OptimismMintableERC721FactoryProxy.address
)
// Check that the admin of the OptimismMintableERC721FactoryProxy is the
// deployer. This makes it easy to upgrade the implementation of the proxy
// and then transfer the admin privilege after deploying the implementation
const admin = await OptimismMintableERC721FactoryProxy.callStatic.admin()
if (getAddress(admin) !== getAddress(deployer)) {
throw new Error('deployer is not proxy admin')
}
let remoteChainId: number
if (hre.network.name === 'optimism') {
remoteChainId = 1
} else if (hre.network.name === 'optimism-goerli') {
remoteChainId = 5
} else if (hre.network.name === 'ops-l2') {
remoteChainId = 31337
} else if (hre.network.name === 'optimism-kovan') {
remoteChainId = 42
} else {
remoteChainId = hre.deployConfig.remoteChainId
}
if (typeof remoteChainId !== 'number') {
throw new Error('remoteChainId not defined')
}
await hre.deployments.deploy('OptimismMintableERC721Factory', {
from: deployer,
args: [predeploy, remoteChainId],
log: true,
waitConfirmations: 1,
})
const Deployment__OptimismMintableERC721Factory = await hre.deployments.get(
'OptimismMintableERC721Factory'
)
console.log(
`OptimismMintableERC721Factory deployed to ${Deployment__OptimismMintableERC721Factory.address}`
)
{
// Upgrade the Proxy to the newly deployed implementation
const tx = await OptimismMintableERC721FactoryProxy.upgradeTo(
Deployment__OptimismMintableERC721Factory.address
)
const receipt = await tx.wait()
console.log(
`OptimismMintableERC721FactoryProxy upgraded: ${receipt.transactionHash}`
)
}
{
const newAdmin = getProxyAdmin(hre.network.name)
const tx = await OptimismMintableERC721FactoryProxy.changeAdmin(newAdmin)
const receipt = await tx.wait()
console.log(
`OptimismMintableERC721FactoryProxy admin updated: ${receipt.transactionHash}`
)
}
}
deployFn.tags = ['OptimismMintableERC721FactoryImplementation']
deployFn.dependencies = ['OptimismMintableERC721FactoryProxy']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = hre.deployments
console.log(
`Deploying OptimismMintableERC721FactoryProxy to ${hre.network.name}`
)
console.log(`Using deployer ${deployer}`)
// Deploy the OptimismMintableERC721FactoryProxy with
// the deployer as the admin. The admin and implementation
// will be updated with the deployment of the implementation
await deploy('OptimismMintableERC721FactoryProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: 1,
})
const Deployment__OptimismMintableERC721FactoryProxy =
await hre.deployments.get('OptimismMintableERC721FactoryProxy')
console.log(
`OptimismMintableERC721FactoryProxy deployed to ${Deployment__OptimismMintableERC721FactoryProxy.address}`
)
}
deployFn.tags = ['OptimismMintableERC721FactoryProxy']
export default deployFn
...@@ -55,7 +55,6 @@ ...@@ -55,7 +55,6 @@
}, },
"devDependencies": { "devDependencies": {
"@defi-wonderland/smock": "^2.0.7", "@defi-wonderland/smock": "^2.0.7",
"@eth-optimism/contracts": "^0.5.39",
"@eth-optimism/contracts-bedrock": "0.10.0", "@eth-optimism/contracts-bedrock": "0.10.0",
"@eth-optimism/core-utils": "^0.12.0", "@eth-optimism/core-utils": "^0.12.0",
"@eth-optimism/hardhat-deploy-config": "^0.2.5", "@eth-optimism/hardhat-deploy-config": "^0.2.5",
......
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, Contract } from 'ethers'
import { smock, FakeContract } from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../setup'
const TOKEN_ID = 10
const DUMMY_L1ERC721_ADDRESS: string =
'0x0034223412342234223422342234223422342234'
describe('OptimismMintableERC721', () => {
let l2BridgeImpersonator: Signer
let alice: Signer
let Fake__L2ERC721Bridge: FakeContract
let OptimismMintableERC721: Contract
let l2BridgeImpersonatorAddress: string
let aliceAddress: string
let baseUri: string
const remoteChainId = 100
let Factory__OptimismMintableERC721
before(async () => {
;[l2BridgeImpersonator, alice] = await ethers.getSigners()
l2BridgeImpersonatorAddress = await l2BridgeImpersonator.getAddress()
aliceAddress = await alice.getAddress()
baseUri = ''.concat(
'ethereum:',
DUMMY_L1ERC721_ADDRESS,
'@',
remoteChainId.toString(),
'/tokenURI?uint256='
)
Factory__OptimismMintableERC721 = await ethers.getContractFactory(
'OptimismMintableERC721'
)
OptimismMintableERC721 = await Factory__OptimismMintableERC721.deploy(
l2BridgeImpersonatorAddress,
remoteChainId,
DUMMY_L1ERC721_ADDRESS,
'L2ERC721',
'ERC'
)
// Get a new fake L2 bridge
Fake__L2ERC721Bridge = await smock.fake<Contract>(
'L2ERC721Bridge',
// This allows us to use an ethers override {from: Fake__L2ERC721Bridge.address} to mock calls
{ address: await l2BridgeImpersonator.getAddress() }
)
// mint an nft to alice
await OptimismMintableERC721.connect(l2BridgeImpersonator).safeMint(
aliceAddress,
TOKEN_ID,
{
from: Fake__L2ERC721Bridge.address,
}
)
})
describe('constructor', () => {
it('should revert if bridge is address(0)', async () => {
await expect(
Factory__OptimismMintableERC721.deploy(
ethers.constants.AddressZero,
remoteChainId,
DUMMY_L1ERC721_ADDRESS,
'L2ERC721',
'ERC'
)
).to.be.revertedWith(
'OptimismMintableERC721: bridge cannot be address(0)'
)
})
it('should revert if remote chain id is address(0)', async () => {
await expect(
Factory__OptimismMintableERC721.deploy(
l2BridgeImpersonatorAddress,
0,
DUMMY_L1ERC721_ADDRESS,
'L2ERC721',
'ERC'
)
).to.be.revertedWith(
'OptimismMintableERC721: remote chain id cannot be zero'
)
})
it('should revert if remote token is address(0)', async () => {
await expect(
Factory__OptimismMintableERC721.deploy(
l2BridgeImpersonatorAddress,
remoteChainId,
ethers.constants.AddressZero,
'L2ERC721',
'ERC'
)
).to.be.revertedWith(
'OptimismMintableERC721: remote token cannot be address(0)'
)
})
it('should be able to create a standard ERC721 contract with the correct parameters', async () => {
expect(await OptimismMintableERC721.bridge()).to.equal(
l2BridgeImpersonatorAddress
)
expect(await OptimismMintableERC721.remoteToken()).to.equal(
DUMMY_L1ERC721_ADDRESS
)
expect(await OptimismMintableERC721.name()).to.equal('L2ERC721')
expect(await OptimismMintableERC721.symbol()).to.equal('ERC')
expect(await OptimismMintableERC721.baseTokenURI()).to.equal(baseUri)
// alice has been minted an nft
expect(await OptimismMintableERC721.ownerOf(TOKEN_ID)).to.equal(
aliceAddress
)
})
})
describe('mint and burn', () => {
it('should not allow anyone but the L2 bridge to mint and burn', async () => {
await expect(
OptimismMintableERC721.connect(alice).safeMint(aliceAddress, 100)
).to.be.revertedWith(
'OptimismMintableERC721: only bridge can call this function'
)
await expect(
OptimismMintableERC721.connect(alice).burn(aliceAddress, 100)
).to.be.revertedWith(
'OptimismMintableERC721: only bridge can call this function'
)
})
})
describe('supportsInterface', () => {
it('should return the correct interface support', async () => {
// ERC165
expect(await OptimismMintableERC721.supportsInterface(0x01ffc9a7)).to.be
.true
// OptimismMintableERC721
expect(await OptimismMintableERC721.supportsInterface(0xe49bc7f8)).to.be
.true
// ERC721
expect(await OptimismMintableERC721.supportsInterface(0x80ac58cd)).to.be
.true
// Some bad interface
expect(await OptimismMintableERC721.supportsInterface(0xffffffff)).to.be
.false
})
})
describe('tokenURI', () => {
it('should return the correct token uri', async () => {
const tokenUri = baseUri.concat(TOKEN_ID.toString())
expect(await OptimismMintableERC721.tokenURI(TOKEN_ID)).to.equal(tokenUri)
})
})
})
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import {
smock,
MockContractFactory,
MockContract,
} from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../setup'
const DUMMY_L2_BRIDGE_ADDRESS: string = ethers.utils.getAddress(
'0x' + 'acdc'.repeat(10)
)
describe('OptimismMintableERC721Factory', () => {
let signer: Signer
let Factory__L1ERC721: MockContractFactory<ContractFactory>
let L1ERC721: MockContract<Contract>
let OptimismMintableERC721Factory: Contract
let baseURI: string
const remoteChainId = 100
let Factory__OptimismMintableERC721Factory: ContractFactory
beforeEach(async () => {
;[signer] = await ethers.getSigners()
// deploy an ERC721 contract on L1
Factory__L1ERC721 = await smock.mock(
'@openzeppelin/contracts/token/ERC721/ERC721.sol:ERC721'
)
L1ERC721 = await Factory__L1ERC721.deploy('L1ERC721', 'ERC')
Factory__OptimismMintableERC721Factory = await ethers.getContractFactory(
'OptimismMintableERC721Factory'
)
OptimismMintableERC721Factory =
await Factory__OptimismMintableERC721Factory.deploy(
DUMMY_L2_BRIDGE_ADDRESS,
remoteChainId
)
baseURI = ''.concat(
'ethereum:',
L1ERC721.address.toLowerCase(),
'@',
remoteChainId.toString(),
'/tokenURI?uint256='
)
})
it('should revert if bridge is initialized as address(0)', async () => {
await expect(
Factory__OptimismMintableERC721Factory.deploy(
ethers.constants.AddressZero,
remoteChainId
)
).to.be.revertedWith(
'OptimismMintableERC721Factory: bridge cannot be address(0)'
)
})
it('should revert if remote chain id is initialized as zero', async () => {
await expect(
Factory__OptimismMintableERC721Factory.deploy(DUMMY_L2_BRIDGE_ADDRESS, 0)
).to.be.revertedWith(
'OptimismMintableERC721Factory: remote chain id cannot be zero'
)
})
it('should be deployed with the correct constructor argument', async () => {
expect(await OptimismMintableERC721Factory.bridge()).to.equal(
DUMMY_L2_BRIDGE_ADDRESS
)
})
it('should be able to create a standard ERC721 contract', async () => {
const tx = await OptimismMintableERC721Factory.createOptimismMintableERC721(
L1ERC721.address,
'L2ERC721',
'ERC'
)
const receipt = await tx.wait()
// Get the OptimismMintableERC721Created event
const erc721CreatedEvent = receipt.events[0]
// Expect there to be an event emitted for the standard token creation
expect(erc721CreatedEvent.event).to.be.eq('OptimismMintableERC721Created')
// Get the L2 ERC721 address from the emitted event and check it was created correctly
const l2ERC721Address = erc721CreatedEvent.args.localToken
const OptimismMintableERC721 = new Contract(
l2ERC721Address,
(await ethers.getContractFactory('OptimismMintableERC721')).interface,
signer
)
expect(await OptimismMintableERC721.bridge()).to.equal(
DUMMY_L2_BRIDGE_ADDRESS
)
expect(await OptimismMintableERC721.remoteToken()).to.equal(
L1ERC721.address
)
expect(await OptimismMintableERC721.name()).to.equal('L2ERC721')
expect(await OptimismMintableERC721.symbol()).to.equal('ERC')
expect(await OptimismMintableERC721.baseTokenURI()).to.equal(baseURI)
expect(
await OptimismMintableERC721Factory.isOptimismMintableERC721(
OptimismMintableERC721.address
)
).to.equal(true)
})
it('should not be able to create a standard token with a 0 address for l1 token', async () => {
await expect(
OptimismMintableERC721Factory.createOptimismMintableERC721(
ethers.constants.AddressZero,
'L2ERC721',
'ERC'
)
).to.be.revertedWith(
'OptimismMintableERC721Factory: L1 token address cannot be address(0)'
)
})
})
This diff is collapsed.
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