Commit 3a726175 authored by Matthew Slipper's avatar Matthew Slipper

Merge branch 'develop' into fix/eip2930

parents a5254658 d14ee9fa
---
'@eth-optimism/integration-tests': minor
---
Updates to work with a live network
---
'@eth-optimism/batch-submitter-service': patch
---
Adds confirmation depth awareness to txmgr
---
'@eth-optimism/proxyd': minor
---
proxyd: Cache block-dependent RPCs
......@@ -2,4 +2,4 @@
'@eth-optimism/proxyd': minor
---
Add integration tests and batching
Add debug cache status header to proxyd responses
---
'@eth-optimism/integration-tests': patch
---
Use hardhat-ethers for importing factories in integration tests
---
'@eth-optimism/l2geth': patch
---
Add reinitialize-by-url command, add dump chain state command
---
'@eth-optimism/integration-tests': patch
---
Split OVMMulticall.sol into Multicall.sol & OVMContext.sol
---
'@eth-optimism/l2geth': patch
---
Fix blocknumber monotonicity logging bug
......@@ -101,7 +101,17 @@ module.exports = {
'id-match': 'off',
'import/no-extraneous-dependencies': ['error'],
'import/no-internal-modules': 'off',
'import/order': 'off',
'import/order': [
"error",
{
groups: [
'builtin',
'external',
'internal',
],
'newlines-between': 'always',
},
],
indent: 'off',
'jsdoc/check-alignment': 'error',
'jsdoc/check-indentation': 'error',
......
......@@ -6,6 +6,8 @@ on:
- 'master'
- 'develop'
pull_request:
paths:
- 'go/proxyd/**'
workflow_dispatch:
defaults:
......@@ -13,7 +15,9 @@ defaults:
working-directory: ./go/proxyd
jobs:
test:
tests:
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v2
......
......@@ -29,6 +29,7 @@ jobs:
rpc-proxy : ${{ steps.packages.outputs.rpc-proxy }}
op-exporter : ${{ steps.packages.outputs.op-exporter }}
l2geth-exporter : ${{ steps.packages.outputs.l2geth-exporter }}
batch-submitter-service : ${{ steps.packages.outputs.batch-submitter-service }}
steps:
- name: Check out source code
......@@ -506,3 +507,29 @@ jobs:
file: ./ops/docker/Dockerfile.rpc-proxy
push: true
tags: ethereumoptimism/rpc-proxy:${{ needs.canary-publish.outputs.rpc-proxy }}
batch-submitter-service:
name: Publish batch-submitter-service Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish
if: needs.canary-publish.outputs.batch-submitter-service != ''
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: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.batch-submitter-service
push: true
tags: ethereumoptimism/batch-submitter-service:${{ needs.canary-publish.outputs.batch-submitter-service }}
......@@ -25,6 +25,7 @@ jobs:
hardhat-node: ${{ steps.packages.outputs.hardhat-node }}
op-exporter : ${{ steps.packages.outputs.op-exporter }}
l2geth-exporter : ${{ steps.packages.outputs.l2geth-exporter }}
batch-submitter-service : ${{ steps.packages.outputs.batch-submitter-service }}
steps:
- name: Checkout Repo
......@@ -502,3 +503,29 @@ jobs:
push: true
tags: ethereumoptimism/replica-healthcheck:${{ needs.builder.outputs.replica-healthcheck }},ethereumoptimism/replica-healthcheck:latest
build-args: BUILDER_TAG=${{ needs.builder.outputs.builder }}
batch-submitter-service:
name: Publish batch-submitter-service Version ${{ needs.release.outputs.batch-submitter-service }}
needs: release
if: needs.release.outputs.batch-submitter-service != ''
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: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.batch-submitter-service
push: true
tags: ethereumoptimism/batch-submitter-service:${{ needs.release.outputs.batch-submitter-service }},ethereumoptimism/batch-submitter-service:latest
# @eth-optimism/batch-submitter-service
## 0.1.0
### Minor Changes
- 356b7271: Add multi-tx support, clear pending txs on startup
### Patch Changes
- 85aa148d: Adds confirmation depth awareness to txmgr
## 0.0.2
### Patch Changes
- d6e0de5a: Fix metrics server
{
"name": "@eth-optimism/batch-submitter-service",
"version": "0.0.2",
"version": "0.1.0",
"private": true,
"devDependencies": {}
}
# @eth-optimism/proxyd
## 3.6.0
### Minor Changes
- 096c5f20: proxyd: Allow cached RPCs to be evicted by redis
- 71d64834: Add caching for block-dependent RPCs
- fd2e1523: proxyd: Cache block-dependent RPCs
- 1760613c: Add integration tests and batching
## 3.5.0
### Minor Changes
......
......@@ -2,6 +2,7 @@ package proxyd
import (
"context"
"time"
"github.com/go-redis/redis/v8"
"github.com/golang/snappy"
......@@ -16,6 +17,8 @@ type Cache interface {
const (
// assuming an average RPCRes size of 3 KB
memoryCacheLimit = 4096
// Set a large ttl to avoid expirations. However, a ttl must be set for volatile-lru to take effect.
redisTTL = 30 * 7 * 24 * time.Hour
)
type cache struct {
......@@ -67,7 +70,7 @@ func (c *redisCache) Get(ctx context.Context, key string) (string, error) {
}
func (c *redisCache) Put(ctx context.Context, key string, value string) error {
err := c.rdb.Set(ctx, key, value, 0).Err()
err := c.rdb.SetEX(ctx, key, value, redisTTL).Err()
if err != nil {
RecordRedisError("CacheSet")
}
......
......@@ -16,12 +16,14 @@ func TestCaching(t *testing.T) {
require.NoError(t, err)
defer redis.Close()
backend := NewMockBackend(RPCResponseHandler(map[string]string{
hdlr := NewRPCResponseHandler(map[string]string{
"eth_chainId": "0x420",
"net_version": "0x1234",
"eth_blockNumber": "0x64",
"eth_getBlockByNumber": "dummy_block",
}))
"eth_call": "dummy_call",
})
backend := NewMockBackend(hdlr)
defer backend.Close()
require.NoError(t, os.Setenv("GOOD_BACKEND_RPC_URL", backend.URL()))
......@@ -36,19 +38,22 @@ func TestCaching(t *testing.T) {
time.Sleep(1500 * time.Millisecond)
tests := []struct {
method string
params []interface{}
response string
method string
params []interface{}
response string
backendCalls int
}{
{
"eth_chainId",
nil,
"{\"jsonrpc\": \"2.0\", \"result\": \"0x420\", \"id\": 999}",
1,
},
{
"net_version",
nil,
"{\"jsonrpc\": \"2.0\", \"result\": \"0x1234\", \"id\": 999}",
1,
},
{
"eth_getBlockByNumber",
......@@ -57,23 +62,79 @@ func TestCaching(t *testing.T) {
true,
},
"{\"jsonrpc\": \"2.0\", \"result\": \"dummy_block\", \"id\": 999}",
1,
},
{
"eth_call",
[]interface{}{
struct {
To string `json:"to"`
}{
"0x1234",
},
"0x60",
},
"{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"dummy_call\"}",
1,
},
{
"eth_blockNumber",
nil,
"{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"0x64\"}",
0,
},
{
"eth_call",
[]interface{}{
struct {
To string `json:"to"`
}{
"0x1234",
},
"latest",
},
"{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"dummy_call\"}",
2,
},
{
"eth_call",
[]interface{}{
struct {
To string `json:"to"`
}{
"0x1234",
},
"pending",
},
"{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"dummy_call\"}",
2,
},
}
for _, tt := range tests {
t.Run(tt.method, func(t *testing.T) {
_, _, err := client.SendRPC(tt.method, tt.params)
resRaw, _, err := client.SendRPC(tt.method, tt.params)
require.NoError(t, err)
res, _, err := client.SendRPC(tt.method, tt.params)
resCache, _, err := client.SendRPC(tt.method, tt.params)
require.NoError(t, err)
RequireEqualJSON(t, []byte(tt.response), res)
var count int
for _, req := range backend.Requests() {
if bytes.Contains(req.Body, []byte(tt.method)) {
count++
}
}
require.Equal(t, 1, count)
RequireEqualJSON(t, []byte(tt.response), resCache)
RequireEqualJSON(t, resRaw, resCache)
require.Equal(t, tt.backendCalls, countRequests(backend, tt.method))
backend.Reset()
})
}
hdlr.SetResponse("eth_blockNumber", "0x100")
time.Sleep(1500 * time.Millisecond)
resRaw, _, err := client.SendRPC("eth_blockNumber", nil)
RequireEqualJSON(t, []byte("{\"id\":999,\"jsonrpc\":\"2.0\",\"result\":\"0x100\"}"), resRaw)
}
func countRequests(backend *MockBackend, name string) int {
var count int
for _, req := range backend.Requests() {
if bytes.Contains(req.Body, []byte(name)) {
count++
}
}
return count
}
......@@ -31,31 +31,48 @@ func SingleResponseHandler(code int, response string) http.HandlerFunc {
}
}
func RPCResponseHandler(rpcResponses map[string]string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
req, err := proxyd.ParseRPCReq(body)
if err != nil {
panic(err)
}
res := rpcResponses[req.Method]
if res == "" {
w.WriteHeader(400)
return
}
out := &proxyd.RPCRes{
JSONRPC: proxyd.JSONRPCVersion,
Result: res,
ID: req.ID,
}
enc := json.NewEncoder(w)
if err := enc.Encode(out); err != nil {
panic(err)
}
type RPCResponseHandler struct {
mtx sync.RWMutex
rpcResponses map[string]string
}
func NewRPCResponseHandler(rpcResponses map[string]string) *RPCResponseHandler {
return &RPCResponseHandler{
rpcResponses: rpcResponses,
}
}
func (h *RPCResponseHandler) SetResponse(method, response string) {
h.mtx.Lock()
defer h.mtx.Unlock()
h.rpcResponses[method] = response
}
func (h *RPCResponseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
req, err := proxyd.ParseRPCReq(body)
if err != nil {
panic(err)
}
h.mtx.RLock()
res := h.rpcResponses[req.Method]
h.mtx.RUnlock()
if res == "" {
w.WriteHeader(400)
return
}
out := &proxyd.RPCRes{
JSONRPC: proxyd.JSONRPCVersion,
Result: res,
ID: req.ID,
}
enc := json.NewEncoder(w)
if err := enc.Encode(out); err != nil {
panic(err)
}
}
......
......@@ -25,3 +25,5 @@ backends = ["good"]
eth_chainId = "main"
net_version = "main"
eth_getBlockByNumber = "main"
eth_blockNumber = "main"
eth_call = "main"
{
"name": "@eth-optimism/proxyd",
"version": "3.5.0",
"version": "3.6.0",
"private": true,
"dependencies": {}
}
......@@ -15,16 +15,46 @@ type RPCReq struct {
}
type RPCRes struct {
JSONRPC string
Result interface{}
Error *RPCErr
ID json.RawMessage
}
type rpcResJSON struct {
JSONRPC string `json:"jsonrpc"`
Result interface{} `json:"result,omitempty"`
Error *RPCErr `json:"error,omitempty"`
ID json.RawMessage `json:"id"`
}
type nullResultRPCRes struct {
JSONRPC string `json:"jsonrpc"`
Result interface{} `json:"result"`
ID json.RawMessage `json:"id"`
}
func (r *RPCRes) IsError() bool {
return r.Error != nil
}
func (r *RPCRes) MarshalJSON() ([]byte, error) {
if r.Result == nil && r.Error == nil {
return json.Marshal(&nullResultRPCRes{
JSONRPC: r.JSONRPC,
Result: nil,
ID: r.ID,
})
}
return json.Marshal(&rpcResJSON{
JSONRPC: r.JSONRPC,
Result: r.Result,
Error: r.Error,
ID: r.ID,
})
}
type RPCErr struct {
Code int `json:"code"`
Message string `json:"message"`
......
package proxyd
import (
"encoding/json"
"github.com/stretchr/testify/require"
"testing"
)
func TestRPCResJSON(t *testing.T) {
tests := []struct {
name string
in *RPCRes
out string
}{
{
"string result",
&RPCRes{
JSONRPC: JSONRPCVersion,
Result: "foobar",
ID: []byte("123"),
},
`{"jsonrpc":"2.0","result":"foobar","id":123}`,
},
{
"object result",
&RPCRes{
JSONRPC: JSONRPCVersion,
Result: struct {
Str string `json:"str"`
}{
"test",
},
ID: []byte("123"),
},
`{"jsonrpc":"2.0","result":{"str":"test"},"id":123}`,
},
{
"nil result",
&RPCRes{
JSONRPC: JSONRPCVersion,
Result: nil,
ID: []byte("123"),
},
`{"jsonrpc":"2.0","result":null,"id":123}`,
},
{
"error result",
&RPCRes{
JSONRPC: JSONRPCVersion,
Error: &RPCErr{
Code: 1234,
Message: "test err",
},
ID: []byte("123"),
},
`{"jsonrpc":"2.0","error":{"code":1234,"message":"test err"},"id":123}`,
},
{
"string ID",
&RPCRes{
JSONRPC: JSONRPCVersion,
Result: "foobar",
ID: []byte("\"123\""),
},
`{"jsonrpc":"2.0","result":"foobar","id":"123"}`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out, err := json.Marshal(tt.in)
require.NoError(t, err)
require.Equal(t, tt.out, string(out))
})
}
}
......@@ -25,6 +25,7 @@ const (
ContextKeyReqID = "req_id"
ContextKeyXForwardedFor = "x_forwarded_for"
MaxBatchRPCCalls = 100
cacheStatusHdr = "X-Proxyd-Cache-Status"
)
type Server struct {
......@@ -159,6 +160,7 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
}
batchRes := make([]*RPCRes, len(reqs), len(reqs))
var batchContainsCached bool
for i := 0; i < len(reqs); i++ {
req, err := ParseRPCReq(reqs[i])
if err != nil {
......@@ -167,9 +169,14 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
continue
}
batchRes[i] = s.handleSingleRPC(ctx, req)
var cached bool
batchRes[i], cached = s.handleSingleRPC(ctx, req)
if cached {
batchContainsCached = true
}
}
setCacheHeader(w, batchContainsCached)
writeBatchRPCRes(ctx, w, batchRes)
return
}
......@@ -181,14 +188,15 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
return
}
backendRes := s.handleSingleRPC(ctx, req)
backendRes, cached := s.handleSingleRPC(ctx, req)
setCacheHeader(w, cached)
writeRPCRes(ctx, w, backendRes)
}
func (s *Server) handleSingleRPC(ctx context.Context, req *RPCReq) *RPCRes {
func (s *Server) handleSingleRPC(ctx context.Context, req *RPCReq) (*RPCRes, bool) {
if err := ValidateRPCReq(req); err != nil {
RecordRPCError(ctx, BackendProxyd, MethodUnknown, err)
return NewRPCErrorRes(nil, err)
return NewRPCErrorRes(nil, err), false
}
group := s.rpcMethodMappings[req.Method]
......@@ -202,7 +210,7 @@ func (s *Server) handleSingleRPC(ctx context.Context, req *RPCReq) *RPCRes {
"method", req.Method,
)
RecordRPCError(ctx, BackendProxyd, MethodUnknown, ErrMethodNotWhitelisted)
return NewRPCErrorRes(req.ID, ErrMethodNotWhitelisted)
return NewRPCErrorRes(req.ID, ErrMethodNotWhitelisted), false
}
var backendRes *RPCRes
......@@ -215,7 +223,7 @@ func (s *Server) handleSingleRPC(ctx context.Context, req *RPCReq) *RPCRes {
)
}
if backendRes != nil {
return backendRes
return backendRes, true
}
backendRes, err = s.backendGroups[group].Forward(ctx, req)
......@@ -226,7 +234,7 @@ func (s *Server) handleSingleRPC(ctx context.Context, req *RPCReq) *RPCRes {
"req_id", GetReqID(ctx),
"err", err,
)
return NewRPCErrorRes(req.ID, err)
return NewRPCErrorRes(req.ID, err), false
}
if backendRes.Error == nil {
......@@ -239,7 +247,7 @@ func (s *Server) handleSingleRPC(ctx context.Context, req *RPCReq) *RPCRes {
}
}
return backendRes
return backendRes, false
}
func (s *Server) HandleWS(w http.ResponseWriter, r *http.Request) {
......@@ -322,6 +330,14 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context
)
}
func setCacheHeader(w http.ResponseWriter, cached bool) {
if cached {
w.Header().Set(cacheStatusHdr, "HIT")
} else {
w.Header().Set(cacheStatusHdr, "MISS")
}
}
func writeRPCError(ctx context.Context, w http.ResponseWriter, id json.RawMessage, err error) {
var res *RPCRes
if r, ok := err.(*RPCErr); ok {
......
# @eth-optimism/integration-tests
## 0.5.0
### Minor Changes
- c1e923f9: Updates to work with a live network
### Patch Changes
- 968fb38d: Use hardhat-ethers for importing factories in integration tests
- a7fbafa8: Split OVMMulticall.sol into Multicall.sol & OVMContext.sol
## 0.4.2
### Patch Changes
......
import { utils, Wallet, BigNumber } from 'ethers'
import { expect } from 'chai'
import { setupActor, setupRun, actor, run } from './lib/convenience'
import { OptimismEnv } from '../test/shared/env'
import { Direction } from '../test/shared/watcher-utils'
import { expect } from 'chai'
interface BenchContext {
l1Wallet: Wallet
......
import { performance } from 'perf_hooks'
import { Mutex } from 'async-mutex'
import { sleep } from '../../test/shared/utils'
import {
sanitizeForMetrics,
benchDurationsSummary,
......@@ -9,7 +11,7 @@ import {
failedBenchRunsTotal,
} from './metrics'
import { ActorLogger, WorkerLogger } from './logger'
import { performance } from 'perf_hooks'
import { sleep } from '../../test/shared/utils'
// eslint-disable-next-line @typescript-eslint/no-empty-function
const asyncNoop = async () => {}
......
import fs from 'fs'
import client from 'prom-client'
import http from 'http'
import url from 'url'
import client from 'prom-client'
export const metricsRegistry = new client.Registry()
const metricName = (name: string) => {
......
import * as path from 'path'
import { Command } from 'commander'
import { defaultRuntime } from './convenience'
import { RunOpts } from './actor'
import { Command } from 'commander'
import pkg from '../../package.json'
import { serveMetrics } from './metrics'
import pkg from '../../package.json'
const program = new Command()
program.version(pkg.version)
......
import { utils, Wallet, Contract } from 'ethers'
import { expect } from 'chai'
import { actor, run, setupActor, setupRun } from './lib/convenience'
import { OptimismEnv } from '../test/shared/env'
import ERC721 from '../artifacts/contracts/NFT.sol/NFT.json'
import { expect } from 'chai'
interface Context {
wallet: Wallet
......
import { utils, Wallet, BigNumber } from 'ethers'
import { expect } from 'chai'
import { actor, setupRun, setupActor, run } from './lib/convenience'
import { OptimismEnv } from '../test/shared/env'
......
import { utils, Wallet, Contract } from 'ethers'
import { ethers } from 'hardhat'
import { expect } from 'chai'
import { actor, setupActor, run, setupRun } from './lib/convenience'
import { OptimismEnv } from '../test/shared/env'
import { expect } from 'chai'
interface Context {
wallet: Wallet
......
import { Contract, utils, Wallet } from 'ethers'
import { actor, run, setupActor, setupRun } from './lib/convenience'
import { OptimismEnv } from '../test/shared/env'
import { FeeAmount } from '@uniswap/v3-sdk'
import ERC20 from '../artifacts/contracts/ERC20.sol/ERC20.json'
import { abi as NFTABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
import { abi as RouterABI } from '@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json'
import { actor, run, setupActor, setupRun } from './lib/convenience'
import { OptimismEnv } from '../test/shared/env'
import ERC20 from '../artifacts/contracts/ERC20.sol/ERC20.json'
interface Context {
contracts: { [name: string]: Contract }
wallet: Wallet
......
{
"private": true,
"name": "@eth-optimism/integration-tests",
"version": "0.4.2",
"version": "0.5.0",
"description": "[Optimism] Integration tests",
"scripts": {
"lint": "yarn lint:fix && yarn lint:check",
......@@ -28,9 +28,9 @@
"url": "https://github.com/ethereum-optimism/optimism.git"
},
"devDependencies": {
"@eth-optimism/contracts": "0.5.8",
"@eth-optimism/core-utils": "0.7.3",
"@eth-optimism/message-relayer": "0.2.12",
"@eth-optimism/contracts": "0.5.9",
"@eth-optimism/core-utils": "0.7.4",
"@eth-optimism/message-relayer": "0.2.13",
"@ethersproject/abstract-provider": "^5.5.1",
"@ethersproject/providers": "^5.4.5",
"@ethersproject/transactions": "^5.4.0",
......
import { expect } from './shared/setup'
/* Imports: External */
import { Contract, ContractFactory } from 'ethers'
import { ethers } from 'hardhat'
import { applyL1ToL2Alias, awaitCondition } from '@eth-optimism/core-utils'
/* Imports: Internal */
import { expect } from './shared/setup'
import { Direction } from './shared/watcher-utils'
import { OptimismEnv } from './shared/env'
import {
......
import { expect } from './shared/setup'
import { BigNumber, Contract, ContractFactory, utils, Wallet } from 'ethers'
import { ethers } from 'hardhat'
import * as L2Artifact from '@eth-optimism/contracts/artifacts/contracts/standards/L2StandardERC20.sol/L2StandardERC20.json'
import { expect } from './shared/setup'
import { OptimismEnv } from './shared/env'
import { withdrawalTest } from './shared/utils'
import { Direction } from './shared/watcher-utils'
......
import { expect } from './shared/setup'
import { BigNumber, Contract, ContractFactory, utils, Wallet } from 'ethers'
import { ethers } from 'hardhat'
import { UniswapV3Deployer } from 'uniswap-v3-deploy-plugin/dist/deployer/UniswapV3Deployer'
import { OptimismEnv } from './shared/env'
import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk'
import { abi as NFTABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
import { abi as RouterABI } from '@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json'
import { OptimismEnv } from './shared/env'
import { expect } from './shared/setup'
// Below methods taken from the Uniswap test suite, see
// https://github.com/Uniswap/v3-periphery/blob/main/test/shared/ticks.ts
const getMinTick = (tickSpacing: number) =>
......
import { expect } from './shared/setup'
/* Imports: External */
import { BigNumber, utils } from 'ethers'
import { serialize } from '@ethersproject/transactions'
import { predeploys, getContractFactory } from '@eth-optimism/contracts'
/* Imports: Internal */
import { expect } from './shared/setup'
import { hardhatTest } from './shared/utils'
import { OptimismEnv } from './shared/env'
import { Direction } from './shared/watcher-utils'
......
import { expect } from './shared/setup'
import { BigNumber, Contract, ContractFactory, Wallet } from 'ethers'
import { ethers } from 'hardhat'
import { expect } from './shared/setup'
import {
fundUser,
encodeSolidityRevertMessage,
......
import { expect } from './shared/setup'
/* Imports: External */
import { Wallet, utils, BigNumber } from 'ethers'
import { serialize } from '@ethersproject/transactions'
......@@ -7,8 +5,8 @@ import { predeploys } from '@eth-optimism/contracts'
import { expectApprox } from '@eth-optimism/core-utils'
/* Imports: Internal */
import { expect } from './shared/setup'
import { Direction } from './shared/watcher-utils'
import {
DEFAULT_TEST_GAS_L1,
DEFAULT_TEST_GAS_L2,
......
import { expect } from './shared/setup'
/* Imports: External */
import { ethers } from 'hardhat'
import { injectL2Context, expectApprox } from '@eth-optimism/core-utils'
......@@ -7,6 +5,7 @@ import { predeploys } from '@eth-optimism/contracts'
import { Contract, BigNumber } from 'ethers'
/* Imports: Internal */
import { expect } from './shared/setup'
import {
l2Provider,
l1Provider,
......
import { expect } from './shared/setup'
/* Imports: Internal */
import { ethers } from 'ethers'
import { predeploys, getContractInterface } from '@eth-optimism/contracts'
/* Imports: External */
import { expect } from './shared/setup'
import { OptimismEnv } from './shared/env'
describe('predeploys', () => {
......
import { expect } from './shared/setup'
/* Imports: Internal */
import { providers } from 'ethers'
import { injectL2Context, applyL1ToL2Alias } from '@eth-optimism/core-utils'
/* Imports: External */
import { expect } from './shared/setup'
import { OptimismEnv } from './shared/env'
import { Direction } from './shared/watcher-utils'
import { DEFAULT_TEST_GAS_L1, envConfig } from './shared/utils'
......
import { TransactionReceipt } from '@ethersproject/abstract-provider'
import { expect } from './shared/setup'
import { OptimismEnv } from './shared/env'
import {
......@@ -6,7 +8,6 @@ import {
sleep,
envConfig,
} from './shared/utils'
import { TransactionReceipt } from '@ethersproject/abstract-provider'
describe('Replica Tests', () => {
let env: OptimismEnv
......
import { expect } from './shared/setup'
import { expectApprox, injectL2Context } from '@eth-optimism/core-utils'
import { Wallet, BigNumber, Contract, ContractFactory, constants } from 'ethers'
import { serialize } from '@ethersproject/transactions'
import { ethers } from 'hardhat'
import {
TransactionReceipt,
TransactionRequest,
} from '@ethersproject/providers'
import {
sleep,
l2Provider,
......@@ -16,10 +19,7 @@ import {
envConfig,
} from './shared/utils'
import { OptimismEnv } from './shared/env'
import {
TransactionReceipt,
TransactionRequest,
} from '@ethersproject/providers'
import { expect } from './shared/setup'
describe('Basic RPC tests', () => {
let env: OptimismEnv
......
......@@ -4,7 +4,6 @@ import {
TransactionResponse,
} from '@ethersproject/providers'
import { Watcher } from '@eth-optimism/core-utils'
import { Contract, Transaction } from 'ethers'
export const initWatcher = async (
......
import { expect } from './shared/setup'
/* Imports: External */
import { Contract, Wallet, utils } from 'ethers'
import { ethers } from 'hardhat'
/* Imports: Internal */
import { expect } from './shared/setup'
import { OptimismEnv } from './shared/env'
import {
executeL1ToL2TransactionsParallel,
......@@ -15,7 +14,6 @@ import {
executeRepeatedL2Transactions,
fundRandomWallet,
} from './shared/stress-test-helpers'
/* Imports: Artifacts */
import { envConfig, fundUser } from './shared/utils'
......
import { expect } from './shared/setup'
/* Imports: External */
import { ContractFactory } from 'ethers'
import { ethers } from 'hardhat'
import { predeploys } from '@eth-optimism/contracts'
/* Imports: Internal */
import { expect } from './shared/setup'
import { OptimismEnv } from './shared/env'
import { l2Provider } from './shared/utils'
......
# Changelog
## 0.5.8
### Patch Changes
- 949916f8: Add a better error message for when the sequencer url is not configured when proxying user requests to the sequencer for `eth_sendRawTransaction` when running as a verifier/replica
- 300f79bf: Fix nonce issue
- ae96d784: Add reinitialize-by-url command, add dump chain state command
- c7569a16: Fix blocknumber monotonicity logging bug
## 0.5.7
### Patch Changes
......
......@@ -209,14 +209,13 @@ func (st *StateTransition) buyGas() error {
func (st *StateTransition) preCheck() error {
// Make sure this transaction's nonce is correct.
if st.msg.CheckNonce() {
if rcfg.UsingOVM {
if st.msg.QueueOrigin() == types.QueueOriginL1ToL2 {
return st.buyGas()
}
}
nonce := st.state.GetNonce(st.msg.From())
if nonce < st.msg.Nonce() {
if rcfg.UsingOVM {
// The nonce never increments for L1ToL2 txs
if st.msg.QueueOrigin() == types.QueueOriginL1ToL2 {
return st.buyGas()
}
}
return ErrNonceTooHigh
} else if nonce > st.msg.Nonce() {
return ErrNonceTooLow
......
......@@ -50,7 +50,10 @@ import (
"github.com/tyler-smith/go-bip39"
)
var errOVMUnsupported = errors.New("OVM: Unsupported RPC Method")
var (
errOVMUnsupported = errors.New("OVM: Unsupported RPC Method")
errNoSequencerURL = errors.New("sequencer transaction forwarding not configured")
)
const (
// defaultDialTimeout is default duration the service will wait on
......@@ -1680,7 +1683,11 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
}
if s.b.IsVerifier() {
client, err := dialSequencerClientWithTimeout(ctx, s.b.SequencerClientHttp())
sequencerURL := s.b.SequencerClientHttp()
if sequencerURL == "" {
return common.Hash{}, errNoSequencerURL
}
client, err := dialSequencerClientWithTimeout(ctx, sequencerURL)
if err != nil {
return common.Hash{}, err
}
......
{
"name": "@eth-optimism/l2geth",
"version": "0.5.7",
"version": "0.5.8",
"private": true,
"devDependencies": {}
}
......@@ -32,6 +32,10 @@ docker-compose \
*Note*: This generates a large amount of log data which docker stores by default. See [Disk Usage](#disk-usage).
Also note that Docker Desktop only allocates 2GB of memory by default, which isn't enough to run the docker-compose services reliably.
To allocate more memory, go to Settings > Resources in the Docker UI and use the slider to change the value (_4GB recommended_). Make sure to click Apply & Restart for the changes to take effect.
To start the stack with monitoring enabled, just add the metric composition file.
```
docker-compose \
......
# Changelog
## 0.4.14
### Patch Changes
- Updated dependencies [ba96a455]
- Updated dependencies [c3e85fef]
- @eth-optimism/core-utils@0.7.4
- @eth-optimism/contracts@0.5.9
## 0.4.13
### Patch Changes
......
{
"private": true,
"name": "@eth-optimism/batch-submitter",
"version": "0.4.13",
"version": "0.4.14",
"description": "[Optimism] Service for submitting transactions and transaction results",
"main": "dist/index",
"types": "dist/index",
......@@ -34,8 +34,8 @@
},
"dependencies": {
"@eth-optimism/common-ts": "0.2.1",
"@eth-optimism/contracts": "0.5.8",
"@eth-optimism/core-utils": "0.7.3",
"@eth-optimism/contracts": "0.5.9",
"@eth-optimism/core-utils": "0.7.4",
"@eth-optimism/ynatm": "^0.2.2",
"@ethersproject/abstract-provider": "^5.4.1",
"@ethersproject/providers": "^5.4.5",
......
......@@ -14,6 +14,7 @@ import { Gauge, Histogram, Counter } from 'prom-client'
import { RollupInfo, sleep } from '@eth-optimism/core-utils'
import { Logger, Metrics } from '@eth-optimism/common-ts'
import { getContractFactory } from 'old-contracts'
/* Internal Imports */
import { TxSubmissionHooks } from '..'
......
......@@ -12,8 +12,8 @@ import {
import { Logger, Metrics } from '@eth-optimism/common-ts'
/* Internal Imports */
import { BlockRange, BatchSubmitter } from '.'
import { TransactionSubmitter } from '../utils'
import { BlockRange, BatchSubmitter } from '.'
export class StateBatchSubmitter extends BatchSubmitter {
// TODO: Change this so that we calculate start = scc.totalElements() and end = ctc.totalElements()!
......
......@@ -20,9 +20,8 @@ import {
BatchContext,
AppendSequencerBatchParams,
} from '../transaction-chain-contract'
import { BlockRange, BatchSubmitter } from '.'
import { TransactionSubmitter } from '../utils'
import { BlockRange, BatchSubmitter } from '.'
export interface AutoFixBatchOptions {
fixDoublePlayedDeposits: boolean
......
/* External Imports */
import { exit } from 'process'
import { injectL2Context, Bcfg } from '@eth-optimism/core-utils'
import * as Sentry from '@sentry/node'
import { Logger, Metrics, createMetricsServer } from '@eth-optimism/common-ts'
import { exit } from 'process'
import { Signer, Wallet } from 'ethers'
import {
StaticJsonRpcProvider,
......
import { expect } from '../setup'
/* External Imports */
import { ethers } from 'hardhat'
import '@nomiclabs/hardhat-ethers'
import { Signer, ContractFactory, Contract, BigNumber } from 'ethers'
import sinon from 'sinon'
import scc from '@eth-optimism/contracts/artifacts/contracts/L1/rollup/StateCommitmentChain.sol/StateCommitmentChain.json'
import { getContractInterface } from '@eth-optimism/contracts'
import { smockit, MockContract } from '@eth-optimism/smock'
import { getContractFactory } from 'old-contracts'
import { QueueOrigin, Batch, remove0x } from '@eth-optimism/core-utils'
import { Logger, Metrics } from '@eth-optimism/common-ts'
/* Internal Imports */
import { MockchainProvider } from './mockchain-provider'
import {
makeAddressManager,
setProxyTarget,
FORCE_INCLUSION_PERIOD_SECONDS,
} from '../helpers'
import { expect } from '../setup'
import {
CanonicalTransactionChainContract,
TransactionBatchSubmitter as RealTransactionBatchSubmitter,
......@@ -28,9 +22,11 @@ import {
YnatmTransactionSubmitter,
ResubmissionConfig,
} from '../../src'
import { QueueOrigin, Batch, remove0x } from '@eth-optimism/core-utils'
import { Logger, Metrics } from '@eth-optimism/common-ts'
import {
makeAddressManager,
setProxyTarget,
FORCE_INCLUSION_PERIOD_SECONDS,
} from '../helpers'
const EXAMPLE_STATE_ROOT =
'0x16b7f83f409c7195b1f4fde5652f1b54a4477eacb6db7927691becafba5f8801'
......
import { expect } from '../setup'
import { ethers, BigNumber, Signer } from 'ethers'
import { submitTransactionWithYNATM } from '../../src/utils/tx-submission'
import { ResubmissionConfig } from '../../src'
import {
TransactionReceipt,
TransactionResponse,
} from '@ethersproject/abstract-provider'
import { expect } from '../setup'
import { submitTransactionWithYNATM } from '../../src/utils/tx-submission'
import { ResubmissionConfig } from '../../src'
const nullFunction = () => undefined
const nullHooks = {
beforeSendTransaction: nullFunction,
......
import { Server } from 'net'
import prometheus, {
collectDefaultMetrics,
DefaultMetricsCollectorConfiguration,
Registry,
} from 'prom-client'
import express from 'express'
import { Server } from 'net'
import { Logger } from './logger'
......
# Changelog
## 0.5.9
### Patch Changes
- Updated dependencies [ba96a455]
- Updated dependencies [c3e85fef]
- @eth-optimism/core-utils@0.7.4
## 0.5.8
### Patch Changes
......
/* External Imports */
import * as fs from 'fs'
import * as path from 'path'
import * as mkdirp from 'mkdirp'
const ensure = (value, key) => {
......
/* eslint @typescript-eslint/no-var-requires: "off" */
import { ethers } from 'ethers'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { awaitCondition } from '@eth-optimism/core-utils'
import {
getContractFromArtifact,
fundAccount,
......@@ -8,7 +10,6 @@ import {
BIG_BALANCE,
} from '../src/deploy-utils'
import { names } from '../src/address-names'
import { awaitCondition } from '@eth-optimism/core-utils'
const deployFn: DeployFunction = async (hre) => {
if ((hre as any).deployConfig.forked !== 'true') {
......
/* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { names } from '../src/address-names'
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments
......
{
"name": "@eth-optimism/contracts",
"version": "0.5.8",
"version": "0.5.9",
"description": "[Optimism] L1 and L2 smart contracts for Optimism",
"main": "dist/index",
"types": "dist/index",
......@@ -58,7 +58,7 @@
"url": "https://github.com/ethereum-optimism/optimism.git"
},
"dependencies": {
"@eth-optimism/core-utils": "0.7.3",
"@eth-optimism/core-utils": "0.7.4",
"@ethersproject/abstract-provider": "^5.4.1",
"@ethersproject/abstract-signer": "^5.4.1",
"@ethersproject/hardware-wallets": "^5.4.0"
......
import path from 'path'
import glob from 'glob'
import fs from 'fs'
import glob from 'glob'
/**
* Script for automatically generating a file which has a series of `require` statements for
* importing JSON contract artifacts. We do this to preserve browser compatibility.
......
import path from 'path'
import glob from 'glob'
import fs from 'fs'
import glob from 'glob'
/**
* Script for automatically generating a TypeScript file for retrieving deploy artifact JSON files.
* We do this to make sure that this package remains browser compatible.
......
import dirtree from 'directory-tree'
import fs from 'fs'
import path from 'path'
import dirtree from 'directory-tree'
import { predeploys } from '../src'
interface DeploymentInfo {
......
/* External Imports */
import { promisify } from 'util'
import { exec } from 'child_process'
import { promisify } from 'util'
import { ethers } from 'ethers'
import {
computeStorageSlots,
......
import { createInterface } from 'readline'
import { hexStringEquals } from '@eth-optimism/core-utils'
export const getInput = (query) => {
......
......@@ -4,9 +4,9 @@ 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, getContractDefinition } from '../src/contract-defs'
import { names } from '../src/address-names'
import {
getInput,
color as c,
......
......@@ -3,8 +3,8 @@
import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes'
import { getContractFactory, getContractDefinition } from '../src/contract-defs'
import { getContractFactory, getContractDefinition } from '../src/contract-defs'
import {
getInput,
color as c,
......
'use strict'
import fs from 'fs'
import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes'
import { LedgerSigner } from '@ethersproject/hardware-wallets'
import { getContractFactory } from '../src/contract-defs'
import { predeploys } from '../src/predeploys'
......
......@@ -4,6 +4,7 @@ import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes'
import { LedgerSigner } from '@ethersproject/hardware-wallets'
import { getContractFactory } from '../src/contract-defs'
import { predeploys } from '../src/predeploys'
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract, BigNumber } from 'ethers'
......@@ -11,6 +9,7 @@ import {
} from '@eth-optimism/core-utils'
/* Internal Imports */
import { expect } from '../../../setup'
import {
makeAddressManager,
setProxyTarget,
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract, constants } from 'ethers'
......@@ -7,6 +5,7 @@ import { Interface } from 'ethers/lib/utils'
import { smockit, MockContract, smoddit } from '@eth-optimism/smock'
/* Internal Imports */
import { expect } from '../../../setup'
import { NON_NULL_BYTES32, NON_ZERO_ADDRESS } from '../../../helpers'
import { getContractInterface, predeploys } from '../../../../src'
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
......@@ -13,6 +11,7 @@ import { keccak256 } from 'ethers/lib/utils'
import _ from 'lodash'
/* Internal Imports */
import { expect } from '../../../setup'
import {
makeAddressManager,
setProxyTarget,
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract, constants } from 'ethers'
import { smockit, MockContract } from '@eth-optimism/smock'
/* Internal Imports */
import { expect } from '../../../setup'
import {
makeAddressManager,
setProxyTarget,
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, Contract } from 'ethers'
/* Internal Imports */
import { expect } from '../../../setup'
import { makeAddressManager } from '../../../helpers'
describe('BondManager', () => {
......
import { expect } from '../../../setup'
/* External Imports */
import hre, { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
......@@ -7,6 +5,7 @@ import { smockit, MockContract } from '@eth-optimism/smock'
import { applyL1ToL2Alias } from '@eth-optimism/core-utils'
/* Internal Imports */
import { expect } from '../../../setup'
import {
NON_NULL_BYTES32,
NON_ZERO_ADDRESS,
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
......@@ -11,8 +9,8 @@ import {
} from '@eth-optimism/smock'
/* Internal Imports */
import { expect } from '../../../setup'
import { NON_NULL_BYTES32, NON_ZERO_ADDRESS } from '../../../helpers'
import { getContractInterface } from '../../../../src'
const ERR_INVALID_MESSENGER = 'OVM_XCHAIN: messenger contract unauthenticated'
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import { smoddit } from '@eth-optimism/smock'
/* Internal Imports */
import { expect } from '../../../setup'
import { predeploys, getContractInterface } from '../../../../src'
describe('L2StandardTokenFactory', () => {
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { ContractFactory, Contract, Signer } from 'ethers'
import { expect } from '../../../setup'
describe('OVM_ETH', () => {
let signer1: Signer
let signer2: Signer
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { ContractFactory, Contract, Signer } from 'ethers'
import { calculateL1GasUsed, calculateL1Fee } from '@eth-optimism/core-utils'
import { expect } from '../../../setup'
describe('OVM_GasPriceOracle', () => {
const initialGasPrice = 0
let signer1: Signer
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { ContractFactory, Contract } from 'ethers'
......@@ -8,6 +6,7 @@ import { remove0x } from '@eth-optimism/core-utils'
import { keccak256 } from 'ethers/lib/utils'
/* Internal Imports */
import { expect } from '../../../setup'
import { NON_ZERO_ADDRESS } from '../../../helpers/constants'
const ELEMENT_TEST_SIZES = [1, 2, 4, 8, 16]
......
import { expect } from '../../../setup'
/* Imports: External */
import hre from 'hardhat'
import { MockContract, smockit } from '@eth-optimism/smock'
import { Contract, Signer } from 'ethers'
/* Imports: Internal */
import { expect } from '../../../setup'
import { predeploys } from '../../../../src'
describe('OVM_SequencerFeeVault', () => {
......
import { expect } from '../../setup'
/* Imports: External */
import hre from 'hardhat'
import { Contract, Signer } from 'ethers'
import { smockit } from '@eth-optimism/smock'
/* Imports: Internal */
import { expect } from '../../setup'
import { getContractInterface } from '../../../src'
describe('L1ChugSplashProxy', () => {
......
import '../../../setup'
/* Internal Imports */
import '../../../setup'
import { Lib_OVMCodec_TEST_JSON } from '../../../data'
import { runJsonTest } from '../../../helpers'
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Contract } from 'ethers'
/* Internal Imports */
import { expect } from '../../../setup'
import { Lib_RLPWriter_TEST_JSON } from '../../../data'
const encode = async (Lib_RLPWriter: Contract, input: any): Promise<void> => {
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Contract } from 'ethers'
import { applyL1ToL2Alias, undoL1ToL2Alias } from '@eth-optimism/core-utils'
import { expect } from '../../../setup'
describe('AddressAliasHelper', () => {
let AddressAliasHelper: Contract
before(async () => {
......
import { expect } from '../../../setup'
/* External Imports */
import * as rlp from 'rlp'
import { ethers } from 'hardhat'
......@@ -8,6 +6,7 @@ import { fromHexString, toHexString } from '@eth-optimism/core-utils'
import { Trie } from 'merkle-patricia-tree/dist/baseTrie'
/* Internal Imports */
import { expect } from '../../../setup'
import { TrieTestGenerator } from '../../../helpers'
import * as officialTestJson from '../../../data/json/libraries/trie/trietest.json'
import * as officialTestAnyOrderJson from '../../../data/json/libraries/trie/trieanyorder.json'
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Contract } from 'ethers'
/* Internal Imports */
import { expect } from '../../../setup'
import { TrieTestGenerator } from '../../../helpers'
const NODE_COUNTS = [1, 2, 128]
......
import { expect } from '../../../setup'
import hre from 'hardhat'
import { Contract, ethers } from 'ethers'
import { expect } from '../../../setup'
describe('Lib_Buffer', () => {
let Lib_Buffer: Contract
beforeEach(async () => {
......
/* Internal Imports */
import { Lib_BytesUtils_TEST_JSON } from '../../../data'
import { runJsonTest } from '../../../helpers'
/* External Imports */
import { ethers } from 'hardhat'
import { Contract } from 'ethers'
/* External Imports */
import { Lib_BytesUtils_TEST_JSON } from '../../../data'
import { runJsonTest } from '../../../helpers'
import { expect } from '../../../setup'
describe('Lib_BytesUtils', () => {
......
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Contract, BigNumber } from 'ethers'
......@@ -7,6 +5,7 @@ import { MerkleTree } from 'merkletreejs'
import { fromHexString, toHexString } from '@eth-optimism/core-utils'
/* Internal Imports */
import { expect } from '../../../setup'
import { NON_NULL_BYTES32 } from '../../../helpers'
const NODE_COUNTS = [
......
import { NON_ZERO_ADDRESS } from '../constants'
import { ethers } from 'hardhat'
import { NON_ZERO_ADDRESS } from '../constants'
export const DUMMY_BATCH_HEADERS = [
{
batchIndex: 0,
......
import { expect } from '../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Contract, BigNumber } from 'ethers'
import { expect } from '../../setup'
const bigNumberify = (arr: any[]) => {
return arr.map((el: any) => {
if (typeof el === 'number') {
......
# @eth-optimism/core-utils
## 0.7.4
### Patch Changes
- ba96a455: Improved docstrings for BCFG typings
- c3e85fef: Cleans up the internal file and folder structure for the typings exported by core-utils
## 0.7.3
### Patch Changes
......
{
"name": "@eth-optimism/core-utils",
"version": "0.7.3",
"version": "0.7.4",
"description": "[Optimism] Core typescript utilities",
"main": "dist/index",
"types": "dist/index",
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment