Commit 68f3b862 authored by Ben Wilson's avatar Ben Wilson Committed by GitHub

Merge pull request #1897 from ethereum-optimism/develop

Develop -> Master Release PR
parents cea6f8fc 5f573335
---
'@eth-optimism/integration-tests': patch
---
Remove sync-tests as coverage lives in itests now
---
'@eth-optimism/contracts': patch
---
Add config checks to validation script
---
'@eth-optimism/contracts': patch
---
Copy the deployments directory into the deployer docker image
---
'@eth-optimism/proxyd': minor
---
Allows string RPC ids on proxyd
---
'@eth-optimism/integration-tests': patch
---
Enforce fees in docker-compose setup and test cases for fee too low and fee too high
---
'@eth-optimism/hardhat-node': patch
---
Add fork mode config to ethereumoptimism/hardhat docker image
---
'@eth-optimism/integration-tests': patch
---
Pass through starting block height to dtl
---
'@eth-optimism/op-exporter': patch
---
Cleanup op-exporter CI, renamed package
---
'@eth-optimism/hardhat-node': patch
---
Update to hardhat@2.7.0
......@@ -27,6 +27,7 @@ jobs:
canary-docker-tag: ${{ steps.docker-image-name.outputs.canary-docker-tag }}
proxyd: ${{ steps.packages.outputs.proxyd }}
rpc-proxy : ${{ steps.packages.outputs.rpc-proxy }}
op-exporter : ${{ steps.packages.outputs.op-exporter }}
steps:
- name: Check out source code
......@@ -405,6 +406,43 @@ jobs:
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
op-exporter:
name: Publish op-exporter Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish
if: needs.canary-publish.outputs.op-exporter != ''
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}
- name: Set build args
id: build_args
run: |
echo ::set-output name=GITDATE::"$(date +%d-%m-%Y)"
echo ::set-output name=GITVERSION::$(jq -r .version ./go/op-exporter/package.json)
echo ::set-output name=GITCOMMIT::"$GITHUB_SHA"
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.op-exporter
push: true
tags: ethereumoptimism/op-exporter:${{ needs.canary-publish.outputs.op-exporter }}
build-args: |
GITDATE=${{ steps.build_args.outputs.GITDATE }}
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
rpc-proxy:
name: Publish rpc-proxy Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish
......
......@@ -23,6 +23,7 @@ jobs:
proxyd: ${{ steps.packages.outputs.proxyd }}
rpc-proxy: ${{ steps.packages.outputs.rpc-proxy }}
hardhat-node: ${{ steps.packages.outputs.hardhat-node }}
op-exporter : ${{ steps.packages.outputs.op-exporter }}
steps:
- name: Checkout Repo
......@@ -98,14 +99,6 @@ jobs:
push: true
tags: ethereumoptimism/l2geth:${{ needs.release.outputs.l2geth }},ethereumoptimism/l2geth:latest
- name: Publish op_exporter
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.op_exporter
push: true
tags: ethereumoptimism/op_exporter:${{ needs.release.outputs.l2geth }}
- name: Publish rpc-proxy
uses: docker/build-push-action@v2
with:
......@@ -203,6 +196,43 @@ jobs:
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
op-exporter:
name: Publish op-exporter Version ${{ needs.release.outputs.canary-docker-tag }}
needs: release
if: needs.release.outputs.op-exporter != ''
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}
- name: Set build args
id: build_args
run: |
echo ::set-output name=GITDATE::"$(date +%d-%m-%Y)"
echo ::set-output name=GITVERSION::$(jq -r .version ./go/op-exporter/package.json)
echo ::set-output name=GITCOMMIT::"$GITHUB_SHA"
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.op-exporter
push: true
tags: ethereumoptimism/op-exporter:${{ needs.canary-publish.outputs.op-exporter }}
build-args: |
GITDATE=${{ steps.build_args.outputs.GITDATE }}
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
rpc-proxy:
name: Publish rpc-proxy Version ${{ needs.release.outputs.rpc-proxy }}
needs: release
......
module github.com/ethereum-optimism/optimism/go/op_exporter
module github.com/ethereum-optimism/optimism/go/op-exporter
go 1.16
require (
github.com/ethereum-optimism/optimism/go/op_exporter v0.0.0-20211207210647-c5a8db939ad4
github.com/ethereum/go-ethereum v1.10.4
github.com/prometheus/client_golang v1.4.0
github.com/sirupsen/logrus v1.4.2
github.com/ybbus/jsonrpc v2.1.2+incompatible
gopkg.in/alecthomas/kingpin.v2 v2.2.6
k8s.io/apimachinery v0.21.2 // indirect
k8s.io/apimachinery v0.21.2
k8s.io/client-go v0.21.2
)
......@@ -124,6 +124,8 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkg
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/optimism/go/op_exporter v0.0.0-20211207210647-c5a8db939ad4 h1:tTFuDWKAWayPWkqWd8CPwSfDoO4tMVScZgM5nhXs2+c=
github.com/ethereum-optimism/optimism/go/op_exporter v0.0.0-20211207210647-c5a8db939ad4/go.mod h1:w2HqYJpeDcqB6ZpPDsD7NmkvJCDAs23uNW7YHTn4g0M=
github.com/ethereum/go-ethereum v1.10.4 h1:JPZPL2MHbegfFStcaOrrggMVIcf57OQHQ0J3UhjQ+xQ=
github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
......@@ -276,6 +278,7 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
......@@ -308,6 +311,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
......@@ -322,6 +326,7 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
......@@ -336,6 +341,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
......@@ -377,6 +383,7 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
......@@ -387,6 +394,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
......@@ -536,7 +544,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988 h1:EjgCl+fVlIaPJSori0ikSz3uV0DOHKWOJFpv1sAAhBM=
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
......@@ -599,6 +606,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
......@@ -656,7 +664,6 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
......@@ -666,6 +673,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
......@@ -684,6 +692,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
......
{
"name": "@eth-optimism/op-exporter",
"version": "0.5.0",
"private": true,
"devDependencies": {}
}
......@@ -25,11 +25,6 @@ const (
)
var (
ErrInvalidRequest = &RPCErr{
Code: -32601,
Message: "invalid request",
HTTPErrorCode: 400,
}
ErrParseErr = &RPCErr{
Code: -32700,
Message: "parse error",
......@@ -67,6 +62,14 @@ var (
}
)
func ErrInvalidRequest(msg string) *RPCErr {
return &RPCErr{
Code: -32601,
Message: msg,
HTTPErrorCode: 400,
}
}
type Backend struct {
Name string
rpcURL string
......@@ -498,7 +501,7 @@ func (w *WSProxier) clientPump(ctx context.Context, errC chan error) {
// just handle them here.
req, err := w.prepareClientMsg(msg)
if err != nil {
var id *int
var id json.RawMessage
method := MethodUnknown
if req != nil {
id = req.ID
......@@ -555,7 +558,7 @@ func (w *WSProxier) backendPump(ctx context.Context, errC chan error) {
res, err := w.parseBackendMsg(msg)
if err != nil {
var id *int
var id json.RawMessage
if res != nil {
id = res.ID
}
......
......@@ -4,20 +4,21 @@ import (
"encoding/json"
"io"
"io/ioutil"
"strings"
)
type RPCReq struct {
JSONRPC string `json:"jsonrpc"`
Method string `json:"method"`
Params json.RawMessage `json:"params"`
ID *int `json:"id"`
ID json.RawMessage `json:"id"`
}
type RPCRes struct {
JSONRPC string `json:"jsonrpc"`
Result interface{} `json:"result,omitempty"`
Error *RPCErr `json:"error,omitempty"`
ID *int `json:"id"`
ID json.RawMessage `json:"id"`
}
func (r *RPCRes) IsError() bool {
......@@ -34,6 +35,17 @@ func (r *RPCErr) Error() string {
return r.Message
}
func IsValidID(id json.RawMessage) bool {
// handle the case where the ID is a string
if strings.HasPrefix(string(id), "\"") && strings.HasSuffix(string(id), "\"") {
return len(id) > 2
}
// technically allows a boolean/null ID, but so does Geth
// https://github.com/ethereum/go-ethereum/blob/master/rpc/json.go#L72
return len(id) > 0 && id[0] != '{' && id[0] != '['
}
func ParseRPCReq(r io.Reader) (*RPCReq, error) {
body, err := ioutil.ReadAll(r)
if err != nil {
......@@ -46,11 +58,15 @@ func ParseRPCReq(r io.Reader) (*RPCReq, error) {
}
if req.JSONRPC != JSONRPCVersion {
return nil, ErrInvalidRequest
return nil, ErrInvalidRequest("invalid JSON-RPC version")
}
if req.Method == "" {
return nil, ErrInvalidRequest
return nil, ErrInvalidRequest("no method specified")
}
if !IsValidID(req.ID) {
return nil, ErrInvalidRequest("invalid ID")
}
return req, nil
......@@ -70,7 +86,7 @@ func ParseRPCRes(r io.Reader) (*RPCRes, error) {
return res, nil
}
func NewRPCErrorRes(id *int, err error) *RPCRes {
func NewRPCErrorRes(id json.RawMessage, err error) *RPCRes {
var rpcErr *RPCErr
if rr, ok := err.(*RPCErr); ok {
rpcErr = rr
......
......@@ -232,7 +232,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context
)
}
func writeRPCError(w http.ResponseWriter, id *int, err error) {
func writeRPCError(w http.ResponseWriter, id json.RawMessage, err error) {
var res *RPCRes
if r, ok := err.(*RPCErr); ok {
res = NewRPCErrorRes(id, r)
......
......@@ -11,7 +11,6 @@
"test:integration": "hardhat --network optimism test",
"test:actor": "IS_LIVE_NETWORK=true ts-node actor-tests/lib/runner.ts",
"test:integration:live": "NO_NETWORK=true IS_LIVE_NETWORK=true hardhat --network optimism test",
"test:sync": "hardhat --network optimism test sync-tests/*.spec.ts --no-compile",
"clean": "rimraf cache artifacts",
"pre-commit": "lint-staged"
},
......
import { expect } from 'chai'
import { Wallet, BigNumber, providers } from 'ethers'
import { injectL2Context } from '@eth-optimism/core-utils'
import {
sleep,
l2Provider,
verifierProvider,
waitForL2Geth,
} from '../test/shared/utils'
import { OptimismEnv } from '../test/shared/env'
import { DockerComposeNetwork } from '../test/shared/docker-compose'
describe('Syncing a verifier', () => {
let env: OptimismEnv
let wallet: Wallet
let verifier: DockerComposeNetwork
let provider: providers.JsonRpcProvider
const sequencerProvider = injectL2Context(l2Provider)
/* Helper functions */
const waitForBatchSubmission = async (
totalElementsBefore: BigNumber
): Promise<BigNumber> => {
// Wait for batch submission to happen by watching the CTC
let totalElementsAfter = (await env.ctc.getTotalElements()) as BigNumber
while (totalElementsBefore.eq(totalElementsAfter)) {
await sleep(500)
totalElementsAfter = (await env.ctc.getTotalElements()) as BigNumber
}
return totalElementsAfter
}
const startVerifier = async () => {
// Bring up new verifier
verifier = new DockerComposeNetwork(['verifier'])
await verifier.up({ commandOptions: ['--scale', 'verifier=1'] })
provider = await waitForL2Geth(verifierProvider)
}
const syncVerifier = async (sequencerBlockNumber: number) => {
// Wait until verifier has caught up to the sequencer
let latestVerifierBlock = (await provider.getBlock('latest')) as any
while (latestVerifierBlock.number < sequencerBlockNumber) {
await sleep(500)
latestVerifierBlock = (await provider.getBlock('latest')) as any
}
return provider.getBlock(sequencerBlockNumber)
}
before(async () => {
env = await OptimismEnv.new()
wallet = env.l2Wallet
})
describe('Basic transactions', () => {
after(async () => {
await verifier.stop('verifier')
await verifier.rm()
})
it('should sync dummy transaction', async () => {
const totalElementsBefore =
(await env.ctc.getTotalElements()) as BigNumber
const tx = {
to: '0x' + '1234'.repeat(10),
gasLimit: 4000000,
gasPrice: 0,
data: '0x',
value: 0,
}
const result = await wallet.sendTransaction(tx)
await result.wait()
const totalElementsAfter = await waitForBatchSubmission(
totalElementsBefore
)
expect(totalElementsAfter.gt(totalElementsAfter))
const latestSequencerBlock = (await sequencerProvider.getBlock(
'latest'
)) as any
await startVerifier()
const matchingVerifierBlock = (await syncVerifier(
latestSequencerBlock.number
)) as any
expect(matchingVerifierBlock.stateRoot).to.eq(
latestSequencerBlock.stateRoot
)
})
it('should have matching block data', async () => {
const sequencerTip = await sequencerProvider.getBlock('latest')
const verifierTip = await provider.getBlock('latest')
expect(sequencerTip.number).to.deep.eq(verifierTip.number)
expect(sequencerTip.hash).to.deep.eq(verifierTip.hash)
})
})
})
import { expect } from 'chai'
import { Wallet, Contract, ContractFactory, providers } from 'ethers'
import { ethers } from 'hardhat'
import { injectL2Context } from '@eth-optimism/core-utils'
import {
sleep,
l2Provider,
replicaProvider,
waitForL2Geth,
} from '../test/shared/utils'
import { OptimismEnv } from '../test/shared/env'
import { DockerComposeNetwork } from '../test/shared/docker-compose'
describe('Syncing a replica', () => {
let env: OptimismEnv
let wallet: Wallet
let replica: DockerComposeNetwork
let provider: providers.JsonRpcProvider
const sequencerProvider = injectL2Context(l2Provider)
/* Helper functions */
const startReplica = async () => {
// Bring up new replica
replica = new DockerComposeNetwork(['replica'])
await replica.up({
commandOptions: ['--scale', 'replica=1'],
})
provider = await waitForL2Geth(replicaProvider)
}
const syncReplica = async (sequencerBlockNumber: number) => {
// Wait until replica has caught up to the sequencer
let latestReplicaBlock = (await provider.getBlock('latest')) as any
while (latestReplicaBlock.number < sequencerBlockNumber) {
await sleep(500)
latestReplicaBlock = (await provider.getBlock('latest')) as any
}
return provider.getBlock(sequencerBlockNumber)
}
before(async () => {
env = await OptimismEnv.new()
wallet = env.l2Wallet
})
after(async () => {
await replica.stop('replica')
await replica.rm()
})
describe('Basic transactions and ERC20s', () => {
const initialAmount = 1000
const tokenName = 'OVM Test'
const tokenDecimals = 8
const TokenSymbol = 'OVM'
let other: Wallet
let Factory__ERC20: ContractFactory
let ERC20: Contract
before(async () => {
other = Wallet.createRandom().connect(ethers.provider)
Factory__ERC20 = await ethers.getContractFactory('ERC20', wallet)
})
it('should sync dummy transaction', async () => {
const tx = {
to: '0x' + '1234'.repeat(10),
gasLimit: 4000000,
gasPrice: 0,
data: '0x',
value: 0,
}
const result = await wallet.sendTransaction(tx)
await result.wait()
const latestSequencerBlock = (await sequencerProvider.getBlock(
'latest'
)) as any
await startReplica()
const matchingReplicaBlock = (await syncReplica(
latestSequencerBlock.number
)) as any
expect(matchingReplicaBlock.stateRoot).to.eq(
latestSequencerBlock.stateRoot
)
})
it('should sync ERC20 deployment and transfer', async () => {
ERC20 = await Factory__ERC20.deploy(
initialAmount,
tokenName,
tokenDecimals,
TokenSymbol
)
const transfer = await ERC20.transfer(other.address, 100)
await transfer.wait()
const latestSequencerBlock = (await provider.getBlock('latest')) as any
const matchingReplicaBlock = (await syncReplica(
latestSequencerBlock.number
)) as any
expect(matchingReplicaBlock.stateRoot).to.eq(
latestSequencerBlock.stateRoot
)
})
})
})
......@@ -8,7 +8,7 @@ import { serialize } from '@ethersproject/transactions'
import { predeploys, getContractFactory } from '@eth-optimism/contracts'
/* Imports: Internal */
import { gasPriceForL2, isLiveNetwork } from './shared/utils'
import { isLiveNetwork } from './shared/utils'
import { OptimismEnv } from './shared/env'
import { Direction } from './shared/watcher-utils'
......@@ -173,10 +173,7 @@ describe('Fee Payment Integration Tests', async () => {
env.sequencerFeeVault.address
)
// Submit the withdrawal.
const withdrawTx = await env.sequencerFeeVault.withdraw({
gasPrice: await gasPriceForL2(env), // Will be zero on HH
})
const withdrawTx = await env.sequencerFeeVault.withdraw()
// Wait for the withdrawal to be relayed to L1.
await withdrawTx.wait()
......
......@@ -140,6 +140,45 @@ describe('Basic RPC tests', () => {
'gas required exceeds allowance'
)
})
it('should reject a transaction with too low of a fee', async () => {
if (isLiveNetwork()) {
console.log('Skipping too low of a fee test on live network')
return
}
const gasPrice = await env.gasPriceOracle.gasPrice()
await env.gasPriceOracle.setGasPrice(1000)
const tx = {
...defaultTransactionFactory(),
gasPrice: 1,
}
await expect(env.l2Wallet.sendTransaction(tx)).to.be.rejectedWith(
`gas price too low: 1 wei, use at least tx.gasPrice = 1000 wei`
)
// Reset the gas price to its original price
await env.gasPriceOracle.setGasPrice(gasPrice)
})
it('should reject a transaction with too high of a fee', async () => {
if (isLiveNetwork()) {
console.log('Skpping too high of a fee test on live network')
return
}
const gasPrice = await env.gasPriceOracle.gasPrice()
const largeGasPrice = gasPrice.mul(10)
const tx = {
...defaultTransactionFactory(),
gasPrice: largeGasPrice,
}
await expect(env.l2Wallet.sendTransaction(tx)).to.be.rejectedWith(
`gas price too high: ${largeGasPrice.toString()} wei, use at most ` +
`tx.gasPrice = ${gasPrice.toString()} wei`
)
})
})
describe('eth_call', () => {
......
......@@ -13,6 +13,7 @@ import {
replicaProvider,
l1Wallet,
l2Wallet,
gasPriceOracleWallet,
fundUser,
getOvmEth,
getL1Bridge,
......@@ -100,7 +101,7 @@ export class OptimismEnv {
.attach(ctcAddress)
const gasPriceOracle = getContractFactory('OVM_GasPriceOracle')
.connect(l2Wallet)
.connect(gasPriceOracleWallet)
.attach(predeploys.OVM_GasPriceOracle)
const sccAddress = await addressManager.getAddress('StateCommitmentChain')
......
......@@ -47,6 +47,10 @@ const env = cleanEnv(process.env, {
ADDRESS_MANAGER: str({
default: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
}),
GAS_PRICE_ORACLE_PRIVATE_KEY: str({
default:
'0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba',
}),
L2_CHAINID: num({ default: 420 }),
IS_LIVE_NETWORK: bool({ default: false }),
})
......@@ -77,6 +81,12 @@ export const l1Wallet = new Wallet(env.PRIVATE_KEY, l1Provider)
// if it's using non-0 gas price
export const l2Wallet = l1Wallet.connect(l2Provider)
// The owner of the GasPriceOracle on L2
export const gasPriceOracleWallet = new Wallet(
env.GAS_PRICE_ORACLE_PRIVATE_KEY,
l2Provider
)
// Predeploys
export const PROXY_SEQUENCER_ENTRYPOINT_ADDRESS =
'0x4200000000000000000000000000000000000004'
......@@ -182,14 +192,17 @@ export const waitForL2Geth = async (
// eslint-disable-next-line @typescript-eslint/no-shadow
export const gasPriceForL2 = async (env: OptimismEnv) => {
if (await isMainnet(env)) {
// The integration tests enforce fees on L2
// which run against hardhat on L1. Update if
// geth --dev is adopted for L1
const chainId = await env.l1Wallet.getChainId()
if ((await isMainnet(env)) || chainId === 31337) {
return env.l2Wallet.getGasPrice()
}
if (isLiveNetwork()) {
return Promise.resolve(BigNumber.from(10000))
}
return Promise.resolve(BigNumber.from(0))
}
......
......@@ -7,6 +7,8 @@ services:
build:
context: ./docker/hardhat
dockerfile: Dockerfile
env_file:
- ./envs/l1_chain.env
ports:
# expose the service to the host for integration testing
- ${L1CHAIN_HTTP_PORT:-9545}:8545
......@@ -26,12 +28,13 @@ services:
DEPLOYER_PRIVATE_KEY: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
SEQUENCER_PRIVATE_KEY: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
PROPOSER_PRIVATE_KEY: "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a"
GAS_PRICE_ORACLE_OWNER: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
# Default hardhat account 5
GAS_PRICE_ORACLE_OWNER: "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc"
# setting the whitelist owner to address(0) disables the whitelist
WHITELIST_OWNER: "0x0000000000000000000000000000000000000000"
L1_FEE_WALLET_ADDRESS: "0x391716d440c151c42cdf1c95c1d83a5427bca52c"
L2_CHAIN_ID: 420
L2_BLOCK_GAS_LIMIT: 11000000
L2_BLOCK_GAS_LIMIT: 15000000
BLOCK_SIGNER_ADDRESS: "0x00000398232E2064F896018496b4b44b3D62751F"
GAS_PRICE_ORACLE_OVERHEAD: "2750"
GAS_PRICE_ORACLE_SCALAR: "1500000"
......@@ -212,4 +215,5 @@ services:
entrypoint: ./gas-oracle.sh
environment:
GAS_PRICE_ORACLE_ETHEREUM_HTTP_URL: http://l2geth:8545
GAS_PRICE_ORACLE_PRIVATE_KEY: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
# Default hardhat account 5
GAS_PRICE_ORACLE_PRIVATE_KEY: "0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba"
......@@ -19,6 +19,7 @@ COPY --from=builder /optimism/packages/core-utils/dist ./packages/core-utils/dis
WORKDIR /opt/optimism/packages/contracts
COPY --from=builder /optimism/packages/contracts/dist ./dist
COPY --from=builder /optimism/packages/contracts/*.json ./
COPY --from=builder /optimism/packages/contracts/deployments ./deployments
COPY --from=builder /optimism/packages/contracts/node_modules ./node_modules
COPY --from=builder /optimism/packages/contracts/artifacts ./artifacts
COPY --from=builder /optimism/packages/contracts/src ./src
......
FROM golang:1.16 as builder
ADD ./go/op_exporter /app/
ADD ./go/op-exporter /app/
WORKDIR /app/
RUN make build
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/op_exporter /usr/local/bin/
ENTRYPOINT ["op_exporter"]
COPY --from=builder /app/op-exporter /usr/local/bin/
ENTRYPOINT ["op-exporter"]
CMD ["--help"]
module.exports = {
const isForkModeEnabled = !!process.env.FORK_URL
const forkUrl = process.env.FORK_URL
const forkStartingBlock = parseInt(process.env.FORK_STARTING_BLOCK) || undefined
const gasPrice = parseInt(process.env.GAS_PRICE) || 0
const config = {
networks: {
hardhat: {
gasPrice: 0,
gasPrice,
initialBaseFeePerGas: 0
},
},
analytics: { enabled: false },
}
if (isForkModeEnabled) {
console.log(`Running hardhat in a fork mode! URL: ${forkUrl}`)
if (forkStartingBlock) {
console.log(`Starting block: ${forkStartingBlock}`)
}
config.networks.hardhat.forking = {
url: forkUrl,
blockNumber: forkStartingBlock,
}
} else {
console.log('Running with a fresh state...')
}
module.exports = config
......@@ -6,6 +6,6 @@
},
"license": "MIT",
"dependencies": {
"hardhat": "^2.6.5"
"hardhat": "^2.7.0"
}
}
......@@ -8,6 +8,7 @@ DATA_TRANSPORT_LAYER__POLLING_INTERVAL=100
DATA_TRANSPORT_LAYER__LOGS_PER_POLLING_INTERVAL=2000
DATA_TRANSPORT_LAYER__DANGEROUSLY_CATCH_ALL_ERRORS=true
DATA_TRANSPORT_LAYER__SERVER_HOSTNAME=0.0.0.0
DATA_TRANSPORT_LAYER__L1_START_HEIGHT=1
DATA_TRANSPORT_LAYER__ADDRESS_MANAGER=
DATA_TRANSPORT_LAYER__L1_RPC_ENDPOINT=
......
......@@ -6,7 +6,7 @@ ETH1_CONFIRMATION_DEPTH=0
ROLLUP_CLIENT_HTTP=
ROLLUP_POLL_INTERVAL_FLAG=500ms
ROLLUP_ENABLE_L2_GAS_POLLING=true
# ROLLUP_ENFORCE_FEES=
ROLLUP_ENFORCE_FEES=true
RPC_ENABLE=true
RPC_ADDR=0.0.0.0
......@@ -36,3 +36,6 @@ BLOCK_SIGNER_KEY=6587ae678cf4fc9a33000cdbf9f35226b71dcc6a4684a31203241f9bcfd55d2
BLOCK_SIGNER_ADDRESS=0x00000398232E2064F896018496b4b44b3D62751F
L2_BLOCK_GAS_LIMIT=15000000
ROLLUP_FEE_THRESHOLD_DOWN=0.9
ROLLUP_FEE_THRESHOLD_UP=1.1
FORK_URL=
FORK_STARTING_BLOCK=
......@@ -12,6 +12,7 @@
"go/gas-oracle",
"go/batch-submitter",
"go/proxyd",
"go/op-exporter",
"ops/docker/rpc-proxy",
"ops/docker/hardhat"
],
......
......@@ -30,9 +30,9 @@ export const color = Object.fromEntries(
])
)
export const getArtifact = (name: string) => {
// Paths to artifacts relative to artifacts/contracts
const locations = {
// helper for finding the right artifact from the deployed name
const locateArtifact = (name: string) => {
return {
'ChainStorageContainer-CTC-batches':
'L1/rollup/ChainStorageContainer.sol/ChainStorageContainer.json',
'ChainStorageContainer-SCC-batches':
......@@ -48,9 +48,12 @@ export const getArtifact = (name: string) => {
'libraries/resolver/Lib_ResolvedDelegateProxy.sol/Lib_ResolvedDelegateProxy.json',
Proxy__OVM_L1StandardBridge:
'chugsplash/L1ChugSplashProxy.sol/L1ChugSplashProxy.json',
}
}[name]
}
export const getArtifactFromManagedName = (name: string) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
return require(`../artifacts/contracts/${locations[name]}`)
return require(`../artifacts/contracts/${locateArtifact(name)}`)
}
export const getEtherscanUrl = (network, address: string) => {
......@@ -63,26 +66,32 @@ const truncateLongString = (value: string): string => {
return value.length > 66 ? `${value.slice(0, 66)}...` : value
}
export const printSectionHead = (msg: string) => {
console.log(color.cyan(msg))
console.log(
color.cyan('='.repeat(Math.max(...msg.split('\n').map((s) => s.length))))
)
}
export const printComparison = (
action: string,
description: string,
expected: { name: string; value: string },
deployed: { name: string; value: string }
expected: { name: string; value: any },
deployed: { name: string; value: any }
) => {
console.log(action + ':')
console.log(`\n${action}:`)
if (hexStringEquals(expected.value, deployed.value)) {
console.log(
color.green(
`${expected.name}: ${truncateLongString(expected.value)}
matches
${deployed.name}: ${truncateLongString(deployed.value)}`
color.green(`${expected.name}: ${truncateLongString(expected.value)}`)
)
console.log('matches')
console.log(
color.green(`${deployed.name}: ${truncateLongString(deployed.value)}`)
)
console.log(color.green(`${description} looks good! 😎`))
} else {
throw new Error(`${description} looks wrong.
${expected.value}\ndoes not match\n${deployed.value}.
`)
throw new Error(
`${description} looks wrong. ${expected.value}\ndoes not match\n${deployed.value}.`
)
}
console.log() // Add some whitespace
}
......@@ -4,13 +4,15 @@ import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes'
import { hexStringEquals } from '@eth-optimism/core-utils'
import { getContractFactory } from '../src/contract-defs'
import { getContractFactory, getContractDefinition } from '../src/contract-defs'
import { names } from '../src/address-names'
import {
getInput,
color as c,
getArtifact,
getArtifactFromManagedName,
getEtherscanUrl,
printSectionHead,
printComparison,
} from '../src/validation-utils'
......@@ -49,7 +51,7 @@ task('validate:address-dictator')
const network = await provider.getNetwork()
console.log()
console.log(c.cyan("First make sure you're on the right chain:"))
printSectionHead("First make sure you're on the right chain:")
console.log(
`Reading from the ${c.red(network.name)} network (Chain ID: ${c.red(
'' + network.chainId
......@@ -57,16 +59,14 @@ task('validate:address-dictator')
)
await getInput(c.yellow('OK? Hit enter to continue.'))
// eslint-disable-next-line @typescript-eslint/no-var-requires
const dictatorArtifact = require('../artifacts/contracts/L1/deployment/AddressDictator.sol/AddressDictator.json')
const dictatorArtifact = getContractDefinition('AddressDictator')
const dictatorCode = await provider.getCode(args.dictator)
console.log(
c.cyan(`
Now validating the Address Dictator deployment at\n${getEtherscanUrl(
printSectionHead(`
Validate the Address Dictator deployment at\n${getEtherscanUrl(
network,
args.dictator
)}`)
)
printComparison(
'Comparing deployed AddressDictator bytecode against local build artifacts',
'Deployed AddressDictator code',
......@@ -87,12 +87,12 @@ Now validating the Address Dictator deployment at\n${getEtherscanUrl(
{ name: 'finalOwner ', value: finalOwner }
)
const manager = await dictatorContract.manager()
const deployedManager = await dictatorContract.manager()
printComparison(
'Validating the AddressManager address in the AddressDictator',
'addressManager',
{ name: 'manager', value: args.manager },
{ name: 'Address Manager', value: manager }
{ name: 'manager ', value: args.manager },
{ name: 'Address Manager', value: deployedManager }
)
await getInput(c.yellow('OK? Hit enter to continue.'))
......@@ -107,15 +107,20 @@ Now validating the Address Dictator deployment at\n${getEtherscanUrl(
// Now we loop over those and compare the addresses/deployedBytecode to deployment artifacts.
for (const pair of namedAddresses) {
if (pair.name === 'L2CrossDomainMessenger') {
console.log('L2CrossDomainMessenger is set to:', pair.addr)
await getInput(c.yellow('OK? Hit enter to continue.'))
// This is an L2 predeploy, so we skip bytecode and config validation.
continue
}
const currentAddress = await managerContract.getAddress(pair.name)
const artifact = getArtifact(pair.name)
const artifact = getArtifactFromManagedName(pair.name)
const addressChanged = !hexStringEquals(currentAddress, pair.addr)
if (addressChanged) {
console.log(
c.cyan(`
Now validating the ${pair.name} deployment.
printSectionHead(
`Validate the ${pair.name} deployment.
Current address: ${getEtherscanUrl(network, currentAddress)}
Upgraded address ${getEtherscanUrl(network, pair.addr)}`)
Upgraded address ${getEtherscanUrl(network, pair.addr)}`
)
const code = await provider.getCode(pair.addr)
......@@ -144,12 +149,138 @@ Upgraded address ${getEtherscanUrl(network, pair.addr)}`)
`Verifying ${pair.name} has the correct AddressManager address`,
`The AddressManager address in ${pair.name}`,
{ name: 'Deployed value', value: libAddressManager },
{ name: 'Expected value', value: manager }
{ name: 'Expected value', value: deployedManager }
)
await getInput(c.yellow('OK? Hit enter to continue.'))
}
}
}
await getInput(c.yellow('OK? Hit enter to continue.'))
await validateDeployedConfig(provider, network, args.manager, pair)
}
console.log(c.green('AddressManager Validation complete!'))
console.log(c.green('\nAddressManager Validation complete!'))
})
/**
* Validates that the deployed contracts have the expected storage variables.
*
* @param {*} provider
* @param {{ name: string; addr: string }} pair The contract name and address
*/
const validateDeployedConfig = async (
provider,
network,
manager,
pair: { name: string; addr: string }
) => {
printSectionHead(`
Ensure that the ${pair.name} at\n${getEtherscanUrl(
network,
pair.addr
)} is configured correctly`)
if (pair.name === names.managed.contracts.StateCommitmentChain) {
const scc = getContractFactory(pair.name)
.attach(pair.addr)
.connect(provider)
// --scc-fraud-proof-window 604800 \
const fraudProofWindow = await scc.FRAUD_PROOF_WINDOW()
printComparison(
'Checking the fraudProofWindow of the StateCommitmentChain',
'StateCommitmentChain.fraudProofWindow',
{
name: 'Configured fraudProofWindow',
value: ethers.BigNumber.from(604_800).toHexString(),
},
{
name: 'Deployed fraudProofWindow ',
value: ethers.BigNumber.from(fraudProofWindow).toHexString(),
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
// --scc-sequencer-publish-window 12592000 \
const sequencerPublishWindow = await scc.SEQUENCER_PUBLISH_WINDOW()
printComparison(
'Checking the sequencerPublishWindow of the StateCommitmentChain',
'StateCommitmentChain.sequencerPublishWindow',
{
name: 'Configured sequencerPublishWindow ',
value: ethers.BigNumber.from(12592000).toHexString(),
},
{
name: 'Deployed sequencerPublishWindow',
value: ethers.BigNumber.from(sequencerPublishWindow).toHexString(),
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
} else if (pair.name === names.managed.contracts.CanonicalTransactionChain) {
const ctc = getContractFactory(pair.name)
.attach(pair.addr)
.connect(provider)
// --ctc-max-transaction-gas-limit 15000000 \
const maxTransactionGasLimit = await ctc.maxTransactionGasLimit()
printComparison(
'Checking the maxTransactionGasLimit of the CanonicalTransactionChain',
'CanonicalTransactionChain.maxTransactionGasLimit',
{
name: 'Configured maxTransactionGasLimit',
value: ethers.BigNumber.from(15_000_000).toHexString(),
},
{
name: 'Deployed maxTransactionGasLimit ',
value: ethers.BigNumber.from(maxTransactionGasLimit).toHexString(),
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
// --ctc-l2-gas-discount-divisor 32 \
const l2GasDiscountDivisor = await ctc.l2GasDiscountDivisor()
printComparison(
'Checking the l2GasDiscountDivisor of the CanonicalTransactionChain',
'CanonicalTransactionChain.l2GasDiscountDivisor',
{
name: 'Configured l2GasDiscountDivisor',
value: ethers.BigNumber.from(32).toHexString(),
},
{
name: 'Deployed l2GasDiscountDivisor ',
value: ethers.BigNumber.from(l2GasDiscountDivisor).toHexString(),
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
// --ctc-enqueue-gas-cost 60000 \
const enqueueGasCost = await ctc.enqueueGasCost()
printComparison(
'Checking the enqueueGasCost of the CanonicalTransactionChain',
'CanonicalTransactionChain.enqueueGasCost',
{
name: 'Configured enqueueGasCost',
value: ethers.BigNumber.from(60000).toHexString(),
},
{
name: 'Deployed enqueueGasCost ',
value: ethers.BigNumber.from(enqueueGasCost).toHexString(),
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
} else if (pair.name === names.managed.contracts.OVM_L1CrossDomainMessenger) {
const messengerManager = await getContractFactory('L1CrossDomainMessenger')
.attach(pair.addr)
.connect(provider)
.libAddressManager()
printComparison(
'Ensure that the L1CrossDomainMessenger (implementation) is initialized with a non-zero Address Manager variable',
"L1CrossDomainMessenger's Lib_AddressManager",
{
name: 'Configured Lib_AddressManager',
value: messengerManager,
},
{
name: 'Deployed Lib_AddressManager ',
value: manager,
}
)
} else {
console.log(c.green(`${pair.name} has no config to check`))
await getInput(c.yellow('OK? Hit enter to continue.'))
}
}
......@@ -3,13 +3,14 @@
import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes'
import { getContractFactory } from '../src/contract-defs'
import { getContractFactory, getContractDefinition } from '../src/contract-defs'
import {
getInput,
color as c,
getEtherscanUrl,
printComparison,
printSectionHead,
} from '../src/validation-utils'
task('validate:chugsplash-dictator')
......@@ -54,24 +55,24 @@ task('validate:chugsplash-dictator')
)})`
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
// eslint-disable-next-line @typescript-eslint/no-var-requires
const dictatorArtifact = require('../artifacts/contracts/L1/deployment/ChugSplashDictator.sol/ChugSplashDictator.json')
const dictatorArtifact = getContractDefinition('ChugSplashDictator')
const dictatorCode = await provider.getCode(args.dictator)
console.log(
c.cyan(`
Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
printSectionHead(
`Validate the Chugsplash Dictator deployment at\n${getEtherscanUrl(
network,
args.dictator
)}`)
)}`
)
printComparison(
'Comparing deployed ChugSplashDictator bytecode against local build artifacts',
'Compare the deployed ChugSplashDictator bytecode against local build artifacts',
'Deployed ChugSplashDictator code',
{ name: 'Compiled bytecode', value: dictatorArtifact.deployedBytecode },
{ name: 'Deployed bytecode', value: dictatorCode }
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
console.log(
c.cyan("The next 4 checks will validate the ChugSplashDictator's config")
......@@ -82,12 +83,13 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
.connect(provider)
const finalOwner = await dictatorContract.finalOwner()
printComparison(
'1. Comparing the finalOwner address in the ChugSplashDictator to the multisig address',
'Compare the finalOwner address in the ChugSplashDictator to the multisig address',
'finalOwner',
{ name: 'multisig address', value: args.multisig },
{ name: 'finalOwner ', value: finalOwner }
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
const dictatorMessengerSlotKey = await dictatorContract.messengerSlotKey()
const dictatorMessengerSlotVal = await dictatorContract.messengerSlotVal()
......@@ -96,7 +98,7 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
dictatorMessengerSlotKey
)
printComparison(
'2. Comparing the messenger slot key/value to be set, with the current values in the proxy',
'Compare the Messenger slot key/value to be set, with the current values in the proxy',
`Storage slot key ${dictatorMessengerSlotKey}`,
{
name: `Value in the proxy at slot key\n${dictatorMessengerSlotKey}`,
......@@ -108,6 +110,7 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
const dictatorBridgeSlotKey = await dictatorContract.bridgeSlotKey()
const dictatorBridgeSlotVal = await dictatorContract.bridgeSlotVal()
......@@ -116,7 +119,7 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
dictatorBridgeSlotKey
)
printComparison(
'3. Comparing the _Bridge_ slot key/value to be set, with the current values in the proxy',
'Compare the Bridge slot key/value to be set, with the current values in the proxy',
`Storage slot key ${dictatorBridgeSlotKey}`,
{
name: `Value currently in the proxy at slot key\n${dictatorBridgeSlotKey}`,
......@@ -128,15 +131,15 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
// eslint-disable-next-line @typescript-eslint/no-var-requires
const bridgeArtifact = require('../artifacts/contracts/L1/messaging/L1StandardBridge.sol/L1StandardBridge.json')
const bridgeArtifact = getContractDefinition('L1StandardBridge')
const expectedCodeHash = ethers.utils.keccak256(
bridgeArtifact.deployedBytecode
)
const actualCodeHash = await dictatorContract.codeHash()
printComparison(
"4. Comparing the Dictator's codeHash against hash of the local L1StandardBridge build artifacts",
"Compare the Dictator's codeHash against hash of the local L1StandardBridge build artifacts",
"Dictator's codeHash",
{
name: 'Expected codeHash',
......@@ -148,5 +151,6 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
console.log(c.green('Chugsplash Dictator Validation complete!'))
})
module.exports = {
extends: '../../.eslintrc.js',
}
node_modules/
build/
module.exports = {
...require('../../.prettierrc.js'),
};
\ No newline at end of file
(The MIT License)
Copyright 2020-2021 Optimism
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/master/graph/badge.svg?token=0VTG7PG7YR&flag=sdk)](https://codecov.io/gh/ethereum-optimism/optimism)
# @eth-optimism/sdk
The `@eth-optimism/sdk` package provides a set of tools for interacting with Optimistic Ethereum.
## Installation
```
npm install @eth-optimism/sdk
```
## API
TODO: Fill this in once the initial package version is finished.
{
"name": "@eth-optimism/sdk",
"version": "0.0.1",
"description": "[Optimism] Tools for working with Optimistic Ethereum",
"main": "dist/index",
"types": "dist/index",
"files": [
"dist/index"
],
"scripts": {
"all": "yarn clean && yarn build && yarn test && yarn lint:fix && yarn lint",
"build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check",
"lint:check": "eslint .",
"lint:fix": "yarn lint:check --fix",
"pre-commit": "lint-staged"
},
"keywords": [
"optimism",
"ethereum",
"sdk"
],
"homepage": "https://github.com/ethereum-optimism/optimism-monorepo/tree/master/packages/sdk#readme",
"license": "MIT",
"author": "Optimism PBC",
"repository": {
"type": "git",
"url": "https://github.com/ethereum-optimism/optimism-monorepo.git"
},
"devDependencies": {
"@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@types/chai": "^4.2.18",
"@types/chai-as-promised": "^7.1.4",
"@types/mocha": "^8.2.2",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"chai": "^4.3.4",
"chai-as-promised": "^7.1.1",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"ethereum-waffle": "^3.4.0",
"hardhat": "^2.3.0",
"lint-staged": "11.0.0",
"mocha": "^8.4.0",
"nyc": "^15.1.0",
"prettier": "^2.3.1",
"ts-mocha": "^8.0.0",
"typescript": "^4.3.5"
},
"dependencies": {
"@eth-optimism/contracts": "0.5.5",
"@eth-optimism/core-utils": "0.7.3",
"@ethersproject/abstract-provider": "^5.5.1",
"@ethersproject/abstract-signer": "^5.5.0",
"ethers": "^5.5.2"
}
}
export * from './interfaces'
import { Overrides, Signer } from 'ethers'
import {
TransactionRequest,
TransactionResponse,
} from '@ethersproject/abstract-provider'
import {
MessageLike,
AddressLike,
NumberLike,
CrossChainMessageRequest,
L1ToL2Overrides,
} from './types'
import { ICrossChainProvider } from './cross-chain-provider'
/**
* Represents a utility class for making L1/L2 cross-chain transactions.
*/
export interface ICrossChainMessenger {
/**
* Provider that will be used to interact with the L1/L2 system.
*/
provider: ICrossChainProvider
/**
* Signer that will carry out L1/L2 transactions.
*/
signer: Signer
/**
* Sends a given cross chain message. Where the message is sent depends on the direction attached
* to the message itself.
*
* @param message Cross chain message to send.
* @param overrides Optional transaction overrides.
* @returns Transaction response for the message sending transaction.
*/
sendMessage(
message: CrossChainMessageRequest,
overrides?: L1ToL2Overrides
): Promise<TransactionResponse>
/**
* Resends a given cross chain message with a different gas limit. Only applies to L1 to L2
* messages. If provided an L2 to L1 message, this function will throw an error.
*
* @param message Cross chain message to resend.
* @param messageGasLimit New gas limit to use for the message.
* @param overrides Optional transaction overrides.
* @returns Transaction response for the message resending transaction.
*/
resendMessage(
message: MessageLike,
messageGasLimit: NumberLike,
overrides?: Overrides
): Promise<TransactionResponse>
/**
* Finalizes a cross chain message that was sent from L2 to L1. Only applicable for L2 to L1
* messages. Will throw an error if the message has not completed its challenge period yet.
*
* @param message Message to finalize.
* @param overrides Optional transaction overrides.
* @returns Transaction response for the finalization transaction.
*/
finalizeMessage(
message: MessageLike,
overrides?: Overrides
): Promise<TransactionResponse>
/**
* Deposits some tokens into the L2 chain.
*
* @param token Address of the token to deposit.
* @param amount Amount of the token to deposit.
* @param overrides Optional transaction overrides.
* @returns Transaction response for the deposit transaction.
*/
depositTokens(
token: AddressLike,
amount: NumberLike,
overrides?: L1ToL2Overrides
): Promise<TransactionResponse>
/**
* Deposits some ETH into the L2 chain.
*
* @param amount Amount of ETH to deposit (in wei).
* @param overrides Optional transaction overrides.
* @returns Transaction response for the deposit transaction.
*/
depositETH(
amount: NumberLike,
overrides?: L1ToL2Overrides
): Promise<TransactionResponse>
/**
* Withdraws some tokens back to the L1 chain.
*
* @param token Address of the token to withdraw.
* @param amount Amount of the token to withdraw.
* @param overrides Optional transaction overrides.
* @returns Transaction response for the withdraw transaction.
*/
withdrawTokens(
token: AddressLike,
amount: NumberLike,
overrides?: Overrides
): Promise<TransactionResponse>
/**
* Withdraws some ETH back to the L1 chain.
*
* @param amount Amount of ETH to withdraw.
* @param overrides Optional transaction overrides.
* @returns Transaction response for the withdraw transaction.
*/
withdrawETH(
amount: NumberLike,
overrides?: Overrides
): Promise<TransactionResponse>
/**
* Object that holds the functions that generate transactions to be signed by the user.
* Follows the pattern used by ethers.js.
*/
populateTransaction: {
/**
* Generates a transaction that sends a given cross chain message. This transaction can be signed
* and executed by a signer.
*
* @param message Cross chain message to send.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to send the message.
*/
sendMessage: (
message: CrossChainMessageRequest,
overrides?: L1ToL2Overrides
) => Promise<TransactionResponse>
/**
* Generates a transaction that resends a given cross chain message. Only applies to L1 to L2
* messages. This transaction can be signed and executed by a signer.
*
* @param message Cross chain message to resend.
* @param messageGasLimit New gas limit to use for the message.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to resend the message.
*/
resendMessage(
message: MessageLike,
messageGasLimit: NumberLike,
overrides?: Overrides
): Promise<TransactionRequest>
/**
* Generates a message finalization transaction that can be signed and executed. Only
* applicable for L2 to L1 messages. Will throw an error if the message has not completed
* its challenge period yet.
*
* @param message Message to generate the finalization transaction for.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to finalize the message.
*/
finalizeMessage(
message: MessageLike,
overrides?: Overrides
): Promise<TransactionRequest>
/**
* Generates a transaction for depositing some tokens into the L2 chain.
*
* @param token Address of the token to deposit.
* @param amount Amount of the token to deposit.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to deposit the tokens.
*/
depositTokens(
token: AddressLike,
amount: NumberLike,
overrides?: L1ToL2Overrides
): Promise<TransactionResponse>
/**
* Generates a transaction for depositing some ETH into the L2 chain.
*
* @param amount Amount of ETH to deposit.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to deposit the ETH.
*/
depositETH(
amount: NumberLike,
overrides?: L1ToL2Overrides
): Promise<TransactionRequest>
/**
* Generates a transaction for withdrawing some tokens back to the L1 chain.
*
* @param token Address of the token to withdraw.
* @param amount Amount of the token to withdraw.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to withdraw the tokens.
*/
withdrawTokens(
token: AddressLike,
amount: NumberLike,
overrides?: Overrides
): Promise<TransactionRequest>
/**
* Generates a transaction for withdrawing some ETH back to the L1 chain.
*
* @param amount Amount of ETH to withdraw.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to withdraw the tokens.
*/
withdrawETH(
amount: NumberLike,
overrides?: Overrides
): Promise<TransactionRequest>
}
/**
* Object that holds the functions that estimates the gas required for a given transaction.
* Follows the pattern used by ethers.js.
*/
estimateGas: {
/**
* Estimates gas required to send a cross chain message.
*
* @param message Cross chain message to send.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to send the message.
*/
sendMessage: (
message: CrossChainMessageRequest,
overrides?: L1ToL2Overrides
) => Promise<TransactionResponse>
/**
* Estimates gas required to resend a cross chain message. Only applies to L1 to L2 messages.
*
* @param message Cross chain message to resend.
* @param messageGasLimit New gas limit to use for the message.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to resend the message.
*/
resendMessage(
message: MessageLike,
messageGasLimit: NumberLike,
overrides?: Overrides
): Promise<TransactionRequest>
/**
* Estimates gas required to finalize a cross chain message. Only applies to L2 to L1 messages.
*
* @param message Message to generate the finalization transaction for.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to finalize the message.
*/
finalizeMessage(
message: MessageLike,
overrides?: Overrides
): Promise<TransactionRequest>
/**
* Estimates gas required to deposit some tokens into the L2 chain.
*
* @param token Address of the token to deposit.
* @param amount Amount of the token to deposit.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to deposit the tokens.
*/
depositTokens(
token: AddressLike,
amount: NumberLike,
overrides?: L1ToL2Overrides
): Promise<TransactionResponse>
/**
* Estimates gas required to deposit some ETH into the L2 chain.
*
* @param amount Amount of ETH to deposit.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to deposit the ETH.
*/
depositETH(
amount: NumberLike,
overrides?: L1ToL2Overrides
): Promise<TransactionRequest>
/**
* Estimates gas required to withdraw some tokens back to the L1 chain.
*
* @param token Address of the token to withdraw.
* @param amount Amount of the token to withdraw.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to withdraw the tokens.
*/
withdrawTokens(
token: AddressLike,
amount: NumberLike,
overrides?: Overrides
): Promise<TransactionRequest>
/**
* Estimates gas required to withdraw some ETH back to the L1 chain.
*
* @param amount Amount of ETH to withdraw.
* @param overrides Optional transaction overrides.
* @returns Transaction that can be signed and executed to withdraw the tokens.
*/
withdrawETH(
amount: NumberLike,
overrides?: Overrides
): Promise<TransactionRequest>
}
}
import { BigNumber } from 'ethers'
import { Provider, BlockTag } from '@ethersproject/abstract-provider'
import {
MessageLike,
TransactionLike,
AddressLike,
NumberLike,
CrossChainMessage,
MessageDirection,
MessageStatus,
TokenBridgeMessage,
OEContracts,
MessageReceipt,
} from './types'
/**
* Represents the L1/L2 connection. Only handles read requests. If you want to send messages, use
* the CrossChainMessenger contract which takes a CrossChainProvider and a signer as inputs.
*/
export interface ICrossChainProvider {
/**
* Provider connected to the L1 chain.
*/
l1Provider: Provider
/**
* Provider connected to the L2 chain.
*/
l2Provider: Provider
/**
* Chain ID for the L1 network.
*/
l1ChainId: number
/**
* Chain ID for the L2 network.
*/
l2ChainId: number
/**
* Contract objects attached to their respective providers and addresses.
*/
contracts: OEContracts
/**
* Retrieves all cross chain messages sent within a given transaction.
*
* @param transaction Transaction hash or receipt to find messages from.
* @param opts Options object.
* @param opts.direction Direction to search for messages in. If not provided, will attempt to
* automatically search both directions under the assumption that a transaction hash will only
* exist on one chain. If the hash exists on both chains, will throw an error.
* @returns All cross chain messages sent within the transaction.
*/
getMessagesByTransaction(
transaction: TransactionLike,
opts?: {
direction?: MessageDirection
}
): Promise<CrossChainMessage[]>
/**
* Retrieves all cross chain messages sent by a particular address.
*
* @param address Address to search for messages from.
* @param opts Options object.
* @param opts.direction Direction to search for messages in. If not provided, will attempt to
* find all messages in both directions.
* @param opts.fromBlock Block to start searching for messages from. If not provided, will start
* from the first block (block #0).
* @param opts.toBlock Block to stop searching for messages at. If not provided, will stop at the
* latest known block ("latest").
* @returns All cross chain messages sent by the particular address.
*/
getMessagesByAddress(
address: AddressLike,
opts?: {
direction?: MessageDirection
fromBlock?: NumberLike
toBlock?: NumberLike
}
): Promise<CrossChainMessage[]>
/**
* Finds all cross chain messages that correspond to token deposits or withdrawals sent by a
* particular address. Useful for finding deposits/withdrawals because the sender of the message
* will appear to be the StandardBridge contract and not the actual end user. Returns
*
* @param address Address to search for messages from.
* @param opts Options object.
* @param opts.direction Direction to search for messages in. If not provided, will attempt to
* find all messages in both directions.
* @param opts.fromBlock Block to start searching for messages from. If not provided, will start
* from the first block (block #0).
* @param opts.toBlock Block to stop searching for messages at. If not provided, will stop at the
* latest known block ("latest").
* @returns All token bridge messages sent by the given address.
*/
getTokenBridgeMessagesByAddress(
address: AddressLike,
opts?: {
direction?: MessageDirection
fromBlock?: BlockTag
toBlock?: BlockTag
}
): Promise<TokenBridgeMessage[]>
/**
* Retrieves the status of a particular message as an enum.
*
* @param message Cross chain message to check the status of.
* @returns Status of the message.
*/
getMessageStatus(message: MessageLike): Promise<MessageStatus>
/**
* Finds the receipt of the transaction that executed a particular cross chain message.
*
* @param message Message to find the receipt of.
* @returns CrossChainMessage receipt including receipt of the transaction that relayed the
* given message.
*/
getMessageReceipt(message: MessageLike): Promise<MessageReceipt>
/**
* Waits for a message to be executed and returns the receipt of the transaction that executed
* the given message.
*
* @param message Message to wait for.
* @param opts Options to pass to the waiting function.
* - `confirmations` (number): Number of transaction confirmations to wait for before returning.
* - `pollIntervalMs` (number): Number of milliseconds to wait between polling for the receipt.
* - `loopsBeforeTimeout` (number): Number of times to poll before timing out.
* @returns CrossChainMessage receipt including receipt of the transaction that relayed the
* given message.
*/
waitForMessageReciept(
message: MessageLike,
opts?: {
confirmations?: number
pollIntervalMs?: number
loopsBeforeTimeout?: number
}
): Promise<MessageReceipt>
/**
* Estimates the amount of gas required to fully execute a given message. Behavior of this
* function depends on the direction of the message. If the message is an L1 to L2 message,
* then this will estimate the amount of gas required to execute the message on L2. If the
* message is an L2 to L1 message, then this estimate will also include the amount of gas
* required to execute the Merkle Patricia Trie proof on L1.
*
* @param message Message get a gas estimate for.
*/
estimateMessageExecutionGas(message: MessageLike): Promise<BigNumber>
/**
* Returns the estimated amount of time before the message can be executed. When this is a
* message being sent to L1, this will return the estimated time until the message will complete
* its challenge period. When this is a message being sent to L2, this will return the estimated
* amount of time until the message will be picked up and executed on L2.
*
* @param message Message to estimate the time remaining for.
* @returns Estimated amount of time remaining (in seconds) before the message can be executed.
*/
estimateMessageWaitTimeSeconds(message: MessageLike): Promise<number>
/**
* Returns the estimated amount of time before the message can be executed (in L1 blocks).
* When this is a message being sent to L1, this will return the estimated time until the message
* will complete its challenge period. When this is a message being sent to L2, this will return
* the estimated amount of time until the message will be picked up and executed on L2.
*
* @param message Message to estimate the time remaining for.
* @returns Estimated amount of time remaining (in blocks) before the message can be executed.
*/
estimateMessageWaitTimeBlocks(message: MessageLike): Promise<number>
}
export * from './cross-chain-messenger'
export * from './cross-chain-provider'
export * from './l2-provider'
export * from './types'
import { Provider, TransactionRequest } from '@ethersproject/abstract-provider'
import { BigNumber } from 'ethers'
/**
* Represents an extended version of an normal ethers Provider that returns additional L2 info and
* has special functions for L2-specific interactions.
*/
export interface L2Provider extends Provider {
/**
* Gets the current L1 (data) gas price.
*
* @returns Current L1 data gas price in wei.
*/
getL1GasPrice(): Promise<BigNumber>
/**
* Estimates the L1 (data) gas required for a transaction.
*
* @param tx Transaction to estimate L1 gas for.
* @returns Estimated L1 gas.
*/
estimateL1Gas(tx: TransactionRequest): Promise<BigNumber>
/**
* Estimates the L1 (data) gas cost for a transaction in wei by multiplying the estimated L1 gas
* cost by the current L1 gas price.
*
* @param tx Transaction to estimate L1 gas cost for.
* @returns Estimated L1 gas cost.
*/
estimateL1GasCost(tx: TransactionRequest): Promise<BigNumber>
/**
* Estimates the L2 (execution) gas cost for a transaction in wei by multiplying the estimated L1
* gas cost by the current L2 gas price. This is a simple multiplication of the result of
* getGasPrice and estimateGas for the given transaction request.
*
* @param tx Transaction to estimate L2 gas cost for.
* @returns Estimated L2 gas cost.
*/
estimateL2GasCost(tx: TransactionRequest): Promise<BigNumber>
/**
* Estimates the total gas cost for a transaction in wei by adding the estimated the L1 gas cost
* and the estimated L2 gas cost.
*
* @param tx Transaction to estimate total gas cost for.
* @returns Estimated total gas cost.
*/
estimateTotalGasCost(tx: TransactionRequest): Promise<BigNumber>
}
import {
Provider,
TransactionReceipt,
TransactionResponse,
} from '@ethersproject/abstract-provider'
import { Signer } from '@ethersproject/abstract-signer'
import { Contract, BigNumber, Overrides } from 'ethers'
/**
* Represents Optimistic Ethereum contracts, assumed to be connected to their appropriate
* providers and addresses.
*/
export interface OEContracts {
/**
* L1 contract references.
*/
l1: {
AddressManager: Contract
L1CrossDomainMessenger: Contract
L1StandardBridge: Contract
StateCommitmentChain: Contract
CanonicalTransactionChain: Contract
BondManager: Contract
}
/**
* L2 contract references.
*/
l2: {
L2CrossDomainMessenger: Contract
L2StandardBridge: Contract
OVM_L1BlockNumber: Contract
OVM_L2ToL1MessagePasser: Contract
OVM_DeployerWhitelist: Contract
OVM_ETH: Contract
OVM_GasPriceOracle: Contract
OVM_SequencerFeeVault: Contract
WETH: Contract
}
}
/**
* Enum describing the status of a message.
*/
export enum MessageStatus {
/**
* Message is an L1 to L2 message and has not been processed by the L2.
*/
UNCONFIRMED_L1_TO_L2_MESSAGE,
/**
* Message is an L2 to L1 message and no state root has been published yet.
*/
STATE_ROOT_NOT_PUBLISHED,
/**
* Message is an L2 to L1 message and awaiting the challenge period.
*/
IN_CHALLENGE_PERIOD,
/**
* Message is ready to be relayed.
*/
READY_FOR_RELAY,
/**
* Message has been relayed.
*/
RELAYED,
}
/**
* Enum describing the direction of a message.
*/
export enum MessageDirection {
L1_TO_L2,
L2_TO_L1,
}
/**
* Partial message that needs to be signed and executed by a specific signer.
*/
export interface CrossChainMessageRequest {
direction: MessageDirection
target: string
message: string
l2GasLimit: NumberLike
}
/**
* Describes a message that is sent between L1 and L2. Direction determines where the message was
* sent from and where it's being sent to.
*/
export interface CrossChainMessage {
direction: MessageDirection
sender: string
target: string
message: string
messageNonce: number
}
/**
* Describes a token withdrawal or deposit, along with the underlying raw cross chain message
* behind the deposit or withdrawal.
*/
export interface TokenBridgeMessage {
direction: MessageDirection
from: string
to: string
l1Token: string
l2Token: string
amount: BigNumber
raw: CrossChainMessage
}
/**
* Enum describing the status of a CrossDomainMessage message receipt.
*/
export enum MessageReceiptStatus {
RELAYED_SUCCEEDED,
RELAYED_FAILED,
}
/**
* CrossDomainMessage receipt.
*/
export interface MessageReceipt {
messageHash: string
receiptStatus: MessageReceiptStatus
transactionReceipt: TransactionReceipt
}
/**
* Header for a state root batch.
*/
export interface StateRootBatchHeader {
batchIndex: BigNumber
batchRoot: string
batchSize: BigNumber
prevTotalElements: BigNumber
extraData: string
}
/**
* State root batch, including header and actual state roots.
*/
export interface StateRootBatch {
header: StateRootBatchHeader
stateRoots: string[]
}
/**
* Utility type for deep partials.
*/
export type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>
}
/**
* Extended Ethers overrides object with an l2GasLimit field.
* Only meant to be used for L1 to L2 messages, since L2 to L1 messages don't have a specified gas
* limit field (gas used depends on the amount of gas provided).
*/
export type L1ToL2Overrides = Overrides & {
l2GasLimit: NumberLike
}
/**
* Stuff that can be coerced into a transaction.
*/
export type TransactionLike = string | TransactionReceipt | TransactionResponse
/**
* Stuff that can be coerced into a message.
*/
export type MessageLike =
| CrossChainMessage
| TransactionLike
| TokenBridgeMessage
/**
* Stuff that can be coerced into a provider.
*/
export type ProviderLike = string | Provider
/**
* Stuff that can be coerced into a signer.
*/
export type SignerLike = string | Signer
/**
* Stuff that can be coerced into a signer or provider.
*/
export type SignerOrProviderLike = SignerLike | ProviderLike
/**
* Stuff that can be coerced into an address.
*/
export type AddressLike = string | Contract
/**
* Stuff that can be coerced into a number.
*/
export type NumberLike = string | number | BigNumber
/* External Imports */
import chai = require('chai')
import Mocha from 'mocha'
import chaiAsPromised from 'chai-as-promised'
chai.use(chaiAsPromised)
const should = chai.should()
const expect = chai.expect
export { should, expect, Mocha }
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
{
"extends": "../../tsconfig.json"
}
......@@ -709,6 +709,21 @@
"@ethersproject/properties" "^5.4.0"
"@ethersproject/strings" "^5.4.0"
"@ethersproject/abi@5.5.0", "@ethersproject/abi@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.5.0.tgz#fb52820e22e50b854ff15ce1647cc508d6660613"
integrity sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w==
dependencies:
"@ethersproject/address" "^5.5.0"
"@ethersproject/bignumber" "^5.5.0"
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/constants" "^5.5.0"
"@ethersproject/hash" "^5.5.0"
"@ethersproject/keccak256" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/properties" "^5.5.0"
"@ethersproject/strings" "^5.5.0"
"@ethersproject/abi@^5.0.12":
version "5.4.1"
resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.4.1.tgz#6ac28fafc9ef6f5a7a37e30356a2eb31fa05d39b"
......@@ -724,21 +739,6 @@
"@ethersproject/properties" "^5.4.0"
"@ethersproject/strings" "^5.4.0"
"@ethersproject/abi@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.5.0.tgz#fb52820e22e50b854ff15ce1647cc508d6660613"
integrity sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w==
dependencies:
"@ethersproject/address" "^5.5.0"
"@ethersproject/bignumber" "^5.5.0"
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/constants" "^5.5.0"
"@ethersproject/hash" "^5.5.0"
"@ethersproject/keccak256" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/properties" "^5.5.0"
"@ethersproject/strings" "^5.5.0"
"@ethersproject/abstract-provider@5.4.1", "@ethersproject/abstract-provider@^5.0.0", "@ethersproject/abstract-provider@^5.4.0", "@ethersproject/abstract-provider@^5.4.1":
version "5.4.1"
resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.4.1.tgz#e404309a29f771bd4d28dbafadcaa184668c2a6e"
......@@ -752,7 +752,7 @@
"@ethersproject/transactions" "^5.4.0"
"@ethersproject/web" "^5.4.0"
"@ethersproject/abstract-provider@^5.5.0", "@ethersproject/abstract-provider@^5.5.1":
"@ethersproject/abstract-provider@5.5.1", "@ethersproject/abstract-provider@^5.5.0", "@ethersproject/abstract-provider@^5.5.1":
version "5.5.1"
resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz#2f1f6e8a3ab7d378d8ad0b5718460f85649710c5"
integrity sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg==
......@@ -776,7 +776,7 @@
"@ethersproject/logger" "^5.4.0"
"@ethersproject/properties" "^5.4.0"
"@ethersproject/abstract-signer@^5.5.0":
"@ethersproject/abstract-signer@5.5.0", "@ethersproject/abstract-signer@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz#590ff6693370c60ae376bf1c7ada59eb2a8dd08d"
integrity sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA==
......@@ -798,7 +798,7 @@
"@ethersproject/logger" "^5.4.0"
"@ethersproject/rlp" "^5.4.0"
"@ethersproject/address@^5.5.0":
"@ethersproject/address@5.5.0", "@ethersproject/address@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.5.0.tgz#bcc6f576a553f21f3dd7ba17248f81b473c9c78f"
integrity sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw==
......@@ -816,7 +816,7 @@
dependencies:
"@ethersproject/bytes" "^5.4.0"
"@ethersproject/base64@^5.5.0":
"@ethersproject/base64@5.5.0", "@ethersproject/base64@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.5.0.tgz#881e8544e47ed976930836986e5eb8fab259c090"
integrity sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA==
......@@ -831,7 +831,7 @@
"@ethersproject/bytes" "^5.4.0"
"@ethersproject/properties" "^5.4.0"
"@ethersproject/basex@^5.5.0":
"@ethersproject/basex@5.5.0", "@ethersproject/basex@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.5.0.tgz#e40a53ae6d6b09ab4d977bd037010d4bed21b4d3"
integrity sha512-ZIodwhHpVJ0Y3hUCfUucmxKsWQA5TMnavp5j/UOuDdzZWzJlRmuOjcTMIGgHCYuZmHt36BfiSyQPSRskPxbfaQ==
......@@ -848,6 +848,15 @@
"@ethersproject/logger" "^5.4.0"
bn.js "^4.11.9"
"@ethersproject/bignumber@5.5.0", "@ethersproject/bignumber@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.5.0.tgz#875b143f04a216f4f8b96245bde942d42d279527"
integrity sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg==
dependencies:
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
bn.js "^4.11.9"
"@ethersproject/bignumber@^5.4.1":
version "5.4.2"
resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.4.2.tgz#44232e015ae4ce82ac034de549eb3583c71283d8"
......@@ -857,15 +866,6 @@
"@ethersproject/logger" "^5.4.0"
bn.js "^4.11.9"
"@ethersproject/bignumber@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.5.0.tgz#875b143f04a216f4f8b96245bde942d42d279527"
integrity sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg==
dependencies:
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
bn.js "^4.11.9"
"@ethersproject/bytes@5.4.0", "@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@^5.0.0", "@ethersproject/bytes@^5.0.4", "@ethersproject/bytes@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.4.0.tgz#56fa32ce3bf67153756dbaefda921d1d4774404e"
......@@ -873,7 +873,7 @@
dependencies:
"@ethersproject/logger" "^5.4.0"
"@ethersproject/bytes@^5.5.0":
"@ethersproject/bytes@5.5.0", "@ethersproject/bytes@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c"
integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog==
......@@ -887,7 +887,7 @@
dependencies:
"@ethersproject/bignumber" "^5.4.0"
"@ethersproject/constants@^5.5.0":
"@ethersproject/constants@5.5.0", "@ethersproject/constants@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.5.0.tgz#d2a2cd7d94bd1d58377d1d66c4f53c9be4d0a45e"
integrity sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ==
......@@ -910,6 +910,22 @@
"@ethersproject/properties" "^5.4.0"
"@ethersproject/transactions" "^5.4.0"
"@ethersproject/contracts@5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.5.0.tgz#b735260d4bd61283a670a82d5275e2a38892c197"
integrity sha512-2viY7NzyvJkh+Ug17v7g3/IJC8HqZBDcOjYARZLdzRxrfGlRgmYgl6xPRKVbEzy1dWKw/iv7chDcS83pg6cLxg==
dependencies:
"@ethersproject/abi" "^5.5.0"
"@ethersproject/abstract-provider" "^5.5.0"
"@ethersproject/abstract-signer" "^5.5.0"
"@ethersproject/address" "^5.5.0"
"@ethersproject/bignumber" "^5.5.0"
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/constants" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/properties" "^5.5.0"
"@ethersproject/transactions" "^5.5.0"
"@ethersproject/hardware-wallets@^5.0.8", "@ethersproject/hardware-wallets@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@ethersproject/hardware-wallets/-/hardware-wallets-5.4.0.tgz#bce275b395e26b6f50481095331157614490a473"
......@@ -936,7 +952,7 @@
"@ethersproject/properties" "^5.4.0"
"@ethersproject/strings" "^5.4.0"
"@ethersproject/hash@^5.5.0":
"@ethersproject/hash@5.5.0", "@ethersproject/hash@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.5.0.tgz#7cee76d08f88d1873574c849e0207dcb32380cc9"
integrity sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg==
......@@ -968,6 +984,24 @@
"@ethersproject/transactions" "^5.4.0"
"@ethersproject/wordlists" "^5.4.0"
"@ethersproject/hdnode@5.5.0", "@ethersproject/hdnode@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.5.0.tgz#4a04e28f41c546f7c978528ea1575206a200ddf6"
integrity sha512-mcSOo9zeUg1L0CoJH7zmxwUG5ggQHU1UrRf8jyTYy6HxdZV+r0PBoL1bxr+JHIPXRzS6u/UW4mEn43y0tmyF8Q==
dependencies:
"@ethersproject/abstract-signer" "^5.5.0"
"@ethersproject/basex" "^5.5.0"
"@ethersproject/bignumber" "^5.5.0"
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/pbkdf2" "^5.5.0"
"@ethersproject/properties" "^5.5.0"
"@ethersproject/sha2" "^5.5.0"
"@ethersproject/signing-key" "^5.5.0"
"@ethersproject/strings" "^5.5.0"
"@ethersproject/transactions" "^5.5.0"
"@ethersproject/wordlists" "^5.5.0"
"@ethersproject/json-wallets@5.4.0", "@ethersproject/json-wallets@^5.0.0", "@ethersproject/json-wallets@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.4.0.tgz#2583341cfe313fc9856642e8ace3080154145e95"
......@@ -987,6 +1021,25 @@
aes-js "3.0.0"
scrypt-js "3.0.1"
"@ethersproject/json-wallets@5.5.0", "@ethersproject/json-wallets@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.5.0.tgz#dd522d4297e15bccc8e1427d247ec8376b60e325"
integrity sha512-9lA21XQnCdcS72xlBn1jfQdj2A1VUxZzOzi9UkNdnokNKke/9Ya2xA9aIK1SC3PQyBDLt4C+dfps7ULpkvKikQ==
dependencies:
"@ethersproject/abstract-signer" "^5.5.0"
"@ethersproject/address" "^5.5.0"
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/hdnode" "^5.5.0"
"@ethersproject/keccak256" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/pbkdf2" "^5.5.0"
"@ethersproject/properties" "^5.5.0"
"@ethersproject/random" "^5.5.0"
"@ethersproject/strings" "^5.5.0"
"@ethersproject/transactions" "^5.5.0"
aes-js "3.0.0"
scrypt-js "3.0.1"
"@ethersproject/keccak256@5.4.0", "@ethersproject/keccak256@>=5.0.0-beta.127", "@ethersproject/keccak256@^5.0.0", "@ethersproject/keccak256@^5.0.3", "@ethersproject/keccak256@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.4.0.tgz#7143b8eea4976080241d2bd92e3b1f1bf7025318"
......@@ -995,7 +1048,7 @@
"@ethersproject/bytes" "^5.4.0"
js-sha3 "0.5.7"
"@ethersproject/keccak256@^5.5.0":
"@ethersproject/keccak256@5.5.0", "@ethersproject/keccak256@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.5.0.tgz#e4b1f9d7701da87c564ffe336f86dcee82983492"
integrity sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg==
......@@ -1008,7 +1061,7 @@
resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.4.0.tgz#f39adadf62ad610c420bcd156fd41270e91b3ca9"
integrity sha512-xYdWGGQ9P2cxBayt64d8LC8aPFJk6yWCawQi/4eJ4+oJdMMjEBMrIcIMZ9AxhwpPVmnBPrsB10PcXGmGAqgUEQ==
"@ethersproject/logger@^5.5.0":
"@ethersproject/logger@5.5.0", "@ethersproject/logger@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d"
integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==
......@@ -1020,6 +1073,13 @@
dependencies:
"@ethersproject/logger" "^5.4.0"
"@ethersproject/networks@5.5.1":
version "5.5.1"
resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.5.1.tgz#b7f7b9fb88dec1ea48f739b7fb9621311aa8ce6c"
integrity sha512-tYRDM4zZtSUcKnD4UMuAlj7SeXH/k5WC4SP2u1Pn57++JdXHkRu2zwNkgNogZoxHzhm9Q6qqurDBVptHOsW49Q==
dependencies:
"@ethersproject/logger" "^5.5.0"
"@ethersproject/networks@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.5.0.tgz#babec47cab892c51f8dd652ce7f2e3e14283981a"
......@@ -1035,6 +1095,14 @@
"@ethersproject/bytes" "^5.4.0"
"@ethersproject/sha2" "^5.4.0"
"@ethersproject/pbkdf2@5.5.0", "@ethersproject/pbkdf2@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.5.0.tgz#e25032cdf02f31505d47afbf9c3e000d95c4a050"
integrity sha512-SaDvQFvXPnz1QGpzr6/HToLifftSXGoXrbpZ6BvoZhmx4bNLHrxDe8MZisuecyOziP1aVEwzC2Hasj+86TgWVg==
dependencies:
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/sha2" "^5.5.0"
"@ethersproject/properties@5.4.0", "@ethersproject/properties@>=5.0.0-beta.131", "@ethersproject/properties@^5.0.0", "@ethersproject/properties@^5.0.3", "@ethersproject/properties@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.4.0.tgz#38ba20539b44dcc5d5f80c45ad902017dcdbefe7"
......@@ -1042,7 +1110,7 @@
dependencies:
"@ethersproject/logger" "^5.4.0"
"@ethersproject/properties@^5.5.0":
"@ethersproject/properties@5.5.0", "@ethersproject/properties@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.5.0.tgz#61f00f2bb83376d2071baab02245f92070c59995"
integrity sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA==
......@@ -1074,6 +1142,31 @@
bech32 "1.1.4"
ws "7.4.6"
"@ethersproject/providers@5.5.1":
version "5.5.1"
resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.5.1.tgz#ba87e3c93219bbd2e2edf8b369873aee774abf04"
integrity sha512-2zdD5sltACDWhjUE12Kucg2PcgM6V2q9JMyVvObtVGnzJu+QSmibbP+BHQyLWZUBfLApx2942+7DC5D+n4wBQQ==
dependencies:
"@ethersproject/abstract-provider" "^5.5.0"
"@ethersproject/abstract-signer" "^5.5.0"
"@ethersproject/address" "^5.5.0"
"@ethersproject/basex" "^5.5.0"
"@ethersproject/bignumber" "^5.5.0"
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/constants" "^5.5.0"
"@ethersproject/hash" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/networks" "^5.5.0"
"@ethersproject/properties" "^5.5.0"
"@ethersproject/random" "^5.5.0"
"@ethersproject/rlp" "^5.5.0"
"@ethersproject/sha2" "^5.5.0"
"@ethersproject/strings" "^5.5.0"
"@ethersproject/transactions" "^5.5.0"
"@ethersproject/web" "^5.5.0"
bech32 "1.1.4"
ws "7.4.6"
"@ethersproject/providers@^5.4.4", "@ethersproject/providers@^5.4.5":
version "5.4.5"
resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.4.5.tgz#eb2ea2a743a8115f79604a8157233a3a2c832928"
......@@ -1132,7 +1225,7 @@
"@ethersproject/bytes" "^5.4.0"
"@ethersproject/logger" "^5.4.0"
"@ethersproject/random@^5.5.0":
"@ethersproject/random@5.5.0", "@ethersproject/random@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.5.0.tgz#305ed9e033ca537735365ac12eed88580b0f81f9"
integrity sha512-egGYZwZ/YIFKMHcoBUo8t3a8Hb/TKYX8BCBoLjudVCZh892welR3jOxgOmb48xznc9bTcMm7Tpwc1gHC1PFNFQ==
......@@ -1148,7 +1241,7 @@
"@ethersproject/bytes" "^5.4.0"
"@ethersproject/logger" "^5.4.0"
"@ethersproject/rlp@^5.5.0":
"@ethersproject/rlp@5.5.0", "@ethersproject/rlp@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.5.0.tgz#530f4f608f9ca9d4f89c24ab95db58ab56ab99a0"
integrity sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA==
......@@ -1165,7 +1258,7 @@
"@ethersproject/logger" "^5.4.0"
hash.js "1.1.7"
"@ethersproject/sha2@^5.5.0":
"@ethersproject/sha2@5.5.0", "@ethersproject/sha2@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.5.0.tgz#a40a054c61f98fd9eee99af2c3cc6ff57ec24db7"
integrity sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA==
......@@ -1186,7 +1279,7 @@
elliptic "6.5.4"
hash.js "1.1.7"
"@ethersproject/signing-key@^5.5.0":
"@ethersproject/signing-key@5.5.0", "@ethersproject/signing-key@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.5.0.tgz#2aa37169ce7e01e3e80f2c14325f624c29cedbe0"
integrity sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng==
......@@ -1209,6 +1302,18 @@
"@ethersproject/sha2" "^5.4.0"
"@ethersproject/strings" "^5.4.0"
"@ethersproject/solidity@5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.5.0.tgz#2662eb3e5da471b85a20531e420054278362f93f"
integrity sha512-9NgZs9LhGMj6aCtHXhtmFQ4AN4sth5HuFXVvAQtzmm0jpSCNOTGtrHZJAeYTh7MBjRR8brylWZxBZR9zDStXbw==
dependencies:
"@ethersproject/bignumber" "^5.5.0"
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/keccak256" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/sha2" "^5.5.0"
"@ethersproject/strings" "^5.5.0"
"@ethersproject/strings@5.4.0", "@ethersproject/strings@>=5.0.0-beta.130", "@ethersproject/strings@^5.0.0", "@ethersproject/strings@^5.0.4", "@ethersproject/strings@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.4.0.tgz#fb12270132dd84b02906a8d895ae7e7fa3d07d9a"
......@@ -1218,7 +1323,7 @@
"@ethersproject/constants" "^5.4.0"
"@ethersproject/logger" "^5.4.0"
"@ethersproject/strings@^5.5.0":
"@ethersproject/strings@5.5.0", "@ethersproject/strings@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.5.0.tgz#e6784d00ec6c57710755699003bc747e98c5d549"
integrity sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ==
......@@ -1242,7 +1347,7 @@
"@ethersproject/rlp" "^5.4.0"
"@ethersproject/signing-key" "^5.4.0"
"@ethersproject/transactions@^5.5.0":
"@ethersproject/transactions@5.5.0", "@ethersproject/transactions@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.5.0.tgz#7e9bf72e97bcdf69db34fe0d59e2f4203c7a2908"
integrity sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA==
......@@ -1266,6 +1371,15 @@
"@ethersproject/constants" "^5.4.0"
"@ethersproject/logger" "^5.4.0"
"@ethersproject/units@5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.5.0.tgz#104d02db5b5dc42cc672cc4587bafb87a95ee45e"
integrity sha512-7+DpjiZk4v6wrikj+TCyWWa9dXLNU73tSTa7n0TSJDxkYbV3Yf1eRh9ToMLlZtuctNYu9RDNNy2USq3AdqSbag==
dependencies:
"@ethersproject/bignumber" "^5.5.0"
"@ethersproject/constants" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/wallet@5.4.0", "@ethersproject/wallet@^5.0.0", "@ethersproject/wallet@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.4.0.tgz#fa5b59830b42e9be56eadd45a16a2e0933ad9353"
......@@ -1287,6 +1401,27 @@
"@ethersproject/transactions" "^5.4.0"
"@ethersproject/wordlists" "^5.4.0"
"@ethersproject/wallet@5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.5.0.tgz#322a10527a440ece593980dca6182f17d54eae75"
integrity sha512-Mlu13hIctSYaZmUOo7r2PhNSd8eaMPVXe1wxrz4w4FCE4tDYBywDH+bAR1Xz2ADyXGwqYMwstzTrtUVIsKDO0Q==
dependencies:
"@ethersproject/abstract-provider" "^5.5.0"
"@ethersproject/abstract-signer" "^5.5.0"
"@ethersproject/address" "^5.5.0"
"@ethersproject/bignumber" "^5.5.0"
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/hash" "^5.5.0"
"@ethersproject/hdnode" "^5.5.0"
"@ethersproject/json-wallets" "^5.5.0"
"@ethersproject/keccak256" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/properties" "^5.5.0"
"@ethersproject/random" "^5.5.0"
"@ethersproject/signing-key" "^5.5.0"
"@ethersproject/transactions" "^5.5.0"
"@ethersproject/wordlists" "^5.5.0"
"@ethersproject/web@5.4.0", "@ethersproject/web@^5.0.0", "@ethersproject/web@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.4.0.tgz#49fac173b96992334ed36a175538ba07a7413d1f"
......@@ -1298,6 +1433,17 @@
"@ethersproject/properties" "^5.4.0"
"@ethersproject/strings" "^5.4.0"
"@ethersproject/web@5.5.1":
version "5.5.1"
resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.1.tgz#cfcc4a074a6936c657878ac58917a61341681316"
integrity sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg==
dependencies:
"@ethersproject/base64" "^5.5.0"
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/properties" "^5.5.0"
"@ethersproject/strings" "^5.5.0"
"@ethersproject/web@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.0.tgz#0e5bb21a2b58fb4960a705bfc6522a6acf461e28"
......@@ -1320,6 +1466,17 @@
"@ethersproject/properties" "^5.4.0"
"@ethersproject/strings" "^5.4.0"
"@ethersproject/wordlists@5.5.0", "@ethersproject/wordlists@^5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.5.0.tgz#aac74963aa43e643638e5172353d931b347d584f"
integrity sha512-bL0UTReWDiaQJJYOC9sh/XcRu/9i2jMrzf8VLRmPKx58ckSlOJiohODkECCO50dtLZHcGU6MLXQ4OOrgBwP77Q==
dependencies:
"@ethersproject/bytes" "^5.5.0"
"@ethersproject/hash" "^5.5.0"
"@ethersproject/logger" "^5.5.0"
"@ethersproject/properties" "^5.5.0"
"@ethersproject/strings" "^5.5.0"
"@hapi/bourne@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-2.0.0.tgz#5bb2193eb685c0007540ca61d166d4e1edaf918d"
......@@ -2639,6 +2796,13 @@
dependencies:
antlr4ts "^0.5.0-alpha.4"
"@solidity-parser/parser@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.0.tgz#d51f074efb0acce0e953ec48133561ed710cebc0"
integrity sha512-cX0JJRcmPtNUJpzD2K7FdA7qQsTOk1UZnFx2k7qAg9ZRvuaH5NBe5IEdBMXGlmf2+FmjhqbygJ26H8l2SV7aKQ==
dependencies:
antlr4ts "^0.5.0-alpha.4"
"@szmarczak/http-timer@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
......@@ -7234,6 +7398,42 @@ ethers@^5.0.0, ethers@^5.0.1, ethers@^5.0.2, ethers@^5.4.0, ethers@^5.4.5:
"@ethersproject/web" "5.4.0"
"@ethersproject/wordlists" "5.4.0"
ethers@^5.5.2:
version "5.5.2"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.5.2.tgz#cd2e508c7342c44fa70392f722e8de8f2416489f"
integrity sha512-EF5W+6Wwcu6BqVwpgmyR5U2+L4c1FQzlM/02dkZOugN3KF0cG9bzHZP+TDJglmPm2/IzCEJDT7KBxzayk7SAHw==
dependencies:
"@ethersproject/abi" "5.5.0"
"@ethersproject/abstract-provider" "5.5.1"
"@ethersproject/abstract-signer" "5.5.0"
"@ethersproject/address" "5.5.0"
"@ethersproject/base64" "5.5.0"
"@ethersproject/basex" "5.5.0"
"@ethersproject/bignumber" "5.5.0"
"@ethersproject/bytes" "5.5.0"
"@ethersproject/constants" "5.5.0"
"@ethersproject/contracts" "5.5.0"
"@ethersproject/hash" "5.5.0"
"@ethersproject/hdnode" "5.5.0"
"@ethersproject/json-wallets" "5.5.0"
"@ethersproject/keccak256" "5.5.0"
"@ethersproject/logger" "5.5.0"
"@ethersproject/networks" "5.5.1"
"@ethersproject/pbkdf2" "5.5.0"
"@ethersproject/properties" "5.5.0"
"@ethersproject/providers" "5.5.1"
"@ethersproject/random" "5.5.0"
"@ethersproject/rlp" "5.5.0"
"@ethersproject/sha2" "5.5.0"
"@ethersproject/signing-key" "5.5.0"
"@ethersproject/solidity" "5.5.0"
"@ethersproject/strings" "5.5.0"
"@ethersproject/transactions" "5.5.0"
"@ethersproject/units" "5.5.0"
"@ethersproject/wallet" "5.5.0"
"@ethersproject/web" "5.5.1"
"@ethersproject/wordlists" "5.5.0"
ethjs-unit@0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699"
......@@ -8456,10 +8656,10 @@ hardhat@^2.3.0:
uuid "^3.3.2"
ws "^7.4.6"
hardhat@^2.6.5:
version "2.6.5"
resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.6.5.tgz#61d3e22da34e1b175bbe599f77396b32f9788b58"
integrity sha512-sBhREWZjQTtR/KMMp2F3ySuDqL0norjNq68geR3nlXRHXYKuNKeL7xqVsmldekt3sVB5Wh1WX7xDX79kvUr+fA==
hardhat@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.7.0.tgz#d8f01bc07bdd88ccaa00719ddb18618bc59a73b5"
integrity sha512-DqweY3KH5gwExoZ8EtsAfioj0Hk0NBXWXT3fMXWkiQNfyYBoZLrqdPNkbJ/E2LD4mZ+BKF7v/1chYR9ZCn2Z+g==
dependencies:
"@ethereumjs/block" "^3.4.0"
"@ethereumjs/blockchain" "^5.4.0"
......@@ -8468,7 +8668,7 @@ hardhat@^2.6.5:
"@ethereumjs/vm" "^5.5.2"
"@ethersproject/abi" "^5.1.2"
"@sentry/node" "^5.18.1"
"@solidity-parser/parser" "^0.11.0"
"@solidity-parser/parser" "^0.14.0"
"@types/bn.js" "^5.1.0"
"@types/lru-cache" "^5.1.0"
abort-controller "^3.0.0"
......@@ -8506,7 +8706,7 @@ hardhat@^2.6.5:
stacktrace-parser "^0.1.10"
"true-case-path" "^2.2.1"
tsort "0.0.1"
uuid "^3.3.2"
uuid "^8.3.2"
ws "^7.4.6"
has-ansi@^2.0.0:
......@@ -15513,6 +15713,11 @@ uuid@^3.3.2, uuid@^3.3.3:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-compile-cache@^2.0.3:
version "2.3.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
......
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