Commit 87231e92 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into willc/go-chi-latest

parents b8c10f77 efea631c
...@@ -51,6 +51,36 @@ Refer to the Directory Structure section below to understand which packages are ...@@ -51,6 +51,36 @@ Refer to the Directory Structure section below to understand which packages are
~~ Production ~~ ~~ Production ~~
├── <a href="./packages">packages</a> ├── <a href="./packages">packages</a>
│ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript │ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript
│ ├── <a href="./packages/contracts-bedrock">contracts-bedrock</a>: Bedrock smart contracts.
│ ├── <a href="./packages/contracts-periphery">contracts-periphery</a>: Peripheral contracts for Optimism
│ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier
│ ├── <a href="./packages/data-transport-layer">data-transport-layer</a>: Service for indexing Optimism-related L1 data
│ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services
│ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults
│ ├── <a href="./packages/message-relayer">message-relayer</a>: Tool for automatically relaying L1<>L2 messages in development
│ ├── <a href="./packages/replica-healthcheck">replica-healthcheck</a>: Service for monitoring the health of a replica node
│ └── <a href="./packages/sdk">sdk</a>: provides a set of tools for interacting with Optimism
├── <a href="./op-bindings">op-bindings</a>: Go bindings for Bedrock smart contracts.
├── <a href="./op-batcher">op-batcher</a>: L2-Batch Submitter, submits bundles of batches to L1
├── <a href="./op-bootnode">op-bootnode</a>: Standalone op-node discovery bootnode
├── <a href="./op-chain-ops">op-chain-ops</a>: State surgery utilities
├── <a href="./op-challenger">op-challenger</a>: Dispute game challenge agent
├── <a href="./op-e2e">op-e2e</a>: End-to-End testing of all bedrock components in Go
├── <a href="./op-exporter">op-exporter</a>: Prometheus exporter client
├── <a href="./op-heartbeat">op-heartbeat</a>: Heartbeat monitor service
├── <a href="./op-node">op-node</a>: rollup consensus-layer client
├── <a href="./op-program">op-program</a>: Fault proof program
├── <a href="./op-proposer">op-proposer</a>: L2-Output Submitter, submits proposals to L1
├── <a href="./op-service">op-service</a>: Common codebase utilities
├── <a href="./op-signer">op-signer</a>: Client signer
├── <a href="./op-wheel">op-wheel</a>: Database utilities
├── <a href="./ops-bedrock">ops-bedrock</a>: Bedrock devnet work
├── <a href="./proxyd">proxyd</a>: Configurable RPC request router and proxy
└── <a href="./specs">specs</a>: Specs of the rollup starting at the Bedrock upgrade
~~ Pre-BEDROCK ~~
├── <a href="./packages">packages</a>
│ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript
│ ├── <a href="./packages/contracts">contracts</a>: L1 and L2 smart contracts for Optimism │ ├── <a href="./packages/contracts">contracts</a>: L1 and L2 smart contracts for Optimism
│ ├── <a href="./packages/contracts-periphery">contracts-periphery</a>: Peripheral contracts for Optimism │ ├── <a href="./packages/contracts-periphery">contracts-periphery</a>: Peripheral contracts for Optimism
│ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier │ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier
...@@ -69,18 +99,7 @@ Refer to the Directory Structure section below to understand which packages are ...@@ -69,18 +99,7 @@ Refer to the Directory Structure section below to understand which packages are
├── <a href="./l2geth-exporter">l2geth-exporter</a>: A prometheus exporter to collect/serve metrics from an L2 geth node ├── <a href="./l2geth-exporter">l2geth-exporter</a>: A prometheus exporter to collect/serve metrics from an L2 geth node
├── <a href="./op-exporter">op-exporter</a>: A prometheus exporter to collect/serve metrics from an Optimism node ├── <a href="./op-exporter">op-exporter</a>: A prometheus exporter to collect/serve metrics from an Optimism node
├── <a href="./proxyd">proxyd</a>: Configurable RPC request router and proxy ├── <a href="./proxyd">proxyd</a>: Configurable RPC request router and proxy
├── <a href="./technical-documents">technical-documents</a>: audits and post-mortem documents └── <a href="./technical-documents">technical-documents</a>: audits and post-mortem documents
~~ BEDROCK upgrade - Not production-ready yet, part of next major upgrade ~~
├── <a href="./packages">packages</a>
│ └── <a href="./packages/contracts-bedrock">contracts-bedrock</a>: Bedrock smart contracts. To be merged with ./packages/contracts.
├── <a href="./op-bindings">op-bindings</a>: Go bindings for Bedrock smart contracts.
├── <a href="./op-batcher">op-batcher</a>: L2-Batch Submitter, submits bundles of batches to L1
├── <a href="./op-e2e">op-e2e</a>: End-to-End testing of all bedrock components in Go
├── <a href="./op-node">op-node</a>: rollup consensus-layer client.
├── <a href="./op-proposer">op-proposer</a>: L2-Output Submitter, submits proposals to L1
├── <a href="./ops-bedrock">ops-bedrock</a>: Bedrock devnet work
└── <a href="./specs">specs</a>: Specs of the rollup starting at the Bedrock upgrade
</pre> </pre>
## Branching Model ## Branching Model
......
...@@ -190,6 +190,6 @@ require ( ...@@ -190,6 +190,6 @@ require (
nhooyr.io/websocket v1.8.7 // indirect nhooyr.io/websocket v1.8.7 // indirect
) )
replace github.com/ethereum/go-ethereum v1.11.6 => github.com/ethereum-optimism/op-geth v1.101105.2-0.20230526154603-bdab05ca786f replace github.com/ethereum/go-ethereum v1.11.6 => github.com/ethereum-optimism/op-geth v1.101106.0-rc.2
//replace github.com/ethereum/go-ethereum v1.11.6 => ../go-ethereum //replace github.com/ethereum/go-ethereum v1.11.6 => ../go-ethereum
...@@ -151,8 +151,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 ...@@ -151,8 +151,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v1.101105.2-0.20230526154603-bdab05ca786f h1:+yZN8K/4AIN5f+gazMwZAeqzDG2EL2GydMrccjnEK+A= github.com/ethereum-optimism/op-geth v1.101106.0-rc.2 h1:F3SGS0XIvRQ0MjL3Rzbx3A688hNsqv/DtdlBnZimFTw=
github.com/ethereum-optimism/op-geth v1.101105.2-0.20230526154603-bdab05ca786f/go.mod h1:X9t7oeerFMU9/zMIjZKT/jbIca+O05QqtBTLjL+XVeA= github.com/ethereum-optimism/op-geth v1.101106.0-rc.2/go.mod h1:X9t7oeerFMU9/zMIjZKT/jbIca+O05QqtBTLjL+XVeA=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
......
...@@ -228,6 +228,7 @@ func (s *channelManager) processBlocks() error { ...@@ -228,6 +228,7 @@ func (s *channelManager) processBlocks() error {
} }
blocksAdded += 1 blocksAdded += 1
latestL2ref = l2BlockRefFromBlockAndL1Info(block, l1info) latestL2ref = l2BlockRefFromBlockAndL1Info(block, l1info)
s.metr.RecordL2BlockInChannel(block)
// current block got added but channel is now full // current block got added but channel is now full
if s.currentChannel.IsFull() { if s.currentChannel.IsFull() {
break break
...@@ -298,6 +299,8 @@ func (s *channelManager) AddL2Block(block *types.Block) error { ...@@ -298,6 +299,8 @@ func (s *channelManager) AddL2Block(block *types.Block) error {
if s.tip != (common.Hash{}) && s.tip != block.ParentHash() { if s.tip != (common.Hash{}) && s.tip != block.ParentHash() {
return ErrReorg return ErrReorg
} }
s.metr.RecordL2BlockInPendingQueue(block)
s.blocks = append(s.blocks, block) s.blocks = append(s.blocks, block)
s.tip = block.Hash() s.tip = block.Hash()
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
...@@ -30,6 +31,8 @@ type Metricer interface { ...@@ -30,6 +31,8 @@ type Metricer interface {
RecordL2BlocksLoaded(l2ref eth.L2BlockRef) RecordL2BlocksLoaded(l2ref eth.L2BlockRef)
RecordChannelOpened(id derive.ChannelID, numPendingBlocks int) RecordChannelOpened(id derive.ChannelID, numPendingBlocks int)
RecordL2BlocksAdded(l2ref eth.L2BlockRef, numBlocksAdded, numPendingBlocks, inputBytes, outputComprBytes int) RecordL2BlocksAdded(l2ref eth.L2BlockRef, numBlocksAdded, numPendingBlocks, inputBytes, outputComprBytes int)
RecordL2BlockInPendingQueue(block *types.Block)
RecordL2BlockInChannel(block *types.Block)
RecordChannelClosed(id derive.ChannelID, numPendingBlocks int, numFrames int, inputBytes int, outputComprBytes int, reason error) RecordChannelClosed(id derive.ChannelID, numPendingBlocks int, numFrames int, inputBytes int, outputComprBytes int, reason error)
RecordChannelFullySubmitted(id derive.ChannelID) RecordChannelFullySubmitted(id derive.ChannelID)
RecordChannelTimedOut(id derive.ChannelID) RecordChannelTimedOut(id derive.ChannelID)
...@@ -55,8 +58,10 @@ type Metrics struct { ...@@ -55,8 +58,10 @@ type Metrics struct {
// label by openend, closed, fully_submitted, timed_out // label by openend, closed, fully_submitted, timed_out
channelEvs opmetrics.EventVec channelEvs opmetrics.EventVec
pendingBlocksCount prometheus.GaugeVec pendingBlocksCount prometheus.GaugeVec
blocksAddedCount prometheus.Gauge pendingBlocksBytesTotal prometheus.Counter
pendingBlocksBytesCurrent prometheus.Gauge
blocksAddedCount prometheus.Gauge
channelInputBytes prometheus.GaugeVec channelInputBytes prometheus.GaugeVec
channelReadyBytes prometheus.Gauge channelReadyBytes prometheus.Gauge
...@@ -109,6 +114,16 @@ func NewMetrics(procName string) *Metrics { ...@@ -109,6 +114,16 @@ func NewMetrics(procName string) *Metrics {
Name: "pending_blocks_count", Name: "pending_blocks_count",
Help: "Number of pending blocks, not added to a channel yet.", Help: "Number of pending blocks, not added to a channel yet.",
}, []string{"stage"}), }, []string{"stage"}),
pendingBlocksBytesTotal: factory.NewCounter(prometheus.CounterOpts{
Namespace: ns,
Name: "pending_blocks_bytes_total",
Help: "Total size of transactions in pending blocks as they are fetched from L2",
}),
pendingBlocksBytesCurrent: factory.NewGauge(prometheus.GaugeOpts{
Namespace: ns,
Name: "pending_blocks_bytes_current",
Help: "Current size of transactions in the pending (fetched from L2 but not in a channel) stage.",
}),
blocksAddedCount: factory.NewGauge(prometheus.GaugeOpts{ blocksAddedCount: factory.NewGauge(prometheus.GaugeOpts{
Namespace: ns, Namespace: ns,
Name: "blocks_added_count", Name: "blocks_added_count",
...@@ -243,6 +258,18 @@ func (m *Metrics) RecordChannelClosed(id derive.ChannelID, numPendingBlocks int, ...@@ -243,6 +258,18 @@ func (m *Metrics) RecordChannelClosed(id derive.ChannelID, numPendingBlocks int,
m.channelClosedReason.Set(float64(ClosedReasonToNum(reason))) m.channelClosedReason.Set(float64(ClosedReasonToNum(reason)))
} }
func (m *Metrics) RecordL2BlockInPendingQueue(block *types.Block) {
size := float64(estimateBatchSize(block))
m.pendingBlocksBytesTotal.Add(size)
m.pendingBlocksBytesCurrent.Add(size)
}
func (m *Metrics) RecordL2BlockInChannel(block *types.Block) {
size := float64(estimateBatchSize(block))
m.pendingBlocksBytesCurrent.Add(-1 * size)
// Refer to RecordL2BlocksAdded to see the current + count of bytes added to a channel
}
func ClosedReasonToNum(reason error) int { func ClosedReasonToNum(reason error) int {
// CLI-3640 // CLI-3640
return 0 return 0
...@@ -267,3 +294,17 @@ func (m *Metrics) RecordBatchTxSuccess() { ...@@ -267,3 +294,17 @@ func (m *Metrics) RecordBatchTxSuccess() {
func (m *Metrics) RecordBatchTxFailed() { func (m *Metrics) RecordBatchTxFailed() {
m.batcherTxEvs.Record(TxStageFailed) m.batcherTxEvs.Record(TxStageFailed)
} }
// estimateBatchSize estimates the size of the batch
func estimateBatchSize(block *types.Block) uint64 {
size := uint64(70) // estimated overhead of batch metadata
for _, tx := range block.Transactions() {
// Don't include deposit transactions in the batch.
if tx.IsDepositTx() {
continue
}
// Add 2 for the overhead of encoding the tx bytes in a RLP list
size += tx.Size() + 2
}
return size
}
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/derive"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
txmetrics "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics" txmetrics "github.com/ethereum-optimism/optimism/op-service/txmgr/metrics"
"github.com/ethereum/go-ethereum/core/types"
) )
type noopMetrics struct { type noopMetrics struct {
...@@ -23,6 +24,8 @@ func (*noopMetrics) RecordLatestL1Block(l1ref eth.L1BlockRef) {} ...@@ -23,6 +24,8 @@ func (*noopMetrics) RecordLatestL1Block(l1ref eth.L1BlockRef) {}
func (*noopMetrics) RecordL2BlocksLoaded(eth.L2BlockRef) {} func (*noopMetrics) RecordL2BlocksLoaded(eth.L2BlockRef) {}
func (*noopMetrics) RecordChannelOpened(derive.ChannelID, int) {} func (*noopMetrics) RecordChannelOpened(derive.ChannelID, int) {}
func (*noopMetrics) RecordL2BlocksAdded(eth.L2BlockRef, int, int, int, int) {} func (*noopMetrics) RecordL2BlocksAdded(eth.L2BlockRef, int, int, int, int) {}
func (*noopMetrics) RecordL2BlockInPendingQueue(*types.Block) {}
func (*noopMetrics) RecordL2BlockInChannel(*types.Block) {}
func (*noopMetrics) RecordChannelClosed(derive.ChannelID, int, int, int, int, error) {} func (*noopMetrics) RecordChannelClosed(derive.ChannelID, int, int, int, int, error) {}
......
...@@ -31,7 +31,7 @@ var ( ...@@ -31,7 +31,7 @@ var (
// DisputeGameFactoryMetaData contains all meta data concerning the DisputeGameFactory contract. // DisputeGameFactoryMetaData contains all meta data concerning the DisputeGameFactory contract.
var DisputeGameFactoryMetaData = &bind.MetaData{ var DisputeGameFactoryMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"Hash\",\"name\":\"uuid\",\"type\":\"bytes32\"}],\"name\":\"GameAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"}],\"name\":\"NoImplementation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"disputeProxy\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"},{\"indexed\":true,\"internalType\":\"Claim\",\"name\":\"rootClaim\",\"type\":\"bytes32\"}],\"name\":\"DisputeGameCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"impl\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"}],\"name\":\"ImplementationSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"},{\"internalType\":\"Claim\",\"name\":\"rootClaim\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"create\",\"outputs\":[{\"internalType\":\"contractIDisputeGame\",\"name\":\"proxy\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"gameImpls\",\"outputs\":[{\"internalType\":\"contractIDisputeGame\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"},{\"internalType\":\"Claim\",\"name\":\"rootClaim\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"games\",\"outputs\":[{\"internalType\":\"contractIDisputeGame\",\"name\":\"_proxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"},{\"internalType\":\"Claim\",\"name\":\"rootClaim\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"getGameUUID\",\"outputs\":[{\"internalType\":\"Hash\",\"name\":\"_uuid\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"},{\"internalType\":\"contractIDisputeGame\",\"name\":\"impl\",\"type\":\"address\"}],\"name\":\"setImplementation\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"Hash\",\"name\":\"uuid\",\"type\":\"bytes32\"}],\"name\":\"GameAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"}],\"name\":\"NoImplementation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"disputeProxy\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"},{\"indexed\":true,\"internalType\":\"Claim\",\"name\":\"rootClaim\",\"type\":\"bytes32\"}],\"name\":\"DisputeGameCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"impl\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"}],\"name\":\"ImplementationSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"},{\"internalType\":\"Claim\",\"name\":\"rootClaim\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"create\",\"outputs\":[{\"internalType\":\"contractIDisputeGame\",\"name\":\"proxy\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"\",\"type\":\"uint8\"}],\"name\":\"gameImpls\",\"outputs\":[{\"internalType\":\"contractIDisputeGame\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"},{\"internalType\":\"Claim\",\"name\":\"rootClaim\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"games\",\"outputs\":[{\"internalType\":\"contractIDisputeGame\",\"name\":\"_proxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"},{\"internalType\":\"Claim\",\"name\":\"rootClaim\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"getGameUUID\",\"outputs\":[{\"internalType\":\"Hash\",\"name\":\"_uuid\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumGameType\",\"name\":\"gameType\",\"type\":\"uint8\"},{\"internalType\":\"contractIDisputeGame\",\"name\":\"impl\",\"type\":\"address\"}],\"name\":\"setImplementation\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
Bin: "0x608060405234801561001057600080fd5b50604051610d90380380610d9083398101604081905261002f91610171565b61003833610047565b61004181610097565b506101a1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61009f610115565b6001600160a01b0381166101095760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61011281610047565b50565b6000546001600160a01b0316331461016f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610100565b565b60006020828403121561018357600080fd5b81516001600160a01b038116811461019a57600080fd5b9392505050565b610be0806101b06000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c80638da5cb5b1161005b5780638da5cb5b14610194578063c49d5271146101b2578063dfa162d3146101c5578063f2fde38b146101fb57600080fd5b806326daafbe1461008d5780633142e55e1461013f57806345583b7a14610177578063715018a61461018c575b600080fd5b61012c61009b366004610941565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0810180517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0830180517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08086018051988652968352606087529451609f0190941683209190925291905291905290565b6040519081526020015b60405180910390f35b61015261014d366004610a2a565b61020e565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610136565b61018a610185366004610ad3565b6104bf565b005b61018a610592565b60005473ffffffffffffffffffffffffffffffffffffffff16610152565b6101526101c0366004610a2a565b6105a6565b6101526101d3366004610b0a565b60016020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b61018a610209366004610b2c565b61061d565b6000806001600087600281111561022757610227610b49565b600281111561023857610238610b49565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff169050806102a357856040517f44265d6f00000000000000000000000000000000000000000000000000000000815260040161029a9190610b78565b60405180910390fd5b60008585856040516020016102ba93929190610bb9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905061030a73ffffffffffffffffffffffffffffffffffffffff8316826106d4565b92508273ffffffffffffffffffffffffffffffffffffffff16638129fc1c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561035457600080fd5b505af1158015610368573d6000803e3d6000fd5b5050505060006103af888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061009b92505050565b60008181526002602052604090205490915073ffffffffffffffffffffffffffffffffffffffff1615610411576040517f014f6fe50000000000000000000000000000000000000000000000000000000081526004810182905260240161029a565b600081815260026020819052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87161790558790899081111561047357610473610b49565b60405173ffffffffffffffffffffffffffffffffffffffff8716907ffad0599ff449d8d9685eadecca8cb9e00924c5fd8367c1c09469824939e1ffec90600090a4505050949350505050565b6104c7610808565b80600160008460028111156104de576104de610b49565b60028111156104ef576104ef610b49565b815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600281111561054d5761054d610b49565b60405173ffffffffffffffffffffffffffffffffffffffff8316907f623713f72f6e427a8044bb8b3bd6834357cf285decbaa21bcc73c1d0632c4d8490600090a35050565b61059a610808565b6105a46000610889565b565b6000600260006105ed878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061009b92505050565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1695945050505050565b610625610808565b73ffffffffffffffffffffffffffffffffffffffff81166106c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161029a565b6106d181610889565b50565b60006002825101603f8101600a81036040518360581b8260e81b177f6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d7300001781528660601b601e8201527f5af43d3d93803e603357fd5bf300000000000000000000000000000000000000603282015285519150603f8101602087015b6020841061078c57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909301926020918201910161074f565b517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602085900360031b1b16815260f085901b9083015282816000f09450846107f9577febfef1880000000000000000000000000000000000000000000000000000000060005260206000fd5b90910160405250909392505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161029a565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80356003811061090d57600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561095657600080fd5b61095f846108fe565b925060208401359150604084013567ffffffffffffffff8082111561098357600080fd5b818601915086601f83011261099757600080fd5b8135818111156109a9576109a9610912565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156109ef576109ef610912565b81604052828152896020848701011115610a0857600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60008060008060608587031215610a4057600080fd5b610a49856108fe565b935060208501359250604085013567ffffffffffffffff80821115610a6d57600080fd5b818701915087601f830112610a8157600080fd5b813581811115610a9057600080fd5b886020828501011115610aa257600080fd5b95989497505060200194505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106d157600080fd5b60008060408385031215610ae657600080fd5b610aef836108fe565b91506020830135610aff81610ab1565b809150509250929050565b600060208284031215610b1c57600080fd5b610b25826108fe565b9392505050565b600060208284031215610b3e57600080fd5b8135610b2581610ab1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310610bb3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b83815281836020830137600091016020019081529291505056fea164736f6c634300080f000a", Bin: "0x608060405234801561001057600080fd5b50604051610d8b380380610d8b83398101604081905261002f91610171565b61003833610047565b61004181610097565b506101a1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61009f610115565b6001600160a01b0381166101095760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61011281610047565b50565b6000546001600160a01b0316331461016f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610100565b565b60006020828403121561018357600080fd5b81516001600160a01b038116811461019a57600080fd5b9392505050565b610bdb806101b06000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c80638da5cb5b1161005b5780638da5cb5b14610194578063c49d5271146101b2578063dfa162d3146101c5578063f2fde38b146101fb57600080fd5b806326daafbe1461008d5780633142e55e1461013f57806345583b7a14610177578063715018a61461018c575b600080fd5b61012c61009b36600461093c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0810180517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0830180517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08086018051988652968352606087529451609f0190941683209190925291905291905290565b6040519081526020015b60405180910390f35b61015261014d366004610a25565b61020e565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610136565b61018a610185366004610ace565b6104ba565b005b61018a61058d565b60005473ffffffffffffffffffffffffffffffffffffffff16610152565b6101526101c0366004610a25565b6105a1565b6101526101d3366004610b05565b60016020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b61018a610209366004610b27565b610618565b6000806001600087600281111561022757610227610b44565b600281111561023857610238610b44565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff169050806102a357856040517f44265d6f00000000000000000000000000000000000000000000000000000000815260040161029a9190610b73565b60405180910390fd5b6103068585856040516020016102bb93929190610bb4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905273ffffffffffffffffffffffffffffffffffffffff8316906106cf565b91508173ffffffffffffffffffffffffffffffffffffffff16638129fc1c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561035057600080fd5b505af1158015610364573d6000803e3d6000fd5b5050505060006103ab878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061009b92505050565b60008181526002602052604090205490915073ffffffffffffffffffffffffffffffffffffffff161561040d576040517f014f6fe50000000000000000000000000000000000000000000000000000000081526004810182905260240161029a565b600081815260026020819052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86161790558690889081111561046f5761046f610b44565b60405173ffffffffffffffffffffffffffffffffffffffff8616907ffad0599ff449d8d9685eadecca8cb9e00924c5fd8367c1c09469824939e1ffec90600090a45050949350505050565b6104c2610803565b80600160008460028111156104d9576104d9610b44565b60028111156104ea576104ea610b44565b815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600281111561054857610548610b44565b60405173ffffffffffffffffffffffffffffffffffffffff8316907f623713f72f6e427a8044bb8b3bd6834357cf285decbaa21bcc73c1d0632c4d8490600090a35050565b610595610803565b61059f6000610884565b565b6000600260006105e8878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061009b92505050565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1695945050505050565b610620610803565b73ffffffffffffffffffffffffffffffffffffffff81166106c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161029a565b6106cc81610884565b50565b60006002825101603f8101600a81036040518360581b8260e81b177f6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d7300001781528660601b601e8201527f5af43d3d93803e603357fd5bf300000000000000000000000000000000000000603282015285519150603f8101602087015b6020841061078757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909301926020918201910161074a565b517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602085900360031b1b16815260f085901b9083015282816000f09450846107f4577febfef1880000000000000000000000000000000000000000000000000000000060005260206000fd5b90910160405250909392505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461059f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161029a565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80356003811061090857600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561095157600080fd5b61095a846108f9565b925060208401359150604084013567ffffffffffffffff8082111561097e57600080fd5b818601915086601f83011261099257600080fd5b8135818111156109a4576109a461090d565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156109ea576109ea61090d565b81604052828152896020848701011115610a0357600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60008060008060608587031215610a3b57600080fd5b610a44856108f9565b935060208501359250604085013567ffffffffffffffff80821115610a6857600080fd5b818701915087601f830112610a7c57600080fd5b813581811115610a8b57600080fd5b886020828501011115610a9d57600080fd5b95989497505060200194505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106cc57600080fd5b60008060408385031215610ae157600080fd5b610aea836108f9565b91506020830135610afa81610aac565b809150509250929050565b600060208284031215610b1757600080fd5b610b20826108f9565b9392505050565b600060208284031215610b3957600080fd5b8135610b2081610aac565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310610bae577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b83815281836020830137600091016020019081529291505056fea164736f6c634300080f000a",
} }
// DisputeGameFactoryABI is the input ABI used to generate the binding from. // DisputeGameFactoryABI is the input ABI used to generate the binding from.
......
...@@ -1084,11 +1084,6 @@ func TestWithdrawals(t *testing.T) { ...@@ -1084,11 +1084,6 @@ func TestWithdrawals(t *testing.T) {
proveReceipt, finalizeReceipt := ProveAndFinalizeWithdrawal(t, cfg, l1Client, sys.Nodes["verifier"], ethPrivKey, receipt) proveReceipt, finalizeReceipt := ProveAndFinalizeWithdrawal(t, cfg, l1Client, sys.Nodes["verifier"], ethPrivKey, receipt)
// Verify balance after withdrawal // Verify balance after withdrawal
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
header, err = l1Client.HeaderByNumber(ctx, finalizeReceipt.BlockNumber)
require.Nil(t, err)
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel() defer cancel()
endBalance, err = l1Client.BalanceAt(ctx, fromAddr, nil) endBalance, err = l1Client.BalanceAt(ctx, fromAddr, nil)
...@@ -1098,7 +1093,9 @@ func TestWithdrawals(t *testing.T) { ...@@ -1098,7 +1093,9 @@ func TestWithdrawals(t *testing.T) {
// Fun fact, the fee is greater than the withdrawal amount // Fun fact, the fee is greater than the withdrawal amount
// NOTE: The gas fees include *both* the ProveWithdrawalTransaction and FinalizeWithdrawalTransaction transactions. // NOTE: The gas fees include *both* the ProveWithdrawalTransaction and FinalizeWithdrawalTransaction transactions.
diff = new(big.Int).Sub(endBalance, startBalance) diff = new(big.Int).Sub(endBalance, startBalance)
fees = calcGasFees(proveReceipt.GasUsed+finalizeReceipt.GasUsed, tx.GasTipCap(), tx.GasFeeCap(), header.BaseFee) proveFee := new(big.Int).Mul(new(big.Int).SetUint64(proveReceipt.GasUsed), proveReceipt.EffectiveGasPrice)
finalizeFee := new(big.Int).Mul(new(big.Int).SetUint64(finalizeReceipt.GasUsed), finalizeReceipt.EffectiveGasPrice)
fees = new(big.Int).Add(proveFee, finalizeFee)
withdrawAmount = withdrawAmount.Sub(withdrawAmount, fees) withdrawAmount = withdrawAmount.Sub(withdrawAmount, fees)
require.Equal(t, withdrawAmount, diff) require.Equal(t, withdrawAmount, diff)
} }
......
...@@ -179,6 +179,7 @@ func (r ReceiptsFetchingMethod) String() string { ...@@ -179,6 +179,7 @@ func (r ReceiptsFetchingMethod) String() string {
addMaybe(DebugGetRawReceipts, "debug_getRawReceipts") addMaybe(DebugGetRawReceipts, "debug_getRawReceipts")
addMaybe(ParityGetBlockReceipts, "parity_getBlockReceipts") addMaybe(ParityGetBlockReceipts, "parity_getBlockReceipts")
addMaybe(EthGetBlockReceipts, "eth_getBlockReceipts") addMaybe(EthGetBlockReceipts, "eth_getBlockReceipts")
addMaybe(ErigonGetBlockReceiptsByBlockHash, "erigon_getBlockReceiptsByBlockHash")
addMaybe(^ReceiptsFetchingMethod(0), "unknown") // if anything is left, describe it as unknown addMaybe(^ReceiptsFetchingMethod(0), "unknown") // if anything is left, describe it as unknown
return out return out
} }
...@@ -230,10 +231,9 @@ const ( ...@@ -230,10 +231,9 @@ const (
// - Nethermind: https://docs.nethermind.io/nethermind/ethereum-client/json-rpc/parity#parity_getblockreceipts // - Nethermind: https://docs.nethermind.io/nethermind/ethereum-client/json-rpc/parity#parity_getblockreceipts
ParityGetBlockReceipts ParityGetBlockReceipts
// EthGetBlockReceipts is a non-standard receipt fetching method in the eth namespace, // EthGetBlockReceipts is a non-standard receipt fetching method in the eth namespace,
// supported by some RPC platforms and Erigon. // supported by some RPC platforms.
// Available in: // Available in:
// - Alchemy: 500 CU total (and deprecated) // - Alchemy: 500 CU total (and deprecated)
// - Erigon: free
// - QuickNode: 59 credits total (does not seem to work with block hash arg, inaccurate docs) // - QuickNode: 59 credits total (does not seem to work with block hash arg, inaccurate docs)
// Method: eth_getBlockReceipts // Method: eth_getBlockReceipts
// Params: // Params:
...@@ -243,7 +243,21 @@ const ( ...@@ -243,7 +243,21 @@ const (
// See: // See:
// - QuickNode: https://www.quicknode.com/docs/ethereum/eth_getBlockReceipts // - QuickNode: https://www.quicknode.com/docs/ethereum/eth_getBlockReceipts
// - Alchemy: https://docs.alchemy.com/reference/eth-getblockreceipts // - Alchemy: https://docs.alchemy.com/reference/eth-getblockreceipts
// Erigon has this available, but does not support block-hash argument to the method:
// https://github.com/ledgerwatch/erigon/blob/287a3d1d6c90fc6a7a088b5ae320f93600d5a167/cmd/rpcdaemon/commands/eth_receipts.go#L571
EthGetBlockReceipts EthGetBlockReceipts
// ErigonGetBlockReceiptsByBlockHash is an Erigon-specific receipt fetching method,
// the same as EthGetBlockReceipts but supporting a block-hash argument.
// Available in:
// - Erigon
// Method: erigon_getBlockReceiptsByBlockHash
// Params:
// - Erigon: string, hex-encoded block hash
// Returns:
// - Erigon: array of json-ified receipts
// See:
// https://github.com/ledgerwatch/erigon/blob/287a3d1d6c90fc6a7a088b5ae320f93600d5a167/cmd/rpcdaemon/commands/erigon_receipts.go#LL391C24-L391C51
ErigonGetBlockReceiptsByBlockHash
// Other: // Other:
// - 250 credits, not supported, strictly worse than other options. In quicknode price-table. // - 250 credits, not supported, strictly worse than other options. In quicknode price-table.
...@@ -269,13 +283,14 @@ func AvailableReceiptsFetchingMethods(kind RPCProviderKind) ReceiptsFetchingMeth ...@@ -269,13 +283,14 @@ func AvailableReceiptsFetchingMethods(kind RPCProviderKind) ReceiptsFetchingMeth
case RPCKindDebugGeth: case RPCKindDebugGeth:
return DebugGetRawReceipts | EthGetTransactionReceiptBatch return DebugGetRawReceipts | EthGetTransactionReceiptBatch
case RPCKindErigon: case RPCKindErigon:
return EthGetBlockReceipts | EthGetTransactionReceiptBatch return ErigonGetBlockReceiptsByBlockHash | EthGetTransactionReceiptBatch
case RPCKindBasic: case RPCKindBasic:
return EthGetTransactionReceiptBatch return EthGetTransactionReceiptBatch
case RPCKindAny: case RPCKindAny:
// if it's any kind of RPC provider, then try all methods // if it's any kind of RPC provider, then try all methods
return AlchemyGetTransactionReceipts | EthGetBlockReceipts | return AlchemyGetTransactionReceipts | EthGetBlockReceipts |
DebugGetRawReceipts | ParityGetBlockReceipts | EthGetTransactionReceiptBatch DebugGetRawReceipts | ErigonGetBlockReceiptsByBlockHash |
ParityGetBlockReceipts | EthGetTransactionReceiptBatch
default: default:
return EthGetTransactionReceiptBatch return EthGetTransactionReceiptBatch
} }
...@@ -310,6 +325,9 @@ func PickBestReceiptsFetchingMethod(kind RPCProviderKind, available ReceiptsFetc ...@@ -310,6 +325,9 @@ func PickBestReceiptsFetchingMethod(kind RPCProviderKind, available ReceiptsFetc
if available&DebugGetRawReceipts != 0 { if available&DebugGetRawReceipts != 0 {
return DebugGetRawReceipts return DebugGetRawReceipts
} }
if available&ErigonGetBlockReceiptsByBlockHash != 0 {
return ErigonGetBlockReceiptsByBlockHash
}
if available&EthGetBlockReceipts != 0 { if available&EthGetBlockReceipts != 0 {
return EthGetBlockReceipts return EthGetBlockReceipts
} }
...@@ -428,6 +446,8 @@ func (job *receiptsFetchingJob) runAltMethod(ctx context.Context, m ReceiptsFetc ...@@ -428,6 +446,8 @@ func (job *receiptsFetchingJob) runAltMethod(ctx context.Context, m ReceiptsFetc
err = job.client.CallContext(ctx, &result, "parity_getBlockReceipts", job.block.Hash) err = job.client.CallContext(ctx, &result, "parity_getBlockReceipts", job.block.Hash)
case EthGetBlockReceipts: case EthGetBlockReceipts:
err = job.client.CallContext(ctx, &result, "eth_getBlockReceipts", job.block.Hash) err = job.client.CallContext(ctx, &result, "eth_getBlockReceipts", job.block.Hash)
case ErigonGetBlockReceiptsByBlockHash:
err = job.client.CallContext(ctx, &result, "erigon_getBlockReceiptsByBlockHash", job.block.Hash)
default: default:
err = fmt.Errorf("unknown receipt fetching method: %d", uint64(m)) err = fmt.Errorf("unknown receipt fetching method: %d", uint64(m))
} }
......
...@@ -40,6 +40,15 @@ func (b *ethBackend) GetBlockReceipts(id string) ([]*types.Receipt, error) { ...@@ -40,6 +40,15 @@ func (b *ethBackend) GetBlockReceipts(id string) ([]*types.Receipt, error) {
return out[0].([]*types.Receipt), *out[1].(*error) return out[0].([]*types.Receipt), *out[1].(*error)
} }
type erigonBackend struct {
*mock.Mock
}
func (b *erigonBackend) GetBlockReceiptsByBlockHash(id string) ([]*types.Receipt, error) {
out := b.Mock.MethodCalled("erigon_getBlockReceiptsByBlockHash", id)
return out[0].([]*types.Receipt), *out[1].(*error)
}
type alchemyBackend struct { type alchemyBackend struct {
*mock.Mock *mock.Mock
} }
...@@ -99,6 +108,7 @@ func (tc *ReceiptsTestCase) Run(t *testing.T) { ...@@ -99,6 +108,7 @@ func (tc *ReceiptsTestCase) Run(t *testing.T) {
require.NoError(t, srv.RegisterName("alchemy", &alchemyBackend{Mock: m})) require.NoError(t, srv.RegisterName("alchemy", &alchemyBackend{Mock: m}))
require.NoError(t, srv.RegisterName("debug", &debugBackend{Mock: m})) require.NoError(t, srv.RegisterName("debug", &debugBackend{Mock: m}))
require.NoError(t, srv.RegisterName("parity", &parityBackend{Mock: m})) require.NoError(t, srv.RegisterName("parity", &parityBackend{Mock: m}))
require.NoError(t, srv.RegisterName("erigon", &erigonBackend{Mock: m}))
block, requests := tc.setup(t) block, requests := tc.setup(t)
...@@ -127,6 +137,8 @@ func (tc *ReceiptsTestCase) Run(t *testing.T) { ...@@ -127,6 +137,8 @@ func (tc *ReceiptsTestCase) Run(t *testing.T) {
m.On("parity_getBlockReceipts", block.Hash.String()).Once().Return(req.result, &req.err) m.On("parity_getBlockReceipts", block.Hash.String()).Once().Return(req.result, &req.err)
case EthGetBlockReceipts: case EthGetBlockReceipts:
m.On("eth_getBlockReceipts", block.Hash.String()).Once().Return(req.result, &req.err) m.On("eth_getBlockReceipts", block.Hash.String()).Once().Return(req.result, &req.err)
case ErigonGetBlockReceiptsByBlockHash:
m.On("erigon_getBlockReceiptsByBlockHash", block.Hash.String()).Once().Return(req.result, &req.err)
default: default:
t.Fatalf("unrecognized request method: %d", uint64(req.method)) t.Fatalf("unrecognized request method: %d", uint64(req.method))
} }
...@@ -286,7 +298,7 @@ func TestEthClient_FetchReceipts(t *testing.T) { ...@@ -286,7 +298,7 @@ func TestEthClient_FetchReceipts(t *testing.T) {
{ {
name: "erigon", name: "erigon",
providerKind: RPCKindErigon, providerKind: RPCKindErigon,
setup: fallbackCase(4, EthGetBlockReceipts), setup: fallbackCase(4, ErigonGetBlockReceiptsByBlockHash),
}, },
{ {
name: "basic", name: "basic",
...@@ -305,6 +317,7 @@ func TestEthClient_FetchReceipts(t *testing.T) { ...@@ -305,6 +317,7 @@ func TestEthClient_FetchReceipts(t *testing.T) {
setup: fallbackCase(4, setup: fallbackCase(4,
AlchemyGetTransactionReceipts, AlchemyGetTransactionReceipts,
DebugGetRawReceipts, DebugGetRawReceipts,
ErigonGetBlockReceiptsByBlockHash,
EthGetBlockReceipts, EthGetBlockReceipts,
ParityGetBlockReceipts, ParityGetBlockReceipts,
), ),
......
...@@ -248,3 +248,21 @@ ...@@ -248,3 +248,21 @@
| Name | Type | Slot | Offset | Bytes | Contract | | Name | Type | Slot | Offset | Bytes | Contract |
|------|------|------|--------|-------|----------| |------|------|------|--------|-------|----------|
=======================
➡ contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory
=======================
| Name | Type | Slot | Offset | Bytes | Contract |
|--------------|-------------------------------------------------|------|--------|-------|-------------------------------------------------------------|
| _owner | address | 0 | 0 | 20 | contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory |
| gameImpls | mapping(enum GameType => contract IDisputeGame) | 1 | 0 | 32 | contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory |
| disputeGames | mapping(Hash => contract IDisputeGame) | 2 | 0 | 32 | contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory |
=======================
➡ contracts/dispute/BondManager.sol:BondManager
=======================
| Name | Type | Slot | Offset | Bytes | Contract |
|-------|---------------------------------------------|------|--------|-------|-----------------------------------------------|
| bonds | mapping(bytes32 => struct BondManager.Bond) | 0 | 0 | 32 | contracts/dispute/BondManager.sol:BondManager |
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.15; pragma solidity ^0.8.15;
import { GameType } from "../libraries/DisputeTypes.sol"; import "../libraries/DisputeTypes.sol";
import { GameStatus } from "../libraries/DisputeTypes.sol";
import { SafeCall } from "../libraries/SafeCall.sol"; import { SafeCall } from "../libraries/SafeCall.sol";
import { IDisputeGame } from "./IDisputeGame.sol"; import { IDisputeGame } from "./interfaces/IDisputeGame.sol";
import { IDisputeGameFactory } from "./IDisputeGameFactory.sol"; import { IDisputeGameFactory } from "./interfaces/IDisputeGameFactory.sol";
import { IBondManager } from "./interfaces/IBondManager.sol";
/** /**
* @title BondManager * @title BondManager
* @notice The Bond Manager serves as an escrow for permissionless output proposal bonds. * @notice The Bond Manager serves as an escrow for permissionless output proposal bonds.
*/ */
contract BondManager { contract BondManager is IBondManager {
/** /**
* @notice The Bond Type * @notice The Bond Type
*/ */
struct Bond { struct Bond {
address owner; address owner;
uint256 expiration;
bytes32 id; bytes32 id;
uint256 amount; uint128 expiration;
uint128 amount;
} }
/**
* @notice Mapping from bondId to bond.
*/
mapping(bytes32 => Bond) public bonds;
/**
* @notice BondPosted is emitted when a bond is posted.
* @param bondId is the id of the bond.
* @param owner is the address that owns the bond.
* @param expiration is the time at which the bond expires.
* @param amount is the amount of the bond.
*/
event BondPosted(bytes32 bondId, address owner, uint256 expiration, uint256 amount);
/**
* @notice BondSeized is emitted when a bond is seized.
* @param bondId is the id of the bond.
* @param owner is the address that owns the bond.
* @param seizer is the address that seized the bond.
* @param amount is the amount of the bond.
*/
event BondSeized(bytes32 bondId, address owner, address seizer, uint256 amount);
/**
* @notice BondReclaimed is emitted when a bond is reclaimed by the owner.
* @param bondId is the id of the bond.
* @param claiment is the address that reclaimed the bond.
* @param amount is the amount of the bond.
*/
event BondReclaimed(bytes32 bondId, address claiment, uint256 amount);
/** /**
* @notice The permissioned dispute game factory. * @notice The permissioned dispute game factory.
* @dev Used to verify the status of bonds. * @dev Used to verify the status of bonds.
...@@ -67,6 +37,11 @@ contract BondManager { ...@@ -67,6 +37,11 @@ contract BondManager {
*/ */
uint256 private constant TRANSFER_GAS = 30_000; uint256 private constant TRANSFER_GAS = 30_000;
/**
* @notice Mapping from bondId to bond.
*/
mapping(bytes32 => Bond) public bonds;
/** /**
* @notice Instantiates the bond maanger with the registered dispute game factory. * @notice Instantiates the bond maanger with the registered dispute game factory.
* @param _disputeGameFactory is the dispute game factory. * @param _disputeGameFactory is the dispute game factory.
...@@ -76,37 +51,30 @@ contract BondManager { ...@@ -76,37 +51,30 @@ contract BondManager {
} }
/** /**
* @notice Post a bond with a given id and owner. * @inheritdoc IBondManager
* @dev This function will revert if the provided bondId is already in use.
* @param _bondId is the id of the bond.
* @param _bondOwner is the address that owns the bond.
* @param _minClaimHold is the minimum amount of time the owner
* must wait before reclaiming their bond.
*/ */
function post( function post(
bytes32 _bondId, bytes32 _bondId,
address _bondOwner, address _bondOwner,
uint256 _minClaimHold uint128 _minClaimHold
) external payable { ) external payable {
require(bonds[_bondId].owner == address(0), "BondManager: BondId already posted."); require(bonds[_bondId].owner == address(0), "BondManager: BondId already posted.");
require(_bondOwner != address(0), "BondManager: Owner cannot be the zero address."); require(_bondOwner != address(0), "BondManager: Owner cannot be the zero address.");
require(msg.value > 0, "BondManager: Value must be non-zero."); require(msg.value > 0, "BondManager: Value must be non-zero.");
uint256 expiration = _minClaimHold + block.timestamp; uint128 expiration = uint128(_minClaimHold + block.timestamp);
bonds[_bondId] = Bond({ bonds[_bondId] = Bond({
owner: _bondOwner, owner: _bondOwner,
expiration: expiration,
id: _bondId, id: _bondId,
amount: msg.value expiration: expiration,
amount: uint128(msg.value)
}); });
emit BondPosted(_bondId, _bondOwner, expiration, msg.value); emit BondPosted(_bondId, _bondOwner, expiration, msg.value);
} }
/** /**
* @notice Seizes the bond with the given id. * @inheritdoc IBondManager
* @dev This function will revert if there is no bond at the given id.
* @param _bondId is the id of the bond.
*/ */
function seize(bytes32 _bondId) external { function seize(bytes32 _bondId) external {
Bond memory b = bonds[_bondId]; Bond memory b = bonds[_bondId];
...@@ -131,10 +99,7 @@ contract BondManager { ...@@ -131,10 +99,7 @@ contract BondManager {
} }
/** /**
* @notice Seizes the bond with the given id and distributes it to recipients. * @inheritdoc IBondManager
* @dev This function will revert if there is no bond at the given id.
* @param _bondId is the id of the bond.
* @param _claimRecipients is a set of addresses to split the bond amongst.
*/ */
function seizeAndSplit(bytes32 _bondId, address[] calldata _claimRecipients) external { function seizeAndSplit(bytes32 _bondId, address[] calldata _claimRecipients) external {
Bond memory b = bonds[_bondId]; Bond memory b = bonds[_bondId];
...@@ -168,9 +133,7 @@ contract BondManager { ...@@ -168,9 +133,7 @@ contract BondManager {
} }
/** /**
* @notice Reclaims the bond of the bond owner. * @inheritdoc IBondManager
* @dev This function will revert if there is no bond at the given id.
* @param _bondId is the id of the bond.
*/ */
function reclaim(bytes32 _bondId) external { function reclaim(bytes32 _bondId) external {
Bond memory b = bonds[_bondId]; Bond memory b = bonds[_bondId];
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.15; pragma solidity ^0.8.15;
import "../libraries/DisputeTypes.sol";
import "../libraries/DisputeErrors.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ClonesWithImmutableArgs } from "@cwia/ClonesWithImmutableArgs.sol"; import { ClonesWithImmutableArgs } from "@cwia/ClonesWithImmutableArgs.sol";
import { Claim } from "../libraries/DisputeTypes.sol"; import { IDisputeGame } from "./interfaces/IDisputeGame.sol";
import { Hash } from "../libraries/DisputeTypes.sol"; import { IDisputeGameFactory } from "./interfaces/IDisputeGameFactory.sol";
import { GameType } from "../libraries/DisputeTypes.sol";
import { NoImplementation } from "../libraries/DisputeErrors.sol";
import { GameAlreadyExists } from "../libraries/DisputeErrors.sol";
import { IDisputeGame } from "./IDisputeGame.sol";
import { IDisputeGameFactory } from "./IDisputeGameFactory.sol";
/** /**
* @title DisputeGameFactory * @title DisputeGameFactory
...@@ -25,7 +21,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory { ...@@ -25,7 +21,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
using ClonesWithImmutableArgs for address; using ClonesWithImmutableArgs for address;
/** /**
* @notice Mapping of `GameType`s to their respective `IDisputeGame` implementations. * @inheritdoc IDisputeGameFactory
*/ */
mapping(GameType => IDisputeGame) public gameImpls; mapping(GameType => IDisputeGame) public gameImpls;
...@@ -45,16 +41,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory { ...@@ -45,16 +41,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
} }
/** /**
* @notice Retrieves the hash of `gameType . rootClaim . extraData` * @inheritdoc IDisputeGameFactory
* to the deployed `DisputeGame` clone.
* @dev Note: `.` denotes concatenation.
* @param gameType The type of the DisputeGame.
* Used to decide the implementation to clone.
* @param rootClaim The root claim of the DisputeGame.
* @param extraData Any extra data that should be provided to the
* created dispute game.
* @return _proxy The clone of the `DisputeGame` created with the
* given parameters. `address(0)` if nonexistent.
*/ */
function games( function games(
GameType gameType, GameType gameType,
...@@ -65,15 +52,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory { ...@@ -65,15 +52,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
} }
/** /**
* @notice Creates a new DisputeGame proxy contract. * @inheritdoc IDisputeGameFactory
* @notice If a dispute game with the given parameters already exists,
* it will be returned.
* @param gameType The type of the DisputeGame.
* Used to decide the proxy implementation.
* @param rootClaim The root claim of the DisputeGame.
* @param extraData Any extra data that should be provided
* to the created dispute game.
* @return proxy The clone of the `DisputeGame`.
*/ */
function create( function create(
GameType gameType, GameType gameType,
...@@ -89,8 +68,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory { ...@@ -89,8 +68,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
} }
// Clone the implementation contract and initialize it with the given parameters. // Clone the implementation contract and initialize it with the given parameters.
bytes memory data = abi.encodePacked(rootClaim, extraData); proxy = IDisputeGame(address(impl).clone(abi.encodePacked(rootClaim, extraData)));
proxy = IDisputeGame(address(impl).clone(data));
proxy.initialize(); proxy.initialize();
// Compute the unique identifier for the dispute game. // Compute the unique identifier for the dispute game.
...@@ -107,23 +85,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory { ...@@ -107,23 +85,7 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
} }
/** /**
* @notice Sets the implementation contract for a specific `GameType`. * @inheritdoc IDisputeGameFactory
* @param gameType The type of the DisputeGame.
* @param impl The implementation contract for the given `GameType`.
*/
function setImplementation(GameType gameType, IDisputeGame impl) external onlyOwner {
gameImpls[gameType] = impl;
emit ImplementationSet(address(impl), gameType);
}
/**
* @notice Returns a unique identifier for the given dispute game parameters.
* @dev Hashes the concatenation of `gameType . rootClaim . extraData`
* without expanding memory.
* @param gameType The type of the DisputeGame.
* @param rootClaim The root claim of the DisputeGame.
* @param extraData Any extra data that should be provided to the created dispute game.
* @return _uuid The unique identifier for the given dispute game parameters.
*/ */
function getGameUUID( function getGameUUID(
GameType gameType, GameType gameType,
...@@ -160,4 +122,12 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory { ...@@ -160,4 +122,12 @@ contract DisputeGameFactory is Ownable, IDisputeGameFactory {
mstore(pointerOffset, tempC) mstore(pointerOffset, tempC)
} }
} }
/**
* @inheritdoc IDisputeGameFactory
*/
function setImplementation(GameType gameType, IDisputeGame impl) external onlyOwner {
gameImpls[gameType] = impl;
emit ImplementationSet(address(impl), gameType);
}
} }
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import { IDisputeGame } from "./IDisputeGame.sol";
/**
* @title IAttestationDisputeGame
* @notice The interface for an attestation-based DisputeGame meant to contest output
* proposals in Optimism's `L2OutputOracle` contract.
*/
interface IAttestationDisputeGame is IDisputeGame {
/**
* @notice A mapping of addresses from the `signerSet` to booleans signifying whether
* or not they have authorized the `rootClaim` to be invalidated.
* @param challenger The address to check for authorization.
* @return _challenged Whether or not the `challenger` has challenged the `rootClaim`.
*/
function challenges(address challenger) external view returns (bool _challenged);
/**
* @notice The signer set consists of authorized public keys that may challenge
* the `rootClaim`.
* @param addr The address to check for authorization.
* @return _isAuthorized Whether or not the `addr` is part of the signer set.
*/
function signerSet(address addr) external view returns (bool _isAuthorized);
/**
* @notice The amount of signatures required to successfully challenge the `rootClaim`
* output proposal. Once this threshold is met by members of the `signerSet`
* calling `challenge`, the game will be resolved to `CHALLENGER_WINS`.
* @custom:invariant The `signatureThreshold` may never be greater than the length
* of the `signerSet`.
* @return _signatureThreshold The amount of signatures required to successfully
* challenge the `rootClaim` output proposal.
*/
function frozenSignatureThreshold() external view returns (uint256 _signatureThreshold);
/**
* @notice Returns the L2 Block Number that the `rootClaim` commits to.
* Exists within the `extraData`.
* @return _l2BlockNumber The L2 Block Number that the `rootClaim` commits to.
*/
function l2BlockNumber() external view returns (uint256 _l2BlockNumber);
/**
* @notice Challenge the `rootClaim`.
* @dev - If the `ecrecover`ed address that created the signature is not a part of
* the signer set returned by `signerSet`, this function should revert.
* - If the `ecrecover`ed address that created the signature is not the
* msg.sender, this function should revert.
* - If the signature provided is the signature that breaches the signature
* threshold, the function should call the `resolve` function to resolve
* the game as `CHALLENGER_WINS`.
* - When the game resolves, the bond attached to the root claim should be
* distributed among the signers who participated in challenging the
* invalid claim.
* @param signature An EIP-712 signature committing to the `rootClaim` and
* `l2BlockNumber` (within the `extraData`) from a key that exists
* within the `signerSet`.
*/
function challenge(bytes calldata signature) external;
}
...@@ -6,6 +6,32 @@ pragma solidity ^0.8.15; ...@@ -6,6 +6,32 @@ pragma solidity ^0.8.15;
* @notice The Bond Manager holds ether posted as a bond for a bond id. * @notice The Bond Manager holds ether posted as a bond for a bond id.
*/ */
interface IBondManager { interface IBondManager {
/**
* @notice BondPosted is emitted when a bond is posted.
* @param bondId is the id of the bond.
* @param owner is the address that owns the bond.
* @param expiration is the time at which the bond expires.
* @param amount is the amount of the bond.
*/
event BondPosted(bytes32 bondId, address owner, uint256 expiration, uint256 amount);
/**
* @notice BondSeized is emitted when a bond is seized.
* @param bondId is the id of the bond.
* @param owner is the address that owns the bond.
* @param seizer is the address that seized the bond.
* @param amount is the amount of the bond.
*/
event BondSeized(bytes32 bondId, address owner, address seizer, uint256 amount);
/**
* @notice BondReclaimed is emitted when a bond is reclaimed by the owner.
* @param bondId is the id of the bond.
* @param claiment is the address that reclaimed the bond.
* @param amount is the amount of the bond.
*/
event BondReclaimed(bytes32 bondId, address claiment, uint256 amount);
/** /**
* @notice Post a bond with a given id and owner. * @notice Post a bond with a given id and owner.
* @dev This function will revert if the provided bondId is already in use. * @dev This function will revert if the provided bondId is already in use.
...@@ -17,7 +43,7 @@ interface IBondManager { ...@@ -17,7 +43,7 @@ interface IBondManager {
function post( function post(
bytes32 _bondId, bytes32 _bondId,
address _bondOwner, address _bondOwner,
uint256 _minClaimHold uint128 _minClaimHold
) external payable; ) external payable;
/** /**
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.15; pragma solidity ^0.8.15;
import { Claim } from "../libraries/DisputeTypes.sol"; import "../../libraries/DisputeTypes.sol";
import { GameType } from "../libraries/DisputeTypes.sol";
import { GameStatus } from "../libraries/DisputeTypes.sol";
import { Timestamp } from "../libraries/DisputeTypes.sol";
import { IVersioned } from "./IVersioned.sol"; import { IVersioned } from "./IVersioned.sol";
import { IBondManager } from "./IBondManager.sol"; import { IBondManager } from "./IBondManager.sol";
...@@ -21,8 +18,6 @@ interface IDisputeGame is IInitializable, IVersioned { ...@@ -21,8 +18,6 @@ interface IDisputeGame is IInitializable, IVersioned {
*/ */
event Resolved(GameStatus indexed status); event Resolved(GameStatus indexed status);
/// @notice Returns the timestamp that the DisputeGame contract was created at.
/** /**
* @notice Returns the timestamp that the DisputeGame contract was created at. * @notice Returns the timestamp that the DisputeGame contract was created at.
* @return _createdAt The timestamp that the DisputeGame contract was created at. * @return _createdAt The timestamp that the DisputeGame contract was created at.
...@@ -42,21 +37,21 @@ interface IDisputeGame is IInitializable, IVersioned { ...@@ -42,21 +37,21 @@ interface IDisputeGame is IInitializable, IVersioned {
* i.e. The game type should indicate the security model. * i.e. The game type should indicate the security model.
* @return _gameType The type of proof system being used. * @return _gameType The type of proof system being used.
*/ */
function gameType() external view returns (GameType _gameType); function gameType() external pure returns (GameType _gameType);
/** /**
* @notice Getter for the root claim. * @notice Getter for the root claim.
* @dev `clones-with-immutable-args` argument #2 * @dev `clones-with-immutable-args` argument #2
* @return _rootClaim The root claim of the DisputeGame. * @return _rootClaim The root claim of the DisputeGame.
*/ */
function rootClaim() external view returns (Claim _rootClaim); function rootClaim() external pure returns (Claim _rootClaim);
/** /**
* @notice Getter for the extra data. * @notice Getter for the extra data.
* @dev `clones-with-immutable-args` argument #3 * @dev `clones-with-immutable-args` argument #3
* @return _extraData Any extra data supplied to the dispute game contract by the creator. * @return _extraData Any extra data supplied to the dispute game contract by the creator.
*/ */
function extraData() external view returns (bytes memory _extraData); function extraData() external pure returns (bytes memory _extraData);
/** /**
* @notice Returns the address of the `BondManager` used. * @notice Returns the address of the `BondManager` used.
...@@ -73,4 +68,19 @@ interface IDisputeGame is IInitializable, IVersioned { ...@@ -73,4 +68,19 @@ interface IDisputeGame is IInitializable, IVersioned {
* @return _status The status of the game after resolution. * @return _status The status of the game after resolution.
*/ */
function resolve() external returns (GameStatus _status); function resolve() external returns (GameStatus _status);
/**
* @notice A compliant implementation of this interface should return the components of the
* game UUID's preimage provided in the cwia payload. The preimage of the UUID is
* constructed as `keccak256(gameType . rootClaim . extraData)` where `.` denotes
* concatenation.
*/
function gameData()
external
pure
returns (
GameType _gameType,
Claim _rootClaim,
bytes memory _extraData
);
} }
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.15; pragma solidity ^0.8.15;
import { Claim } from "../libraries/DisputeTypes.sol"; import "../../libraries/DisputeTypes.sol";
import { GameType } from "../libraries/DisputeTypes.sol";
import { IDisputeGame } from "./IDisputeGame.sol"; import { IDisputeGame } from "./IDisputeGame.sol";
...@@ -75,4 +74,19 @@ interface IDisputeGameFactory { ...@@ -75,4 +74,19 @@ interface IDisputeGameFactory {
* @param impl The implementation contract for the given `GameType`. * @param impl The implementation contract for the given `GameType`.
*/ */
function setImplementation(GameType gameType, IDisputeGame impl) external; function setImplementation(GameType gameType, IDisputeGame impl) external;
/**
* @notice Returns a unique identifier for the given dispute game parameters.
* @dev Hashes the concatenation of `gameType . rootClaim . extraData`
* without expanding memory.
* @param gameType The type of the DisputeGame.
* @param rootClaim The root claim of the DisputeGame.
* @param extraData Any extra data that should be provided to the created dispute game.
* @return _uuid The unique identifier for the given dispute game parameters.
*/
function getGameUUID(
GameType gameType,
Claim rootClaim,
bytes memory extraData
) external pure returns (Hash _uuid);
} }
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.15; pragma solidity ^0.8.15;
import { Clock } from "../libraries/DisputeTypes.sol"; import "../../libraries/DisputeTypes.sol";
import { Claim } from "../libraries/DisputeTypes.sol";
import { Position } from "../libraries/DisputeTypes.sol";
import { Timestamp } from "../libraries/DisputeTypes.sol";
import { ClaimHash } from "../libraries/DisputeTypes.sol";
import { BondAmount } from "../libraries/DisputeTypes.sol";
import { IDisputeGame } from "./IDisputeGame.sol"; import { IDisputeGame } from "./IDisputeGame.sol";
...@@ -33,12 +28,6 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -33,12 +28,6 @@ interface IFaultDisputeGame is IDisputeGame {
*/ */
event Defend(ClaimHash indexed claimHash, Claim indexed pivot, address indexed claimant); event Defend(ClaimHash indexed claimHash, Claim indexed pivot, address indexed claimant);
/**
* @notice State variable of the starting timestamp of the game, set on deployment.
* @return The starting timestamp of the game
*/
function gameStart() external view returns (Timestamp);
/** /**
* @notice Maps a unique ClaimHash to a Claim. * @notice Maps a unique ClaimHash to a Claim.
* @param claimHash The unique ClaimHash * @param claimHash The unique ClaimHash
......
// SPDX-License-Identifier: BSD
pragma solidity ^0.8.15;
// solhint-disable
/**
* @title Clone
* @author zefram.eth, Saw-mon & Natalie, clabby
* @notice Provides helper functions for reading immutable args from calldata
* @dev Original: https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args/blob/105efee1b9127ed7f6fedf139e1fc796ce8791f2/src/Clone.sol
* @dev MODIFICATIONS:
* - Added `_getArgDynBytes` function.
*/
// solhint-enable
contract Clone {
uint256 private constant ONE_WORD = 0x20;
/**
* @notice Reads an immutable arg with type address
* @param argOffset The offset of the arg in the packed data
* @return arg The arg value
*/
function _getArgAddress(uint256 argOffset) internal pure returns (address arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := shr(0x60, calldataload(add(offset, argOffset)))
}
}
/**
* @notice Reads an immutable arg with type uint256
* @param argOffset The offset of the arg in the packed data
* @return arg The arg value
*/
function _getArgUint256(uint256 argOffset) internal pure returns (uint256 arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := calldataload(add(offset, argOffset))
}
}
/**
* @notice Reads an immutable arg with type bytes32
* @param argOffset The offset of the arg in the packed data
* @return arg The arg value
*/
function _getArgFixedBytes(uint256 argOffset) internal pure returns (bytes32 arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := calldataload(add(offset, argOffset))
}
}
/**
* @notice Reads a uint256 array stored in the immutable args.
* @param argOffset The offset of the arg in the packed data
* @param arrLen Number of elements in the array
* @return arr The array
*/
function _getArgUint256Array(uint256 argOffset, uint64 arrLen)
internal
pure
returns (uint256[] memory arr)
{
uint256 offset = _getImmutableArgsOffset() + argOffset;
arr = new uint256[](arrLen);
assembly {
calldatacopy(add(arr, ONE_WORD), offset, shl(5, arrLen))
}
}
/**
* @notice Reads a dynamic bytes array stored in the immutable args.
* @param argOffset The offset of the arg in the packed data
* @param arrLen Number of elements in the array
* @return arr The array
*/
function _getArgDynBytes(uint256 argOffset, uint64 arrLen)
internal
pure
returns (bytes memory arr)
{
uint256 offset = _getImmutableArgsOffset() + argOffset;
arr = new bytes(arrLen);
assembly {
calldatacopy(add(arr, ONE_WORD), offset, arrLen)
}
}
/**
* @notice Reads an immutable arg with type uint64
* @param argOffset The offset of the arg in the packed data
* @return arg The arg value
*/
function _getArgUint64(uint256 argOffset) internal pure returns (uint64 arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := shr(0xc0, calldataload(add(offset, argOffset)))
}
}
/**
* @notice Reads an immutable arg with type uint8
* @param argOffset The offset of the arg in the packed data
* @return arg The arg value
*/
function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := shr(0xf8, calldataload(add(offset, argOffset)))
}
}
/**
* @return offset The offset of the packed immutable args in calldata
*/
function _getImmutableArgsOffset() internal pure returns (uint256 offset) {
assembly {
offset := sub(calldatasize(), shr(0xf0, calldataload(sub(calldatasize(), 2))))
}
}
}
...@@ -5,8 +5,8 @@ import "forge-std/Test.sol"; ...@@ -5,8 +5,8 @@ import "forge-std/Test.sol";
import "../libraries/DisputeTypes.sol"; import "../libraries/DisputeTypes.sol";
import { IDisputeGame } from "../dispute/IDisputeGame.sol"; import { IDisputeGame } from "../dispute/interfaces/IDisputeGame.sol";
import { IBondManager } from "../dispute/IBondManager.sol"; import { IBondManager } from "../dispute/interfaces/IBondManager.sol";
import { DisputeGameFactory } from "../dispute/DisputeGameFactory.sol"; import { DisputeGameFactory } from "../dispute/DisputeGameFactory.sol";
...@@ -45,23 +45,21 @@ contract BondManager_Test is Test { ...@@ -45,23 +45,21 @@ contract BondManager_Test is Test {
function testFuzz_post_succeeds( function testFuzz_post_succeeds(
bytes32 bondId, bytes32 bondId,
address owner, address owner,
uint256 minClaimHold, uint128 minClaimHold,
uint256 amount uint128 amount
) public { ) public {
vm.assume(owner != address(0)); vm.assume(owner != address(0));
vm.assume(owner != address(bm)); vm.assume(owner != address(bm));
vm.assume(owner != address(this)); vm.assume(owner != address(this));
// Create2Deployer // Create2Deployer
vm.assume(owner != address(0x4e59b44847b379578588920cA78FbF26c0B4956C)); vm.assume(owner != address(0x4e59b44847b379578588920cA78FbF26c0B4956C));
vm.assume(amount != 0); amount = uint128(bound(amount, 1, type(uint128).max));
unchecked { minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
vm.deal(address(this), amount); vm.deal(address(this), amount);
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
uint256 expiration = block.timestamp + minClaimHold; uint128 expiration = uint128(block.timestamp + minClaimHold);
emit BondPosted(bondId, owner, expiration, amount); emit BondPosted(bondId, owner, expiration, amount);
bm.post{ value: amount }(bondId, owner, minClaimHold); bm.post{ value: amount }(bondId, owner, minClaimHold);
...@@ -69,9 +67,9 @@ contract BondManager_Test is Test { ...@@ -69,9 +67,9 @@ contract BondManager_Test is Test {
// Validate the bond // Validate the bond
( (
address newFetchedOwner, address newFetchedOwner,
uint256 fetchedExpiration,
bytes32 fetchedBondId, bytes32 fetchedBondId,
uint256 bondAmount uint128 fetchedExpiration,
uint128 bondAmount
) = bm.bonds(bondId); ) = bm.bonds(bondId);
assertEq(newFetchedOwner, owner); assertEq(newFetchedOwner, owner);
assertEq(fetchedExpiration, block.timestamp + minClaimHold); assertEq(fetchedExpiration, block.timestamp + minClaimHold);
...@@ -85,15 +83,13 @@ contract BondManager_Test is Test { ...@@ -85,15 +83,13 @@ contract BondManager_Test is Test {
function testFuzz_post_duplicates_reverts( function testFuzz_post_duplicates_reverts(
bytes32 bondId, bytes32 bondId,
address owner, address owner,
uint256 minClaimHold, uint128 minClaimHold,
uint256 amount uint128 amount
) public { ) public {
vm.assume(owner != address(0)); vm.assume(owner != address(0));
amount = amount / 2; amount = amount / 2;
vm.assume(amount != 0); amount = uint128(bound(amount, 1, type(uint128).max));
unchecked { minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
vm.deal(address(this), amount); vm.deal(address(this), amount);
bm.post{ value: amount }(bondId, owner, minClaimHold); bm.post{ value: amount }(bondId, owner, minClaimHold);
...@@ -108,8 +104,8 @@ contract BondManager_Test is Test { ...@@ -108,8 +104,8 @@ contract BondManager_Test is Test {
*/ */
function testFuzz_post_zeroAddress_reverts( function testFuzz_post_zeroAddress_reverts(
bytes32 bondId, bytes32 bondId,
uint256 minClaimHold, uint128 minClaimHold,
uint256 amount uint128 amount
) public { ) public {
address owner = address(0); address owner = address(0);
vm.deal(address(this), amount); vm.deal(address(this), amount);
...@@ -123,10 +119,10 @@ contract BondManager_Test is Test { ...@@ -123,10 +119,10 @@ contract BondManager_Test is Test {
function testFuzz_post_zeroAddress_reverts( function testFuzz_post_zeroAddress_reverts(
bytes32 bondId, bytes32 bondId,
address owner, address owner,
uint256 minClaimHold uint128 minClaimHold
) public { ) public {
vm.assume(owner != address(0)); vm.assume(owner != address(0));
uint256 amount = 0; uint128 amount = 0;
vm.deal(address(this), amount); vm.deal(address(this), amount);
vm.expectRevert("BondManager: Value must be non-zero."); vm.expectRevert("BondManager: Value must be non-zero.");
bm.post{ value: amount }(bondId, owner, minClaimHold); bm.post{ value: amount }(bondId, owner, minClaimHold);
...@@ -152,16 +148,14 @@ contract BondManager_Test is Test { ...@@ -152,16 +148,14 @@ contract BondManager_Test is Test {
function testFuzz_seize_expired_reverts( function testFuzz_seize_expired_reverts(
bytes32 bondId, bytes32 bondId,
address owner, address owner,
uint256 minClaimHold, uint128 minClaimHold,
uint256 amount uint128 amount
) public { ) public {
vm.assume(owner != address(0)); vm.assume(owner != address(0));
vm.assume(owner != address(bm)); vm.assume(owner != address(bm));
vm.assume(owner != address(this)); vm.assume(owner != address(this));
vm.assume(amount != 0); amount = uint128(bound(amount, 1, type(uint128).max));
unchecked { minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.assume(block.timestamp + minClaimHold + 1 > minClaimHold);
}
vm.deal(address(this), amount); vm.deal(address(this), amount);
bm.post{ value: amount }(bondId, owner, minClaimHold); bm.post{ value: amount }(bondId, owner, minClaimHold);
...@@ -176,16 +170,15 @@ contract BondManager_Test is Test { ...@@ -176,16 +170,15 @@ contract BondManager_Test is Test {
function testFuzz_seize_unauthorized_reverts( function testFuzz_seize_unauthorized_reverts(
bytes32 bondId, bytes32 bondId,
address owner, address owner,
uint256 minClaimHold, uint128 minClaimHold,
uint256 amount uint128 amount
) public { ) public {
vm.assume(owner != address(0)); vm.assume(owner != address(0));
vm.assume(owner != address(bm)); vm.assume(owner != address(bm));
vm.assume(owner != address(this)); vm.assume(owner != address(this));
vm.assume(amount != 0); amount = uint128(bound(amount, 1, type(uint128).max));
unchecked { minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
vm.deal(address(this), amount); vm.deal(address(this), amount);
bm.post{ value: amount }(bondId, owner, minClaimHold); bm.post{ value: amount }(bondId, owner, minClaimHold);
...@@ -200,12 +193,10 @@ contract BondManager_Test is Test { ...@@ -200,12 +193,10 @@ contract BondManager_Test is Test {
*/ */
function testFuzz_seize_succeeds( function testFuzz_seize_succeeds(
bytes32 bondId, bytes32 bondId,
uint256 minClaimHold, uint128 minClaimHold,
bytes calldata extraData bytes calldata extraData
) public { ) public {
unchecked { minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
vm.deal(address(this), 1 ether); vm.deal(address(this), 1 ether);
bm.post{ value: 1 ether }(bondId, address(0xba5ed), minClaimHold); bm.post{ value: 1 ether }(bondId, address(0xba5ed), minClaimHold);
...@@ -255,12 +246,10 @@ contract BondManager_Test is Test { ...@@ -255,12 +246,10 @@ contract BondManager_Test is Test {
*/ */
function testFuzz_seizeAndSplit_succeeds( function testFuzz_seizeAndSplit_succeeds(
bytes32 bondId, bytes32 bondId,
uint256 minClaimHold, uint128 minClaimHold,
bytes calldata extraData bytes calldata extraData
) public { ) public {
unchecked { minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
vm.deal(address(this), 1 ether); vm.deal(address(this), 1 ether);
bm.post{ value: 1 ether }(bondId, address(0xba5ed), minClaimHold); bm.post{ value: 1 ether }(bondId, address(0xba5ed), minClaimHold);
...@@ -316,15 +305,16 @@ contract BondManager_Test is Test { ...@@ -316,15 +305,16 @@ contract BondManager_Test is Test {
function testFuzz_reclaim_succeeds( function testFuzz_reclaim_succeeds(
bytes32 bondId, bytes32 bondId,
address owner, address owner,
uint256 minClaimHold, uint128 minClaimHold,
uint256 amount uint128 amount
) public { ) public {
vm.assume(owner != address(factory));
vm.assume(owner != address(bm));
vm.assume(owner != address(this));
vm.assume(owner != address(0)); vm.assume(owner != address(0));
vm.assume(owner.code.length == 0); vm.assume(owner.code.length == 0);
vm.assume(amount != 0); amount = uint128(bound(amount, 1, type(uint128).max));
unchecked { minClaimHold = uint128(bound(minClaimHold, 0, type(uint128).max - block.timestamp));
vm.assume(block.timestamp + minClaimHold > minClaimHold);
}
assumeNoPrecompiles(owner); assumeNoPrecompiles(owner);
// Post the bond // Post the bond
...@@ -332,7 +322,7 @@ contract BondManager_Test is Test { ...@@ -332,7 +322,7 @@ contract BondManager_Test is Test {
bm.post{ value: amount }(bondId, owner, minClaimHold); bm.post{ value: amount }(bondId, owner, minClaimHold);
// We can't claim if the block.timestamp is less than the bond expiration. // We can't claim if the block.timestamp is less than the bond expiration.
(, uint256 expiration, , ) = bm.bonds(bondId); (, , uint256 expiration, ) = bm.bonds(bondId);
if (expiration > block.timestamp) { if (expiration > block.timestamp) {
vm.prank(owner); vm.prank(owner);
vm.expectRevert("BondManager: Bond isn't claimable yet."); vm.expectRevert("BondManager: Bond isn't claimable yet.");
...@@ -351,7 +341,7 @@ contract BondManager_Test is Test { ...@@ -351,7 +341,7 @@ contract BondManager_Test is Test {
* @title MockAttestationDisputeGame * @title MockAttestationDisputeGame
* @dev A mock dispute game for testing bond seizures. * @dev A mock dispute game for testing bond seizures.
*/ */
contract MockAttestationDisputeGame is IDisputeGame { contract MockAttestationDisputeGame {
GameStatus internal gameStatus; GameStatus internal gameStatus;
BondManager bm; BondManager bm;
Claim internal rc; Claim internal rc;
...@@ -419,11 +409,11 @@ contract MockAttestationDisputeGame is IDisputeGame { ...@@ -419,11 +409,11 @@ contract MockAttestationDisputeGame is IDisputeGame {
* ------------------------------------------- * -------------------------------------------
*/ */
function createdAt() external pure override returns (Timestamp _createdAt) { function createdAt() external pure returns (Timestamp _createdAt) {
return Timestamp.wrap(uint64(0)); return Timestamp.wrap(uint64(0));
} }
function status() external view override returns (GameStatus _status) { function status() external view returns (GameStatus _status) {
return gameStatus; return gameStatus;
} }
...@@ -431,7 +421,7 @@ contract MockAttestationDisputeGame is IDisputeGame { ...@@ -431,7 +421,7 @@ contract MockAttestationDisputeGame is IDisputeGame {
return GameType.ATTESTATION; return GameType.ATTESTATION;
} }
function rootClaim() external view override returns (Claim _rootClaim) { function rootClaim() external view returns (Claim _rootClaim) {
return rc; return rc;
} }
...@@ -439,7 +429,21 @@ contract MockAttestationDisputeGame is IDisputeGame { ...@@ -439,7 +429,21 @@ contract MockAttestationDisputeGame is IDisputeGame {
return ed; return ed;
} }
function bondManager() external view override returns (IBondManager _bondManager) { function gameData()
external
pure
returns (
GameType,
Claim,
bytes memory
)
{
assembly {
revert(0, 0)
}
}
function bondManager() external view returns (IBondManager _bondManager) {
return IBondManager(address(bm)); return IBondManager(address(bm));
} }
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "forge-std/Test.sol";
import { ClonesWithImmutableArgs } from "@cwia/ClonesWithImmutableArgs.sol";
import { Clone } from "../libraries/Clone.sol";
contract ExampleClone is Clone {
uint256 argOffset;
constructor(uint256 _argOffset) {
argOffset = _argOffset;
}
function addressArg() public view returns (address) {
return _getArgAddress(argOffset);
}
function uintArg() public view returns (uint256) {
return _getArgUint256(argOffset);
}
function fixedBytesArg() public view returns (bytes32) {
return _getArgFixedBytes(argOffset);
}
function uintArrayArg(uint64 arrLen) public view returns (uint256[] memory) {
return _getArgUint256Array(argOffset, arrLen);
}
function dynBytesArg(uint64 arrLen) public view returns (bytes memory) {
return _getArgDynBytes(argOffset, arrLen);
}
function uint64Arg() public view returns (uint64) {
return _getArgUint64(argOffset);
}
function uint8Arg() public view returns (uint8) {
return _getArgUint8(argOffset);
}
}
contract ExampleCloneFactory {
using ClonesWithImmutableArgs for address;
ExampleClone public implementation;
constructor(ExampleClone implementation_) {
implementation = implementation_;
}
function createAddressClone(address arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createUintClone(uint256 arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createFixedBytesClone(bytes32 arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createUintArrayClone(uint256[] memory arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createDynBytesClone(bytes memory arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createUint64Clone(uint64 arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createUint8Clone(uint8 arg) external returns (ExampleClone clone) {
bytes memory data = abi.encodePacked(arg);
clone = ExampleClone(address(implementation).clone(data));
}
function createClone(bytes memory randomCalldata) external returns (ExampleClone clone) {
clone = ExampleClone(address(implementation).clone(randomCalldata));
}
}
contract Clones_Test is Test {
function testFuzz_clone_addressArg_succeeds(uint256 argOffset, address param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createAddressClone(param);
address fetched = clone.addressArg();
assertEq(fetched, param);
}
function testFuzz_clone_uintArg_succeeds(uint256 argOffset, uint256 param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createUintClone(param);
uint256 fetched = clone.uintArg();
assertEq(fetched, param);
}
function testFuzz_clone_fixedBytesArg_succeeds(uint256 argOffset, bytes32 param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createFixedBytesClone(param);
bytes32 fetched = clone.fixedBytesArg();
assertEq(fetched, param);
}
function testFuzz_clone_uintArrayArg_succeeds(uint256 argOffset, uint256[] memory param)
public
{
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createUintArrayClone(param);
uint256[] memory fetched = clone.uintArrayArg(uint64(param.length));
assertEq(fetched, param);
}
function testFuzz_clone_dynBytesArg_succeeds(uint256 argOffset, bytes memory param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createDynBytesClone(param);
bytes memory fetched = clone.dynBytesArg(uint64(param.length));
assertEq(fetched, param);
}
function testFuzz_clone_uint64Arg_succeeds(uint256 argOffset, uint64 param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createUint64Clone(param);
uint64 fetched = clone.uint64Arg();
assertEq(fetched, param);
}
function testFuzz_clone_uint8Arg_succeeds(uint256 argOffset, uint8 param) public {
ExampleClone implementation = new ExampleClone(argOffset);
ExampleCloneFactory factory = new ExampleCloneFactory(implementation);
ExampleClone clone = factory.createUint8Clone(param);
uint8 fetched = clone.uint8Arg();
assertEq(fetched, param);
}
}
...@@ -6,7 +6,7 @@ import "../libraries/DisputeErrors.sol"; ...@@ -6,7 +6,7 @@ import "../libraries/DisputeErrors.sol";
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { DisputeGameFactory } from "../dispute/DisputeGameFactory.sol"; import { DisputeGameFactory } from "../dispute/DisputeGameFactory.sol";
import { IDisputeGame } from "../dispute/IDisputeGame.sol"; import { IDisputeGame } from "../dispute/interfaces/IDisputeGame.sol";
contract DisputeGameFactory_Test is Test { contract DisputeGameFactory_Test is Test {
DisputeGameFactory factory; DisputeGameFactory factory;
......
...@@ -31,6 +31,8 @@ contracts=( ...@@ -31,6 +31,8 @@ contracts=(
contracts/legacy/L1ChugSplashProxy.sol:L1ChugSplashProxy contracts/legacy/L1ChugSplashProxy.sol:L1ChugSplashProxy
contracts/universal/OptimismMintableERC20.sol:OptimismMintableERC20 contracts/universal/OptimismMintableERC20.sol:OptimismMintableERC20
contracts/universal/OptimismMintableERC20Factory.sol:OptimismMintableERC20Factory contracts/universal/OptimismMintableERC20Factory.sol:OptimismMintableERC20Factory
contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory
contracts/dispute/BondManager.sol:BondManager
) )
dir=$(dirname "$0") dir=$(dirname "$0")
......
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