├── .env.example
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── challenger
├── build.go
├── challenger.go
├── config.go
├── engine.go
├── factory_hook.go
├── main.go
├── oracle_hook.go
├── outputs.go
├── signer.go
└── utils.go
├── cmd
└── main.go
├── contracts
├── README.md
├── abi
│ ├── l2OutputOracle.abi
│ ├── mockAttestationDisputeGame.abi
│ └── mockDisputeGameFactory.abi
├── bin
│ ├── l2OutputOracle.bin
│ ├── mockAttestationDisputeGame.bin
│ └── mockDisputeGameFactory.bin
├── bindings
│ ├── l2OutputOracle.go
│ ├── mockAttestationDisputeGame.go
│ └── mockDisputeGameFactory.go
├── generate.sh
└── project
│ ├── .gitignore
│ ├── foundry.toml
│ ├── lib
│ └── forge-std
│ │ ├── .github
│ │ └── workflows
│ │ │ └── ci.yml
│ │ ├── .gitignore
│ │ ├── .gitmodules
│ │ ├── LICENSE-APACHE
│ │ ├── LICENSE-MIT
│ │ ├── README.md
│ │ ├── foundry.toml
│ │ ├── lib
│ │ └── ds-test
│ │ │ ├── .github
│ │ │ └── workflows
│ │ │ │ └── build.yml
│ │ │ ├── .gitignore
│ │ │ ├── LICENSE
│ │ │ ├── Makefile
│ │ │ ├── default.nix
│ │ │ ├── demo
│ │ │ └── demo.sol
│ │ │ ├── package.json
│ │ │ └── src
│ │ │ ├── test.sol
│ │ │ └── test.t.sol
│ │ ├── package.json
│ │ ├── src
│ │ ├── Base.sol
│ │ ├── Script.sol
│ │ ├── StdAssertions.sol
│ │ ├── StdChains.sol
│ │ ├── StdCheats.sol
│ │ ├── StdError.sol
│ │ ├── StdInvariant.sol
│ │ ├── StdJson.sol
│ │ ├── StdMath.sol
│ │ ├── StdStorage.sol
│ │ ├── StdStyle.sol
│ │ ├── StdUtils.sol
│ │ ├── Test.sol
│ │ ├── Vm.sol
│ │ ├── console.sol
│ │ ├── console2.sol
│ │ └── interfaces
│ │ │ ├── IERC1155.sol
│ │ │ ├── IERC165.sol
│ │ │ ├── IERC20.sol
│ │ │ ├── IERC4626.sol
│ │ │ ├── IERC721.sol
│ │ │ └── IMulticall3.sol
│ │ └── test
│ │ ├── StdAssertions.t.sol
│ │ ├── StdChains.t.sol
│ │ ├── StdCheats.t.sol
│ │ ├── StdError.t.sol
│ │ ├── StdMath.t.sol
│ │ ├── StdStorage.t.sol
│ │ ├── StdStyle.t.sol
│ │ ├── StdUtils.t.sol
│ │ ├── compilation
│ │ ├── CompilationScript.sol
│ │ ├── CompilationScriptBase.sol
│ │ ├── CompilationTest.sol
│ │ └── CompilationTestBase.sol
│ │ └── fixtures
│ │ └── broadcast.log.json
│ ├── script
│ └── DeployMocks.s.sol
│ ├── src
│ ├── IDisputeGame.sol
│ ├── IL2OutputOracle.sol
│ ├── MockAttestationDisputeGame.sol
│ ├── MockDisputeGameFactory.sol
│ └── Types.sol
│ └── test
│ └── Mocks.t.sol
├── docker
├── .env.devnet
├── Dockerfile
└── start_devnet.sh
├── flags
├── flags.go
└── txmgr.go
├── go.mod
├── go.sum
├── metrics
├── metrics.go
└── noop.go
└── public
├── op-challenger.excalidraw
├── op-challenger.png
├── op-gopher.jpeg
└── op-gopher.png
/.env.example:
--------------------------------------------------------------------------------
1 | # The directory of your `optimism` monorepo
2 | MONOREPO_DIR="$HOME/optimism/optimism"
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | on: [push]
4 |
5 | jobs:
6 | foundry-tests:
7 | name: Foundry project
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v3
11 | with:
12 | submodules: recursive
13 | - name: Install Foundry
14 | uses: foundry-rs/foundry-toolchain@v1
15 | with:
16 | version: nightly
17 | - name: Run Forge build
18 | run: cd contracts/project && forge test
19 | id: build
20 | tests:
21 | runs-on: ubuntu-latest
22 | steps:
23 | - uses: actions/checkout@v3
24 | - name: Set up Go
25 | uses: actions/setup-go@v3
26 | with:
27 | go-version: 1.19
28 | - name: CI
29 | run: make ci
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Environment Variables
15 | .env
16 |
17 | # Solidity-related files
18 | out
19 | cache
20 |
21 | bin
22 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thank you for looking to contribute!
4 |
5 | We welcome all contributions! Before opening a PR, please submit an issue detailing the bug or feature. When opening a PR, please ensure that your contribution builds using the configured build target `make build`, has been linted with `golangci-lint` (simply run `make lint`), and contains tests when applicable.
6 |
7 | ## Dependencies
8 |
9 | To work in this repo, you'll need to install:
10 |
11 | 1. [Golang](https://go.dev/)
12 | 1. [Docker](https://docs.docker.com/get-docker/)
13 |
14 | And clone the [Optimism Monorepo](https://github.com/ethereum-optimism/optimism)
15 |
16 | ## Quickstart
17 |
18 | 1. Clone the repo
19 | ```sh
20 | git clone git@github.com:refcell/op-challenger.git
21 | ```
22 |
23 | 2. Configure your dev environment
24 | ```sh
25 | # Set the MONOREPO_DIR variable
26 | nvim .env.devnet
27 | # Set up your env vars
28 | source .env.devnet
29 | # On the L1 service, port forward the websocket endpoint port (8546)
30 | nvim $MONOREPO_DIR/ops-bedrock/docker-compose.yml
31 | # Install forge deps
32 | (cd ./testdata/mock-dgf && forge install)
33 | # Start the devnet and deploy the mock dispute game factory
34 | ./start_devnet.sh
35 | ```
36 | 3. Start the `op-challenger`.
37 | ```sh
38 | make run
39 | ```
40 |
41 | ## Linting
42 |
43 | To lint your code, run:
44 | ```sh
45 | make lint
46 | ```
47 |
48 | You can also run `make format` to format your code and fix most linting errors.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 refcell.eth
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: clean tidy format lint build run test
2 |
3 | all: clean tidy format golangci lint build start-devnet run
4 |
5 | ci: clean tidy format golangci lint build test
6 |
7 | start-devnet:
8 | ./docker/start_devnet.sh
9 |
10 | clean:
11 | rm -rf bin/op-challenger
12 | go clean -cache
13 | go clean -modcache
14 |
15 | golangci:
16 | go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
17 |
18 | format:
19 | gofmt -s -w -l .
20 |
21 | lint:
22 | golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint -e "errors.As" -e "errors.Is" --timeout 5m
23 |
24 | build:
25 | env GO111MODULE=on go build -o bin/op-challenger ./cmd
26 |
27 | run:
28 | make build
29 | bin/op-challenger
30 |
31 | test:
32 | go test -v ./...
33 |
34 | tidy:
35 | go mod tidy
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # op-challenger • [](https://github.com/refcell/op-challenger/actions/workflows/ci.yml)  
4 |
5 | A modular [op-stack](https://stack.optimism.io/) challenge agent for attestation (fault and validity soon™) dispute games written in golang. Please note this is a proof of concept not intended for production use. The authors of this repository expressely recommond following the [rust-based op-challenger](https://github.com/clabby/op-challenger) for performance.
6 |
7 | ## Quickstart
8 |
9 | First, clone the [Optimism Monorepo](https://github.com/ethereum-optimism/optimism) and set the `MONOREPO_DIR` environment variable to the path of that directory in a `.env` file as shown in `.env.example`.
10 |
11 | Then, you can simply run `make`, which will compile all solidity + golang sources, bring up the Optimism [devnet](https://github.com/ethereum-optimism/optimism/blob/develop/ops-bedrock/devnet-up.sh) while also deploying the [mock dispute game contracts](./contracts), and then run the `op-challenger`.
12 |
13 | Alternatively, you can build the `op-challenger` binary locally using the pre-configured makefile target by running `make build`, and then running `./op-challenger --help` to see the available options.
14 |
15 | In the future, we intend to support downloading the `op-challenger` binary from [challenger.refcell.org](https://challenger.refcell.org) using `curl -s https://challenger.refcell.org | sh`
16 |
17 | ## Usage
18 |
19 | `op-challenger` is configurable via command line flags and environment variables. The help menu shows the available config options and can be accessed by running `./op-challenger --help`.
20 |
21 | Note that there are many global options, but the most important ones are:
22 |
23 | - `OP_CHALLENGER_L1_ETH_RPC`: An L1 Ethereum RPC URL
24 | - `OP_CHALLENGER_ROLLUP_RPC`: A Rollup Node RPC URL
25 | - `OP_CHALLENGER_L2OO_ADDRESS`: The L2OutputOracle Contract Address
26 | - `OP_CHALLENGER_DGF_ADDRESS`: Dispute Game Factory Contract Address
27 | - `OP_CHALLENGER_PRIVATE_KEY`: The Private Key of the account that will be used to send challenge transactions
28 | - `OP_CHALLENGER_L2_CHAIN_ID`: The chain id of the L2 network
29 |
30 | Here is a reduced output from running `./op-challenger --help`:
31 |
32 | ```bash
33 | NAME:
34 | op-challenger - Modular Challenger Agent
35 |
36 | USAGE:
37 | main [global options] command [command options] [arguments...]
38 |
39 | VERSION:
40 | 1.0.0
41 |
42 | DESCRIPTION:
43 | A modular op-stack challenge agent for output dispute games written in golang.
44 |
45 | COMMANDS:
46 | help, h Shows a list of commands or help for one command
47 |
48 | GLOBAL OPTIONS:
49 | --l1-eth-rpc value HTTP provider URL for L1. [$OP_CHALLENGER_L1_ETH_RPC]
50 | --rollup-rpc value HTTP provider URL for the rollup node. [$OP_CHALLENGER_ROLLUP_RPC]
51 | --l2oo-address value Address of the L2OutputOracle contract. [$OP_CHALLENGER_L2OO_ADDRESS]
52 | --dgf-address value Address of the DisputeGameFactory contract. [$OP_CHALLENGER_DGF_ADDRESS]
53 | --private-key value The private key to use with the service. Must not be used with mnemonic. [$OP_CHALLENGER_PRIVATE_KEY]
54 | ...
55 | --help, -h show help
56 | --version, -v print the version
57 | ```
58 |
59 |
60 | ## Inner Workings
61 |
62 | The op-challenger is a challenge agent for the output dispute game. It is responsible for challenging output roots.
63 |
64 | This implementation is loosely based off the `op-proposer`, a proposer agent that is responsible for proposing new outputs to the `L2OutputOracle`. And this should make sense; where the `op-proposer` _posts_ `output`s to the `L2OutputOracle`, the `op-challenger` validates these outputs and disputes them if invalid. The primary functional difference the `op-challenger` must implement is the ability to challenge invalid outputs.
65 |
66 | The naive challenge agent will be an attestation challenger which is a permissioned set of actors running the `op-challenger`. Below we illustrate how the challenger agent interacts with the [op-stack](https://stack.optimism.io/)'s permissionless output proposal system.
67 |
68 |
69 |
70 | The next iteration of the challenge agent will use fault proofs to challenge invalid outputs. This will involve a more complex dispute game which will allow for permissionless challengers by attaching bonds to each level of the dispute game. A future iteration could allow for validity (zero-knowledge) proofs.
71 |
72 |
73 | ## Contributing
74 |
75 | See [CONTRIBUTING.md](./CONTRIBUTING.md)
76 |
77 |
78 | ## License
79 |
80 | [MIT](./LICENSE.md), forever and always.
81 |
82 |
83 | ## Acknowledgements
84 |
85 | - [op-challenger](https://github.com/clabby/op-challenger): a rust challenge agent 🦀
86 | - [optimism](https://github.com/ethereum-optimism/optimism): the optimism monorepo 🚀
87 | - [op-stack](https://stack.optimism.io/): the op-stack 🥳
88 |
--------------------------------------------------------------------------------
/challenger/build.go:
--------------------------------------------------------------------------------
1 | package challenger
2 |
3 | import (
4 | "context"
5 | _ "net/http/pprof"
6 |
7 | bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
8 | "github.com/ethereum/go-ethereum/crypto"
9 | log "github.com/ethereum/go-ethereum/log"
10 |
11 | bindings "github.com/refcell/op-challenger/contracts/bindings"
12 | flags "github.com/refcell/op-challenger/flags"
13 | metrics "github.com/refcell/op-challenger/metrics"
14 |
15 | opBindings "github.com/ethereum-optimism/optimism/op-bindings/bindings"
16 | txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
17 | )
18 |
19 | // NewChallengerFromCLIConfig creates a new Challenger given the CLI Config
20 | func NewChallengerFromCLIConfig(cfg CLIConfig, l log.Logger, m metrics.Metricer) (*Challenger, error) {
21 | challengerConfig, err := NewChallengerConfigFromCLIConfig(cfg, l, m)
22 | if err != nil {
23 | return nil, err
24 | }
25 | return NewChallenger(*challengerConfig, l, m)
26 | }
27 |
28 | // NewChallengerConfigFromCLIConfig creates the challenger config from the CLI config.
29 | func NewChallengerConfigFromCLIConfig(cfg CLIConfig, l log.Logger, m metrics.Metricer) (*Config, error) {
30 | l2ooAddress, err := parseAddress(cfg.L2OOAddress)
31 | if err != nil {
32 | return nil, err
33 | }
34 |
35 | dgfAddress, err := parseAddress(cfg.DGFAddress)
36 | if err != nil {
37 | return nil, err
38 | }
39 |
40 | // Connect to L1 and L2 providers. Perform these last since they are the most expensive.
41 | ctx := context.Background()
42 | l1Client, err := dialEthClientWithTimeout(ctx, cfg.L1EthRpc)
43 | if err != nil {
44 | return nil, err
45 | }
46 |
47 | txManagerConfig, err := flags.NewTxManagerConfig(cfg.TxMgrConfig, l)
48 | if err != nil {
49 | return nil, err
50 | }
51 | txManager := txmgr.NewSimpleTxManager("challenger", l, txManagerConfig, l1Client)
52 |
53 | rollupClient, err := dialRollupClientWithTimeout(ctx, cfg.RollupRpc)
54 | if err != nil {
55 | return nil, err
56 | }
57 |
58 | return &Config{
59 | L2OutputOracleAddr: l2ooAddress,
60 | DisputeGameFactory: dgfAddress,
61 | NetworkTimeout: txManagerConfig.NetworkTimeout,
62 | L1Client: l1Client,
63 | RollupClient: rollupClient,
64 | TxManager: txManager,
65 | From: txManagerConfig.From,
66 | privateKey: cfg.PrivateKey,
67 | }, nil
68 | }
69 |
70 | // NewChallenger creates a new Challenger
71 | func NewChallenger(cfg Config, l log.Logger, m metrics.Metricer) (*Challenger, error) {
72 | ctx, cancel := context.WithCancel(context.Background())
73 |
74 | l2ooContract, err := opBindings.NewL2OutputOracleCaller(cfg.L2OutputOracleAddr, cfg.L1Client)
75 | if err != nil {
76 | cancel()
77 | return nil, err
78 | }
79 |
80 | cCtx, cCancel := context.WithTimeout(ctx, cfg.NetworkTimeout)
81 | defer cCancel()
82 | version, err := l2ooContract.Version(&bind.CallOpts{Context: cCtx})
83 | if err != nil {
84 | cancel()
85 | return nil, err
86 | }
87 | log.Info("Connected to L2OutputOracle", "address", cfg.L2OutputOracleAddr, "version", version)
88 |
89 | parsed, err := opBindings.L2OutputOracleMetaData.GetAbi()
90 | if err != nil {
91 | cancel()
92 | return nil, err
93 | }
94 |
95 | dgfContract, err := bindings.NewMockDisputeGameFactoryCaller(cfg.DisputeGameFactory, cfg.L1Client)
96 | if err != nil {
97 | cancel()
98 | return nil, err
99 | }
100 |
101 | dgfAbi, err := bindings.MockDisputeGameFactoryMetaData.GetAbi()
102 | if err != nil {
103 | cancel()
104 | return nil, err
105 | }
106 |
107 | adgAbi, err := bindings.MockAttestationDisputeGameMetaData.GetAbi()
108 | if err != nil {
109 | cancel()
110 | return nil, err
111 | }
112 |
113 | privateKey, err := crypto.HexToECDSA(cfg.privateKey)
114 | if err != nil {
115 | cancel()
116 | return nil, err
117 | }
118 |
119 | return &Challenger{
120 | txMgr: cfg.TxManager,
121 | done: make(chan struct{}),
122 | log: l,
123 | ctx: ctx,
124 | cancel: cancel,
125 | metr: m,
126 | privateKey: privateKey,
127 |
128 | from: cfg.From,
129 |
130 | l1Client: cfg.L1Client,
131 |
132 | rollupClient: cfg.RollupClient,
133 |
134 | l2ooContract: l2ooContract,
135 | l2ooContractAddr: cfg.L2OutputOracleAddr,
136 | l2ooABI: parsed,
137 |
138 | dgfContract: dgfContract,
139 | dgfContractAddr: cfg.DisputeGameFactory,
140 | dgfABI: dgfAbi,
141 |
142 | adgABI: adgAbi,
143 |
144 | networkTimeout: cfg.NetworkTimeout,
145 | }, nil
146 | }
147 |
--------------------------------------------------------------------------------
/challenger/challenger.go:
--------------------------------------------------------------------------------
1 | package challenger
2 |
3 | import (
4 | "context"
5 | "crypto/ecdsa"
6 | _ "net/http/pprof"
7 | "sync"
8 | "time"
9 |
10 | abi "github.com/ethereum/go-ethereum/accounts/abi"
11 | common "github.com/ethereum/go-ethereum/common"
12 | ethclient "github.com/ethereum/go-ethereum/ethclient"
13 | log "github.com/ethereum/go-ethereum/log"
14 |
15 | bindings "github.com/refcell/op-challenger/contracts/bindings"
16 | metrics "github.com/refcell/op-challenger/metrics"
17 |
18 | opBindings "github.com/ethereum-optimism/optimism/op-bindings/bindings"
19 | eth "github.com/ethereum-optimism/optimism/op-node/eth"
20 | sources "github.com/ethereum-optimism/optimism/op-node/sources"
21 | txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
22 | )
23 |
24 | var supportedL2OutputVersion = eth.Bytes32{}
25 |
26 | const (
27 | // FaultDisputeGameType is the uint8 enum value for the fault dispute game
28 | FaultDisputeGameType = 0
29 | // ValidityDisputeGameType is the uint8 enum value for the validity dispute game
30 | ValidityDisputeGameType = 1
31 | // AttestationDisputeGameType is the uint8 enum value for the attestation dispute game
32 | AttestationDisputeGameType = 2
33 | )
34 |
35 | // Challenger is responsible for disputing L2OutputOracle outputs
36 | type Challenger struct {
37 | txMgr txmgr.TxManager
38 | wg sync.WaitGroup
39 | done chan struct{}
40 | log log.Logger
41 | metr metrics.Metricer
42 |
43 | privateKey *ecdsa.PrivateKey
44 | from common.Address
45 |
46 | ctx context.Context
47 | cancel context.CancelFunc
48 |
49 | l1Client *ethclient.Client
50 |
51 | rollupClient *sources.RollupClient
52 |
53 | l2ooContract *opBindings.L2OutputOracleCaller
54 | l2ooContractAddr common.Address
55 | l2ooABI *abi.ABI
56 |
57 | dgfContract *bindings.MockDisputeGameFactoryCaller
58 | dgfContractAddr common.Address
59 | dgfABI *abi.ABI
60 |
61 | adgABI *abi.ABI
62 |
63 | networkTimeout time.Duration
64 | }
65 |
--------------------------------------------------------------------------------
/challenger/config.go:
--------------------------------------------------------------------------------
1 | package challenger
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/ethereum/go-ethereum/common"
7 | "github.com/ethereum/go-ethereum/ethclient"
8 | "github.com/urfave/cli"
9 |
10 | flags "github.com/refcell/op-challenger/flags"
11 |
12 | sources "github.com/ethereum-optimism/optimism/op-node/sources"
13 | oplog "github.com/ethereum-optimism/optimism/op-service/log"
14 | opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
15 | oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
16 |
17 | // oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
18 | txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
19 | )
20 |
21 | // Config contains the well typed fields that are used to initialize the challenger.
22 | // It is intended for programmatic use.
23 | type Config struct {
24 | L2OutputOracleAddr common.Address
25 | DisputeGameFactory common.Address
26 | NetworkTimeout time.Duration
27 | TxManager txmgr.TxManager
28 | L1Client *ethclient.Client
29 | RollupClient *sources.RollupClient
30 | From common.Address
31 | privateKey string
32 | }
33 |
34 | // CLIConfig is a well typed config that is parsed from the CLI params.
35 | // This also contains config options for auxiliary services.
36 | // It is transformed into a `Config` before the challenger is started.
37 | type CLIConfig struct {
38 | // L1EthRpc is the HTTP provider URL for L1.
39 | L1EthRpc string
40 |
41 | // RollupRpc is the HTTP provider URL for the rollup node.
42 | RollupRpc string
43 |
44 | // L2OOAddress is the L2OutputOracle contract address.
45 | L2OOAddress string
46 |
47 | // DGFAddress is the DisputeGameFactory contract address.
48 | DGFAddress string
49 |
50 | // PrivateKey is the private key of the account that will be used to send transactions.
51 | PrivateKey string
52 |
53 | TxMgrConfig flags.TxManagerCLIConfig
54 |
55 | // RPCConfig oprpc.CLIConfig
56 |
57 | LogConfig oplog.CLIConfig
58 |
59 | MetricsConfig opmetrics.CLIConfig
60 |
61 | PprofConfig oppprof.CLIConfig
62 | }
63 |
64 | func (c CLIConfig) Check() error {
65 | // if err := c.RPCConfig.Check(); err != nil {
66 | // return err
67 | // }
68 | if err := c.LogConfig.Check(); err != nil {
69 | return err
70 | }
71 | if err := c.MetricsConfig.Check(); err != nil {
72 | return err
73 | }
74 | if err := c.PprofConfig.Check(); err != nil {
75 | return err
76 | }
77 | if err := c.TxMgrConfig.Check(); err != nil {
78 | return err
79 | }
80 | return nil
81 | }
82 |
83 | // NewConfig parses the Config from the provided flags or environment variables.
84 | func NewConfig(ctx *cli.Context) CLIConfig {
85 | return CLIConfig{
86 | // Required Flags
87 | L1EthRpc: ctx.GlobalString(flags.L1EthRpcFlag.Name),
88 | RollupRpc: ctx.GlobalString(flags.RollupRpcFlag.Name),
89 | L2OOAddress: ctx.GlobalString(flags.L2OOAddressFlag.Name),
90 | DGFAddress: ctx.GlobalString(flags.DGFAddressFlag.Name),
91 | PrivateKey: ctx.GlobalString(flags.PrivateKeyFlag.Name),
92 | TxMgrConfig: flags.ReadTxManagerCLIConfig(ctx),
93 | // Optional Flags
94 | // RPCConfig: oprpc.ReadCLIConfig(ctx),
95 | LogConfig: oplog.ReadCLIConfig(ctx),
96 | MetricsConfig: opmetrics.ReadCLIConfig(ctx),
97 | PprofConfig: oppprof.ReadCLIConfig(ctx),
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/challenger/engine.go:
--------------------------------------------------------------------------------
1 | package challenger
2 |
3 | // Start begins the Challenger's engine driver,
4 | // adding an instance to the waitgroup.
5 | func (c *Challenger) Start() error {
6 | c.wg.Add(1)
7 | go c.drive()
8 | return nil
9 | }
10 |
11 | // Stop shuts down the Challenger.
12 | func (c *Challenger) Stop() {
13 | c.cancel()
14 | close(c.done)
15 | c.wg.Wait()
16 | }
17 |
18 | // drive executes the Challenger's drive train.
19 | func (c *Challenger) drive() {
20 | defer c.wg.Done()
21 |
22 | // Spawn the Oracle Hook
23 | c.wg.Add(1)
24 | go c.oracle()
25 |
26 | // Spawn the Factory Hook
27 | c.wg.Add(1)
28 | go c.factory()
29 | }
30 |
--------------------------------------------------------------------------------
/challenger/factory_hook.go:
--------------------------------------------------------------------------------
1 | package challenger
2 |
3 | import (
4 | "context"
5 | "math/big"
6 | _ "net/http/pprof"
7 |
8 | goEth "github.com/ethereum/go-ethereum"
9 | bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
10 | common "github.com/ethereum/go-ethereum/common"
11 | goTypes "github.com/ethereum/go-ethereum/core/types"
12 | bindings "github.com/refcell/op-challenger/contracts/bindings"
13 |
14 | txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
15 | )
16 |
17 | // factory executes the Challenger's factory hook.
18 | // This function is intended to be spawned in a goroutine.
19 | // It will run until the Challenger's context is cancelled.
20 | //
21 | // The factory hook listens for `DisputeGameCreated` events from the dispute game factory contract.
22 | // When it receives an event, it will check the dispute game parameters and submit a challenge if valid.
23 | func (c *Challenger) factory() {
24 | defer c.wg.Done()
25 |
26 | // `DisputeGameCreated`` event encoded as:
27 | // 0: address indexed disputeProxy
28 | // 1: GameType indexed gameType
29 | // 2: Claim indexed rootClaim
30 |
31 | // Listen for `DisputeGameCreated` events from the Dispute Game Factory contract
32 | event := c.dgfABI.Events["DisputeGameCreated"]
33 | query := goEth.FilterQuery{
34 | Topics: [][]common.Hash{
35 | {event.ID},
36 | },
37 | }
38 |
39 | logs := make(chan goTypes.Log)
40 | sub, err := c.l1Client.SubscribeFilterLogs(context.Background(), query, logs)
41 | if err != nil {
42 | c.log.Error("failed to subscribe to logs", "err", err)
43 | return
44 | }
45 |
46 | for {
47 | select {
48 | case err := <-sub.Err():
49 | c.log.Error("failed to subscribe to logs", "err", err)
50 | return
51 |
52 | case vLog := <-logs:
53 | // Parse the `DisputeGameCreated` event
54 | adgProxy := common.BytesToAddress(vLog.Topics[1][:])
55 | gameType := new(big.Int).SetBytes(vLog.Topics[2][:])
56 | rootClaim := vLog.Topics[3]
57 |
58 | // Dispatch on the game type
59 | switch gameType.Uint64() {
60 | case AttestationDisputeGameType:
61 | err := c.attestationChallenge(adgProxy, rootClaim)
62 | if err != nil {
63 | c.log.Error("failed to challenge attestation dispute game", "err", err)
64 | }
65 | }
66 | case <-c.done:
67 | return
68 | }
69 | }
70 | }
71 |
72 | // attestationChallenge sends a challenge to the given attestation dispute game.
73 | func (c *Challenger) attestationChallenge(adgProxy common.Address, rootClaim common.Hash) error {
74 | cCtx, cCancel := context.WithTimeout(c.ctx, c.networkTimeout)
75 | defer cCancel()
76 | adgContract, err := bindings.NewMockAttestationDisputeGameCaller(adgProxy, c.l1Client)
77 | if err != nil {
78 | return err
79 | }
80 | l2BlockNumber, err := adgContract.L2BLOCKNUMBER(&bind.CallOpts{Context: cCtx})
81 | if err != nil {
82 | return err
83 | }
84 |
85 | // Create an eip-712 signature for the contested output
86 | signature, err := c.signOutput(l2BlockNumber, rootClaim)
87 | if err != nil {
88 | return err
89 | }
90 |
91 | data, err := c.adgABI.Pack("challenge", signature)
92 | if err != nil {
93 | return err
94 | }
95 | receipt, err := c.txMgr.Send(cCtx, txmgr.TxCandidate{
96 | TxData: data,
97 | To: adgProxy,
98 | GasLimit: 0,
99 | From: c.from,
100 | })
101 | if err != nil {
102 | return err
103 | }
104 | c.log.Info("attestation challenge tx successful", "tx_hash", receipt.TxHash)
105 | c.metr.RecordChallengeSent(l2BlockNumber, rootClaim)
106 | return nil
107 | }
108 |
--------------------------------------------------------------------------------
/challenger/main.go:
--------------------------------------------------------------------------------
1 | package challenger
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "os"
7 | "os/signal"
8 | "syscall"
9 |
10 | cli "github.com/urfave/cli"
11 |
12 | metrics "github.com/refcell/op-challenger/metrics"
13 |
14 | oplog "github.com/ethereum-optimism/optimism/op-service/log"
15 | oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
16 | )
17 |
18 | // Main is the entrypoint into the Challenger.
19 | // This executes and blocks until the service exits.
20 | func Main(version string, cliCtx *cli.Context) error {
21 | cfg := NewConfig(cliCtx)
22 | if err := cfg.Check(); err != nil {
23 | return fmt.Errorf("invalid CLI flags: %w", err)
24 | }
25 |
26 | l := oplog.NewLogger(cfg.LogConfig)
27 | m := metrics.NewMetrics("default")
28 |
29 | challengerConfig, err := NewChallengerConfigFromCLIConfig(cfg, l, m)
30 | if err != nil {
31 | l.Error("Unable to create the Challenger", "error", err)
32 | return err
33 | }
34 |
35 | challenger, err := NewChallenger(*challengerConfig, l, m)
36 | if err != nil {
37 | l.Error("Unable to create the Challenger", "error", err)
38 | return err
39 | }
40 |
41 | l.Info("Starting Challenger")
42 | ctx, cancel := context.WithCancel(context.Background())
43 | if err := challenger.Start(); err != nil {
44 | cancel()
45 | l.Error("Unable to start Challenger", "error", err)
46 | return err
47 | }
48 | defer challenger.Stop()
49 |
50 | pprofConfig := cfg.PprofConfig
51 | if pprofConfig.Enabled {
52 | l.Info("starting pprof", "addr", pprofConfig.ListenAddr, "port", pprofConfig.ListenPort)
53 | go func() {
54 | if err := oppprof.ListenAndServe(ctx, pprofConfig.ListenAddr, pprofConfig.ListenPort); err != nil {
55 | l.Error("error starting pprof", "err", err)
56 | }
57 | }()
58 | }
59 |
60 | metricsCfg := cfg.MetricsConfig
61 | if metricsCfg.Enabled {
62 | l.Info("starting metrics server", "addr", metricsCfg.ListenAddr, "port", metricsCfg.ListenPort)
63 | go func() {
64 | if err := m.Serve(ctx, metricsCfg.ListenAddr, metricsCfg.ListenPort); err != nil {
65 | l.Error("error starting metrics server", err)
66 | }
67 | }()
68 | m.StartBalanceMetrics(ctx, l, challengerConfig.L1Client, challengerConfig.From)
69 | }
70 |
71 | // rpcCfg := cfg.RPCConfig
72 | // server := oprpc.NewServer(rpcCfg.ListenAddr, rpcCfg.ListenPort, version, oprpc.WithLogger(l))
73 | // if err := server.Start(); err != nil {
74 | // cancel()
75 | // return fmt.Errorf("error starting RPC server: %w", err)
76 | // }
77 |
78 | m.RecordInfo(version)
79 | m.RecordUp()
80 |
81 | interruptChannel := make(chan os.Signal, 1)
82 | signal.Notify(interruptChannel, []os.Signal{
83 | os.Interrupt,
84 | os.Kill,
85 | syscall.SIGTERM,
86 | syscall.SIGQUIT,
87 | }...)
88 | <-interruptChannel
89 | cancel()
90 |
91 | return nil
92 | }
93 |
--------------------------------------------------------------------------------
/challenger/oracle_hook.go:
--------------------------------------------------------------------------------
1 | package challenger
2 |
3 | import (
4 | "context"
5 | "math/big"
6 | _ "net/http/pprof"
7 | "time"
8 |
9 | goEth "github.com/ethereum/go-ethereum"
10 | common "github.com/ethereum/go-ethereum/common"
11 | goTypes "github.com/ethereum/go-ethereum/core/types"
12 |
13 | txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
14 |
15 | eth "github.com/ethereum-optimism/optimism/op-node/eth"
16 | )
17 |
18 | // oracle executes the Challenger's oracle hook.
19 | // This function is intended to be spawned in a goroutine.
20 | // It will run until the Challenger's context is cancelled.
21 | //
22 | // The oracle hook listen's for `OutputProposed` events from the L2 Output Oracle contract.
23 | // When it receives an event, it will validate the output against the trusted rollup node.
24 | // If an output is invalid, it will create a dispute game of the given configuration.
25 | func (c *Challenger) oracle() {
26 | defer c.wg.Done()
27 |
28 | // The `OutputProposed` event is encoded as:
29 | // 0: bytes32 indexed outputRoot,
30 | // 1: uint256 indexed l2OutputIndex,
31 | // 2: uint256 indexed l2BlockNumber,
32 | // 3: uint256 l1Timestamp
33 |
34 | // Listen for `OutputProposed` events from the L2 Output Oracle contract
35 | event := c.l2ooABI.Events["OutputProposed"]
36 | query := goEth.FilterQuery{
37 | Topics: [][]common.Hash{
38 | {event.ID},
39 | },
40 | }
41 |
42 | logs := make(chan goTypes.Log)
43 | sub, err := c.l1Client.SubscribeFilterLogs(context.Background(), query, logs)
44 | if err != nil {
45 | c.log.Error("failed to subscribe to logs", "err", err)
46 | return
47 | }
48 |
49 | for {
50 | select {
51 | case err := <-sub.Err():
52 | c.log.Error("failed to subscribe to logs", "err", err)
53 | return
54 |
55 | case vLog := <-logs:
56 | l2BlockNumber := new(big.Int).SetBytes(vLog.Topics[3][:])
57 | expected := vLog.Topics[1]
58 | c.log.Info("Validating output", "l2BlockNumber", l2BlockNumber, "outputRoot", expected.Hex())
59 | isValid, rootClaim, err := c.ValidateOutput(c.ctx, l2BlockNumber, (eth.Bytes32)(expected))
60 | if err != nil || isValid {
61 | break
62 | }
63 |
64 | c.metr.RecordInvalidOutput(
65 | eth.L2BlockRef{
66 | Hash: vLog.Topics[0],
67 | Number: l2BlockNumber.Uint64(),
68 | },
69 | )
70 | c.log.Debug("Creating dispute game for", "l2BlockNumber", l2BlockNumber, "rootClaim", rootClaim)
71 | cCtx, cancel := context.WithTimeout(c.ctx, 10*time.Minute)
72 | contract, err := c.createDisputeGame(cCtx, AttestationDisputeGameType, rootClaim, l2BlockNumber)
73 | if err != nil {
74 | c.log.Error("Failed to challenge transaction", "err", err)
75 | cancel()
76 | break
77 | }
78 | c.metr.RecordDisputeGameCreated(l2BlockNumber, common.Hash(*rootClaim), *contract)
79 | cancel()
80 | case <-c.done:
81 | return
82 | }
83 | }
84 | }
85 |
86 | // createDisputeGame creates a dispute game.
87 | // It will create a dispute game of type `gameType` with the given output and l2BlockNumber.
88 | // The `gameType` must be a valid dispute game type as defined by the `GameType` enum in the DisputeGameFactory contract.
89 | func (c *Challenger) createDisputeGame(ctx context.Context, gameType uint8, output *eth.Bytes32, l2BlockNumber *big.Int) (*common.Address, error) {
90 | cCtx, cCancel := context.WithTimeout(ctx, c.networkTimeout)
91 | defer cCancel()
92 | data, err := c.dgfABI.Pack("create", gameType, output, common.BigToHash(l2BlockNumber))
93 | if err != nil {
94 | return nil, err
95 | }
96 | receipt, err := c.txMgr.Send(cCtx, txmgr.TxCandidate{
97 | TxData: data,
98 | To: c.dgfContractAddr,
99 | GasLimit: 0,
100 | From: c.from,
101 | })
102 | if err != nil {
103 | return nil, err
104 | }
105 | c.log.Info("challenger successfully sent tx", "tx_hash", receipt.TxHash, "output", output, "l2BlockNumber", l2BlockNumber)
106 | c.log.Info("challenger dispute game contract", "contract", receipt.ContractAddress)
107 | return &receipt.ContractAddress, nil
108 | }
109 |
--------------------------------------------------------------------------------
/challenger/outputs.go:
--------------------------------------------------------------------------------
1 | package challenger
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "math/big"
7 |
8 | eth "github.com/ethereum-optimism/optimism/op-node/eth"
9 | )
10 |
11 | // ValidateOutput checks that a given output is expected via a trusted rollup node rpc.
12 | // It returns: if the output is correct, error
13 | func (c *Challenger) ValidateOutput(ctx context.Context, l2BlockNumber *big.Int, expected eth.Bytes32) (bool, *eth.Bytes32, error) {
14 | ctx, cancel := context.WithTimeout(ctx, c.networkTimeout)
15 | defer cancel()
16 | output, err := c.rollupClient.OutputAtBlock(ctx, l2BlockNumber.Uint64())
17 | if err != nil {
18 | c.log.Error("failed to fetch output for l2BlockNumber %d: %w", l2BlockNumber, err)
19 | return true, nil, err
20 | }
21 | if output.Version != supportedL2OutputVersion {
22 | c.log.Error("unsupported l2 output version: %s", output.Version)
23 | return true, nil, errors.New("unsupported l2 output version")
24 | }
25 | // If the block numbers don't match, we should try to fetch the output again
26 | if output.BlockRef.Number != l2BlockNumber.Uint64() {
27 | c.log.Error("invalid blockNumber: next blockNumber is %v, blockNumber of block is %v", l2BlockNumber, output.BlockRef.Number)
28 | return true, nil, errors.New("invalid blockNumber")
29 | }
30 | if output.OutputRoot == expected {
31 | c.metr.RecordValidOutput(output.BlockRef)
32 | }
33 | return output.OutputRoot != expected, &output.OutputRoot, nil
34 | }
35 |
--------------------------------------------------------------------------------
/challenger/signer.go:
--------------------------------------------------------------------------------
1 | package challenger
2 |
3 | import (
4 | "bytes"
5 | "crypto/ecdsa"
6 | "fmt"
7 | "math/big"
8 |
9 | "github.com/ethereum/go-ethereum/common"
10 | "github.com/ethereum/go-ethereum/crypto"
11 | )
12 |
13 | // OutputAtBlock is the struct representation of an L2OutputOracle output
14 | // at a given L2 block number.
15 | type OutputAtBlock struct {
16 | Output common.Hash
17 | L2BlockNumber *big.Int
18 | }
19 |
20 | const domainType = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
21 | const structType = "OutputAtBlock(bytes32 output,uint256 l2BlockNumber)"
22 |
23 | func hashDomain(name, version string, chainID uint64, verifyingContract common.Address) []byte {
24 | domain := fmt.Sprintf("%s(%s)", domainType, "MyApp,1,1,")
25 | domainHash := crypto.Keccak256([]byte(domain))
26 | return domainHash
27 | }
28 |
29 | func hashTypedData(data OutputAtBlock) ([]byte, error) {
30 | structData := fmt.Sprintf("%s(%x,%x)", structType, data.Output, data.L2BlockNumber)
31 | structHash := crypto.Keccak256([]byte(structData))
32 |
33 | return structHash, nil
34 | }
35 |
36 | func signTypedData(privateKey *ecdsa.PrivateKey, data OutputAtBlock) ([]byte, error) {
37 | domainSeparator := hashDomain("MyApp", "1", 1, common.Address{})
38 | typedDataHash, err := hashTypedData(data)
39 | if err != nil {
40 | return nil, err
41 | }
42 |
43 | buf := new(bytes.Buffer)
44 | buf.Write([]byte("\x19\x01"))
45 | buf.Write(domainSeparator)
46 | buf.Write(typedDataHash)
47 |
48 | msg := crypto.Keccak256(buf.Bytes())
49 | signature, err := crypto.Sign(msg, privateKey)
50 | if err != nil {
51 | return nil, err
52 | }
53 |
54 | return signature, nil
55 | }
56 |
57 | // signOutput signs the typed data for a given output and L2 block number.
58 | func (c *Challenger) signOutput(l2BlockNumber *big.Int, rootClaim common.Hash) ([]byte, error) {
59 | data := OutputAtBlock{
60 | Output: rootClaim,
61 | L2BlockNumber: l2BlockNumber,
62 | }
63 | signature, err := signTypedData(c.privateKey, data)
64 | if err != nil {
65 | return nil, err
66 | }
67 | return signature, nil
68 | }
69 |
--------------------------------------------------------------------------------
/challenger/utils.go:
--------------------------------------------------------------------------------
1 | package challenger
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "time"
7 |
8 | "github.com/ethereum-optimism/optimism/op-node/client"
9 | "github.com/ethereum-optimism/optimism/op-node/sources"
10 | "github.com/ethereum/go-ethereum/common"
11 | "github.com/ethereum/go-ethereum/ethclient"
12 | "github.com/ethereum/go-ethereum/rpc"
13 | )
14 |
15 | var defaultDialTimeout = 5 * time.Second
16 |
17 | // dialEthClientWithTimeout attempts to dial the L1 provider using the provided
18 | // URL. If the dial doesn't complete within defaultDialTimeout seconds, this
19 | // method will return an error.
20 | func dialEthClientWithTimeout(ctx context.Context, url string) (*ethclient.Client, error) {
21 | ctxt, cancel := context.WithTimeout(ctx, defaultDialTimeout)
22 | defer cancel()
23 |
24 | return ethclient.DialContext(ctxt, url)
25 | }
26 |
27 | // dialRollupClientWithTimeout attempts to dial the RPC provider using the provided
28 | // URL. If the dial doesn't complete within defaultDialTimeout seconds, this
29 | // method will return an error.
30 | func dialRollupClientWithTimeout(ctx context.Context, url string) (*sources.RollupClient, error) {
31 | ctxt, cancel := context.WithTimeout(ctx, defaultDialTimeout)
32 | defer cancel()
33 |
34 | rpcCl, err := rpc.DialContext(ctxt, url)
35 | if err != nil {
36 | return nil, err
37 | }
38 |
39 | return sources.NewRollupClient(client.NewBaseRPCClient(rpcCl)), nil
40 | }
41 |
42 | // parseAddress parses an ETH address from a hex string. This method will fail if
43 | // the address is not a valid hexadecimal address.
44 | func parseAddress(address string) (common.Address, error) {
45 | if common.IsHexAddress(address) {
46 | return common.HexToAddress(address), nil
47 | }
48 | return common.Address{}, fmt.Errorf("invalid address: %v", address)
49 | }
50 |
--------------------------------------------------------------------------------
/cmd/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 |
6 | challenger "github.com/refcell/op-challenger/challenger"
7 | flags "github.com/refcell/op-challenger/flags"
8 |
9 | log "github.com/ethereum/go-ethereum/log"
10 | cli "github.com/urfave/cli"
11 |
12 | oplog "github.com/ethereum-optimism/optimism/op-service/log"
13 | )
14 |
15 | const Version = "1.0.0"
16 |
17 | func main() {
18 | oplog.SetupDefaults()
19 |
20 | app := cli.NewApp()
21 | app.Flags = flags.Flags
22 | app.Version = Version
23 | app.Name = "op-challenger"
24 | app.Usage = "Modular Challenger Agent"
25 | app.Description = "A modular op-stack challenge agent for output dispute games written in golang."
26 |
27 | app.Action = func(ctx *cli.Context) error {
28 | return challenger.Main(Version, ctx)
29 | }
30 | err := app.Run(os.Args)
31 | if err != nil {
32 | log.Crit("Application failed", "message", err)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/contracts/README.md:
--------------------------------------------------------------------------------
1 | # Mock Dispute Game Contracts
2 |
3 | Mock contracts and scripts for testing the `op-challenger`.
4 |
--------------------------------------------------------------------------------
/contracts/abi/l2OutputOracle.abi:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "anonymous": false,
4 | "inputs": [
5 | {
6 | "indexed": true,
7 | "internalType": "bytes32",
8 | "name": "outputRoot",
9 | "type": "bytes32"
10 | },
11 | {
12 | "indexed": true,
13 | "internalType": "uint256",
14 | "name": "l2OutputIndex",
15 | "type": "uint256"
16 | },
17 | {
18 | "indexed": true,
19 | "internalType": "uint256",
20 | "name": "l2BlockNumber",
21 | "type": "uint256"
22 | },
23 | {
24 | "indexed": false,
25 | "internalType": "uint256",
26 | "name": "l1Timestamp",
27 | "type": "uint256"
28 | }
29 | ],
30 | "name": "OutputProposed",
31 | "type": "event"
32 | },
33 | {
34 | "inputs": [
35 | {
36 | "internalType": "uint256",
37 | "name": "",
38 | "type": "uint256"
39 | }
40 | ],
41 | "name": "deleteL2Outputs",
42 | "outputs": [],
43 | "stateMutability": "nonpayable",
44 | "type": "function"
45 | },
46 | {
47 | "inputs": [
48 | {
49 | "internalType": "uint256",
50 | "name": "_l2OutputIndex",
51 | "type": "uint256"
52 | }
53 | ],
54 | "name": "getL2Output",
55 | "outputs": [
56 | {
57 | "components": [
58 | {
59 | "internalType": "bytes32",
60 | "name": "outputRoot",
61 | "type": "bytes32"
62 | },
63 | {
64 | "internalType": "uint128",
65 | "name": "timestamp",
66 | "type": "uint128"
67 | },
68 | {
69 | "internalType": "uint128",
70 | "name": "l2BlockNumber",
71 | "type": "uint128"
72 | }
73 | ],
74 | "internalType": "struct IL2OutputOracle.OutputProposal",
75 | "name": "",
76 | "type": "tuple"
77 | }
78 | ],
79 | "stateMutability": "view",
80 | "type": "function"
81 | }
82 | ]
83 |
--------------------------------------------------------------------------------
/contracts/abi/mockAttestationDisputeGame.abi:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "Claim",
6 | "name": "_rootClaim",
7 | "type": "bytes32"
8 | },
9 | {
10 | "internalType": "uint256",
11 | "name": "l2BlockNumber",
12 | "type": "uint256"
13 | },
14 | {
15 | "internalType": "address",
16 | "name": "_creator",
17 | "type": "address"
18 | }
19 | ],
20 | "stateMutability": "nonpayable",
21 | "type": "constructor"
22 | },
23 | {
24 | "inputs": [],
25 | "name": "L2_BLOCK_NUMBER",
26 | "outputs": [
27 | {
28 | "internalType": "uint256",
29 | "name": "",
30 | "type": "uint256"
31 | }
32 | ],
33 | "stateMutability": "view",
34 | "type": "function"
35 | },
36 | {
37 | "inputs": [],
38 | "name": "ROOT_CLAIM",
39 | "outputs": [
40 | {
41 | "internalType": "Claim",
42 | "name": "",
43 | "type": "bytes32"
44 | }
45 | ],
46 | "stateMutability": "view",
47 | "type": "function"
48 | },
49 | {
50 | "inputs": [
51 | {
52 | "internalType": "bytes",
53 | "name": "_signature",
54 | "type": "bytes"
55 | }
56 | ],
57 | "name": "challenge",
58 | "outputs": [],
59 | "stateMutability": "nonpayable",
60 | "type": "function"
61 | },
62 | {
63 | "inputs": [
64 | {
65 | "internalType": "address",
66 | "name": "",
67 | "type": "address"
68 | }
69 | ],
70 | "name": "challenges",
71 | "outputs": [
72 | {
73 | "internalType": "bool",
74 | "name": "",
75 | "type": "bool"
76 | }
77 | ],
78 | "stateMutability": "view",
79 | "type": "function"
80 | }
81 | ]
82 |
--------------------------------------------------------------------------------
/contracts/abi/mockDisputeGameFactory.abi:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "anonymous": false,
4 | "inputs": [
5 | {
6 | "indexed": true,
7 | "internalType": "address",
8 | "name": "disputeProxy",
9 | "type": "address"
10 | },
11 | {
12 | "indexed": true,
13 | "internalType": "enum GameType",
14 | "name": "gameType",
15 | "type": "uint8"
16 | },
17 | {
18 | "indexed": true,
19 | "internalType": "Claim",
20 | "name": "rootClaim",
21 | "type": "bytes32"
22 | }
23 | ],
24 | "name": "DisputeGameCreated",
25 | "type": "event"
26 | },
27 | {
28 | "inputs": [
29 | {
30 | "internalType": "enum GameType",
31 | "name": "gameType",
32 | "type": "uint8"
33 | },
34 | {
35 | "internalType": "Claim",
36 | "name": "rootClaim",
37 | "type": "bytes32"
38 | },
39 | {
40 | "internalType": "bytes",
41 | "name": "extraData",
42 | "type": "bytes"
43 | }
44 | ],
45 | "name": "create",
46 | "outputs": [
47 | {
48 | "internalType": "contract MockAttestationDisputeGame",
49 | "name": "mock",
50 | "type": "address"
51 | }
52 | ],
53 | "stateMutability": "nonpayable",
54 | "type": "function"
55 | },
56 | {
57 | "inputs": [
58 | {
59 | "internalType": "enum GameType",
60 | "name": "gameType",
61 | "type": "uint8"
62 | },
63 | {
64 | "internalType": "Claim",
65 | "name": "rootClaim",
66 | "type": "bytes32"
67 | },
68 | {
69 | "internalType": "bytes",
70 | "name": "extraData",
71 | "type": "bytes"
72 | }
73 | ],
74 | "name": "games",
75 | "outputs": [
76 | {
77 | "internalType": "contract IDisputeGame",
78 | "name": "_proxy",
79 | "type": "address"
80 | }
81 | ],
82 | "stateMutability": "view",
83 | "type": "function"
84 | }
85 | ]
86 |
--------------------------------------------------------------------------------
/contracts/bin/l2OutputOracle.bin:
--------------------------------------------------------------------------------
1 | 0x
2 |
--------------------------------------------------------------------------------
/contracts/bin/mockAttestationDisputeGame.bin:
--------------------------------------------------------------------------------
1 | 0x60c060405234801561001057600080fd5b506040516102b33803806102b383398101604081905261002f9161005f565b60809290925260a0526001600160a01b03166000908152602081905260409020805460ff191660011790556100a5565b60008060006060848603121561007457600080fd5b83516020850151604086015191945092506001600160a01b038116811461009a57600080fd5b809150509250925092565b60805160a0516101eb6100c86000396000608e0152600060c301526101eb6000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806308b43a1914610051578063326f8195146100895780634a1890f0146100be578063b8b9c188146100e5575b600080fd5b61007461005f366004610113565b60006020819052908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6100b07f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610080565b6100b07f000000000000000000000000000000000000000000000000000000000000000081565b6101116100f3366004610143565b5050336000908152602081905260409020805460ff19166001179055565b005b60006020828403121561012557600080fd5b81356001600160a01b038116811461013c57600080fd5b9392505050565b6000806020838503121561015657600080fd5b823567ffffffffffffffff8082111561016e57600080fd5b818501915085601f83011261018257600080fd5b81358181111561019157600080fd5b8660208285010111156101a357600080fd5b6020929092019691955090935050505056fea2646970667358221220a15f2b475fb3640846a10e20b1d980b5a93201e53321f773b79c483277a32aa364736f6c63430008130033
2 |
--------------------------------------------------------------------------------
/contracts/bin/mockDisputeGameFactory.bin:
--------------------------------------------------------------------------------
1 | 0x608060405234801561001057600080fd5b506105d6806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80633142e55e1461003b578063c49d52711461006a575b600080fd5b61004e6100493660046101ec565b61007d565b6040516001600160a01b03909116815260200160405180910390f35b61004e6100783660046101ec565b61018b565b60008061008c83850185610279565b905084813360405161009d906101df565b92835260208301919091526001600160a01b03166040820152606001604051809103906000f0801580156100d5573d6000803e3d6000fd5b509150848660028111156100eb576100eb610292565b6040516001600160a01b038516907ffad0599ff449d8d9685eadecca8cb9e00924c5fd8367c1c09469824939e1ffec90600090a4816000808888888860405160200161013a94939291906102a8565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555050949350505050565b6000806000868686866040516020016101a794939291906102a8565b60408051601f19818403018152918152815160209283012083529082019290925201600020546001600160a01b031695945050505050565b6102b3806102ee83390190565b6000806000806060858703121561020257600080fd5b84356003811061021157600080fd5b935060208501359250604085013567ffffffffffffffff8082111561023557600080fd5b818701915087601f83011261024957600080fd5b81358181111561025857600080fd5b88602082850101111561026a57600080fd5b95989497505060200194505050565b60006020828403121561028b57600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b6000600386106102c857634e487b7160e01b600052602160045260246000fd5b8560f81b8252846001830152828460218401375060009101602101908152939250505056fe60c060405234801561001057600080fd5b506040516102b33803806102b383398101604081905261002f9161005f565b60809290925260a0526001600160a01b03166000908152602081905260409020805460ff191660011790556100a5565b60008060006060848603121561007457600080fd5b83516020850151604086015191945092506001600160a01b038116811461009a57600080fd5b809150509250925092565b60805160a0516101eb6100c86000396000608e0152600060c301526101eb6000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806308b43a1914610051578063326f8195146100895780634a1890f0146100be578063b8b9c188146100e5575b600080fd5b61007461005f366004610113565b60006020819052908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6100b07f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610080565b6100b07f000000000000000000000000000000000000000000000000000000000000000081565b6101116100f3366004610143565b5050336000908152602081905260409020805460ff19166001179055565b005b60006020828403121561012557600080fd5b81356001600160a01b038116811461013c57600080fd5b9392505050565b6000806020838503121561015657600080fd5b823567ffffffffffffffff8082111561016e57600080fd5b818501915085601f83011261018257600080fd5b81358181111561019157600080fd5b8660208285010111156101a357600080fd5b6020929092019691955090935050505056fea2646970667358221220a15f2b475fb3640846a10e20b1d980b5a93201e53321f773b79c483277a32aa364736f6c63430008130033a2646970667358221220b4c9410279382b1338bd3a1d99779f93e552ef22ee4c93df63943561dea0f18764736f6c63430008130033
2 |
--------------------------------------------------------------------------------
/contracts/generate.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | cd project
4 | forge inspect IL2OutputOracle abi > ../abi/l2OutputOracle.abi
5 | forge inspect IL2OutputOracle bytecode > ../bin/l2OutputOracle.bin
6 | forge inspect MockAttestationDisputeGame abi > ../abi/mockAttestationDisputeGame.abi
7 | forge inspect MockAttestationDisputeGame bytecode > ../bin/mockAttestationDisputeGame.bin
8 | forge inspect MockDisputeGameFactory abi > ../abi/mockDisputeGameFactory.abi
9 | forge inspect MockDisputeGameFactory bytecode > ../bin/mockDisputeGameFactory.bin
10 | cd ..
11 |
12 | abigen \
13 | --abi abi/l2OutputOracle.abi \
14 | --bin bin/l2OutputOracle.bin \
15 | --pkg bindings \
16 | --type L2OutputOracle \
17 | --out ./bindings/l2OutputOracle.go
18 |
19 | abigen \
20 | --abi abi/mockAttestationDisputeGame.abi \
21 | --bin bin/mockAttestationDisputeGame.bin \
22 | --pkg bindings \
23 | --type MockAttestationDisputeGame \
24 | --out ./bindings/mockAttestationDisputeGame.go
25 |
26 | abigen \
27 | --abi abi/mockDisputeGameFactory.abi \
28 | --bin bin/mockDisputeGameFactory.bin \
29 | --pkg bindings \
30 | --type MockDisputeGameFactory \
31 | --out ./bindings/mockDisputeGameFactory.go
--------------------------------------------------------------------------------
/contracts/project/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiler files
2 | cache/
3 | out/
4 |
5 | # Ignores broadcast logs
6 | /broadcast
7 |
8 | # Docs
9 | docs/
10 |
11 | # Dotenv file
12 | .env
13 |
--------------------------------------------------------------------------------
/contracts/project/foundry.toml:
--------------------------------------------------------------------------------
1 | [profile.default]
2 | src = 'src'
3 | out = 'out'
4 | libs = ['lib']
5 |
6 | [fmt]
7 | bracket_spacing = true
8 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | push:
7 | branches:
8 | - master
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 |
16 | - name: Install Foundry
17 | uses: onbjerg/foundry-toolchain@v1
18 | with:
19 | version: nightly
20 |
21 | - name: Print forge version
22 | run: forge --version
23 |
24 | # Backwards compatibility checks.
25 | - name: Check compatibility with 0.8.0
26 | if: always()
27 | run: forge build --skip test --use solc:0.8.0
28 |
29 | - name: Check compatibility with 0.7.6
30 | if: always()
31 | run: forge build --skip test --use solc:0.7.6
32 |
33 | - name: Check compatibility with 0.7.0
34 | if: always()
35 | run: forge build --skip test --use solc:0.7.0
36 |
37 | - name: Check compatibility with 0.6.12
38 | if: always()
39 | run: forge build --skip test --use solc:0.6.12
40 |
41 | - name: Check compatibility with 0.6.2
42 | if: always()
43 | run: forge build --skip test --use solc:0.6.2
44 |
45 | # via-ir compilation time checks.
46 | - name: Measure compilation time of Test with 0.8.17 --via-ir
47 | if: always()
48 | run: forge build --skip test --contracts test/compilation/CompilationTest.sol --use solc:0.8.17 --via-ir
49 |
50 | - name: Measure compilation time of TestBase with 0.8.17 --via-ir
51 | if: always()
52 | run: forge build --skip test --contracts test/compilation/CompilationTestBase.sol --use solc:0.8.17 --via-ir
53 |
54 | - name: Measure compilation time of Script with 0.8.17 --via-ir
55 | if: always()
56 | run: forge build --skip test --contracts test/compilation/CompilationScript.sol --use solc:0.8.17 --via-ir
57 |
58 | - name: Measure compilation time of ScriptBase with 0.8.17 --via-ir
59 | if: always()
60 | run: forge build --skip test --contracts test/compilation/CompilationScriptBase.sol --use solc:0.8.17 --via-ir
61 |
62 | test:
63 | runs-on: ubuntu-latest
64 | steps:
65 | - uses: actions/checkout@v3
66 |
67 | - name: Install Foundry
68 | uses: onbjerg/foundry-toolchain@v1
69 | with:
70 | version: nightly
71 |
72 | - name: Print forge version
73 | run: forge --version
74 |
75 | - name: Run tests
76 | run: forge test -vvv
77 |
78 | fmt:
79 | runs-on: ubuntu-latest
80 | steps:
81 | - uses: actions/checkout@v3
82 |
83 | - name: Install Foundry
84 | uses: onbjerg/foundry-toolchain@v1
85 | with:
86 | version: nightly
87 |
88 | - name: Print forge version
89 | run: forge --version
90 |
91 | - name: Check formatting
92 | run: forge fmt --check
93 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/.gitignore:
--------------------------------------------------------------------------------
1 | cache/
2 | out/
3 | .vscode
4 | .idea
5 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/ds-test"]
2 | path = lib/ds-test
3 | url = https://github.com/dapphub/ds-test
4 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Copyright Contributors to Forge Standard Library
2 |
3 | Apache License
4 | Version 2.0, January 2004
5 | http://www.apache.org/licenses/
6 |
7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8 |
9 | 1. Definitions.
10 |
11 | "License" shall mean the terms and conditions for use, reproduction,
12 | and distribution as defined by Sections 1 through 9 of this document.
13 |
14 | "Licensor" shall mean the copyright owner or entity authorized by
15 | the copyright owner that is granting the License.
16 |
17 | "Legal Entity" shall mean the union of the acting entity and all
18 | other entities that control, are controlled by, or are under common
19 | control with that entity. For the purposes of this definition,
20 | "control" means (i) the power, direct or indirect, to cause the
21 | direction or management of such entity, whether by contract or
22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
23 | outstanding shares, or (iii) beneficial ownership of such entity.
24 |
25 | "You" (or "Your") shall mean an individual or Legal Entity
26 | exercising permissions granted by this License.
27 |
28 | "Source" form shall mean the preferred form for making modifications,
29 | including but not limited to software source code, documentation
30 | source, and configuration files.
31 |
32 | "Object" form shall mean any form resulting from mechanical
33 | transformation or translation of a Source form, including but
34 | not limited to compiled object code, generated documentation,
35 | and conversions to other media types.
36 |
37 | "Work" shall mean the work of authorship, whether in Source or
38 | Object form, made available under the License, as indicated by a
39 | copyright notice that is included in or attached to the work
40 | (an example is provided in the Appendix below).
41 |
42 | "Derivative Works" shall mean any work, whether in Source or Object
43 | form, that is based on (or derived from) the Work and for which the
44 | editorial revisions, annotations, elaborations, or other modifications
45 | represent, as a whole, an original work of authorship. For the purposes
46 | of this License, Derivative Works shall not include works that remain
47 | separable from, or merely link (or bind by name) to the interfaces of,
48 | the Work and Derivative Works thereof.
49 |
50 | "Contribution" shall mean any work of authorship, including
51 | the original version of the Work and any modifications or additions
52 | to that Work or Derivative Works thereof, that is intentionally
53 | submitted to Licensor for inclusion in the Work by the copyright owner
54 | or by an individual or Legal Entity authorized to submit on behalf of
55 | the copyright owner. For the purposes of this definition, "submitted"
56 | means any form of electronic, verbal, or written communication sent
57 | to the Licensor or its representatives, including but not limited to
58 | communication on electronic mailing lists, source code control systems,
59 | and issue tracking systems that are managed by, or on behalf of, the
60 | Licensor for the purpose of discussing and improving the Work, but
61 | excluding communication that is conspicuously marked or otherwise
62 | designated in writing by the copyright owner as "Not a Contribution."
63 |
64 | "Contributor" shall mean Licensor and any individual or Legal Entity
65 | on behalf of whom a Contribution has been received by Licensor and
66 | subsequently incorporated within the Work.
67 |
68 | 2. Grant of Copyright License. Subject to the terms and conditions of
69 | this License, each Contributor hereby grants to You a perpetual,
70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71 | copyright license to reproduce, prepare Derivative Works of,
72 | publicly display, publicly perform, sublicense, and distribute the
73 | Work and such Derivative Works in Source or Object form.
74 |
75 | 3. Grant of Patent License. Subject to the terms and conditions of
76 | this License, each Contributor hereby grants to You a perpetual,
77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78 | (except as stated in this section) patent license to make, have made,
79 | use, offer to sell, sell, import, and otherwise transfer the Work,
80 | where such license applies only to those patent claims licensable
81 | by such Contributor that are necessarily infringed by their
82 | Contribution(s) alone or by combination of their Contribution(s)
83 | with the Work to which such Contribution(s) was submitted. If You
84 | institute patent litigation against any entity (including a
85 | cross-claim or counterclaim in a lawsuit) alleging that the Work
86 | or a Contribution incorporated within the Work constitutes direct
87 | or contributory patent infringement, then any patent licenses
88 | granted to You under this License for that Work shall terminate
89 | as of the date such litigation is filed.
90 |
91 | 4. Redistribution. You may reproduce and distribute copies of the
92 | Work or Derivative Works thereof in any medium, with or without
93 | modifications, and in Source or Object form, provided that You
94 | meet the following conditions:
95 |
96 | (a) You must give any other recipients of the Work or
97 | Derivative Works a copy of this License; and
98 |
99 | (b) You must cause any modified files to carry prominent notices
100 | stating that You changed the files; and
101 |
102 | (c) You must retain, in the Source form of any Derivative Works
103 | that You distribute, all copyright, patent, trademark, and
104 | attribution notices from the Source form of the Work,
105 | excluding those notices that do not pertain to any part of
106 | the Derivative Works; and
107 |
108 | (d) If the Work includes a "NOTICE" text file as part of its
109 | distribution, then any Derivative Works that You distribute must
110 | include a readable copy of the attribution notices contained
111 | within such NOTICE file, excluding those notices that do not
112 | pertain to any part of the Derivative Works, in at least one
113 | of the following places: within a NOTICE text file distributed
114 | as part of the Derivative Works; within the Source form or
115 | documentation, if provided along with the Derivative Works; or,
116 | within a display generated by the Derivative Works, if and
117 | wherever such third-party notices normally appear. The contents
118 | of the NOTICE file are for informational purposes only and
119 | do not modify the License. You may add Your own attribution
120 | notices within Derivative Works that You distribute, alongside
121 | or as an addendum to the NOTICE text from the Work, provided
122 | that such additional attribution notices cannot be construed
123 | as modifying the License.
124 |
125 | You may add Your own copyright statement to Your modifications and
126 | may provide additional or different license terms and conditions
127 | for use, reproduction, or distribution of Your modifications, or
128 | for any such Derivative Works as a whole, provided Your use,
129 | reproduction, and distribution of the Work otherwise complies with
130 | the conditions stated in this License.
131 |
132 | 5. Submission of Contributions. Unless You explicitly state otherwise,
133 | any Contribution intentionally submitted for inclusion in the Work
134 | by You to the Licensor shall be under the terms and conditions of
135 | this License, without any additional terms or conditions.
136 | Notwithstanding the above, nothing herein shall supersede or modify
137 | the terms of any separate license agreement you may have executed
138 | with Licensor regarding such Contributions.
139 |
140 | 6. Trademarks. This License does not grant permission to use the trade
141 | names, trademarks, service marks, or product names of the Licensor,
142 | except as required for reasonable and customary use in describing the
143 | origin of the Work and reproducing the content of the NOTICE file.
144 |
145 | 7. Disclaimer of Warranty. Unless required by applicable law or
146 | agreed to in writing, Licensor provides the Work (and each
147 | Contributor provides its Contributions) on an "AS IS" BASIS,
148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149 | implied, including, without limitation, any warranties or conditions
150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151 | PARTICULAR PURPOSE. You are solely responsible for determining the
152 | appropriateness of using or redistributing the Work and assume any
153 | risks associated with Your exercise of permissions under this License.
154 |
155 | 8. Limitation of Liability. In no event and under no legal theory,
156 | whether in tort (including negligence), contract, or otherwise,
157 | unless required by applicable law (such as deliberate and grossly
158 | negligent acts) or agreed to in writing, shall any Contributor be
159 | liable to You for damages, including any direct, indirect, special,
160 | incidental, or consequential damages of any character arising as a
161 | result of this License or out of the use or inability to use the
162 | Work (including but not limited to damages for loss of goodwill,
163 | work stoppage, computer failure or malfunction, or any and all
164 | other commercial damages or losses), even if such Contributor
165 | has been advised of the possibility of such damages.
166 |
167 | 9. Accepting Warranty or Additional Liability. While redistributing
168 | the Work or Derivative Works thereof, You may choose to offer,
169 | and charge a fee for, acceptance of support, warranty, indemnity,
170 | or other liability obligations and/or rights consistent with this
171 | License. However, in accepting such obligations, You may act only
172 | on Your own behalf and on Your sole responsibility, not on behalf
173 | of any other Contributor, and only if You agree to indemnify,
174 | defend, and hold each Contributor harmless for any liability
175 | incurred by, or claims asserted against, such Contributor by reason
176 | of your accepting any such warranty or additional liability.
177 |
178 | END OF TERMS AND CONDITIONS
179 |
180 | APPENDIX: How to apply the Apache License to your work.
181 |
182 | To apply the Apache License to your work, attach the following
183 | boilerplate notice, with the fields enclosed by brackets "[]"
184 | replaced with your own identifying information. (Don't include
185 | the brackets!) The text should be enclosed in the appropriate
186 | comment syntax for the file format. We also recommend that a
187 | file or class name and description of purpose be included on the
188 | same "printed page" as the copyright notice for easier
189 | identification within third-party archives.
190 |
191 | Copyright [yyyy] [name of copyright owner]
192 |
193 | Licensed under the Apache License, Version 2.0 (the "License");
194 | you may not use this file except in compliance with the License.
195 | You may obtain a copy of the License at
196 |
197 | http://www.apache.org/licenses/LICENSE-2.0
198 |
199 | Unless required by applicable law or agreed to in writing, software
200 | distributed under the License is distributed on an "AS IS" BASIS,
201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202 | See the License for the specific language governing permissions and
203 | limitations under the License.
204 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright Contributors to Forge Standard Library
2 |
3 | Permission is hereby granted, free of charge, to any
4 | person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the
6 | Software without restriction, including without
7 | limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following
11 | conditions:
12 |
13 | The above copyright notice and this permission notice
14 | shall be included in all copies or substantial portions
15 | of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24 | IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.R
26 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/README.md:
--------------------------------------------------------------------------------
1 | # Forge Standard Library • [](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml)
2 |
3 | Forge Standard Library is a collection of helpful contracts and libraries for use with [Forge and Foundry](https://github.com/foundry-rs/foundry). It leverages Forge's cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes.
4 |
5 | **Learn how to use Forge-Std with the [📖 Foundry Book (Forge-Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).**
6 |
7 | ## Install
8 |
9 | ```bash
10 | forge install foundry-rs/forge-std
11 | ```
12 |
13 | ## Contracts
14 | ### stdError
15 |
16 | This is a helper contract for errors and reverts. In Forge, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors.
17 |
18 | See the contract itself for all error codes.
19 |
20 | #### Example usage
21 |
22 | ```solidity
23 |
24 | import "forge-std/Test.sol";
25 |
26 | contract TestContract is Test {
27 | ErrorsTest test;
28 |
29 | function setUp() public {
30 | test = new ErrorsTest();
31 | }
32 |
33 | function testExpectArithmetic() public {
34 | vm.expectRevert(stdError.arithmeticError);
35 | test.arithmeticError(10);
36 | }
37 | }
38 |
39 | contract ErrorsTest {
40 | function arithmeticError(uint256 a) public {
41 | uint256 a = a - 100;
42 | }
43 | }
44 | ```
45 |
46 | ### stdStorage
47 |
48 | This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`).
49 |
50 | This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth.
51 |
52 | I.e.:
53 | ```solidity
54 | struct T {
55 | // depth 0
56 | uint256 a;
57 | // depth 1
58 | uint256 b;
59 | }
60 | ```
61 |
62 | #### Example usage
63 |
64 | ```solidity
65 | import "forge-std/Test.sol";
66 |
67 | contract TestContract is Test {
68 | using stdStorage for StdStorage;
69 |
70 | Storage test;
71 |
72 | function setUp() public {
73 | test = new Storage();
74 | }
75 |
76 | function testFindExists() public {
77 | // Lets say we want to find the slot for the public
78 | // variable `exists`. We just pass in the function selector
79 | // to the `find` command
80 | uint256 slot = stdstore.target(address(test)).sig("exists()").find();
81 | assertEq(slot, 0);
82 | }
83 |
84 | function testWriteExists() public {
85 | // Lets say we want to write to the slot for the public
86 | // variable `exists`. We just pass in the function selector
87 | // to the `checked_write` command
88 | stdstore.target(address(test)).sig("exists()").checked_write(100);
89 | assertEq(test.exists(), 100);
90 | }
91 |
92 | // It supports arbitrary storage layouts, like assembly based storage locations
93 | function testFindHidden() public {
94 | // `hidden` is a random hash of a bytes, iteration through slots would
95 | // not find it. Our mechanism does
96 | // Also, you can use the selector instead of a string
97 | uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find();
98 | assertEq(slot, uint256(keccak256("my.random.var")));
99 | }
100 |
101 | // If targeting a mapping, you have to pass in the keys necessary to perform the find
102 | // i.e.:
103 | function testFindMapping() public {
104 | uint256 slot = stdstore
105 | .target(address(test))
106 | .sig(test.map_addr.selector)
107 | .with_key(address(this))
108 | .find();
109 | // in the `Storage` constructor, we wrote that this address' value was 1 in the map
110 | // so when we load the slot, we expect it to be 1
111 | assertEq(uint(vm.load(address(test), bytes32(slot))), 1);
112 | }
113 |
114 | // If the target is a struct, you can specify the field depth:
115 | function testFindStruct() public {
116 | // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc.
117 | uint256 slot_for_a_field = stdstore
118 | .target(address(test))
119 | .sig(test.basicStruct.selector)
120 | .depth(0)
121 | .find();
122 |
123 | uint256 slot_for_b_field = stdstore
124 | .target(address(test))
125 | .sig(test.basicStruct.selector)
126 | .depth(1)
127 | .find();
128 |
129 | assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1);
130 | assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2);
131 | }
132 | }
133 |
134 | // A complex storage contract
135 | contract Storage {
136 | struct UnpackedStruct {
137 | uint256 a;
138 | uint256 b;
139 | }
140 |
141 | constructor() {
142 | map_addr[msg.sender] = 1;
143 | }
144 |
145 | uint256 public exists = 1;
146 | mapping(address => uint256) public map_addr;
147 | // mapping(address => Packed) public map_packed;
148 | mapping(address => UnpackedStruct) public map_struct;
149 | mapping(address => mapping(address => uint256)) public deep_map;
150 | mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct;
151 | UnpackedStruct public basicStruct = UnpackedStruct({
152 | a: 1,
153 | b: 2
154 | });
155 |
156 | function hidden() public view returns (bytes32 t) {
157 | // an extremely hidden storage slot
158 | bytes32 slot = keccak256("my.random.var");
159 | assembly {
160 | t := sload(slot)
161 | }
162 | }
163 | }
164 | ```
165 |
166 | ### stdCheats
167 |
168 | This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you.
169 |
170 |
171 | #### Example usage:
172 | ```solidity
173 |
174 | // SPDX-License-Identifier: MIT
175 | pragma solidity ^0.8.0;
176 |
177 | import "forge-std/Test.sol";
178 |
179 | // Inherit the stdCheats
180 | contract StdCheatsTest is Test {
181 | Bar test;
182 | function setUp() public {
183 | test = new Bar();
184 | }
185 |
186 | function testHoax() public {
187 | // we call `hoax`, which gives the target address
188 | // eth and then calls `prank`
189 | hoax(address(1337));
190 | test.bar{value: 100}(address(1337));
191 |
192 | // overloaded to allow you to specify how much eth to
193 | // initialize the address with
194 | hoax(address(1337), 1);
195 | test.bar{value: 1}(address(1337));
196 | }
197 |
198 | function testStartHoax() public {
199 | // we call `startHoax`, which gives the target address
200 | // eth and then calls `startPrank`
201 | //
202 | // it is also overloaded so that you can specify an eth amount
203 | startHoax(address(1337));
204 | test.bar{value: 100}(address(1337));
205 | test.bar{value: 100}(address(1337));
206 | vm.stopPrank();
207 | test.bar(address(this));
208 | }
209 | }
210 |
211 | contract Bar {
212 | function bar(address expectedSender) public payable {
213 | require(msg.sender == expectedSender, "!prank");
214 | }
215 | }
216 | ```
217 |
218 | ### Std Assertions
219 |
220 | Expand upon the assertion functions from the `DSTest` library.
221 |
222 | ### `console.log`
223 |
224 | Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log).
225 | It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces.
226 |
227 | ```solidity
228 | // import it indirectly via Test.sol
229 | import "forge-std/Test.sol";
230 | // or directly import it
231 | import "forge-std/console2.sol";
232 | ...
233 | console2.log(someValue);
234 | ```
235 |
236 | If you need compatibility with Hardhat, you must use the standard `console.sol` instead.
237 | Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces.
238 |
239 | ```solidity
240 | // import it indirectly via Test.sol
241 | import "forge-std/Test.sol";
242 | // or directly import it
243 | import "forge-std/console.sol";
244 | ...
245 | console.log(someValue);
246 | ```
247 |
248 | ## License
249 |
250 | Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license.
251 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/foundry.toml:
--------------------------------------------------------------------------------
1 | [profile.default]
2 | fs_permissions = [{ access = "read-write", path = "./"}]
3 |
4 | [rpc_endpoints]
5 | # The RPC URLs are modified versions of the default for testing initialization.
6 | mainnet = "https://mainnet.infura.io/v3/16a8be88795540b9b3903d8de0f7baa5" # Different API key.
7 | optimism_goerli = "https://goerli.optimism.io/" # Adds a trailing slash.
8 | arbitrum_one_goerli = "https://goerli-rollup.arbitrum.io/rpc/" # Adds a trailing slash.
9 | needs_undefined_env_var = "${UNDEFINED_RPC_URL_PLACEHOLDER}"
10 |
11 | [fmt]
12 | # These are all the `forge fmt` defaults.
13 | line_length = 120
14 | tab_width = 4
15 | bracket_spacing = false
16 | int_types = 'long'
17 | multiline_func_header = 'attributes_first'
18 | quote_style = 'double'
19 | number_underscore = 'preserve'
20 | single_line_statement_blocks = 'preserve'
21 | ignore = ["src/console.sol", "src/console2.sol"]
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/lib/ds-test/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: "Build"
2 | on:
3 | pull_request:
4 | push:
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v3
10 | - uses: cachix/install-nix-action@v18
11 | with:
12 | nix_path: nixpkgs=channel:nixos-unstable
13 | extra_nix_config: |
14 | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
15 |
16 | - name: setup dapp binary cache
17 | uses: cachix/cachix-action@v12
18 | with:
19 | name: dapp
20 |
21 | - name: install dapptools
22 | run: nix profile install github:dapphub/dapptools#dapp --accept-flake-config
23 |
24 | - name: install foundry
25 | uses: foundry-rs/foundry-toolchain@v1
26 |
27 | - name: test with solc-0.5.17
28 | run: dapp --use solc-0.5.17 test -v
29 |
30 | - name: test with solc-0.6.11
31 | run: dapp --use solc-0.6.11 test -v
32 |
33 | - name: test with solc-0.7.6
34 | run: dapp --use solc-0.7.6 test -v
35 |
36 | - name: test with solc-0.8.18
37 | run: dapp --use solc-0.8.18 test -v
38 |
39 | - name: Run tests with foundry
40 | run: forge test -vvv
41 |
42 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/lib/ds-test/.gitignore:
--------------------------------------------------------------------------------
1 | /.dapple
2 | /build
3 | /out
4 | /cache/
5 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/lib/ds-test/Makefile:
--------------------------------------------------------------------------------
1 | all:; dapp build
2 |
3 | test:
4 | -dapp --use solc:0.4.23 build
5 | -dapp --use solc:0.4.26 build
6 | -dapp --use solc:0.5.17 build
7 | -dapp --use solc:0.6.12 build
8 | -dapp --use solc:0.7.5 build
9 |
10 | demo:
11 | DAPP_SRC=demo dapp --use solc:0.7.5 build
12 | -hevm dapp-test --verbose 3
13 |
14 | .PHONY: test demo
15 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/lib/ds-test/default.nix:
--------------------------------------------------------------------------------
1 | { solidityPackage, dappsys }: solidityPackage {
2 | name = "ds-test";
3 | src = ./src;
4 | }
5 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/lib/ds-test/demo/demo.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: GPL-3.0-or-later
2 | pragma solidity >=0.5.0;
3 |
4 | import "../src/test.sol";
5 |
6 | contract DemoTest is DSTest {
7 | function test_this() public pure {
8 | require(true);
9 | }
10 | function test_logs() public {
11 | emit log("-- log(string)");
12 | emit log("a string");
13 |
14 | emit log("-- log_named_uint(string, uint)");
15 | emit log_named_uint("uint", 512);
16 |
17 | emit log("-- log_named_int(string, int)");
18 | emit log_named_int("int", -512);
19 |
20 | emit log("-- log_named_address(string, address)");
21 | emit log_named_address("address", address(this));
22 |
23 | emit log("-- log_named_bytes32(string, bytes32)");
24 | emit log_named_bytes32("bytes32", "a string");
25 |
26 | emit log("-- log_named_bytes(string, bytes)");
27 | emit log_named_bytes("bytes", hex"cafefe");
28 |
29 | emit log("-- log_named_string(string, string)");
30 | emit log_named_string("string", "a string");
31 |
32 | emit log("-- log_named_decimal_uint(string, uint, uint)");
33 | emit log_named_decimal_uint("decimal uint", 1.0e18, 18);
34 |
35 | emit log("-- log_named_decimal_int(string, int, uint)");
36 | emit log_named_decimal_int("decimal int", -1.0e18, 18);
37 | }
38 | event log_old_named_uint(bytes32,uint);
39 | function test_old_logs() public {
40 | emit log_old_named_uint("key", 500);
41 | emit log_named_bytes32("bkey", "val");
42 | }
43 | function test_trace() public view {
44 | this.echo("string 1", "string 2");
45 | }
46 | function test_multiline() public {
47 | emit log("a multiline\\nstring");
48 | emit log("a multiline string");
49 | emit log_bytes("a string");
50 | emit log_bytes("a multiline\nstring");
51 | emit log_bytes("a multiline\\nstring");
52 | emit logs(hex"0000");
53 | emit log_named_bytes("0x0000", hex"0000");
54 | emit logs(hex"ff");
55 | }
56 | function echo(string memory s1, string memory s2) public pure
57 | returns (string memory, string memory)
58 | {
59 | return (s1, s2);
60 | }
61 |
62 | function prove_this(uint x) public {
63 | emit log_named_uint("sym x", x);
64 | assertGt(x + 1, 0);
65 | }
66 |
67 | function test_logn() public {
68 | assembly {
69 | log0(0x01, 0x02)
70 | log1(0x01, 0x02, 0x03)
71 | log2(0x01, 0x02, 0x03, 0x04)
72 | log3(0x01, 0x02, 0x03, 0x04, 0x05)
73 | }
74 | }
75 |
76 | event MyEvent(uint, uint indexed, uint, uint indexed);
77 | function test_events() public {
78 | emit MyEvent(1, 2, 3, 4);
79 | }
80 |
81 | function test_asserts() public {
82 | string memory err = "this test has failed!";
83 | emit log("## assertTrue(bool)\n");
84 | assertTrue(false);
85 | emit log("\n");
86 | assertTrue(false, err);
87 |
88 | emit log("\n## assertEq(address,address)\n");
89 | assertEq(address(this), msg.sender);
90 | emit log("\n");
91 | assertEq(address(this), msg.sender, err);
92 |
93 | emit log("\n## assertEq32(bytes32,bytes32)\n");
94 | assertEq32("bytes 1", "bytes 2");
95 | emit log("\n");
96 | assertEq32("bytes 1", "bytes 2", err);
97 |
98 | emit log("\n## assertEq(bytes32,bytes32)\n");
99 | assertEq32("bytes 1", "bytes 2");
100 | emit log("\n");
101 | assertEq32("bytes 1", "bytes 2", err);
102 |
103 | emit log("\n## assertEq(uint,uint)\n");
104 | assertEq(uint(0), 1);
105 | emit log("\n");
106 | assertEq(uint(0), 1, err);
107 |
108 | emit log("\n## assertEq(int,int)\n");
109 | assertEq(-1, -2);
110 | emit log("\n");
111 | assertEq(-1, -2, err);
112 |
113 | emit log("\n## assertEqDecimal(int,int,uint)\n");
114 | assertEqDecimal(-1.0e18, -1.1e18, 18);
115 | emit log("\n");
116 | assertEqDecimal(-1.0e18, -1.1e18, 18, err);
117 |
118 | emit log("\n## assertEqDecimal(uint,uint,uint)\n");
119 | assertEqDecimal(uint(1.0e18), 1.1e18, 18);
120 | emit log("\n");
121 | assertEqDecimal(uint(1.0e18), 1.1e18, 18, err);
122 |
123 | emit log("\n## assertGt(uint,uint)\n");
124 | assertGt(uint(0), 0);
125 | emit log("\n");
126 | assertGt(uint(0), 0, err);
127 |
128 | emit log("\n## assertGt(int,int)\n");
129 | assertGt(-1, -1);
130 | emit log("\n");
131 | assertGt(-1, -1, err);
132 |
133 | emit log("\n## assertGtDecimal(int,int,uint)\n");
134 | assertGtDecimal(-2.0e18, -1.1e18, 18);
135 | emit log("\n");
136 | assertGtDecimal(-2.0e18, -1.1e18, 18, err);
137 |
138 | emit log("\n## assertGtDecimal(uint,uint,uint)\n");
139 | assertGtDecimal(uint(1.0e18), 1.1e18, 18);
140 | emit log("\n");
141 | assertGtDecimal(uint(1.0e18), 1.1e18, 18, err);
142 |
143 | emit log("\n## assertGe(uint,uint)\n");
144 | assertGe(uint(0), 1);
145 | emit log("\n");
146 | assertGe(uint(0), 1, err);
147 |
148 | emit log("\n## assertGe(int,int)\n");
149 | assertGe(-1, 0);
150 | emit log("\n");
151 | assertGe(-1, 0, err);
152 |
153 | emit log("\n## assertGeDecimal(int,int,uint)\n");
154 | assertGeDecimal(-2.0e18, -1.1e18, 18);
155 | emit log("\n");
156 | assertGeDecimal(-2.0e18, -1.1e18, 18, err);
157 |
158 | emit log("\n## assertGeDecimal(uint,uint,uint)\n");
159 | assertGeDecimal(uint(1.0e18), 1.1e18, 18);
160 | emit log("\n");
161 | assertGeDecimal(uint(1.0e18), 1.1e18, 18, err);
162 |
163 | emit log("\n## assertLt(uint,uint)\n");
164 | assertLt(uint(0), 0);
165 | emit log("\n");
166 | assertLt(uint(0), 0, err);
167 |
168 | emit log("\n## assertLt(int,int)\n");
169 | assertLt(-1, -1);
170 | emit log("\n");
171 | assertLt(-1, -1, err);
172 |
173 | emit log("\n## assertLtDecimal(int,int,uint)\n");
174 | assertLtDecimal(-1.0e18, -1.1e18, 18);
175 | emit log("\n");
176 | assertLtDecimal(-1.0e18, -1.1e18, 18, err);
177 |
178 | emit log("\n## assertLtDecimal(uint,uint,uint)\n");
179 | assertLtDecimal(uint(2.0e18), 1.1e18, 18);
180 | emit log("\n");
181 | assertLtDecimal(uint(2.0e18), 1.1e18, 18, err);
182 |
183 | emit log("\n## assertLe(uint,uint)\n");
184 | assertLe(uint(1), 0);
185 | emit log("\n");
186 | assertLe(uint(1), 0, err);
187 |
188 | emit log("\n## assertLe(int,int)\n");
189 | assertLe(0, -1);
190 | emit log("\n");
191 | assertLe(0, -1, err);
192 |
193 | emit log("\n## assertLeDecimal(int,int,uint)\n");
194 | assertLeDecimal(-1.0e18, -1.1e18, 18);
195 | emit log("\n");
196 | assertLeDecimal(-1.0e18, -1.1e18, 18, err);
197 |
198 | emit log("\n## assertLeDecimal(uint,uint,uint)\n");
199 | assertLeDecimal(uint(2.0e18), 1.1e18, 18);
200 | emit log("\n");
201 | assertLeDecimal(uint(2.0e18), 1.1e18, 18, err);
202 |
203 | emit log("\n## assertEq(string,string)\n");
204 | string memory s1 = "string 1";
205 | string memory s2 = "string 2";
206 | assertEq(s1, s2);
207 | emit log("\n");
208 | assertEq(s1, s2, err);
209 |
210 | emit log("\n## assertEq0(bytes,bytes)\n");
211 | assertEq0(hex"abcdef01", hex"abcdef02");
212 | emit log("\n");
213 | assertEq0(hex"abcdef01", hex"abcdef02", err);
214 | }
215 | }
216 |
217 | contract DemoTestWithSetUp {
218 | function setUp() public {
219 | }
220 | function test_pass() public pure {
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/lib/ds-test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ds-test",
3 | "version": "1.0.0",
4 | "description": "Assertions, equality checks and other test helpers ",
5 | "bugs": "https://github.com/dapphub/ds-test/issues",
6 | "license": "GPL-3.0",
7 | "author": "Contributors to ds-test",
8 | "files": [
9 | "src/*"
10 | ],
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/dapphub/ds-test.git"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/lib/ds-test/src/test.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: GPL-3.0-or-later
2 | pragma solidity >=0.5.0;
3 |
4 | import {DSTest} from "./test.sol";
5 |
6 | contract DemoTest is DSTest {
7 |
8 | // --- assertTrue ---
9 |
10 | function testAssertTrue() public {
11 | assertTrue(true, "msg");
12 | assertTrue(true);
13 | }
14 | function testFailAssertTrue() public {
15 | assertTrue(false);
16 | }
17 | function testFailAssertTrueWithMsg() public {
18 | assertTrue(false, "msg");
19 | }
20 |
21 | // --- assertEq (Addr) ---
22 |
23 | function testAssertEqAddr() public {
24 | assertEq(address(0x0), address(0x0), "msg");
25 | assertEq(address(0x0), address(0x0));
26 | }
27 | function testFailAssertEqAddr() public {
28 | assertEq(address(0x0), address(0x1));
29 | }
30 | function testFailAssertEqAddrWithMsg() public {
31 | assertEq(address(0x0), address(0x1), "msg");
32 | }
33 |
34 | // --- assertEq (Bytes32) ---
35 |
36 | function testAssertEqBytes32() public {
37 | assertEq(bytes32("hi"), bytes32("hi"), "msg");
38 | assertEq(bytes32("hi"), bytes32("hi"));
39 | }
40 | function testFailAssertEqBytes32() public {
41 | assertEq(bytes32("hi"), bytes32("ho"));
42 | }
43 | function testFailAssertEqBytes32WithMsg() public {
44 | assertEq(bytes32("hi"), bytes32("ho"), "msg");
45 | }
46 |
47 | // --- assertEq (Int) ---
48 |
49 | function testAssertEqInt() public {
50 | assertEq(-1, -1, "msg");
51 | assertEq(-1, -1);
52 | }
53 | function testFailAssertEqInt() public {
54 | assertEq(-1, -2);
55 | }
56 | function testFailAssertEqIntWithMsg() public {
57 | assertEq(-1, -2, "msg");
58 | }
59 |
60 | // --- assertEq (UInt) ---
61 |
62 | function testAssertEqUInt() public {
63 | assertEq(uint(1), uint(1), "msg");
64 | assertEq(uint(1), uint(1));
65 | }
66 | function testFailAssertEqUInt() public {
67 | assertEq(uint(1), uint(2));
68 | }
69 | function testFailAssertEqUIntWithMsg() public {
70 | assertEq(uint(1), uint(2), "msg");
71 | }
72 |
73 | // --- assertEqDecimal (Int) ---
74 |
75 | function testAssertEqDecimalInt() public {
76 | assertEqDecimal(-1, -1, 18, "msg");
77 | assertEqDecimal(-1, -1, 18);
78 | }
79 | function testFailAssertEqDecimalInt() public {
80 | assertEqDecimal(-1, -2, 18);
81 | }
82 | function testFailAssertEqDecimalIntWithMsg() public {
83 | assertEqDecimal(-1, -2, 18, "msg");
84 | }
85 |
86 | // --- assertEqDecimal (UInt) ---
87 |
88 | function testAssertEqDecimalUInt() public {
89 | assertEqDecimal(uint(1), uint(1), 18, "msg");
90 | assertEqDecimal(uint(1), uint(1), 18);
91 | }
92 | function testFailAssertEqDecimalUInt() public {
93 | assertEqDecimal(uint(1), uint(2), 18);
94 | }
95 | function testFailAssertEqDecimalUIntWithMsg() public {
96 | assertEqDecimal(uint(1), uint(2), 18, "msg");
97 | }
98 |
99 | // --- assertGt (UInt) ---
100 |
101 | function testAssertGtUInt() public {
102 | assertGt(uint(2), uint(1), "msg");
103 | assertGt(uint(3), uint(2));
104 | }
105 | function testFailAssertGtUInt() public {
106 | assertGt(uint(1), uint(2));
107 | }
108 | function testFailAssertGtUIntWithMsg() public {
109 | assertGt(uint(1), uint(2), "msg");
110 | }
111 |
112 | // --- assertGt (Int) ---
113 |
114 | function testAssertGtInt() public {
115 | assertGt(-1, -2, "msg");
116 | assertGt(-1, -3);
117 | }
118 | function testFailAssertGtInt() public {
119 | assertGt(-2, -1);
120 | }
121 | function testFailAssertGtIntWithMsg() public {
122 | assertGt(-2, -1, "msg");
123 | }
124 |
125 | // --- assertGtDecimal (UInt) ---
126 |
127 | function testAssertGtDecimalUInt() public {
128 | assertGtDecimal(uint(2), uint(1), 18, "msg");
129 | assertGtDecimal(uint(3), uint(2), 18);
130 | }
131 | function testFailAssertGtDecimalUInt() public {
132 | assertGtDecimal(uint(1), uint(2), 18);
133 | }
134 | function testFailAssertGtDecimalUIntWithMsg() public {
135 | assertGtDecimal(uint(1), uint(2), 18, "msg");
136 | }
137 |
138 | // --- assertGtDecimal (Int) ---
139 |
140 | function testAssertGtDecimalInt() public {
141 | assertGtDecimal(-1, -2, 18, "msg");
142 | assertGtDecimal(-1, -3, 18);
143 | }
144 | function testFailAssertGtDecimalInt() public {
145 | assertGtDecimal(-2, -1, 18);
146 | }
147 | function testFailAssertGtDecimalIntWithMsg() public {
148 | assertGtDecimal(-2, -1, 18, "msg");
149 | }
150 |
151 | // --- assertGe (UInt) ---
152 |
153 | function testAssertGeUInt() public {
154 | assertGe(uint(2), uint(1), "msg");
155 | assertGe(uint(2), uint(2));
156 | }
157 | function testFailAssertGeUInt() public {
158 | assertGe(uint(1), uint(2));
159 | }
160 | function testFailAssertGeUIntWithMsg() public {
161 | assertGe(uint(1), uint(2), "msg");
162 | }
163 |
164 | // --- assertGe (Int) ---
165 |
166 | function testAssertGeInt() public {
167 | assertGe(-1, -2, "msg");
168 | assertGe(-1, -1);
169 | }
170 | function testFailAssertGeInt() public {
171 | assertGe(-2, -1);
172 | }
173 | function testFailAssertGeIntWithMsg() public {
174 | assertGe(-2, -1, "msg");
175 | }
176 |
177 | // --- assertGeDecimal (UInt) ---
178 |
179 | function testAssertGeDecimalUInt() public {
180 | assertGeDecimal(uint(2), uint(1), 18, "msg");
181 | assertGeDecimal(uint(2), uint(2), 18);
182 | }
183 | function testFailAssertGeDecimalUInt() public {
184 | assertGeDecimal(uint(1), uint(2), 18);
185 | }
186 | function testFailAssertGeDecimalUIntWithMsg() public {
187 | assertGeDecimal(uint(1), uint(2), 18, "msg");
188 | }
189 |
190 | // --- assertGeDecimal (Int) ---
191 |
192 | function testAssertGeDecimalInt() public {
193 | assertGeDecimal(-1, -2, 18, "msg");
194 | assertGeDecimal(-1, -2, 18);
195 | }
196 | function testFailAssertGeDecimalInt() public {
197 | assertGeDecimal(-2, -1, 18);
198 | }
199 | function testFailAssertGeDecimalIntWithMsg() public {
200 | assertGeDecimal(-2, -1, 18, "msg");
201 | }
202 |
203 | // --- assertLt (UInt) ---
204 |
205 | function testAssertLtUInt() public {
206 | assertLt(uint(1), uint(2), "msg");
207 | assertLt(uint(1), uint(3));
208 | }
209 | function testFailAssertLtUInt() public {
210 | assertLt(uint(2), uint(2));
211 | }
212 | function testFailAssertLtUIntWithMsg() public {
213 | assertLt(uint(3), uint(2), "msg");
214 | }
215 |
216 | // --- assertLt (Int) ---
217 |
218 | function testAssertLtInt() public {
219 | assertLt(-2, -1, "msg");
220 | assertLt(-1, 0);
221 | }
222 | function testFailAssertLtInt() public {
223 | assertLt(-1, -2);
224 | }
225 | function testFailAssertLtIntWithMsg() public {
226 | assertLt(-1, -1, "msg");
227 | }
228 |
229 | // --- assertLtDecimal (UInt) ---
230 |
231 | function testAssertLtDecimalUInt() public {
232 | assertLtDecimal(uint(1), uint(2), 18, "msg");
233 | assertLtDecimal(uint(2), uint(3), 18);
234 | }
235 | function testFailAssertLtDecimalUInt() public {
236 | assertLtDecimal(uint(1), uint(1), 18);
237 | }
238 | function testFailAssertLtDecimalUIntWithMsg() public {
239 | assertLtDecimal(uint(2), uint(1), 18, "msg");
240 | }
241 |
242 | // --- assertLtDecimal (Int) ---
243 |
244 | function testAssertLtDecimalInt() public {
245 | assertLtDecimal(-2, -1, 18, "msg");
246 | assertLtDecimal(-2, -1, 18);
247 | }
248 | function testFailAssertLtDecimalInt() public {
249 | assertLtDecimal(-2, -2, 18);
250 | }
251 | function testFailAssertLtDecimalIntWithMsg() public {
252 | assertLtDecimal(-1, -2, 18, "msg");
253 | }
254 |
255 | // --- assertLe (UInt) ---
256 |
257 | function testAssertLeUInt() public {
258 | assertLe(uint(1), uint(2), "msg");
259 | assertLe(uint(1), uint(1));
260 | }
261 | function testFailAssertLeUInt() public {
262 | assertLe(uint(4), uint(2));
263 | }
264 | function testFailAssertLeUIntWithMsg() public {
265 | assertLe(uint(3), uint(2), "msg");
266 | }
267 |
268 | // --- assertLe (Int) ---
269 |
270 | function testAssertLeInt() public {
271 | assertLe(-2, -1, "msg");
272 | assertLe(-1, -1);
273 | }
274 | function testFailAssertLeInt() public {
275 | assertLe(-1, -2);
276 | }
277 | function testFailAssertLeIntWithMsg() public {
278 | assertLe(-1, -3, "msg");
279 | }
280 |
281 | // --- assertLeDecimal (UInt) ---
282 |
283 | function testAssertLeDecimalUInt() public {
284 | assertLeDecimal(uint(1), uint(2), 18, "msg");
285 | assertLeDecimal(uint(2), uint(2), 18);
286 | }
287 | function testFailAssertLeDecimalUInt() public {
288 | assertLeDecimal(uint(1), uint(0), 18);
289 | }
290 | function testFailAssertLeDecimalUIntWithMsg() public {
291 | assertLeDecimal(uint(1), uint(0), 18, "msg");
292 | }
293 |
294 | // --- assertLeDecimal (Int) ---
295 |
296 | function testAssertLeDecimalInt() public {
297 | assertLeDecimal(-2, -1, 18, "msg");
298 | assertLeDecimal(-2, -2, 18);
299 | }
300 | function testFailAssertLeDecimalInt() public {
301 | assertLeDecimal(-2, -3, 18);
302 | }
303 | function testFailAssertLeDecimalIntWithMsg() public {
304 | assertLeDecimal(-1, -2, 18, "msg");
305 | }
306 |
307 | // --- fail override ---
308 |
309 | // ensure that fail can be overridden
310 | function fail() internal override {
311 | super.fail();
312 | }
313 | }
314 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "forge-std",
3 | "version": "1.5.2",
4 | "description": "Forge Standard Library is a collection of helpful contracts and libraries for use with Forge and Foundry.",
5 | "homepage": "https://book.getfoundry.sh/forge/forge-std",
6 | "bugs": "https://github.com/foundry-rs/forge-std/issues",
7 | "license": "(Apache-2.0 OR MIT)",
8 | "author": "Contributors to Forge Standard Library",
9 | "files": [
10 | "src/**/*"
11 | ],
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/foundry-rs/forge-std.git"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/Base.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | import {StdStorage} from "./StdStorage.sol";
5 | import {Vm, VmSafe} from "./Vm.sol";
6 |
7 | abstract contract CommonBase {
8 | // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D.
9 | address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
10 | // console.sol and console2.sol work by executing a staticcall to this address.
11 | address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67;
12 | // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38.
13 | address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller"))));
14 | // Address of the test contract, deployed by the DEFAULT_SENDER.
15 | address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f;
16 | // Deterministic deployment address of the Multicall3 contract.
17 | address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11;
18 |
19 | uint256 internal constant UINT256_MAX =
20 | 115792089237316195423570985008687907853269984665640564039457584007913129639935;
21 |
22 | Vm internal constant vm = Vm(VM_ADDRESS);
23 | StdStorage internal stdstore;
24 | }
25 |
26 | abstract contract TestBase is CommonBase {}
27 |
28 | abstract contract ScriptBase is CommonBase {
29 | // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy.
30 | address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C;
31 |
32 | VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS);
33 | }
34 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/Script.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | // 💬 ABOUT
5 | // Standard Library's default Script.
6 |
7 | // 🧩 MODULES
8 | import {ScriptBase} from "./Base.sol";
9 | import {console} from "./console.sol";
10 | import {console2} from "./console2.sol";
11 | import {StdChains} from "./StdChains.sol";
12 | import {StdCheatsSafe} from "./StdCheats.sol";
13 | import {stdJson} from "./StdJson.sol";
14 | import {stdMath} from "./StdMath.sol";
15 | import {StdStorage, stdStorageSafe} from "./StdStorage.sol";
16 | import {StdUtils} from "./StdUtils.sol";
17 | import {VmSafe} from "./Vm.sol";
18 |
19 | // 📦 BOILERPLATE
20 | import {ScriptBase} from "./Base.sol";
21 |
22 | // ⭐️ SCRIPT
23 | abstract contract Script is StdChains, StdCheatsSafe, StdUtils, ScriptBase {
24 | // Note: IS_SCRIPT() must return true.
25 | bool public IS_SCRIPT = true;
26 | }
27 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/StdError.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | // Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test
3 | pragma solidity >=0.6.2 <0.9.0;
4 |
5 | library stdError {
6 | bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01);
7 | bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11);
8 | bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12);
9 | bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21);
10 | bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22);
11 | bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31);
12 | bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32);
13 | bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41);
14 | bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51);
15 | }
16 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/StdInvariant.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | pragma experimental ABIEncoderV2;
5 |
6 | contract StdInvariant {
7 | struct FuzzSelector {
8 | address addr;
9 | bytes4[] selectors;
10 | }
11 |
12 | address[] private _excludedContracts;
13 | address[] private _excludedSenders;
14 | address[] private _targetedContracts;
15 | address[] private _targetedSenders;
16 |
17 | string[] private _excludedArtifacts;
18 | string[] private _targetedArtifacts;
19 |
20 | FuzzSelector[] private _targetedArtifactSelectors;
21 | FuzzSelector[] private _targetedSelectors;
22 |
23 | // Functions for users:
24 | // These are intended to be called in tests.
25 |
26 | function excludeContract(address newExcludedContract_) internal {
27 | _excludedContracts.push(newExcludedContract_);
28 | }
29 |
30 | function excludeSender(address newExcludedSender_) internal {
31 | _excludedSenders.push(newExcludedSender_);
32 | }
33 |
34 | function excludeArtifact(string memory newExcludedArtifact_) internal {
35 | _excludedArtifacts.push(newExcludedArtifact_);
36 | }
37 |
38 | function targetArtifact(string memory newTargetedArtifact_) internal {
39 | _targetedArtifacts.push(newTargetedArtifact_);
40 | }
41 |
42 | function targetArtifactSelector(FuzzSelector memory newTargetedArtifactSelector_) internal {
43 | _targetedArtifactSelectors.push(newTargetedArtifactSelector_);
44 | }
45 |
46 | function targetContract(address newTargetedContract_) internal {
47 | _targetedContracts.push(newTargetedContract_);
48 | }
49 |
50 | function targetSelector(FuzzSelector memory newTargetedSelector_) internal {
51 | _targetedSelectors.push(newTargetedSelector_);
52 | }
53 |
54 | function targetSender(address newTargetedSender_) internal {
55 | _targetedSenders.push(newTargetedSender_);
56 | }
57 |
58 | // Functions for forge:
59 | // These are called by forge to run invariant tests and don't need to be called in tests.
60 |
61 | function excludeArtifacts() public view returns (string[] memory excludedArtifacts_) {
62 | excludedArtifacts_ = _excludedArtifacts;
63 | }
64 |
65 | function excludeContracts() public view returns (address[] memory excludedContracts_) {
66 | excludedContracts_ = _excludedContracts;
67 | }
68 |
69 | function excludeSenders() public view returns (address[] memory excludedSenders_) {
70 | excludedSenders_ = _excludedSenders;
71 | }
72 |
73 | function targetArtifacts() public view returns (string[] memory targetedArtifacts_) {
74 | targetedArtifacts_ = _targetedArtifacts;
75 | }
76 |
77 | function targetArtifactSelectors() public view returns (FuzzSelector[] memory targetedArtifactSelectors_) {
78 | targetedArtifactSelectors_ = _targetedArtifactSelectors;
79 | }
80 |
81 | function targetContracts() public view returns (address[] memory targetedContracts_) {
82 | targetedContracts_ = _targetedContracts;
83 | }
84 |
85 | function targetSelectors() public view returns (FuzzSelector[] memory targetedSelectors_) {
86 | targetedSelectors_ = _targetedSelectors;
87 | }
88 |
89 | function targetSenders() public view returns (address[] memory targetedSenders_) {
90 | targetedSenders_ = _targetedSenders;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/StdJson.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.0 <0.9.0;
3 |
4 | pragma experimental ABIEncoderV2;
5 |
6 | import {VmSafe} from "./Vm.sol";
7 |
8 | // Helpers for parsing and writing JSON files
9 | // To parse:
10 | // ```
11 | // using stdJson for string;
12 | // string memory json = vm.readFile("some_peth");
13 | // json.parseUint("");
14 | // ```
15 | // To write:
16 | // ```
17 | // using stdJson for string;
18 | // string memory json = "deploymentArtifact";
19 | // Contract contract = new Contract();
20 | // json.serialize("contractAddress", address(contract));
21 | // json = json.serialize("deploymentTimes", uint(1));
22 | // // store the stringified JSON to the 'json' variable we have been using as a key
23 | // // as we won't need it any longer
24 | // string memory json2 = "finalArtifact";
25 | // string memory final = json2.serialize("depArtifact", json);
26 | // final.write("");
27 | // ```
28 |
29 | library stdJson {
30 | VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code")))));
31 |
32 | function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) {
33 | return vm.parseJson(json, key);
34 | }
35 |
36 | function readUint(string memory json, string memory key) internal returns (uint256) {
37 | return vm.parseJsonUint(json, key);
38 | }
39 |
40 | function readUintArray(string memory json, string memory key) internal returns (uint256[] memory) {
41 | return vm.parseJsonUintArray(json, key);
42 | }
43 |
44 | function readInt(string memory json, string memory key) internal returns (int256) {
45 | return vm.parseJsonInt(json, key);
46 | }
47 |
48 | function readIntArray(string memory json, string memory key) internal returns (int256[] memory) {
49 | return vm.parseJsonIntArray(json, key);
50 | }
51 |
52 | function readBytes32(string memory json, string memory key) internal returns (bytes32) {
53 | return vm.parseJsonBytes32(json, key);
54 | }
55 |
56 | function readBytes32Array(string memory json, string memory key) internal returns (bytes32[] memory) {
57 | return vm.parseJsonBytes32Array(json, key);
58 | }
59 |
60 | function readString(string memory json, string memory key) internal returns (string memory) {
61 | return vm.parseJsonString(json, key);
62 | }
63 |
64 | function readStringArray(string memory json, string memory key) internal returns (string[] memory) {
65 | return vm.parseJsonStringArray(json, key);
66 | }
67 |
68 | function readAddress(string memory json, string memory key) internal returns (address) {
69 | return vm.parseJsonAddress(json, key);
70 | }
71 |
72 | function readAddressArray(string memory json, string memory key) internal returns (address[] memory) {
73 | return vm.parseJsonAddressArray(json, key);
74 | }
75 |
76 | function readBool(string memory json, string memory key) internal returns (bool) {
77 | return vm.parseJsonBool(json, key);
78 | }
79 |
80 | function readBoolArray(string memory json, string memory key) internal returns (bool[] memory) {
81 | return vm.parseJsonBoolArray(json, key);
82 | }
83 |
84 | function readBytes(string memory json, string memory key) internal returns (bytes memory) {
85 | return vm.parseJsonBytes(json, key);
86 | }
87 |
88 | function readBytesArray(string memory json, string memory key) internal returns (bytes[] memory) {
89 | return vm.parseJsonBytesArray(json, key);
90 | }
91 |
92 | function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) {
93 | return vm.serializeBool(jsonKey, key, value);
94 | }
95 |
96 | function serialize(string memory jsonKey, string memory key, bool[] memory value)
97 | internal
98 | returns (string memory)
99 | {
100 | return vm.serializeBool(jsonKey, key, value);
101 | }
102 |
103 | function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) {
104 | return vm.serializeUint(jsonKey, key, value);
105 | }
106 |
107 | function serialize(string memory jsonKey, string memory key, uint256[] memory value)
108 | internal
109 | returns (string memory)
110 | {
111 | return vm.serializeUint(jsonKey, key, value);
112 | }
113 |
114 | function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) {
115 | return vm.serializeInt(jsonKey, key, value);
116 | }
117 |
118 | function serialize(string memory jsonKey, string memory key, int256[] memory value)
119 | internal
120 | returns (string memory)
121 | {
122 | return vm.serializeInt(jsonKey, key, value);
123 | }
124 |
125 | function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) {
126 | return vm.serializeAddress(jsonKey, key, value);
127 | }
128 |
129 | function serialize(string memory jsonKey, string memory key, address[] memory value)
130 | internal
131 | returns (string memory)
132 | {
133 | return vm.serializeAddress(jsonKey, key, value);
134 | }
135 |
136 | function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) {
137 | return vm.serializeBytes32(jsonKey, key, value);
138 | }
139 |
140 | function serialize(string memory jsonKey, string memory key, bytes32[] memory value)
141 | internal
142 | returns (string memory)
143 | {
144 | return vm.serializeBytes32(jsonKey, key, value);
145 | }
146 |
147 | function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) {
148 | return vm.serializeBytes(jsonKey, key, value);
149 | }
150 |
151 | function serialize(string memory jsonKey, string memory key, bytes[] memory value)
152 | internal
153 | returns (string memory)
154 | {
155 | return vm.serializeBytes(jsonKey, key, value);
156 | }
157 |
158 | function serialize(string memory jsonKey, string memory key, string memory value)
159 | internal
160 | returns (string memory)
161 | {
162 | return vm.serializeString(jsonKey, key, value);
163 | }
164 |
165 | function serialize(string memory jsonKey, string memory key, string[] memory value)
166 | internal
167 | returns (string memory)
168 | {
169 | return vm.serializeString(jsonKey, key, value);
170 | }
171 |
172 | function write(string memory jsonKey, string memory path) internal {
173 | vm.writeJson(jsonKey, path);
174 | }
175 |
176 | function write(string memory jsonKey, string memory path, string memory valueKey) internal {
177 | vm.writeJson(jsonKey, path, valueKey);
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/StdMath.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | library stdMath {
5 | int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968;
6 |
7 | function abs(int256 a) internal pure returns (uint256) {
8 | // Required or it will fail when `a = type(int256).min`
9 | if (a == INT256_MIN) {
10 | return 57896044618658097711785492504343953926634992332820282019728792003956564819968;
11 | }
12 |
13 | return uint256(a > 0 ? a : -a);
14 | }
15 |
16 | function delta(uint256 a, uint256 b) internal pure returns (uint256) {
17 | return a > b ? a - b : b - a;
18 | }
19 |
20 | function delta(int256 a, int256 b) internal pure returns (uint256) {
21 | // a and b are of the same sign
22 | // this works thanks to two's complement, the left-most bit is the sign bit
23 | if ((a ^ b) > -1) {
24 | return delta(abs(a), abs(b));
25 | }
26 |
27 | // a and b are of opposite signs
28 | return abs(a) + abs(b);
29 | }
30 |
31 | function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) {
32 | uint256 absDelta = delta(a, b);
33 |
34 | return absDelta * 1e18 / b;
35 | }
36 |
37 | function percentDelta(int256 a, int256 b) internal pure returns (uint256) {
38 | uint256 absDelta = delta(a, b);
39 | uint256 absB = abs(b);
40 |
41 | return absDelta * 1e18 / absB;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/StdUtils.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | pragma experimental ABIEncoderV2;
5 |
6 | import {IMulticall3} from "./interfaces/IMulticall3.sol";
7 | // TODO Remove import.
8 | import {VmSafe} from "./Vm.sol";
9 |
10 | abstract contract StdUtils {
11 | /*//////////////////////////////////////////////////////////////////////////
12 | CONSTANTS
13 | //////////////////////////////////////////////////////////////////////////*/
14 |
15 | IMulticall3 private constant multicall = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11);
16 | VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code")))));
17 | address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67;
18 | uint256 private constant INT256_MIN_ABS =
19 | 57896044618658097711785492504343953926634992332820282019728792003956564819968;
20 | uint256 private constant UINT256_MAX =
21 | 115792089237316195423570985008687907853269984665640564039457584007913129639935;
22 |
23 | // Used by default when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy.
24 | address private constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C;
25 |
26 | /*//////////////////////////////////////////////////////////////////////////
27 | INTERNAL FUNCTIONS
28 | //////////////////////////////////////////////////////////////////////////*/
29 |
30 | function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) {
31 | require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min.");
32 | // If x is between min and max, return x directly. This is to ensure that dictionary values
33 | // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188
34 | if (x >= min && x <= max) return x;
35 |
36 | uint256 size = max - min + 1;
37 |
38 | // If the value is 0, 1, 2, 3, warp that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side.
39 | // This helps ensure coverage of the min/max values.
40 | if (x <= 3 && size > x) return min + x;
41 | if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x);
42 |
43 | // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive.
44 | if (x > max) {
45 | uint256 diff = x - max;
46 | uint256 rem = diff % size;
47 | if (rem == 0) return max;
48 | result = min + rem - 1;
49 | } else if (x < min) {
50 | uint256 diff = min - x;
51 | uint256 rem = diff % size;
52 | if (rem == 0) return min;
53 | result = max - rem + 1;
54 | }
55 | }
56 |
57 | function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) {
58 | result = _bound(x, min, max);
59 | console2_log("Bound Result", result);
60 | }
61 |
62 | function bound(int256 x, int256 min, int256 max) internal view virtual returns (int256 result) {
63 | require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min.");
64 |
65 | // Shifting all int256 values to uint256 to use _bound function. The range of two types are:
66 | // int256 : -(2**255) ~ (2**255 - 1)
67 | // uint256: 0 ~ (2**256 - 1)
68 | // So, add 2**255, INT256_MIN_ABS to the integer values.
69 | //
70 | // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow.
71 | // So, use `~uint256(x) + 1` instead.
72 | uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS);
73 | uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS);
74 | uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS);
75 |
76 | uint256 y = _bound(_x, _min, _max);
77 |
78 | // To move it back to int256 value, subtract INT256_MIN_ABS at here.
79 | result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS);
80 | console2_log("Bound result", vm.toString(result));
81 | }
82 |
83 | function bytesToUint(bytes memory b) internal pure virtual returns (uint256) {
84 | require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32.");
85 | return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256));
86 | }
87 |
88 | /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce
89 | /// @notice adapted from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol)
90 | function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) {
91 | // forgefmt: disable-start
92 | // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0.
93 | // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it.
94 | if (nonce == 0x00) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80))));
95 | if (nonce <= 0x7f) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce))));
96 |
97 | // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length.
98 | if (nonce <= 2**8 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce))));
99 | if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce))));
100 | if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce))));
101 | // forgefmt: disable-end
102 |
103 | // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp
104 | // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce)
105 | // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex)
106 | // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex)
107 | // We assume nobody can have a nonce large enough to require more than 32 bytes.
108 | return addressFromLast20Bytes(
109 | keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce)))
110 | );
111 | }
112 |
113 | function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer)
114 | internal
115 | pure
116 | virtual
117 | returns (address)
118 | {
119 | return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash)));
120 | }
121 |
122 | /// @dev returns the address of a contract created with CREATE2 using the default CREATE2 deployer
123 | function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) internal pure returns (address) {
124 | return computeCreate2Address(salt, initCodeHash, CREATE2_FACTORY);
125 | }
126 |
127 | /// @dev returns the hash of the init code (creation code + no args) used in CREATE2 with no constructor arguments
128 | /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode
129 | function hashInitCode(bytes memory creationCode) internal pure returns (bytes32) {
130 | return hashInitCode(creationCode, "");
131 | }
132 |
133 | /// @dev returns the hash of the init code (creation code + ABI-encoded args) used in CREATE2
134 | /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode
135 | /// @param args the ABI-encoded arguments to the constructor of C
136 | function hashInitCode(bytes memory creationCode, bytes memory args) internal pure returns (bytes32) {
137 | return keccak256(abi.encodePacked(creationCode, args));
138 | }
139 |
140 | // Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses.
141 | function getTokenBalances(address token, address[] memory addresses)
142 | internal
143 | virtual
144 | returns (uint256[] memory balances)
145 | {
146 | uint256 tokenCodeSize;
147 | assembly {
148 | tokenCodeSize := extcodesize(token)
149 | }
150 | require(tokenCodeSize > 0, "StdUtils getTokenBalances(address,address[]): Token address is not a contract.");
151 |
152 | // ABI encode the aggregate call to Multicall3.
153 | uint256 length = addresses.length;
154 | IMulticall3.Call[] memory calls = new IMulticall3.Call[](length);
155 | for (uint256 i = 0; i < length; ++i) {
156 | // 0x70a08231 = bytes4("balanceOf(address)"))
157 | calls[i] = IMulticall3.Call({target: token, callData: abi.encodeWithSelector(0x70a08231, (addresses[i]))});
158 | }
159 |
160 | // Make the aggregate call.
161 | (, bytes[] memory returnData) = multicall.aggregate(calls);
162 |
163 | // ABI decode the return data and return the balances.
164 | balances = new uint256[](length);
165 | for (uint256 i = 0; i < length; ++i) {
166 | balances[i] = abi.decode(returnData[i], (uint256));
167 | }
168 | }
169 |
170 | /*//////////////////////////////////////////////////////////////////////////
171 | PRIVATE FUNCTIONS
172 | //////////////////////////////////////////////////////////////////////////*/
173 |
174 | function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) {
175 | return address(uint160(uint256(bytesValue)));
176 | }
177 |
178 | // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere.
179 |
180 | function console2_log(string memory p0, uint256 p1) private view {
181 | (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,uint256)", p0, p1));
182 | status;
183 | }
184 |
185 | function console2_log(string memory p0, string memory p1) private view {
186 | (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,string)", p0, p1));
187 | status;
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/Test.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | pragma experimental ABIEncoderV2;
5 |
6 | // 💬 ABOUT
7 | // Standard Library's default Test
8 |
9 | // 🧩 MODULES
10 | import {console} from "./console.sol";
11 | import {console2} from "./console2.sol";
12 | import {StdAssertions} from "./StdAssertions.sol";
13 | import {StdChains} from "./StdChains.sol";
14 | import {StdCheats} from "./StdCheats.sol";
15 | import {stdError} from "./StdError.sol";
16 | import {StdInvariant} from "./StdInvariant.sol";
17 | import {stdJson} from "./StdJson.sol";
18 | import {stdMath} from "./StdMath.sol";
19 | import {StdStorage, stdStorage} from "./StdStorage.sol";
20 | import {StdUtils} from "./StdUtils.sol";
21 | import {Vm} from "./Vm.sol";
22 | import {StdStyle} from "./StdStyle.sol";
23 |
24 | // 📦 BOILERPLATE
25 | import {TestBase} from "./Base.sol";
26 | import {DSTest} from "ds-test/test.sol";
27 |
28 | // ⭐️ TEST
29 | abstract contract Test is DSTest, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils, TestBase {
30 | // Note: IS_TEST() must return true.
31 | // Note: Must have failure system, https://github.com/dapphub/ds-test/blob/cd98eff28324bfac652e63a239a60632a761790b/src/test.sol#L39-L76.
32 | }
33 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/interfaces/IERC1155.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2;
3 |
4 | import "./IERC165.sol";
5 |
6 | /// @title ERC-1155 Multi Token Standard
7 | /// @dev See https://eips.ethereum.org/EIPS/eip-1155
8 | /// Note: The ERC-165 identifier for this interface is 0xd9b67a26.
9 | interface IERC1155 is IERC165 {
10 | /// @dev
11 | /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard).
12 | /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).
13 | /// - The `_from` argument MUST be the address of the holder whose balance is decreased.
14 | /// - The `_to` argument MUST be the address of the recipient whose balance is increased.
15 | /// - The `_id` argument MUST be the token type being transferred.
16 | /// - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.
17 | /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).
18 | /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).
19 | event TransferSingle(
20 | address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value
21 | );
22 |
23 | /// @dev
24 | /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard).
25 | /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).
26 | /// - The `_from` argument MUST be the address of the holder whose balance is decreased.
27 | /// - The `_to` argument MUST be the address of the recipient whose balance is increased.
28 | /// - The `_ids` argument MUST be the list of tokens being transferred.
29 | /// - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by.
30 | /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).
31 | /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).
32 | event TransferBatch(
33 | address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values
34 | );
35 |
36 | /// @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled).
37 | event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
38 |
39 | /// @dev MUST emit when the URI is updated for a token ID. URIs are defined in RFC 3986.
40 | /// The URI MUST point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema".
41 | event URI(string _value, uint256 indexed _id);
42 |
43 | /// @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call).
44 | /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard).
45 | /// - MUST revert if `_to` is the zero address.
46 | /// - MUST revert if balance of holder for token `_id` is lower than the `_value` sent.
47 | /// - MUST revert on any other error.
48 | /// - MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard).
49 | /// - After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard).
50 | /// @param _from Source address
51 | /// @param _to Target address
52 | /// @param _id ID of the token type
53 | /// @param _value Transfer amount
54 | /// @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to`
55 | function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external;
56 |
57 | /// @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call).
58 | /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard).
59 | /// - MUST revert if `_to` is the zero address.
60 | /// - MUST revert if length of `_ids` is not the same as length of `_values`.
61 | /// - MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient.
62 | /// - MUST revert on any other error.
63 | /// - MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard).
64 | /// - Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).
65 | /// - After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard).
66 | /// @param _from Source address
67 | /// @param _to Target address
68 | /// @param _ids IDs of each token type (order and length must match _values array)
69 | /// @param _values Transfer amounts per token type (order and length must match _ids array)
70 | /// @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to`
71 | function safeBatchTransferFrom(
72 | address _from,
73 | address _to,
74 | uint256[] calldata _ids,
75 | uint256[] calldata _values,
76 | bytes calldata _data
77 | ) external;
78 |
79 | /// @notice Get the balance of an account's tokens.
80 | /// @param _owner The address of the token holder
81 | /// @param _id ID of the token
82 | /// @return The _owner's balance of the token type requested
83 | function balanceOf(address _owner, uint256 _id) external view returns (uint256);
84 |
85 | /// @notice Get the balance of multiple account/token pairs
86 | /// @param _owners The addresses of the token holders
87 | /// @param _ids ID of the tokens
88 | /// @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair)
89 | function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids)
90 | external
91 | view
92 | returns (uint256[] memory);
93 |
94 | /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens.
95 | /// @dev MUST emit the ApprovalForAll event on success.
96 | /// @param _operator Address to add to the set of authorized operators
97 | /// @param _approved True if the operator is approved, false to revoke approval
98 | function setApprovalForAll(address _operator, bool _approved) external;
99 |
100 | /// @notice Queries the approval status of an operator for a given owner.
101 | /// @param _owner The owner of the tokens
102 | /// @param _operator Address of authorized operator
103 | /// @return True if the operator is approved, false if not
104 | function isApprovedForAll(address _owner, address _operator) external view returns (bool);
105 | }
106 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/interfaces/IERC165.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2;
3 |
4 | interface IERC165 {
5 | /// @notice Query if a contract implements an interface
6 | /// @param interfaceID The interface identifier, as specified in ERC-165
7 | /// @dev Interface identification is specified in ERC-165. This function
8 | /// uses less than 30,000 gas.
9 | /// @return `true` if the contract implements `interfaceID` and
10 | /// `interfaceID` is not 0xffffffff, `false` otherwise
11 | function supportsInterface(bytes4 interfaceID) external view returns (bool);
12 | }
13 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/interfaces/IERC20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2;
3 |
4 | /// @dev Interface of the ERC20 standard as defined in the EIP.
5 | /// @dev This includes the optional name, symbol, and decimals metadata.
6 | interface IERC20 {
7 | /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).
8 | event Transfer(address indexed from, address indexed to, uint256 value);
9 |
10 | /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`
11 | /// is the new allowance.
12 | event Approval(address indexed owner, address indexed spender, uint256 value);
13 |
14 | /// @notice Returns the amount of tokens in existence.
15 | function totalSupply() external view returns (uint256);
16 |
17 | /// @notice Returns the amount of tokens owned by `account`.
18 | function balanceOf(address account) external view returns (uint256);
19 |
20 | /// @notice Moves `amount` tokens from the caller's account to `to`.
21 | function transfer(address to, uint256 amount) external returns (bool);
22 |
23 | /// @notice Returns the remaining number of tokens that `spender` is allowed
24 | /// to spend on behalf of `owner`
25 | function allowance(address owner, address spender) external view returns (uint256);
26 |
27 | /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.
28 | /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
29 | function approve(address spender, uint256 amount) external returns (bool);
30 |
31 | /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.
32 | /// `amount` is then deducted from the caller's allowance.
33 | function transferFrom(address from, address to, uint256 amount) external returns (bool);
34 |
35 | /// @notice Returns the name of the token.
36 | function name() external view returns (string memory);
37 |
38 | /// @notice Returns the symbol of the token.
39 | function symbol() external view returns (string memory);
40 |
41 | /// @notice Returns the decimals places of the token.
42 | function decimals() external view returns (uint8);
43 | }
44 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/interfaces/IERC721.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2;
3 |
4 | import "./IERC165.sol";
5 |
6 | /// @title ERC-721 Non-Fungible Token Standard
7 | /// @dev See https://eips.ethereum.org/EIPS/eip-721
8 | /// Note: the ERC-165 identifier for this interface is 0x80ac58cd.
9 | interface IERC721 is IERC165 {
10 | /// @dev This emits when ownership of any NFT changes by any mechanism.
11 | /// This event emits when NFTs are created (`from` == 0) and destroyed
12 | /// (`to` == 0). Exception: during contract creation, any number of NFTs
13 | /// may be created and assigned without emitting Transfer. At the time of
14 | /// any transfer, the approved address for that NFT (if any) is reset to none.
15 | event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
16 |
17 | /// @dev This emits when the approved address for an NFT is changed or
18 | /// reaffirmed. The zero address indicates there is no approved address.
19 | /// When a Transfer event emits, this also indicates that the approved
20 | /// address for that NFT (if any) is reset to none.
21 | event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
22 |
23 | /// @dev This emits when an operator is enabled or disabled for an owner.
24 | /// The operator can manage all NFTs of the owner.
25 | event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
26 |
27 | /// @notice Count all NFTs assigned to an owner
28 | /// @dev NFTs assigned to the zero address are considered invalid, and this
29 | /// function throws for queries about the zero address.
30 | /// @param _owner An address for whom to query the balance
31 | /// @return The number of NFTs owned by `_owner`, possibly zero
32 | function balanceOf(address _owner) external view returns (uint256);
33 |
34 | /// @notice Find the owner of an NFT
35 | /// @dev NFTs assigned to zero address are considered invalid, and queries
36 | /// about them do throw.
37 | /// @param _tokenId The identifier for an NFT
38 | /// @return The address of the owner of the NFT
39 | function ownerOf(uint256 _tokenId) external view returns (address);
40 |
41 | /// @notice Transfers the ownership of an NFT from one address to another address
42 | /// @dev Throws unless `msg.sender` is the current owner, an authorized
43 | /// operator, or the approved address for this NFT. Throws if `_from` is
44 | /// not the current owner. Throws if `_to` is the zero address. Throws if
45 | /// `_tokenId` is not a valid NFT. When transfer is complete, this function
46 | /// checks if `_to` is a smart contract (code size > 0). If so, it calls
47 | /// `onERC721Received` on `_to` and throws if the return value is not
48 | /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
49 | /// @param _from The current owner of the NFT
50 | /// @param _to The new owner
51 | /// @param _tokenId The NFT to transfer
52 | /// @param data Additional data with no specified format, sent in call to `_to`
53 | function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable;
54 |
55 | /// @notice Transfers the ownership of an NFT from one address to another address
56 | /// @dev This works identically to the other function with an extra data parameter,
57 | /// except this function just sets data to "".
58 | /// @param _from The current owner of the NFT
59 | /// @param _to The new owner
60 | /// @param _tokenId The NFT to transfer
61 | function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
62 |
63 | /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
64 | /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
65 | /// THEY MAY BE PERMANENTLY LOST
66 | /// @dev Throws unless `msg.sender` is the current owner, an authorized
67 | /// operator, or the approved address for this NFT. Throws if `_from` is
68 | /// not the current owner. Throws if `_to` is the zero address. Throws if
69 | /// `_tokenId` is not a valid NFT.
70 | /// @param _from The current owner of the NFT
71 | /// @param _to The new owner
72 | /// @param _tokenId The NFT to transfer
73 | function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
74 |
75 | /// @notice Change or reaffirm the approved address for an NFT
76 | /// @dev The zero address indicates there is no approved address.
77 | /// Throws unless `msg.sender` is the current NFT owner, or an authorized
78 | /// operator of the current owner.
79 | /// @param _approved The new approved NFT controller
80 | /// @param _tokenId The NFT to approve
81 | function approve(address _approved, uint256 _tokenId) external payable;
82 |
83 | /// @notice Enable or disable approval for a third party ("operator") to manage
84 | /// all of `msg.sender`'s assets
85 | /// @dev Emits the ApprovalForAll event. The contract MUST allow
86 | /// multiple operators per owner.
87 | /// @param _operator Address to add to the set of authorized operators
88 | /// @param _approved True if the operator is approved, false to revoke approval
89 | function setApprovalForAll(address _operator, bool _approved) external;
90 |
91 | /// @notice Get the approved address for a single NFT
92 | /// @dev Throws if `_tokenId` is not a valid NFT.
93 | /// @param _tokenId The NFT to find the approved address for
94 | /// @return The approved address for this NFT, or the zero address if there is none
95 | function getApproved(uint256 _tokenId) external view returns (address);
96 |
97 | /// @notice Query if an address is an authorized operator for another address
98 | /// @param _owner The address that owns the NFTs
99 | /// @param _operator The address that acts on behalf of the owner
100 | /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
101 | function isApprovedForAll(address _owner, address _operator) external view returns (bool);
102 | }
103 |
104 | /// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
105 | interface IERC721TokenReceiver {
106 | /// @notice Handle the receipt of an NFT
107 | /// @dev The ERC721 smart contract calls this function on the recipient
108 | /// after a `transfer`. This function MAY throw to revert and reject the
109 | /// transfer. Return of other than the magic value MUST result in the
110 | /// transaction being reverted.
111 | /// Note: the contract address is always the message sender.
112 | /// @param _operator The address which called `safeTransferFrom` function
113 | /// @param _from The address which previously owned the token
114 | /// @param _tokenId The NFT identifier which is being transferred
115 | /// @param _data Additional data with no specified format
116 | /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
117 | /// unless throwing
118 | function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data)
119 | external
120 | returns (bytes4);
121 | }
122 |
123 | /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
124 | /// @dev See https://eips.ethereum.org/EIPS/eip-721
125 | /// Note: the ERC-165 identifier for this interface is 0x5b5e139f.
126 | interface IERC721Metadata is IERC721 {
127 | /// @notice A descriptive name for a collection of NFTs in this contract
128 | function name() external view returns (string memory _name);
129 |
130 | /// @notice An abbreviated name for NFTs in this contract
131 | function symbol() external view returns (string memory _symbol);
132 |
133 | /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
134 | /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
135 | /// 3986. The URI may point to a JSON file that conforms to the "ERC721
136 | /// Metadata JSON Schema".
137 | function tokenURI(uint256 _tokenId) external view returns (string memory);
138 | }
139 |
140 | /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
141 | /// @dev See https://eips.ethereum.org/EIPS/eip-721
142 | /// Note: the ERC-165 identifier for this interface is 0x780e9d63.
143 | interface IERC721Enumerable is IERC721 {
144 | /// @notice Count NFTs tracked by this contract
145 | /// @return A count of valid NFTs tracked by this contract, where each one of
146 | /// them has an assigned and queryable owner not equal to the zero address
147 | function totalSupply() external view returns (uint256);
148 |
149 | /// @notice Enumerate valid NFTs
150 | /// @dev Throws if `_index` >= `totalSupply()`.
151 | /// @param _index A counter less than `totalSupply()`
152 | /// @return The token identifier for the `_index`th NFT,
153 | /// (sort order not specified)
154 | function tokenByIndex(uint256 _index) external view returns (uint256);
155 |
156 | /// @notice Enumerate NFTs assigned to an owner
157 | /// @dev Throws if `_index` >= `balanceOf(_owner)` or if
158 | /// `_owner` is the zero address, representing invalid NFTs.
159 | /// @param _owner An address where we are interested in NFTs owned by them
160 | /// @param _index A counter less than `balanceOf(_owner)`
161 | /// @return The token identifier for the `_index`th NFT assigned to `_owner`,
162 | /// (sort order not specified)
163 | function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
164 | }
165 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/src/interfaces/IMulticall3.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | pragma experimental ABIEncoderV2;
5 |
6 | interface IMulticall3 {
7 | struct Call {
8 | address target;
9 | bytes callData;
10 | }
11 |
12 | struct Call3 {
13 | address target;
14 | bool allowFailure;
15 | bytes callData;
16 | }
17 |
18 | struct Call3Value {
19 | address target;
20 | bool allowFailure;
21 | uint256 value;
22 | bytes callData;
23 | }
24 |
25 | struct Result {
26 | bool success;
27 | bytes returnData;
28 | }
29 |
30 | function aggregate(Call[] calldata calls)
31 | external
32 | payable
33 | returns (uint256 blockNumber, bytes[] memory returnData);
34 |
35 | function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData);
36 |
37 | function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData);
38 |
39 | function blockAndAggregate(Call[] calldata calls)
40 | external
41 | payable
42 | returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData);
43 |
44 | function getBasefee() external view returns (uint256 basefee);
45 |
46 | function getBlockHash(uint256 blockNumber) external view returns (bytes32 blockHash);
47 |
48 | function getBlockNumber() external view returns (uint256 blockNumber);
49 |
50 | function getChainId() external view returns (uint256 chainid);
51 |
52 | function getCurrentBlockCoinbase() external view returns (address coinbase);
53 |
54 | function getCurrentBlockDifficulty() external view returns (uint256 difficulty);
55 |
56 | function getCurrentBlockGasLimit() external view returns (uint256 gaslimit);
57 |
58 | function getCurrentBlockTimestamp() external view returns (uint256 timestamp);
59 |
60 | function getEthBalance(address addr) external view returns (uint256 balance);
61 |
62 | function getLastBlockHash() external view returns (bytes32 blockHash);
63 |
64 | function tryAggregate(bool requireSuccess, Call[] calldata calls)
65 | external
66 | payable
67 | returns (Result[] memory returnData);
68 |
69 | function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls)
70 | external
71 | payable
72 | returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData);
73 | }
74 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/test/StdChains.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.7.0 <0.9.0;
3 |
4 | import "../src/Test.sol";
5 |
6 | contract StdChainsTest is Test {
7 | function testChainRpcInitialization() public {
8 | // RPCs specified in `foundry.toml` should be updated.
9 | assertEq(getChain(1).rpcUrl, "https://mainnet.infura.io/v3/16a8be88795540b9b3903d8de0f7baa5");
10 | assertEq(getChain("optimism_goerli").rpcUrl, "https://goerli.optimism.io/");
11 | assertEq(getChain("arbitrum_one_goerli").rpcUrl, "https://goerli-rollup.arbitrum.io/rpc/");
12 |
13 | // Environment variables should be the next fallback
14 | assertEq(getChain("arbitrum_nova").rpcUrl, "https://nova.arbitrum.io/rpc");
15 | vm.setEnv("ARBITRUM_NOVA_RPC_URL", "myoverride");
16 | assertEq(getChain("arbitrum_nova").rpcUrl, "myoverride");
17 | vm.setEnv("ARBITRUM_NOVA_RPC_URL", "https://nova.arbitrum.io/rpc");
18 |
19 | // Cannot override RPCs defined in `foundry.toml`
20 | vm.setEnv("MAINNET_RPC_URL", "myoverride2");
21 | assertEq(getChain("mainnet").rpcUrl, "https://mainnet.infura.io/v3/16a8be88795540b9b3903d8de0f7baa5");
22 |
23 | // Other RPCs should remain unchanged.
24 | assertEq(getChain(31337).rpcUrl, "http://127.0.0.1:8545");
25 | assertEq(getChain("sepolia").rpcUrl, "https://sepolia.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b");
26 | }
27 |
28 | function testRpc(string memory rpcAlias) internal {
29 | string memory rpcUrl = getChain(rpcAlias).rpcUrl;
30 | vm.createSelectFork(rpcUrl);
31 | }
32 |
33 | // Ensure we can connect to the default RPC URL for each chain.
34 | function testRpcs() public {
35 | testRpc("mainnet");
36 | testRpc("goerli");
37 | testRpc("sepolia");
38 | testRpc("optimism");
39 | testRpc("optimism_goerli");
40 | testRpc("arbitrum_one");
41 | testRpc("arbitrum_one_goerli");
42 | testRpc("arbitrum_nova");
43 | testRpc("polygon");
44 | testRpc("polygon_mumbai");
45 | testRpc("avalanche");
46 | testRpc("avalanche_fuji");
47 | testRpc("bnb_smart_chain");
48 | testRpc("bnb_smart_chain_testnet");
49 | testRpc("gnosis_chain");
50 | }
51 |
52 | function testChainNoDefault() public {
53 | vm.expectRevert("StdChains getChain(string): Chain with alias \"does_not_exist\" not found.");
54 | getChain("does_not_exist");
55 | }
56 |
57 | function testSetChainFirstFails() public {
58 | vm.expectRevert("StdChains setChain(string,ChainData): Chain ID 31337 already used by \"anvil\".");
59 | setChain("anvil2", ChainData("Anvil", 31337, "URL"));
60 | }
61 |
62 | function testChainBubbleUp() public {
63 | setChain("needs_undefined_env_var", ChainData("", 123456789, ""));
64 | vm.expectRevert(
65 | "Failed to resolve env var `UNDEFINED_RPC_URL_PLACEHOLDER` in `${UNDEFINED_RPC_URL_PLACEHOLDER}`: environment variable not found"
66 | );
67 | getChain("needs_undefined_env_var");
68 | }
69 |
70 | function testCannotSetChain_ChainIdExists() public {
71 | setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/"));
72 |
73 | vm.expectRevert('StdChains setChain(string,ChainData): Chain ID 123456789 already used by "custom_chain".');
74 |
75 | setChain("another_custom_chain", ChainData("", 123456789, ""));
76 | }
77 |
78 | function testSetChain() public {
79 | setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/"));
80 | Chain memory customChain = getChain("custom_chain");
81 | assertEq(customChain.name, "Custom Chain");
82 | assertEq(customChain.chainId, 123456789);
83 | assertEq(customChain.chainAlias, "custom_chain");
84 | assertEq(customChain.rpcUrl, "https://custom.chain/");
85 | Chain memory chainById = getChain(123456789);
86 | assertEq(chainById.name, customChain.name);
87 | assertEq(chainById.chainId, customChain.chainId);
88 | assertEq(chainById.chainAlias, customChain.chainAlias);
89 | assertEq(chainById.rpcUrl, customChain.rpcUrl);
90 | customChain.name = "Another Custom Chain";
91 | customChain.chainId = 987654321;
92 | setChain("another_custom_chain", customChain);
93 | Chain memory anotherCustomChain = getChain("another_custom_chain");
94 | assertEq(anotherCustomChain.name, "Another Custom Chain");
95 | assertEq(anotherCustomChain.chainId, 987654321);
96 | assertEq(anotherCustomChain.chainAlias, "another_custom_chain");
97 | assertEq(anotherCustomChain.rpcUrl, "https://custom.chain/");
98 | // Verify the first chain data was not overwritten
99 | chainById = getChain(123456789);
100 | assertEq(chainById.name, "Custom Chain");
101 | assertEq(chainById.chainId, 123456789);
102 | }
103 |
104 | function testSetNoEmptyAlias() public {
105 | vm.expectRevert("StdChains setChain(string,ChainData): Chain alias cannot be the empty string.");
106 | setChain("", ChainData("", 123456789, ""));
107 | }
108 |
109 | function testSetNoChainId0() public {
110 | vm.expectRevert("StdChains setChain(string,ChainData): Chain ID cannot be 0.");
111 | setChain("alias", ChainData("", 0, ""));
112 | }
113 |
114 | function testGetNoChainId0() public {
115 | vm.expectRevert("StdChains getChain(uint256): Chain ID cannot be 0.");
116 | getChain(0);
117 | }
118 |
119 | function testGetNoEmptyAlias() public {
120 | vm.expectRevert("StdChains getChain(string): Chain alias cannot be the empty string.");
121 | getChain("");
122 | }
123 |
124 | function testChainIdNotFound() public {
125 | vm.expectRevert("StdChains getChain(string): Chain with alias \"no_such_alias\" not found.");
126 | getChain("no_such_alias");
127 | }
128 |
129 | function testChainAliasNotFound() public {
130 | vm.expectRevert("StdChains getChain(uint256): Chain with ID 321 not found.");
131 | getChain(321);
132 | }
133 |
134 | function testSetChain_ExistingOne() public {
135 | setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/"));
136 | assertEq(getChain(123456789).chainId, 123456789);
137 |
138 | setChain("custom_chain", ChainData("Modified Chain", 999999999, "https://modified.chain/"));
139 | vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found.");
140 | getChain(123456789);
141 |
142 | Chain memory modifiedChain = getChain(999999999);
143 | assertEq(modifiedChain.name, "Modified Chain");
144 | assertEq(modifiedChain.chainId, 999999999);
145 | assertEq(modifiedChain.rpcUrl, "https://modified.chain/");
146 | }
147 |
148 | function testDontUseDefaultRpcUrl() public {
149 | // Should error if default RPCs flag is set to false.
150 | setFallbackToDefaultRpcUrls(false);
151 | vm.expectRevert(
152 | "Failed to get environment variable `ANVIL_RPC_URL` as type `string`: environment variable not found"
153 | );
154 | getChain(31337);
155 | vm.expectRevert(
156 | "Failed to get environment variable `SEPOLIA_RPC_URL` as type `string`: environment variable not found"
157 | );
158 | getChain("sepolia");
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/test/StdError.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.8.0 <0.9.0;
3 |
4 | import "../src/StdError.sol";
5 | import "../src/Test.sol";
6 |
7 | contract StdErrorsTest is Test {
8 | ErrorsTest test;
9 |
10 | function setUp() public {
11 | test = new ErrorsTest();
12 | }
13 |
14 | function testExpectAssertion() public {
15 | vm.expectRevert(stdError.assertionError);
16 | test.assertionError();
17 | }
18 |
19 | function testExpectArithmetic() public {
20 | vm.expectRevert(stdError.arithmeticError);
21 | test.arithmeticError(10);
22 | }
23 |
24 | function testExpectDiv() public {
25 | vm.expectRevert(stdError.divisionError);
26 | test.divError(0);
27 | }
28 |
29 | function testExpectMod() public {
30 | vm.expectRevert(stdError.divisionError);
31 | test.modError(0);
32 | }
33 |
34 | function testExpectEnum() public {
35 | vm.expectRevert(stdError.enumConversionError);
36 | test.enumConversion(1);
37 | }
38 |
39 | function testExpectEncodeStg() public {
40 | vm.expectRevert(stdError.encodeStorageError);
41 | test.encodeStgError();
42 | }
43 |
44 | function testExpectPop() public {
45 | vm.expectRevert(stdError.popError);
46 | test.pop();
47 | }
48 |
49 | function testExpectOOB() public {
50 | vm.expectRevert(stdError.indexOOBError);
51 | test.indexOOBError(1);
52 | }
53 |
54 | function testExpectMem() public {
55 | vm.expectRevert(stdError.memOverflowError);
56 | test.mem();
57 | }
58 |
59 | function testExpectIntern() public {
60 | vm.expectRevert(stdError.zeroVarError);
61 | test.intern();
62 | }
63 | }
64 |
65 | contract ErrorsTest {
66 | enum T {T1}
67 |
68 | uint256[] public someArr;
69 | bytes someBytes;
70 |
71 | function assertionError() public pure {
72 | assert(false);
73 | }
74 |
75 | function arithmeticError(uint256 a) public pure {
76 | a -= 100;
77 | }
78 |
79 | function divError(uint256 a) public pure {
80 | 100 / a;
81 | }
82 |
83 | function modError(uint256 a) public pure {
84 | 100 % a;
85 | }
86 |
87 | function enumConversion(uint256 a) public pure {
88 | T(a);
89 | }
90 |
91 | function encodeStgError() public {
92 | /// @solidity memory-safe-assembly
93 | assembly {
94 | sstore(someBytes.slot, 1)
95 | }
96 | keccak256(someBytes);
97 | }
98 |
99 | function pop() public {
100 | someArr.pop();
101 | }
102 |
103 | function indexOOBError(uint256 a) public pure {
104 | uint256[] memory t = new uint256[](0);
105 | t[a];
106 | }
107 |
108 | function mem() public pure {
109 | uint256 l = 2 ** 256 / 32;
110 | new uint256[](l);
111 | }
112 |
113 | function intern() public returns (uint256) {
114 | function(uint256) internal returns (uint256) x;
115 | x(2);
116 | return 7;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/test/StdMath.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.8.0 <0.9.0;
3 |
4 | import "../src/StdMath.sol";
5 | import "../src/Test.sol";
6 |
7 | contract StdMathTest is Test {
8 | function testGetAbs() external {
9 | assertEq(stdMath.abs(-50), 50);
10 | assertEq(stdMath.abs(50), 50);
11 | assertEq(stdMath.abs(-1337), 1337);
12 | assertEq(stdMath.abs(0), 0);
13 |
14 | assertEq(stdMath.abs(type(int256).min), (type(uint256).max >> 1) + 1);
15 | assertEq(stdMath.abs(type(int256).max), (type(uint256).max >> 1));
16 | }
17 |
18 | function testGetAbs_Fuzz(int256 a) external {
19 | uint256 manualAbs = getAbs(a);
20 |
21 | uint256 abs = stdMath.abs(a);
22 |
23 | assertEq(abs, manualAbs);
24 | }
25 |
26 | function testGetDelta_Uint() external {
27 | assertEq(stdMath.delta(uint256(0), uint256(0)), 0);
28 | assertEq(stdMath.delta(uint256(0), uint256(1337)), 1337);
29 | assertEq(stdMath.delta(uint256(0), type(uint64).max), type(uint64).max);
30 | assertEq(stdMath.delta(uint256(0), type(uint128).max), type(uint128).max);
31 | assertEq(stdMath.delta(uint256(0), type(uint256).max), type(uint256).max);
32 |
33 | assertEq(stdMath.delta(0, uint256(0)), 0);
34 | assertEq(stdMath.delta(1337, uint256(0)), 1337);
35 | assertEq(stdMath.delta(type(uint64).max, uint256(0)), type(uint64).max);
36 | assertEq(stdMath.delta(type(uint128).max, uint256(0)), type(uint128).max);
37 | assertEq(stdMath.delta(type(uint256).max, uint256(0)), type(uint256).max);
38 |
39 | assertEq(stdMath.delta(1337, uint256(1337)), 0);
40 | assertEq(stdMath.delta(type(uint256).max, type(uint256).max), 0);
41 | assertEq(stdMath.delta(5000, uint256(1250)), 3750);
42 | }
43 |
44 | function testGetDelta_Uint_Fuzz(uint256 a, uint256 b) external {
45 | uint256 manualDelta;
46 | if (a > b) {
47 | manualDelta = a - b;
48 | } else {
49 | manualDelta = b - a;
50 | }
51 |
52 | uint256 delta = stdMath.delta(a, b);
53 |
54 | assertEq(delta, manualDelta);
55 | }
56 |
57 | function testGetDelta_Int() external {
58 | assertEq(stdMath.delta(int256(0), int256(0)), 0);
59 | assertEq(stdMath.delta(int256(0), int256(1337)), 1337);
60 | assertEq(stdMath.delta(int256(0), type(int64).max), type(uint64).max >> 1);
61 | assertEq(stdMath.delta(int256(0), type(int128).max), type(uint128).max >> 1);
62 | assertEq(stdMath.delta(int256(0), type(int256).max), type(uint256).max >> 1);
63 |
64 | assertEq(stdMath.delta(0, int256(0)), 0);
65 | assertEq(stdMath.delta(1337, int256(0)), 1337);
66 | assertEq(stdMath.delta(type(int64).max, int256(0)), type(uint64).max >> 1);
67 | assertEq(stdMath.delta(type(int128).max, int256(0)), type(uint128).max >> 1);
68 | assertEq(stdMath.delta(type(int256).max, int256(0)), type(uint256).max >> 1);
69 |
70 | assertEq(stdMath.delta(-0, int256(0)), 0);
71 | assertEq(stdMath.delta(-1337, int256(0)), 1337);
72 | assertEq(stdMath.delta(type(int64).min, int256(0)), (type(uint64).max >> 1) + 1);
73 | assertEq(stdMath.delta(type(int128).min, int256(0)), (type(uint128).max >> 1) + 1);
74 | assertEq(stdMath.delta(type(int256).min, int256(0)), (type(uint256).max >> 1) + 1);
75 |
76 | assertEq(stdMath.delta(int256(0), -0), 0);
77 | assertEq(stdMath.delta(int256(0), -1337), 1337);
78 | assertEq(stdMath.delta(int256(0), type(int64).min), (type(uint64).max >> 1) + 1);
79 | assertEq(stdMath.delta(int256(0), type(int128).min), (type(uint128).max >> 1) + 1);
80 | assertEq(stdMath.delta(int256(0), type(int256).min), (type(uint256).max >> 1) + 1);
81 |
82 | assertEq(stdMath.delta(1337, int256(1337)), 0);
83 | assertEq(stdMath.delta(type(int256).max, type(int256).max), 0);
84 | assertEq(stdMath.delta(type(int256).min, type(int256).min), 0);
85 | assertEq(stdMath.delta(type(int256).min, type(int256).max), type(uint256).max);
86 | assertEq(stdMath.delta(5000, int256(1250)), 3750);
87 | }
88 |
89 | function testGetDelta_Int_Fuzz(int256 a, int256 b) external {
90 | uint256 absA = getAbs(a);
91 | uint256 absB = getAbs(b);
92 | uint256 absDelta = absA > absB ? absA - absB : absB - absA;
93 |
94 | uint256 manualDelta;
95 | if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) {
96 | manualDelta = absDelta;
97 | }
98 | // (a < 0 && b >= 0) || (a >= 0 && b < 0)
99 | else {
100 | manualDelta = absA + absB;
101 | }
102 |
103 | uint256 delta = stdMath.delta(a, b);
104 |
105 | assertEq(delta, manualDelta);
106 | }
107 |
108 | function testGetPercentDelta_Uint() external {
109 | assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18);
110 | assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18);
111 | assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18);
112 | assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18);
113 |
114 | assertEq(stdMath.percentDelta(1337, uint256(1337)), 0);
115 | assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0);
116 | assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18);
117 | assertEq(stdMath.percentDelta(2500, uint256(2500)), 0);
118 | assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18);
119 | assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18);
120 |
121 | vm.expectRevert(stdError.divisionError);
122 | stdMath.percentDelta(uint256(1), 0);
123 | }
124 |
125 | function testGetPercentDelta_Uint_Fuzz(uint192 a, uint192 b) external {
126 | vm.assume(b != 0);
127 | uint256 manualDelta;
128 | if (a > b) {
129 | manualDelta = a - b;
130 | } else {
131 | manualDelta = b - a;
132 | }
133 |
134 | uint256 manualPercentDelta = manualDelta * 1e18 / b;
135 | uint256 percentDelta = stdMath.percentDelta(a, b);
136 |
137 | assertEq(percentDelta, manualPercentDelta);
138 | }
139 |
140 | function testGetPercentDelta_Int() external {
141 | assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18);
142 | assertEq(stdMath.percentDelta(int256(0), -1337), 1e18);
143 | assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18);
144 | assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18);
145 | assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18);
146 | assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18);
147 | assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18);
148 | assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18);
149 |
150 | assertEq(stdMath.percentDelta(1337, int256(1337)), 0);
151 | assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0);
152 | assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0);
153 |
154 | assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down
155 | assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down
156 | assertEq(stdMath.percentDelta(0, int256(2500)), 1e18);
157 | assertEq(stdMath.percentDelta(2500, int256(2500)), 0);
158 | assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18);
159 | assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18);
160 |
161 | vm.expectRevert(stdError.divisionError);
162 | stdMath.percentDelta(int256(1), 0);
163 | }
164 |
165 | function testGetPercentDelta_Int_Fuzz(int192 a, int192 b) external {
166 | vm.assume(b != 0);
167 | uint256 absA = getAbs(a);
168 | uint256 absB = getAbs(b);
169 | uint256 absDelta = absA > absB ? absA - absB : absB - absA;
170 |
171 | uint256 manualDelta;
172 | if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) {
173 | manualDelta = absDelta;
174 | }
175 | // (a < 0 && b >= 0) || (a >= 0 && b < 0)
176 | else {
177 | manualDelta = absA + absB;
178 | }
179 |
180 | uint256 manualPercentDelta = manualDelta * 1e18 / absB;
181 | uint256 percentDelta = stdMath.percentDelta(a, b);
182 |
183 | assertEq(percentDelta, manualPercentDelta);
184 | }
185 |
186 | /*//////////////////////////////////////////////////////////////////////////
187 | HELPERS
188 | //////////////////////////////////////////////////////////////////////////*/
189 |
190 | function getAbs(int256 a) private pure returns (uint256) {
191 | if (a < 0) {
192 | return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a);
193 | }
194 |
195 | return uint256(a);
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/test/StdStyle.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.7.0 <0.9.0;
3 |
4 | import "../src/Test.sol";
5 |
6 | contract StdStyleTest is Test {
7 | function testStyleColor() public view {
8 | console2.log(StdStyle.red("StdStyle.red String Test"));
9 | console2.log(StdStyle.red(uint256(10e18)));
10 | console2.log(StdStyle.red(int256(-10e18)));
11 | console2.log(StdStyle.red(true));
12 | console2.log(StdStyle.red(address(0)));
13 | console2.log(StdStyle.redBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
14 | console2.log(StdStyle.redBytes32("StdStyle.redBytes32"));
15 | console2.log(StdStyle.green("StdStyle.green String Test"));
16 | console2.log(StdStyle.green(uint256(10e18)));
17 | console2.log(StdStyle.green(int256(-10e18)));
18 | console2.log(StdStyle.green(true));
19 | console2.log(StdStyle.green(address(0)));
20 | console2.log(StdStyle.greenBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
21 | console2.log(StdStyle.greenBytes32("StdStyle.greenBytes32"));
22 | console2.log(StdStyle.yellow("StdStyle.yellow String Test"));
23 | console2.log(StdStyle.yellow(uint256(10e18)));
24 | console2.log(StdStyle.yellow(int256(-10e18)));
25 | console2.log(StdStyle.yellow(true));
26 | console2.log(StdStyle.yellow(address(0)));
27 | console2.log(StdStyle.yellowBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
28 | console2.log(StdStyle.yellowBytes32("StdStyle.yellowBytes32"));
29 | console2.log(StdStyle.blue("StdStyle.blue String Test"));
30 | console2.log(StdStyle.blue(uint256(10e18)));
31 | console2.log(StdStyle.blue(int256(-10e18)));
32 | console2.log(StdStyle.blue(true));
33 | console2.log(StdStyle.blue(address(0)));
34 | console2.log(StdStyle.blueBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
35 | console2.log(StdStyle.blueBytes32("StdStyle.blueBytes32"));
36 | console2.log(StdStyle.magenta("StdStyle.magenta String Test"));
37 | console2.log(StdStyle.magenta(uint256(10e18)));
38 | console2.log(StdStyle.magenta(int256(-10e18)));
39 | console2.log(StdStyle.magenta(true));
40 | console2.log(StdStyle.magenta(address(0)));
41 | console2.log(StdStyle.magentaBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
42 | console2.log(StdStyle.magentaBytes32("StdStyle.magentaBytes32"));
43 | console2.log(StdStyle.cyan("StdStyle.cyan String Test"));
44 | console2.log(StdStyle.cyan(uint256(10e18)));
45 | console2.log(StdStyle.cyan(int256(-10e18)));
46 | console2.log(StdStyle.cyan(true));
47 | console2.log(StdStyle.cyan(address(0)));
48 | console2.log(StdStyle.cyanBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
49 | console2.log(StdStyle.cyanBytes32("StdStyle.cyanBytes32"));
50 | }
51 |
52 | function testStyleFontWeight() public view {
53 | console2.log(StdStyle.bold("StdStyle.bold String Test"));
54 | console2.log(StdStyle.bold(uint256(10e18)));
55 | console2.log(StdStyle.bold(int256(-10e18)));
56 | console2.log(StdStyle.bold(address(0)));
57 | console2.log(StdStyle.bold(true));
58 | console2.log(StdStyle.boldBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
59 | console2.log(StdStyle.boldBytes32("StdStyle.boldBytes32"));
60 | console2.log(StdStyle.dim("StdStyle.dim String Test"));
61 | console2.log(StdStyle.dim(uint256(10e18)));
62 | console2.log(StdStyle.dim(int256(-10e18)));
63 | console2.log(StdStyle.dim(address(0)));
64 | console2.log(StdStyle.dim(true));
65 | console2.log(StdStyle.dimBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
66 | console2.log(StdStyle.dimBytes32("StdStyle.dimBytes32"));
67 | console2.log(StdStyle.italic("StdStyle.italic String Test"));
68 | console2.log(StdStyle.italic(uint256(10e18)));
69 | console2.log(StdStyle.italic(int256(-10e18)));
70 | console2.log(StdStyle.italic(address(0)));
71 | console2.log(StdStyle.italic(true));
72 | console2.log(StdStyle.italicBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
73 | console2.log(StdStyle.italicBytes32("StdStyle.italicBytes32"));
74 | console2.log(StdStyle.underline("StdStyle.underline String Test"));
75 | console2.log(StdStyle.underline(uint256(10e18)));
76 | console2.log(StdStyle.underline(int256(-10e18)));
77 | console2.log(StdStyle.underline(address(0)));
78 | console2.log(StdStyle.underline(true));
79 | console2.log(StdStyle.underlineBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
80 | console2.log(StdStyle.underlineBytes32("StdStyle.underlineBytes32"));
81 | console2.log(StdStyle.inverse("StdStyle.inverse String Test"));
82 | console2.log(StdStyle.inverse(uint256(10e18)));
83 | console2.log(StdStyle.inverse(int256(-10e18)));
84 | console2.log(StdStyle.inverse(address(0)));
85 | console2.log(StdStyle.inverse(true));
86 | console2.log(StdStyle.inverseBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D"));
87 | console2.log(StdStyle.inverseBytes32("StdStyle.inverseBytes32"));
88 | }
89 |
90 | function testStyleCombined() public view {
91 | console2.log(StdStyle.red(StdStyle.bold("Red Bold String Test")));
92 | console2.log(StdStyle.green(StdStyle.dim(uint256(10e18))));
93 | console2.log(StdStyle.yellow(StdStyle.italic(int256(-10e18))));
94 | console2.log(StdStyle.blue(StdStyle.underline(address(0))));
95 | console2.log(StdStyle.magenta(StdStyle.inverse(true)));
96 | }
97 |
98 | function testStyleCustom() public view {
99 | console2.log(h1("Custom Style 1"));
100 | console2.log(h2("Custom Style 2"));
101 | }
102 |
103 | function h1(string memory a) private pure returns (string memory) {
104 | return StdStyle.cyan(StdStyle.inverse(StdStyle.bold(a)));
105 | }
106 |
107 | function h2(string memory a) private pure returns (string memory) {
108 | return StdStyle.magenta(StdStyle.bold(StdStyle.underline(a)));
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/test/compilation/CompilationScript.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | pragma experimental ABIEncoderV2;
5 |
6 | import "../../src/Script.sol";
7 |
8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing
9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207
10 | contract CompilationScript is Script {}
11 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/test/compilation/CompilationScriptBase.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | pragma experimental ABIEncoderV2;
5 |
6 | import "../../src/Script.sol";
7 |
8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing
9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207
10 | contract CompilationScriptBase is ScriptBase {}
11 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/test/compilation/CompilationTest.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | pragma experimental ABIEncoderV2;
5 |
6 | import "../../src/Test.sol";
7 |
8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing
9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207
10 | contract CompilationTest is Test {}
11 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/test/compilation/CompilationTestBase.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.6.2 <0.9.0;
3 |
4 | pragma experimental ABIEncoderV2;
5 |
6 | import "../../src/Test.sol";
7 |
8 | // The purpose of this contract is to benchmark compilation time to avoid accidentally introducing
9 | // a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207
10 | contract CompilationTestBase is TestBase {}
11 |
--------------------------------------------------------------------------------
/contracts/project/lib/forge-std/test/fixtures/broadcast.log.json:
--------------------------------------------------------------------------------
1 | {
2 | "transactions": [
3 | {
4 | "hash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f",
5 | "type": "CALL",
6 | "contractName": "Test",
7 | "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512",
8 | "function": "multiple_arguments(uint256,address,uint256[]):(uint256)",
9 | "arguments": ["1", "0000000000000000000000000000000000001337", "[3,4]"],
10 | "tx": {
11 | "type": "0x02",
12 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
13 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512",
14 | "gas": "0x73b9",
15 | "value": "0x0",
16 | "data": "0x23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004",
17 | "nonce": "0x3",
18 | "accessList": []
19 | }
20 | },
21 | {
22 | "hash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298",
23 | "type": "CALL",
24 | "contractName": "Test",
25 | "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512",
26 | "function": "inc():(uint256)",
27 | "arguments": [],
28 | "tx": {
29 | "type": "0x02",
30 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
31 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512",
32 | "gas": "0xdcb2",
33 | "value": "0x0",
34 | "data": "0x371303c0",
35 | "nonce": "0x4",
36 | "accessList": []
37 | }
38 | },
39 | {
40 | "hash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c",
41 | "type": "CALL",
42 | "contractName": "Test",
43 | "contractAddress": "0x7c6b4bbe207d642d98d5c537142d85209e585087",
44 | "function": "t(uint256):(uint256)",
45 | "arguments": ["1"],
46 | "tx": {
47 | "type": "0x02",
48 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
49 | "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087",
50 | "gas": "0x8599",
51 | "value": "0x0",
52 | "data": "0xafe29f710000000000000000000000000000000000000000000000000000000000000001",
53 | "nonce": "0x5",
54 | "accessList": []
55 | }
56 | }
57 | ],
58 | "receipts": [
59 | {
60 | "transactionHash": "0x481dc86e40bba90403c76f8e144aa9ff04c1da2164299d0298573835f0991181",
61 | "transactionIndex": "0x0",
62 | "blockHash": "0xef0730448490304e5403be0fa8f8ce64f118e9adcca60c07a2ae1ab921d748af",
63 | "blockNumber": "0x1",
64 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
65 | "to": null,
66 | "cumulativeGasUsed": "0x13f3a",
67 | "gasUsed": "0x13f3a",
68 | "contractAddress": "0x5fbdb2315678afecb367f032d93f642f64180aa3",
69 | "logs": [],
70 | "status": "0x1",
71 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
72 | "effectiveGasPrice": "0xee6b2800"
73 | },
74 | {
75 | "transactionHash": "0x6a187183545b8a9e7f1790e847139379bf5622baff2cb43acf3f5c79470af782",
76 | "transactionIndex": "0x0",
77 | "blockHash": "0xf3acb96a90071640c2a8c067ae4e16aad87e634ea8d8bbbb5b352fba86ba0148",
78 | "blockNumber": "0x2",
79 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
80 | "to": null,
81 | "cumulativeGasUsed": "0x45d80",
82 | "gasUsed": "0x45d80",
83 | "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512",
84 | "logs": [],
85 | "status": "0x1",
86 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
87 | "effectiveGasPrice": "0xee6b2800"
88 | },
89 | {
90 | "transactionHash": "0x064ad173b4867bdef2fb60060bbdaf01735fbf10414541ea857772974e74ea9d",
91 | "transactionIndex": "0x0",
92 | "blockHash": "0x8373d02109d3ee06a0225f23da4c161c656ccc48fe0fcee931d325508ae73e58",
93 | "blockNumber": "0x3",
94 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
95 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c",
96 | "cumulativeGasUsed": "0x45feb",
97 | "gasUsed": "0x45feb",
98 | "contractAddress": null,
99 | "logs": [],
100 | "status": "0x1",
101 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
102 | "effectiveGasPrice": "0xee6b2800"
103 | },
104 | {
105 | "transactionHash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f",
106 | "transactionIndex": "0x0",
107 | "blockHash": "0x16712fae5c0e18f75045f84363fb6b4d9a9fe25e660c4ce286833a533c97f629",
108 | "blockNumber": "0x4",
109 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
110 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512",
111 | "cumulativeGasUsed": "0x5905",
112 | "gasUsed": "0x5905",
113 | "contractAddress": null,
114 | "logs": [],
115 | "status": "0x1",
116 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
117 | "effectiveGasPrice": "0xee6b2800"
118 | },
119 | {
120 | "transactionHash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298",
121 | "transactionIndex": "0x0",
122 | "blockHash": "0x156b88c3eb9a1244ba00a1834f3f70de735b39e3e59006dd03af4fe7d5480c11",
123 | "blockNumber": "0x5",
124 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
125 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512",
126 | "cumulativeGasUsed": "0xa9c4",
127 | "gasUsed": "0xa9c4",
128 | "contractAddress": null,
129 | "logs": [],
130 | "status": "0x1",
131 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
132 | "effectiveGasPrice": "0xee6b2800"
133 | },
134 | {
135 | "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c",
136 | "transactionIndex": "0x0",
137 | "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb",
138 | "blockNumber": "0x6",
139 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
140 | "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087",
141 | "cumulativeGasUsed": "0x66c5",
142 | "gasUsed": "0x66c5",
143 | "contractAddress": null,
144 | "logs": [
145 | {
146 | "address": "0x7c6b4bbe207d642d98d5c537142d85209e585087",
147 | "topics": [
148 | "0x0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b"
149 | ],
150 | "data": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000",
151 | "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb",
152 | "blockNumber": "0x6",
153 | "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c",
154 | "transactionIndex": "0x1",
155 | "logIndex": "0x0",
156 | "transactionLogIndex": "0x0",
157 | "removed": false
158 | }
159 | ],
160 | "status": "0x1",
161 | "logsBloom": "0x00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100",
162 | "effectiveGasPrice": "0xee6b2800"
163 | },
164 | {
165 | "transactionHash": "0x11fbb10230c168ca1e36a7e5c69a6dbcd04fd9e64ede39d10a83e36ee8065c16",
166 | "transactionIndex": "0x0",
167 | "blockHash": "0xf1e0ed2eda4e923626ec74621006ed50b3fc27580dc7b4cf68a07ca77420e29c",
168 | "blockNumber": "0x7",
169 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
170 | "to": "0x0000000000000000000000000000000000001337",
171 | "cumulativeGasUsed": "0x5208",
172 | "gasUsed": "0x5208",
173 | "contractAddress": null,
174 | "logs": [],
175 | "status": "0x1",
176 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
177 | "effectiveGasPrice": "0xee6b2800"
178 | }
179 | ],
180 | "libraries": [
181 | "src/Broadcast.t.sol:F:0x5fbdb2315678afecb367f032d93f642f64180aa3"
182 | ],
183 | "pending": [],
184 | "path": "broadcast/Broadcast.t.sol/31337/run-latest.json",
185 | "returns": {},
186 | "timestamp": 1655140035
187 | }
188 |
--------------------------------------------------------------------------------
/contracts/project/script/DeployMocks.s.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: UNLICENSED
2 | pragma solidity ^0.8.13;
3 |
4 | import "forge-std/Script.sol";
5 | import { MockDisputeGameFactory } from "src/MockDisputeGameFactory.sol";
6 | import { MockAttestationDisputeGame } from "src/MockAttestationDisputeGame.sol";
7 |
8 | /// @notice This script deploys the mock dispute game factory.
9 | contract DeployMocks is Script {
10 | function run() public {
11 | // Deploy the mock dispute game factory
12 | vm.broadcast();
13 | MockDisputeGameFactory mock = new MockDisputeGameFactory();
14 |
15 | // Write the address to the devnet ENV
16 | console.log(string.concat("ENV Variable: export OP_CHALLENGER_DGF=\"", vm.toString(address(mock)), "\""));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/contracts/project/src/IDisputeGame.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.19;
3 |
4 | /// @title IDisputeGame
5 | /// @notice An interface for the dispute game contract.
6 | interface IDisputeGame {
7 | function challenge(bytes calldata _signature) external;
8 | }
--------------------------------------------------------------------------------
/contracts/project/src/IL2OutputOracle.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.17;
3 |
4 | /// @title L2OutputOracle Interface
5 | /// @notice An interface for the L2OutputOracle contract.
6 | interface IL2OutputOracle {
7 | /// @notice Deletes the L2 output for the given parameter.
8 | function deleteL2Outputs(uint256) external;
9 |
10 | /// @notice OutputProposal represents a commitment to the L2 state. The timestamp is the L1
11 | /// timestamp that the output root is posted. This timestamp is used to verify that the
12 | /// finalization period has passed since the output root was submitted.
13 | /// @custom:field outputRoot Hash of the L2 output.
14 | /// @custom:field timestamp Timestamp of the L1 block that the output root was submitted in.
15 | /// @custom:field l2BlockNumber L2 block number that the output corresponds to.
16 | struct OutputProposal {
17 | bytes32 outputRoot;
18 | uint128 timestamp;
19 | uint128 l2BlockNumber;
20 | }
21 |
22 | /// @notice Emitted when an output is proposed.
23 | /// @param outputRoot The output root.
24 | /// @param l2OutputIndex The index of the output in the l2Outputs array.
25 | /// @param l2BlockNumber The L2 block number of the output root.
26 | /// @param l1Timestamp The L1 timestamp when proposed.
27 | event OutputProposed(
28 | bytes32 indexed outputRoot,
29 | uint256 indexed l2OutputIndex,
30 | uint256 indexed l2BlockNumber,
31 | uint256 l1Timestamp
32 | );
33 |
34 | /// @notice Returns the L2 output for the given parameter.
35 | function getL2Output(uint256 _l2OutputIndex) external view returns (OutputProposal memory);
36 | }
37 |
--------------------------------------------------------------------------------
/contracts/project/src/MockAttestationDisputeGame.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.19;
3 |
4 | import { Claim } from "./Types.sol";
5 |
6 | import { IDisputeGame } from "./IDisputeGame.sol";
7 |
8 | /// @title MockAttestationDisputeGame
9 | /// @dev Tests the `op-challenger` on a local devnet.
10 | contract MockAttestationDisputeGame is IDisputeGame {
11 | Claim public immutable ROOT_CLAIM;
12 | uint256 public immutable L2_BLOCK_NUMBER;
13 | mapping(address => bool) public challenges;
14 |
15 | constructor(Claim _rootClaim, uint256 l2BlockNumber, address _creator) {
16 | ROOT_CLAIM = _rootClaim;
17 | L2_BLOCK_NUMBER = l2BlockNumber;
18 | challenges[_creator] = true;
19 | }
20 |
21 | function challenge(bytes calldata _signature) external {
22 | challenges[msg.sender] = true;
23 | _signature;
24 | }
25 | }
--------------------------------------------------------------------------------
/contracts/project/src/MockDisputeGameFactory.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.19;
3 |
4 | import { GameType, Claim } from "./Types.sol";
5 | import { IDisputeGame } from "./IDisputeGame.sol";
6 | import { MockAttestationDisputeGame } from "./MockAttestationDisputeGame.sol";
7 |
8 | /// @title MockDisputeGameFactory
9 | /// @dev Tests the `op-challenger` on a local devnet.
10 | contract MockDisputeGameFactory {
11 | mapping(bytes32 => IDisputeGame) internal innerGames;
12 |
13 | event DisputeGameCreated(address indexed disputeProxy, GameType indexed gameType, Claim indexed rootClaim);
14 |
15 | /// @notice `games` is a mapping that maps the hash of `gameType ++ rootClaim ++ extraData` to the deployed
16 | /// `DisputeGame` clone.
17 | /// @dev `++` equates to concatenation.
18 | /// @param gameType The type of the DisputeGame - used to decide the proxy implementation
19 | /// @param rootClaim The root claim of the DisputeGame.
20 | /// @param extraData Any extra data that should be provided to the created dispute game.
21 | /// @return _proxy The clone of the `DisputeGame` created with the given parameters. address(0) if nonexistent.
22 | function games(GameType gameType, Claim rootClaim, bytes calldata extraData)
23 | external
24 | view
25 | returns (IDisputeGame _proxy) {
26 | _proxy = innerGames[keccak256(abi.encodePacked(gameType, rootClaim, extraData))];
27 | }
28 |
29 | /// @notice Creates a new DisputeGame proxy contract.
30 | /// @param gameType The type of the DisputeGame - used to decide the proxy implementation
31 | /// @param rootClaim The root claim of the DisputeGame.
32 | /// @param extraData Any extra data that should be provided to the created dispute game.
33 | function create(GameType gameType, Claim rootClaim, bytes calldata extraData) external returns (MockAttestationDisputeGame mock) {
34 | uint256 l2BlockNumber = abi.decode(extraData, (uint256));
35 | mock = new MockAttestationDisputeGame(rootClaim, l2BlockNumber, msg.sender);
36 | emit DisputeGameCreated(address(mock), gameType, rootClaim);
37 | innerGames[keccak256(abi.encodePacked(gameType, rootClaim, extraData))] = IDisputeGame(address(mock));
38 | }
39 | }
--------------------------------------------------------------------------------
/contracts/project/src/Types.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.19;
3 |
4 | /// @notice The type of proof system being used.
5 | enum GameType {
6 | FAULT,
7 | VALIDITY,
8 | ATTESTATION
9 | }
10 |
11 | /// @notice A `Claim` type represents a 32 byte hash or other unique identifier.
12 | /// @dev For the `FAULT` `GameType`, this will be a root of the merklized state of the fault proof
13 | /// program at the end of the state transition.
14 | /// For the `ATTESTATION` `GameType`, this will be an output root.
15 | type Claim is bytes32;
16 |
--------------------------------------------------------------------------------
/contracts/project/test/Mocks.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: UNLICENSED
2 | pragma solidity ^0.8.13;
3 |
4 | import "forge-std/Test.sol";
5 |
6 | import { GameType, Claim } from "src/Types.sol";
7 | import { MockDisputeGameFactory } from "src/MockDisputeGameFactory.sol";
8 |
9 | contract MocksTest is Test {
10 | MockDisputeGameFactory factory;
11 |
12 | event DisputeGameCreated(address indexed disputeProxy, GameType indexed gameType, Claim indexed rootClaim);
13 |
14 | function setUp() public {
15 | factory = new MockDisputeGameFactory();
16 | }
17 |
18 | function testCreate(uint8 gameType, Claim rootClaim, uint256 l2BlockNumber) external {
19 | vm.assume(gameType <= 2);
20 | vm.expectEmit(false, true, true, true);
21 | emit DisputeGameCreated(address(0), GameType(gameType), rootClaim);
22 | factory.create(GameType(gameType), rootClaim, abi.encodePacked(l2BlockNumber));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/docker/.env.devnet:
--------------------------------------------------------------------------------
1 | # Devnet Specs: https://github.com/ethereum-optimism/optimism/blob/develop/specs/meta/devnet.md
2 |
3 | # The L1 Ethereum RPC URL
4 | OP_CHALLENGER_L1_ETH_RPC="ws://127.0.0.1:8546"
5 |
6 | # The Rollup Node RPC URL
7 | OP_CHALLENGER_ROLLUP_RPC="http://localhost:7545"
8 |
9 | # The L2OutputOracle Contract Address
10 | OP_CHALLENGER_L2OO_ADDRESS="0x6900000000000000000000000000000000000000"
11 |
12 | # Dispute Game Factory Contract Address
13 | OP_CHALLENGER_DGF_ADDRESS="0x020000000fc854958a2400c973d2523146343d31"
14 |
15 | # The Private Key of the account that will be used to send challenge transactions
16 | OP_CHALLENGER_PRIVATE_KEY="54FE7CFBA40FE5ABBF9595B06C79C3BDF68FB4C7D8A78A7F53ACC771CEB029C5"
17 |
18 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM --platform=$BUILDPLATFORM golang:1.19.0-alpine3.15 as builder
2 |
3 | ARG VERSION=v0.0.0
4 |
5 | RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
6 |
7 | COPY ./op-challenger /app/op-challenger
8 | COPY ./op-bindings /app/op-bindings
9 | COPY ./op-node /app/op-node
10 | COPY ./op-service /app/op-service
11 | COPY ./op-signer /app/op-signer
12 |
13 | WORKDIR /app/op-challenger
14 |
15 | RUN go mod download
16 |
17 | RUN make op-challenger
18 |
19 | FROM alpine:3.15
20 |
21 | COPY --from=builder /app/op-challenger/bin/op-challenger /usr/local/bin
22 |
23 | CMD ["op-challenger"]
24 |
--------------------------------------------------------------------------------
/docker/start_devnet.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | # Set up environment variables
4 | source ./docker/.env.devnet
5 |
6 | # Pre-funded devnet account
7 | DEVNET_SPONSOR="ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
8 |
9 | # Boot up the devnet
10 | # Before booting, we make sure that we have a fresh devnet
11 | (cd $MONOREPO_DIR && make devnet-down && make devnet-clean && L2OO_ADDRESS="0x6900000000000000000000000000000000000000" make devnet-up)
12 |
13 | # Fetching balance of the sponsor
14 | echo "----------------------------------------------------------------"
15 | echo " - Fetching balance of the sponsor"
16 | cast balance 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://localhost:8545
17 | echo "----------------------------------------------------------------"
18 |
19 | # Send some ETH to the deployer
20 | echo "----------------------------------------------------------------"
21 | echo " - Sending some ETH to the deployer"
22 | cast send --rpc-url http://localhost:8545 --private-key $DEVNET_SPONSOR 0xAF00b1C8A848BE9aFb28860BA0dC27b02fE3BD4d --value 100000000000000000000
23 | echo "----------------------------------------------------------------"
24 |
25 | # Deploy the mock dispute game contract
26 | echo "----------------------------------------------------------------"
27 | echo " - Deploying the mock dispute game contract"
28 | (cd ./contracts/project && forge script script/DeployMocks.s.sol --rpc-url http://localhost:8545 --private-key $OP_CHALLENGER_PRIVATE_KEY --broadcast)
29 | echo "----------------------------------------------------------------"
30 |
31 | echo "----------------------------------------------------------------"
32 | echo " All done! You can now run the \`op-challenger\`."
33 | echo "----------------------------------------------------------------"
34 |
--------------------------------------------------------------------------------
/flags/flags.go:
--------------------------------------------------------------------------------
1 | package flags
2 |
3 | import (
4 | "github.com/urfave/cli"
5 |
6 | opservice "github.com/ethereum-optimism/optimism/op-service"
7 | oplog "github.com/ethereum-optimism/optimism/op-service/log"
8 | opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
9 | oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
10 | oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
11 | )
12 |
13 | const envVarPrefix = "OP_CHALLENGER"
14 |
15 | var (
16 | // Required Flags
17 | L1EthRpcFlag = cli.StringFlag{
18 | Name: "l1-eth-rpc",
19 | Usage: "HTTP provider URL for L1.",
20 | Required: true,
21 | EnvVar: opservice.PrefixEnvVar(envVarPrefix, "L1_ETH_RPC"),
22 | }
23 | RollupRpcFlag = cli.StringFlag{
24 | Name: "rollup-rpc",
25 | Usage: "HTTP provider URL for the rollup node.",
26 | Required: true,
27 | EnvVar: opservice.PrefixEnvVar(envVarPrefix, "ROLLUP_RPC"),
28 | }
29 | L2OOAddressFlag = cli.StringFlag{
30 | Name: "l2oo-address",
31 | Usage: "Address of the L2OutputOracle contract.",
32 | Required: true,
33 | EnvVar: opservice.PrefixEnvVar(envVarPrefix, "L2OO_ADDRESS"),
34 | }
35 | DGFAddressFlag = cli.StringFlag{
36 | Name: "dgf-address",
37 | Usage: "Address of the DisputeGameFactory contract.",
38 | Required: true,
39 | EnvVar: opservice.PrefixEnvVar(envVarPrefix, "DGF_ADDRESS"),
40 | }
41 | PrivateKeyFlag = cli.StringFlag{
42 | Name: "private-key",
43 | Usage: "The private key to use with the service. Must not be used with mnemonic.",
44 | Required: true,
45 | EnvVar: opservice.PrefixEnvVar(envVarPrefix, "PRIVATE_KEY"),
46 | }
47 | )
48 |
49 | var cliFlags = []cli.Flag{
50 | L1EthRpcFlag,
51 | RollupRpcFlag,
52 | L2OOAddressFlag,
53 | DGFAddressFlag,
54 | PrivateKeyFlag,
55 | }
56 |
57 | func init() {
58 | cliFlags = append(cliFlags, oprpc.CLIFlags(envVarPrefix)...)
59 |
60 | cliFlags = append(cliFlags, oplog.CLIFlags(envVarPrefix)...)
61 | cliFlags = append(cliFlags, opmetrics.CLIFlags(envVarPrefix)...)
62 | cliFlags = append(cliFlags, oppprof.CLIFlags(envVarPrefix)...)
63 | cliFlags = append(cliFlags, TxManagerCLIFlags(envVarPrefix)...)
64 |
65 | Flags = cliFlags
66 | }
67 |
68 | // Flags contains the list of configuration options available to the binary.
69 | var Flags []cli.Flag
70 |
--------------------------------------------------------------------------------
/flags/txmgr.go:
--------------------------------------------------------------------------------
1 | package flags
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "fmt"
7 | "time"
8 |
9 | opservice "github.com/ethereum-optimism/optimism/op-service"
10 | opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
11 | txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
12 | client "github.com/ethereum-optimism/optimism/op-signer/client"
13 | ethclient "github.com/ethereum/go-ethereum/ethclient"
14 | log "github.com/ethereum/go-ethereum/log"
15 | cli "github.com/urfave/cli"
16 | )
17 |
18 | const (
19 | // Duplicated L1 RPC flag
20 | L1RPCFlagName = "l1-eth-rpc"
21 | // Key Management Flags (also have op-signer client flags)
22 | MnemonicFlagName = "mnemonic"
23 | HDPathFlagName = "hd-path"
24 | PrivateKeyFlagName = "private-key"
25 | // TxMgr Flags (new + legacy + some shared flags)
26 | NumConfirmationsFlagName = "num-confirmations"
27 | SafeAbortNonceTooLowCountFlagName = "safe-abort-nonce-too-low-count"
28 | ResubmissionTimeoutFlagName = "resubmission-timeout"
29 | NetworkTimeoutFlagName = "network-timeout"
30 | TxSendTimeoutFlagName = "txmgr.send-timeout"
31 | TxNotInMempoolTimeoutFlagName = "txmgr.not-in-mempool-timeout"
32 | ReceiptQueryIntervalFlagName = "txmgr.receipt-query-interval"
33 | )
34 |
35 | var (
36 | SequencerHDPathFlag = cli.StringFlag{
37 | Name: "sequencer-hd-path",
38 | Usage: "DEPRECATED: The HD path used to derive the sequencer wallet from the " +
39 | "mnemonic. The mnemonic flag must also be set.",
40 | EnvVar: "OP_BATCHER_SEQUENCER_HD_PATH",
41 | }
42 | L2OutputHDPathFlag = cli.StringFlag{
43 | Name: "l2-output-hd-path",
44 | Usage: "DEPRECATED:The HD path used to derive the l2output wallet from the " +
45 | "mnemonic. The mnemonic flag must also be set.",
46 | EnvVar: "OP_PROPOSER_L2_OUTPUT_HD_PATH",
47 | }
48 | )
49 |
50 | func TxManagerCLIFlags(envPrefix string) []cli.Flag {
51 | return append([]cli.Flag{
52 | cli.StringFlag{
53 | Name: MnemonicFlagName,
54 | Usage: "The mnemonic used to derive the wallets for either the service",
55 | EnvVar: opservice.PrefixEnvVar(envPrefix, "MNEMONIC"),
56 | },
57 | cli.StringFlag{
58 | Name: HDPathFlagName,
59 | Usage: "The HD path used to derive the sequencer wallet from the mnemonic. The mnemonic flag must also be set.",
60 | EnvVar: opservice.PrefixEnvVar(envPrefix, "HD_PATH"),
61 | },
62 | SequencerHDPathFlag,
63 | L2OutputHDPathFlag,
64 | // cli.StringFlag{
65 | // Name: "private-key",
66 | // Usage: "The private key to use with the service. Must not be used with mnemonic.",
67 | // EnvVar: opservice.PrefixEnvVar(envPrefix, "PRIVATE_KEY"),
68 | // },
69 | cli.Uint64Flag{
70 | Name: NumConfirmationsFlagName,
71 | Usage: "Number of confirmations which we will wait after sending a transaction",
72 | Value: 10,
73 | EnvVar: opservice.PrefixEnvVar(envPrefix, "NUM_CONFIRMATIONS"),
74 | },
75 | cli.Uint64Flag{
76 | Name: SafeAbortNonceTooLowCountFlagName,
77 | Usage: "Number of ErrNonceTooLow observations required to give up on a tx at a particular nonce without receiving confirmation",
78 | Value: 3,
79 | EnvVar: opservice.PrefixEnvVar(envPrefix, "SAFE_ABORT_NONCE_TOO_LOW_COUNT"),
80 | },
81 | cli.DurationFlag{
82 | Name: ResubmissionTimeoutFlagName,
83 | Usage: "Duration we will wait before resubmitting a transaction to L1",
84 | Value: 48 * time.Second,
85 | EnvVar: opservice.PrefixEnvVar(envPrefix, "RESUBMISSION_TIMEOUT"),
86 | },
87 | cli.DurationFlag{
88 | Name: NetworkTimeoutFlagName,
89 | Usage: "Timeout for all network operations",
90 | Value: 2 * time.Second,
91 | EnvVar: opservice.PrefixEnvVar(envPrefix, "NETWORK_TIMEOUT"),
92 | },
93 | cli.DurationFlag{
94 | Name: TxSendTimeoutFlagName,
95 | Usage: "Timeout for sending transactions. If 0 it is disabled.",
96 | Value: 0,
97 | EnvVar: opservice.PrefixEnvVar(envPrefix, "TXMGR_TX_SEND_TIMEOUT"),
98 | },
99 | cli.DurationFlag{
100 | Name: TxNotInMempoolTimeoutFlagName,
101 | Usage: "Timeout for aborting a tx send if the tx does not make it to the mempool.",
102 | Value: 2 * time.Minute,
103 | EnvVar: opservice.PrefixEnvVar(envPrefix, "TXMGR_TX_NOT_IN_MEMPOOL_TIMEOUT"),
104 | },
105 | cli.DurationFlag{
106 | Name: ReceiptQueryIntervalFlagName,
107 | Usage: "Frequency to poll for receipts",
108 | Value: 12 * time.Second,
109 | EnvVar: opservice.PrefixEnvVar(envPrefix, "TXMGR_RECEIPT_QUERY_INTERVAL"),
110 | },
111 | }, client.CLIFlags(envPrefix)...)
112 | }
113 |
114 | type TxManagerCLIConfig struct {
115 | L1RPCURL string
116 | Mnemonic string
117 | HDPath string
118 | SequencerHDPath string
119 | L2OutputHDPath string
120 | PrivateKey string
121 | SignerCLIConfig client.CLIConfig
122 | NumConfirmations uint64
123 | SafeAbortNonceTooLowCount uint64
124 | ResubmissionTimeout time.Duration
125 | ReceiptQueryInterval time.Duration
126 | NetworkTimeout time.Duration
127 | TxSendTimeout time.Duration
128 | TxNotInMempoolTimeout time.Duration
129 | }
130 |
131 | func (m TxManagerCLIConfig) Check() error {
132 | if m.L1RPCURL == "" {
133 | return errors.New("must provide a L1 RPC url")
134 | }
135 | if m.NumConfirmations == 0 {
136 | return errors.New("NumConfirmations must not be 0")
137 | }
138 | if m.NetworkTimeout == 0 {
139 | return errors.New("must provide NetworkTimeout")
140 | }
141 | if m.ResubmissionTimeout == 0 {
142 | return errors.New("must provide ResubmissionTimeout")
143 | }
144 | if m.ReceiptQueryInterval == 0 {
145 | return errors.New("must provide ReceiptQueryInterval")
146 | }
147 | if m.TxNotInMempoolTimeout == 0 {
148 | return errors.New("must provide TxNotInMempoolTimeout")
149 | }
150 | if m.SafeAbortNonceTooLowCount == 0 {
151 | return errors.New("SafeAbortNonceTooLowCount must not be 0")
152 | }
153 | if err := m.SignerCLIConfig.Check(); err != nil {
154 | return err
155 | }
156 | return nil
157 | }
158 |
159 | func ReadTxManagerCLIConfig(ctx *cli.Context) TxManagerCLIConfig {
160 | return TxManagerCLIConfig{
161 | L1RPCURL: ctx.GlobalString(L1RPCFlagName),
162 | Mnemonic: ctx.GlobalString(MnemonicFlagName),
163 | HDPath: ctx.GlobalString(HDPathFlagName),
164 | SequencerHDPath: ctx.GlobalString(SequencerHDPathFlag.Name),
165 | L2OutputHDPath: ctx.GlobalString(L2OutputHDPathFlag.Name),
166 | PrivateKey: ctx.GlobalString(PrivateKeyFlagName),
167 | SignerCLIConfig: client.ReadCLIConfig(ctx),
168 | NumConfirmations: ctx.GlobalUint64(NumConfirmationsFlagName),
169 | SafeAbortNonceTooLowCount: ctx.GlobalUint64(SafeAbortNonceTooLowCountFlagName),
170 | ResubmissionTimeout: ctx.GlobalDuration(ResubmissionTimeoutFlagName),
171 | ReceiptQueryInterval: ctx.GlobalDuration(ReceiptQueryIntervalFlagName),
172 | NetworkTimeout: ctx.GlobalDuration(NetworkTimeoutFlagName),
173 | TxSendTimeout: ctx.GlobalDuration(TxSendTimeoutFlagName),
174 | TxNotInMempoolTimeout: ctx.GlobalDuration(TxNotInMempoolTimeoutFlagName),
175 | }
176 | }
177 |
178 | func NewTxManagerConfig(cfg TxManagerCLIConfig, l log.Logger) (txmgr.Config, error) {
179 | if err := cfg.Check(); err != nil {
180 | return txmgr.Config{}, fmt.Errorf("invalid config: %w", err)
181 | }
182 |
183 | ctx, cancel := context.WithTimeout(context.Background(), cfg.NetworkTimeout)
184 | defer cancel()
185 | l1, err := ethclient.DialContext(ctx, cfg.L1RPCURL)
186 | if err != nil {
187 | return txmgr.Config{}, fmt.Errorf("could not dial eth client: %w", err)
188 | }
189 |
190 | ctx, cancel = context.WithTimeout(context.Background(), cfg.NetworkTimeout)
191 | defer cancel()
192 | chainID, err := l1.ChainID(ctx)
193 | if err != nil {
194 | return txmgr.Config{}, fmt.Errorf("could not dial fetch L1 chain ID: %w", err)
195 | }
196 |
197 | // Allow backwards compatible ways of specifying the HD path
198 | hdPath := cfg.HDPath
199 | if hdPath == "" && cfg.SequencerHDPath != "" {
200 | hdPath = cfg.SequencerHDPath
201 | } else if hdPath == "" && cfg.L2OutputHDPath != "" {
202 | hdPath = cfg.L2OutputHDPath
203 | }
204 |
205 | signerFactory, from, err := opcrypto.SignerFactoryFromConfig(l, cfg.PrivateKey, cfg.Mnemonic, hdPath, cfg.SignerCLIConfig)
206 | if err != nil {
207 | return txmgr.Config{}, fmt.Errorf("could not init signer: %w", err)
208 | }
209 |
210 | return txmgr.Config{
211 | ResubmissionTimeout: cfg.ResubmissionTimeout,
212 | ChainID: chainID,
213 | NetworkTimeout: cfg.NetworkTimeout,
214 | ReceiptQueryInterval: cfg.ReceiptQueryInterval,
215 | NumConfirmations: cfg.NumConfirmations,
216 | SafeAbortNonceTooLowCount: cfg.SafeAbortNonceTooLowCount,
217 | Signer: signerFactory(chainID),
218 | From: from,
219 | }, nil
220 | }
221 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/refcell/op-challenger
2 |
3 | go 1.19
4 |
5 | replace github.com/ethereum/go-ethereum v1.11.4 => github.com/ethereum-optimism/op-geth v1.11.2-de8c5df46.0.20230324105532-555b76f39878
6 |
7 | require (
8 | github.com/ethereum-optimism/optimism v1.0.1
9 | github.com/ethereum/go-ethereum v1.11.4
10 | github.com/prometheus/client_golang v1.14.0
11 | github.com/urfave/cli v1.22.9
12 | )
13 |
14 | require (
15 | github.com/DataDog/zstd v1.5.2 // indirect
16 | github.com/VictoriaMetrics/fastcache v1.10.0 // indirect
17 | github.com/benbjohnson/clock v1.3.0 // indirect
18 | github.com/beorn7/perks v1.0.1 // indirect
19 | github.com/btcsuite/btcd v0.23.3 // indirect
20 | github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
21 | github.com/btcsuite/btcd/btcutil v1.1.0 // indirect
22 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
23 | github.com/cespare/xxhash/v2 v2.2.0 // indirect
24 | github.com/cockroachdb/errors v1.9.1 // indirect
25 | github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
26 | github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect
27 | github.com/cockroachdb/redact v1.1.3 // indirect
28 | github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
29 | github.com/deckarep/golang-set/v2 v2.1.0 // indirect
30 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
31 | github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 // indirect
32 | github.com/fjl/memsize v0.0.1 // indirect
33 | github.com/fsnotify/fsnotify v1.6.0 // indirect
34 | github.com/getsentry/sentry-go v0.18.0 // indirect
35 | github.com/go-ole/go-ole v1.2.6 // indirect
36 | github.com/go-stack/stack v1.8.1 // indirect
37 | github.com/gofrs/flock v0.8.1 // indirect
38 | github.com/gogo/protobuf v1.3.2 // indirect
39 | github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
40 | github.com/golang/protobuf v1.5.2 // indirect
41 | github.com/golang/snappy v0.0.4 // indirect
42 | github.com/google/uuid v1.3.0 // indirect
43 | github.com/gorilla/websocket v1.5.0 // indirect
44 | github.com/hashicorp/errwrap v1.1.0 // indirect
45 | github.com/hashicorp/go-bexpr v0.1.11 // indirect
46 | github.com/hashicorp/go-multierror v1.1.1 // indirect
47 | github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
48 | github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
49 | github.com/holiman/uint256 v1.2.0 // indirect
50 | github.com/huin/goupnp v1.1.0 // indirect
51 | github.com/ipfs/go-cid v0.3.2 // indirect
52 | github.com/jackpal/go-nat-pmp v1.0.2 // indirect
53 | github.com/klauspost/compress v1.15.15 // indirect
54 | github.com/klauspost/cpuid/v2 v2.2.3 // indirect
55 | github.com/kr/pretty v0.3.1 // indirect
56 | github.com/kr/text v0.2.0 // indirect
57 | github.com/libp2p/go-buffer-pool v0.1.0 // indirect
58 | github.com/libp2p/go-flow-metrics v0.1.0 // indirect
59 | github.com/libp2p/go-libp2p v0.25.1 // indirect
60 | github.com/libp2p/go-libp2p-pubsub v0.9.0 // indirect
61 | github.com/mattn/go-colorable v0.1.13 // indirect
62 | github.com/mattn/go-isatty v0.0.17 // indirect
63 | github.com/mattn/go-runewidth v0.0.14 // indirect
64 | github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
65 | github.com/minio/sha256-simd v1.0.0 // indirect
66 | github.com/mitchellh/mapstructure v1.5.0 // indirect
67 | github.com/mitchellh/pointerstructure v1.2.1 // indirect
68 | github.com/mr-tron/base58 v1.2.0 // indirect
69 | github.com/multiformats/go-base32 v0.1.0 // indirect
70 | github.com/multiformats/go-base36 v0.2.0 // indirect
71 | github.com/multiformats/go-multiaddr v0.8.0 // indirect
72 | github.com/multiformats/go-multibase v0.1.1 // indirect
73 | github.com/multiformats/go-multicodec v0.8.1 // indirect
74 | github.com/multiformats/go-multihash v0.2.1 // indirect
75 | github.com/multiformats/go-multistream v0.4.1 // indirect
76 | github.com/multiformats/go-varint v0.0.7 // indirect
77 | github.com/olekukonko/tablewriter v0.0.5 // indirect
78 | github.com/pkg/errors v0.9.1 // indirect
79 | github.com/prometheus/client_model v0.3.0 // indirect
80 | github.com/prometheus/common v0.39.0 // indirect
81 | github.com/prometheus/procfs v0.9.0 // indirect
82 | github.com/rivo/uniseg v0.4.3 // indirect
83 | github.com/rogpeppe/go-internal v1.9.0 // indirect
84 | github.com/rs/cors v1.8.2 // indirect
85 | github.com/russross/blackfriday/v2 v2.1.0 // indirect
86 | github.com/shirou/gopsutil v3.21.11+incompatible // indirect
87 | github.com/spaolacci/murmur3 v1.1.0 // indirect
88 | github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
89 | github.com/tklauser/go-sysconf v0.3.10 // indirect
90 | github.com/tklauser/numcpus v0.5.0 // indirect
91 | github.com/tyler-smith/go-bip39 v1.1.0 // indirect
92 | github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa // indirect
93 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
94 | github.com/yusufpapurcu/wmi v1.2.2 // indirect
95 | golang.org/x/crypto v0.6.0 // indirect
96 | golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb // indirect
97 | golang.org/x/sync v0.1.0 // indirect
98 | golang.org/x/sys v0.5.0 // indirect
99 | golang.org/x/term v0.5.0 // indirect
100 | golang.org/x/text v0.7.0 // indirect
101 | golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
102 | google.golang.org/protobuf v1.28.1 // indirect
103 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
104 | lukechampine.com/blake3 v1.1.7 // indirect
105 | )
106 |
--------------------------------------------------------------------------------
/metrics/metrics.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "context"
5 | "math/big"
6 |
7 | common "github.com/ethereum/go-ethereum/common"
8 | types "github.com/ethereum/go-ethereum/core/types"
9 | ethclient "github.com/ethereum/go-ethereum/ethclient"
10 | log "github.com/ethereum/go-ethereum/log"
11 | params "github.com/ethereum/go-ethereum/params"
12 | prometheus "github.com/prometheus/client_golang/prometheus"
13 |
14 | eth "github.com/ethereum-optimism/optimism/op-node/eth"
15 | opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
16 | )
17 |
18 | const Namespace = "op_challenger"
19 |
20 | type Metricer interface {
21 | RecordInfo(version string)
22 | RecordUp()
23 |
24 | // Records all L1 and L2 block events
25 | opmetrics.RefMetricer
26 |
27 | RecordValidOutput(l2ref eth.L2BlockRef)
28 | RecordInvalidOutput(l2ref eth.L2BlockRef)
29 | RecordChallengeSent(l2BlockNumber *big.Int, outputRoot common.Hash)
30 |
31 | RecordDisputeGameCreated(l2BlockNumber *big.Int, outputRoot common.Hash, contract common.Address)
32 |
33 | RecordL1GasFee(receipt *types.Receipt)
34 | }
35 |
36 | type Metrics struct {
37 | ns string
38 | registry *prometheus.Registry
39 | factory opmetrics.Factory
40 |
41 | opmetrics.RefMetrics
42 |
43 | TxL1GasFee prometheus.Gauge
44 |
45 | Info prometheus.GaugeVec
46 | Up prometheus.Gauge
47 | }
48 |
49 | var _ Metricer = (*Metrics)(nil)
50 |
51 | func NewMetrics(procName string) *Metrics {
52 | if procName == "" {
53 | procName = "default"
54 | }
55 | ns := Namespace + "_" + procName
56 |
57 | registry := opmetrics.NewRegistry()
58 | factory := opmetrics.With(registry)
59 |
60 | return &Metrics{
61 | ns: ns,
62 | registry: registry,
63 | factory: factory,
64 |
65 | RefMetrics: opmetrics.MakeRefMetrics(ns, factory),
66 |
67 | TxL1GasFee: factory.NewGauge(prometheus.GaugeOpts{
68 | Namespace: ns,
69 | Name: "tx_fee_gwei",
70 | Help: "L1 gas fee for transactions in GWEI",
71 | Subsystem: "txmgr",
72 | }),
73 |
74 | Info: *factory.NewGaugeVec(prometheus.GaugeOpts{
75 | Namespace: ns,
76 | Name: "info",
77 | Help: "Pseudo-metric tracking version and config info",
78 | }, []string{
79 | "version",
80 | }),
81 | Up: factory.NewGauge(prometheus.GaugeOpts{
82 | Namespace: ns,
83 | Name: "up",
84 | Help: "1 if the op-challenger has finished starting up",
85 | }),
86 | }
87 | }
88 |
89 | func (m *Metrics) Serve(ctx context.Context, host string, port int) error {
90 | return opmetrics.ListenAndServe(ctx, m.registry, host, port)
91 | }
92 |
93 | func (m *Metrics) StartBalanceMetrics(ctx context.Context,
94 | l log.Logger, client *ethclient.Client, account common.Address) {
95 | opmetrics.LaunchBalanceMetrics(ctx, l, m.registry, m.ns, client, account)
96 | }
97 |
98 | // RecordInfo sets a pseudo-metric that contains versioning and
99 | // config info for the op-challenger.
100 | func (m *Metrics) RecordInfo(version string) {
101 | m.Info.WithLabelValues(version).Set(1)
102 | }
103 |
104 | // RecordUp sets the up metric to 1.
105 | func (m *Metrics) RecordUp() {
106 | prometheus.MustRegister()
107 | m.Up.Set(1)
108 | }
109 |
110 | const (
111 | ValidOutput = "valid_output"
112 | InvalidOutput = "invalid_output"
113 | OutputChallenged = "output_challenged"
114 | )
115 |
116 | // RecordValidOutput should be called when a valid output is found
117 | func (m *Metrics) RecordValidOutput(l2ref eth.L2BlockRef) {
118 | m.RecordL2Ref(ValidOutput, l2ref)
119 | }
120 |
121 | // RecordInvalidOutput should be called when an invalid output is found
122 | func (m *Metrics) RecordInvalidOutput(l2ref eth.L2BlockRef) {
123 | m.RecordL2Ref(InvalidOutput, l2ref)
124 | }
125 |
126 | func (m *Metrics) RecordChallengeSent(l2BlockNumber *big.Int, outputRoot common.Hash) {
127 | m.RecordL2Ref(OutputChallenged, eth.L2BlockRef{
128 | Number: l2BlockNumber.Uint64(),
129 | Hash: outputRoot,
130 | })
131 | }
132 |
133 | func (m *Metrics) RecordDisputeGameCreated(l2BlockNumber *big.Int, outputRoot common.Hash, contract common.Address) {
134 | // TODO: record dg created here
135 | }
136 |
137 | // RecordL1GasFee records the L1 gas fee for a transaction
138 | func (m *Metrics) RecordL1GasFee(receipt *types.Receipt) {
139 | m.TxL1GasFee.Set(float64(receipt.EffectiveGasPrice.Uint64() * receipt.GasUsed / params.GWei))
140 | }
141 |
--------------------------------------------------------------------------------
/metrics/noop.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "math/big"
5 |
6 | eth "github.com/ethereum-optimism/optimism/op-node/eth"
7 | opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
8 | common "github.com/ethereum/go-ethereum/common"
9 | types "github.com/ethereum/go-ethereum/core/types"
10 | )
11 |
12 | type noopMetrics struct {
13 | opmetrics.NoopRefMetrics
14 | }
15 |
16 | var NoopMetrics Metricer = new(noopMetrics)
17 |
18 | func (*noopMetrics) RecordInfo(version string) {}
19 | func (*noopMetrics) RecordUp() {}
20 |
21 | func (*noopMetrics) RecordValidOutput(l2ref eth.L2BlockRef) {}
22 | func (*noopMetrics) RecordInvalidOutput(l2ref eth.L2BlockRef) {}
23 | func (*noopMetrics) RecordChallengeSent(l2BlockNumber *big.Int, outputRoot common.Hash) {}
24 | func (*noopMetrics) RecordL1GasFee(receipt *types.Receipt) {}
25 | func (*noopMetrics) RecordDisputeGameCreated(l2BlockNumber *big.Int, outputRoot common.Hash, contract common.Address) {
26 | }
27 |
--------------------------------------------------------------------------------
/public/op-challenger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/refcell/op-challenger/8dd3e70189c270e7b99dd250b124cccc10424538/public/op-challenger.png
--------------------------------------------------------------------------------
/public/op-gopher.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/refcell/op-challenger/8dd3e70189c270e7b99dd250b124cccc10424538/public/op-gopher.jpeg
--------------------------------------------------------------------------------
/public/op-gopher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/refcell/op-challenger/8dd3e70189c270e7b99dd250b124cccc10424538/public/op-gopher.png
--------------------------------------------------------------------------------