├── .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 • [![ci](https://github.com/refcell/op-challenger/actions/workflows/ci.yml/badge.svg?label=ci)](https://github.com/refcell/op-challenger/actions/workflows/ci.yml) ![license](https://img.shields.io/badge/License-MIT-green.svg?label=license) ![maintainer](https://img.shields.io/badge/maintainer-refcell-orange.svg?label=maintainer) 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 • [![CI status](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml/badge.svg)](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 --------------------------------------------------------------------------------