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

Merge branch 'develop' into aj/enable-p2p-sync

parents 5feb52c0 d1979617
---
'@eth-optimism/chain-mon': patch
---
Update import path for artifact
---
'@eth-optimism/contracts-bedrock': minor
---
Migrate contracts periphery into bedrock
This diff is collapsed.
...@@ -2,11 +2,9 @@ ...@@ -2,11 +2,9 @@
/packages/common-ts @ethereum-optimism/typescript-reviewers /packages/common-ts @ethereum-optimism/typescript-reviewers
/packages/contracts @ethereum-optimism/contract-reviewers /packages/contracts @ethereum-optimism/contract-reviewers
/packages/contracts-bedrock @ethereum-optimism/contract-reviewers /packages/contracts-bedrock @ethereum-optimism/contract-reviewers
/packages/contracts-periphery @ethereum-optimism/contract-reviewers
/packages/core-utils @ethereum-optimism/legacy-reviewers /packages/core-utils @ethereum-optimism/legacy-reviewers
/packages/chain-mon @smartcontracts /packages/chain-mon @smartcontracts
/packages/fault-detector @ethereum-optimism/devxpod /packages/fault-detector @ethereum-optimism/devxpod
/packages/hardhat-deploy-config @ethereum-optimism/legacy-reviewers
/packages/replica-healthcheck @ethereum-optimism/legacy-reviewers /packages/replica-healthcheck @ethereum-optimism/legacy-reviewers
/packages/sdk @ethereum-optimism/devxpod /packages/sdk @ethereum-optimism/devxpod
/packages/atst @ethereum-optimism/devxpod /packages/atst @ethereum-optimism/devxpod
......
...@@ -17,11 +17,6 @@ dist ...@@ -17,11 +17,6 @@ dist
artifacts artifacts
cache cache
packages/contracts-periphery/coverage*
packages/contracts-periphery/@openzeppelin*
packages/contracts-periphery/hardhat*
packages/contracts-periphery/forge-artifacts*
packages/contracts-bedrock/deployments/devnetL1 packages/contracts-bedrock/deployments/devnetL1
packages/contracts-bedrock/deployments/anvil packages/contracts-bedrock/deployments/anvil
......
[submodule "packages/contracts-periphery/lib/multicall"]
path = packages/contracts-periphery/lib/multicall
url = https://github.com/mds1/multicall
[submodule "lib/multicall"]
branch = v3.1.0
...@@ -16,10 +16,6 @@ ...@@ -16,10 +16,6 @@
"directory": "packages/contracts", "directory": "packages/contracts",
"changeProcessCWD": true "changeProcessCWD": true
}, },
{
"directory": "packages/contracts-periphery",
"changeProcessCWD": true
},
{ {
"directory": "packages/chain-mon", "directory": "packages/chain-mon",
"changeProcessCWD": true "changeProcessCWD": true
......
...@@ -52,7 +52,6 @@ Refer to the Directory Structure section below to understand which packages are ...@@ -52,7 +52,6 @@ Refer to the Directory Structure section below to understand which packages are
├── <a href="./packages">packages</a> ├── <a href="./packages">packages</a>
│ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript │ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript
│ ├── <a href="./packages/contracts-bedrock">contracts-bedrock</a>: Bedrock smart contracts. │ ├── <a href="./packages/contracts-bedrock">contracts-bedrock</a>: Bedrock smart contracts.
│ ├── <a href="./packages/contracts-periphery">contracts-periphery</a>: Peripheral contracts for Optimism
│ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier │ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier
│ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services │ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services
│ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults │ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults
...@@ -79,7 +78,6 @@ Refer to the Directory Structure section below to understand which packages are ...@@ -79,7 +78,6 @@ Refer to the Directory Structure section below to understand which packages are
~~ Pre-BEDROCK ~~ ~~ Pre-BEDROCK ~~
├── <a href="./packages">packages</a> ├── <a href="./packages">packages</a>
│ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript │ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript
│ ├── <a href="./packages/contracts-periphery">contracts-periphery</a>: Peripheral contracts for Optimism
│ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier │ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier
│ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services │ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services
│ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults │ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults
......
...@@ -33,7 +33,6 @@ flag_management: ...@@ -33,7 +33,6 @@ flag_management:
- name: common-ts-tests - name: common-ts-tests
- name: contracts-tests - name: contracts-tests
- name: core-utils-tests - name: core-utils-tests
- name: contracts-periphery-tests
- name: dtl-tests - name: dtl-tests
- name: chain-mon-tests - name: chain-mon-tests
- name: fault-detector-tests - name: fault-detector-tests
......
SHELL := /bin/bash SHELL := /bin/bash
pkg := bindings pkg := bindings
contracts-dir := ../packages/contracts-bedrock monorepo-base := $(shell dirname $(realpath .))
contracts-dir := $(monorepo-base)/packages/contracts-bedrock
all: version mkdir bindings all: version mkdir bindings
...@@ -17,11 +18,12 @@ bindings: compile bindings-build ...@@ -17,11 +18,12 @@ bindings: compile bindings-build
bindings-build: bindings-build:
go run ./gen/main.go \ go run ./gen/main.go \
-forge-artifacts ../packages/contracts-bedrock/forge-artifacts \ -forge-artifacts $(contracts-dir)/forge-artifacts \
-out ./bindings \ -out ./bindings \
-contracts ./artifacts.json \ -contracts ./artifacts.json \
-source-maps MIPS,PreimageOracle \ -source-maps MIPS,PreimageOracle \
-package $(pkg) -package $(pkg) \
-monorepo-base $(monorepo-base)
mkdir: mkdir:
mkdir -p $(pkg) mkdir -p $(pkg)
......
package ast package ast
import ( import (
"path/filepath"
"regexp" "regexp"
"sort" "sort"
"strconv" "strconv"
...@@ -33,7 +34,7 @@ type typeRemapping struct { ...@@ -33,7 +34,7 @@ type typeRemapping struct {
// inefficiency comes from replaceType, which performs a linear // inefficiency comes from replaceType, which performs a linear
// search of all replacements when performing substring matches of // search of all replacements when performing substring matches of
// composite types. // composite types.
func CanonicalizeASTIDs(in *solc.StorageLayout) *solc.StorageLayout { func CanonicalizeASTIDs(in *solc.StorageLayout, monorepoBase string) *solc.StorageLayout {
lastId := uint(1000) lastId := uint(1000)
astIDRemappings := make(map[uint]uint) astIDRemappings := make(map[uint]uint)
typeRemappings := make(map[string]string) typeRemappings := make(map[string]string)
...@@ -83,9 +84,18 @@ func CanonicalizeASTIDs(in *solc.StorageLayout) *solc.StorageLayout { ...@@ -83,9 +84,18 @@ func CanonicalizeASTIDs(in *solc.StorageLayout) *solc.StorageLayout {
Types: make(map[string]solc.StorageLayoutType), Types: make(map[string]solc.StorageLayoutType),
} }
for _, slot := range in.Storage { for _, slot := range in.Storage {
contract := slot.Contract
// Normalize the name of the contract since absolute paths
// are used when there are 2 contracts imported with the same
// name
if filepath.IsAbs(contract) {
contract = strings.TrimPrefix(strings.Replace(contract, monorepoBase, "", 1), "/")
}
outLayout.Storage = append(outLayout.Storage, solc.StorageLayoutEntry{ outLayout.Storage = append(outLayout.Storage, solc.StorageLayoutEntry{
AstId: astIDRemappings[slot.AstId], AstId: astIDRemappings[slot.AstId],
Contract: slot.Contract, Contract: contract,
Label: slot.Label, Label: slot.Label,
Offset: slot.Offset, Offset: slot.Offset,
Slot: slot.Slot, Slot: slot.Slot,
......
...@@ -49,7 +49,7 @@ func TestCanonicalize(t *testing.T) { ...@@ -49,7 +49,7 @@ func TestCanonicalize(t *testing.T) {
// Run 100 times to make sure that we aren't relying // Run 100 times to make sure that we aren't relying
// on random map iteration order. // on random map iteration order.
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
require.Equal(t, testData.Out, CanonicalizeASTIDs(testData.In)) require.Equal(t, testData.Out, CanonicalizeASTIDs(testData.In, ""))
} }
}) })
} }
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const ERC20StorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_balances\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1001,\"contract\":\"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_allowances\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_address,t_mapping(t_address,t_uint256))\"},{\"astId\":1002,\"contract\":\"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_totalSupply\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_uint256\"},{\"astId\":1003,\"contract\":\"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_name\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_string_storage\"},{\"astId\":1004,\"contract\":\"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_symbol\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_string_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_mapping(t_address,t_mapping(t_address,t_uint256))\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e mapping(address =\u003e uint256))\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_mapping(t_address,t_uint256)\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_string_storage\":{\"encoding\":\"bytes\",\"label\":\"string\",\"numberOfBytes\":\"32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}" const ERC20StorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"node_modules/.pnpm/@openzeppelin+contracts@4.7.3/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_balances\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1001,\"contract\":\"node_modules/.pnpm/@openzeppelin+contracts@4.7.3/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_allowances\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_address,t_mapping(t_address,t_uint256))\"},{\"astId\":1002,\"contract\":\"node_modules/.pnpm/@openzeppelin+contracts@4.7.3/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_totalSupply\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_uint256\"},{\"astId\":1003,\"contract\":\"node_modules/.pnpm/@openzeppelin+contracts@4.7.3/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_name\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_string_storage\"},{\"astId\":1004,\"contract\":\"node_modules/.pnpm/@openzeppelin+contracts@4.7.3/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_symbol\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_string_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_mapping(t_address,t_mapping(t_address,t_uint256))\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e mapping(address =\u003e uint256))\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_mapping(t_address,t_uint256)\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_string_storage\":{\"encoding\":\"bytes\",\"label\":\"string\",\"numberOfBytes\":\"32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}"
var ERC20StorageLayout = new(solc.StorageLayout) var ERC20StorageLayout = new(solc.StorageLayout)
......
This diff is collapsed.
This diff is collapsed.
...@@ -22,6 +22,7 @@ type flags struct { ...@@ -22,6 +22,7 @@ type flags struct {
SourceMaps string SourceMaps string
OutDir string OutDir string
Package string Package string
MonorepoBase string
} }
type data struct { type data struct {
...@@ -39,8 +40,14 @@ func main() { ...@@ -39,8 +40,14 @@ func main() {
flag.StringVar(&f.Contracts, "contracts", "artifacts.json", "Path to file containing list of contracts to generate bindings for") flag.StringVar(&f.Contracts, "contracts", "artifacts.json", "Path to file containing list of contracts to generate bindings for")
flag.StringVar(&f.SourceMaps, "source-maps", "", "Comma-separated list of contracts to generate source-maps for") flag.StringVar(&f.SourceMaps, "source-maps", "", "Comma-separated list of contracts to generate source-maps for")
flag.StringVar(&f.Package, "package", "artifacts", "Go package name") flag.StringVar(&f.Package, "package", "artifacts", "Go package name")
flag.StringVar(&f.MonorepoBase, "monorepo-base", "", "Base of the monorepo")
flag.Parse() flag.Parse()
if f.MonorepoBase == "" {
log.Fatal("must provide -monorepo-base")
}
log.Printf("Using monorepo base %s\n", f.MonorepoBase)
contractData, err := os.ReadFile(f.Contracts) contractData, err := os.ReadFile(f.Contracts)
if err != nil { if err != nil {
log.Fatal("error reading contract list: %w\n", err) log.Fatal("error reading contract list: %w\n", err)
...@@ -72,21 +79,47 @@ func main() { ...@@ -72,21 +79,47 @@ func main() {
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
log.Printf("created temp dir %s\n", dir) log.Printf("created temp dir %s\n", dir)
// If some contracts have the same name then the path to their
// artifact depends on their full import path. Scan over all artifacts
// and hold a mapping from the contract name to the contract path.
// Walk walks the directory deterministically, so the later instance
// of the contract with the same name will be used
artifactPaths := make(map[string]string)
if err := filepath.Walk(f.ForgeArtifacts,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
base := filepath.Base(path)
if strings.HasSuffix(base, ".json") {
name := base[:len(base)-5]
if _, ok := artifactPaths[name]; !ok {
artifactPaths[name] = path
}
}
return nil
}); err != nil {
log.Fatal(err)
}
for _, name := range contracts { for _, name := range contracts {
log.Printf("generating code for %s\n", name) log.Printf("generating code for %s\n", name)
forgeArtifactData, err := os.ReadFile(path.Join(f.ForgeArtifacts, name+".sol", name+".json")) artifactPath := path.Join(f.ForgeArtifacts, name+".sol", name+".json")
forgeArtifactData, err := os.ReadFile(artifactPath)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
log.Fatalf("cannot find forge-artifact of %q\n", name) artifactPath = artifactPaths[name]
forgeArtifactData, err = os.ReadFile(artifactPath)
if errors.Is(err, os.ErrNotExist) {
log.Fatalf("cannot find forge-artifact of %q\n", name)
}
} }
log.Printf("using forge-artifact %s\n", artifactPath)
var artifact foundry.Artifact var artifact foundry.Artifact
if err := json.Unmarshal(forgeArtifactData, &artifact); err != nil { if err := json.Unmarshal(forgeArtifactData, &artifact); err != nil {
log.Fatalf("failed to parse forge artifact of %q: %v\n", name, err) log.Fatalf("failed to parse forge artifact of %q: %v\n", name, err)
} }
if err != nil {
log.Fatalf("error reading storage layout %s: %v\n", name, err)
}
rawAbi := artifact.Abi rawAbi := artifact.Abi
if err != nil { if err != nil {
...@@ -121,7 +154,7 @@ func main() { ...@@ -121,7 +154,7 @@ func main() {
} }
storage := artifact.StorageLayout storage := artifact.StorageLayout
canonicalStorage := ast.CanonicalizeASTIDs(&storage) canonicalStorage := ast.CanonicalizeASTIDs(&storage, f.MonorepoBase)
ser, err := json.Marshal(canonicalStorage) ser, err := json.Marshal(canonicalStorage)
if err != nil { if err != nil {
log.Fatalf("error marshaling storage: %v\n", err) log.Fatalf("error marshaling storage: %v\n", err)
......
...@@ -10,7 +10,6 @@ import ( ...@@ -10,7 +10,6 @@ import (
type Agent struct { type Agent struct {
solver *Solver solver *Solver
trace TraceProvider
loader Loader loader Loader
responder Responder responder Responder
maxDepth int maxDepth int
...@@ -21,7 +20,6 @@ type Agent struct { ...@@ -21,7 +20,6 @@ type Agent struct {
func NewAgent(loader Loader, maxDepth int, trace TraceProvider, responder Responder, agreeWithProposedOutput bool, log log.Logger) Agent { func NewAgent(loader Loader, maxDepth int, trace TraceProvider, responder Responder, agreeWithProposedOutput bool, log log.Logger) Agent {
return Agent{ return Agent{
solver: NewSolver(maxDepth, trace), solver: NewSolver(maxDepth, trace),
trace: trace,
loader: loader, loader: loader,
responder: responder, responder: responder,
maxDepth: maxDepth, maxDepth: maxDepth,
...@@ -102,19 +100,13 @@ func (a *Agent) step(claim Claim, game Game) error { ...@@ -102,19 +100,13 @@ func (a *Agent) step(claim Claim, game Game) error {
a.log.Warn("Failed to get a step", "err", err) a.log.Warn("Failed to get a step", "err", err)
return err return err
} }
stateData, err := a.trace.GetPreimage(step.PreStateTraceIndex)
if err != nil {
a.log.Warn("Failed to get a state data", "err", err)
return err
}
a.log.Info("Performing step", a.log.Info("Performing step", "is_attack", step.IsAttack,
"depth", step.LeafClaim.Depth(), "index_at_depth", step.LeafClaim.IndexAtDepth(), "value", step.LeafClaim.Value, "depth", step.LeafClaim.Depth(), "index_at_depth", step.LeafClaim.IndexAtDepth(), "value", step.LeafClaim.Value)
"is_attack", step.IsAttack, "prestate_trace_index", step.PreStateTraceIndex)
callData := StepCallData{ callData := StepCallData{
ClaimIndex: uint64(step.LeafClaim.ContractIndex), ClaimIndex: uint64(step.LeafClaim.ContractIndex),
IsAttack: step.IsAttack, IsAttack: step.IsAttack,
StateData: stateData, StateData: step.PreState,
} }
return a.responder.Step(context.TODO(), callData) return a.responder.Step(context.TODO(), callData)
} }
...@@ -8,6 +8,8 @@ import ( ...@@ -8,6 +8,8 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
) )
var _ TraceProvider = (*AlphabetProvider)(nil)
// AlphabetProvider is a [TraceProvider] that provides claims for specific // AlphabetProvider is a [TraceProvider] that provides claims for specific
// indices in the given trace. // indices in the given trace.
type AlphabetProvider struct { type AlphabetProvider struct {
...@@ -45,6 +47,12 @@ func (ap *AlphabetProvider) Get(i uint64) (common.Hash, error) { ...@@ -45,6 +47,12 @@ func (ap *AlphabetProvider) Get(i uint64) (common.Hash, error) {
return crypto.Keccak256Hash(claimBytes), nil return crypto.Keccak256Hash(claimBytes), nil
} }
func (ap *AlphabetProvider) AbsolutePreState() []byte {
out := make([]byte, 32)
out[31] = 140 // ascii character 140 is "`"
return out
}
// BuildAlphabetPreimage constructs the claim bytes for the index and state item. // BuildAlphabetPreimage constructs the claim bytes for the index and state item.
func BuildAlphabetPreimage(i uint64, letter string) []byte { func BuildAlphabetPreimage(i uint64, letter string) []byte {
return append(IndexToBytes(i), LetterToBytes(letter)...) return append(IndexToBytes(i), LetterToBytes(letter)...)
......
package examples
import (
"os"
"github.com/ethereum-optimism/optimism/op-challenger/fault"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
)
func FullGame() {
log.Root().SetHandler(
log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stdout, log.TerminalFormat(true))),
)
canonical := "abcdefgh"
disputed := "abcdexyz"
maxDepth := uint64(3)
canonicalProvider := fault.NewAlphabetProvider(canonical, maxDepth)
disputedProvider := fault.NewAlphabetProvider(disputed, maxDepth)
root := fault.Claim{
ClaimData: fault.ClaimData{
Value: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000077a"),
Position: fault.NewPosition(0, 0),
},
}
o := fault.NewOrchestrator(maxDepth, []fault.TraceProvider{canonicalProvider, disputedProvider}, []string{"charlie", "mallory"}, []bool{false, true}, root)
o.Start()
}
package examples
import (
"github.com/ethereum-optimism/optimism/op-challenger/fault"
)
func PositionExampleOne() {
// Example 1
// abcdefgh
// abcdexyz
// go left to d, then right to f, then left to e
p := fault.Position{}
p.Print(3)
p = p.Attack()
p.Print(3)
p = p.Defend()
p.Print(3)
p = p.Attack()
p.Print(3)
}
func PositionExampleTwo() {
// Example 2
// abcdefgh
// abqrstuv
// go left r, then left to b, then right to q
p := fault.Position{}
p.Print(3)
p = p.Attack()
p.Print(3)
p = p.Attack()
p.Print(3)
p = p.Defend()
p.Print(3)
}
package examples
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-challenger/fault"
)
func PrettyPrintAlphabetClaim(name string, claim fault.Claim) {
value := claim.Value
idx := value[30]
letter := value[31]
if claim.IsRoot() {
fmt.Printf("%s\ttrace %v letter %c\n", name, idx, letter)
} else {
fmt.Printf("%s\ttrace %v letter %c is attack %v\n", name, idx, letter, !claim.DefendsParent())
}
}
// SolverExampleOne uses the [fault.Solver] with a [fault.AlphabetProvider]
// to print out fault game traces for the "abcdexyz" counter-state.
func SolverExampleOne() {
fmt.Println("Solver: Example 1")
// Construct the fault position.
canonical := "abcdefgh"
disputed := "abcdexyz"
maxDepth := 3
// Root claim is z at trace index 7 from the disputed provider
root := fault.Claim{
ClaimData: fault.ClaimData{
Value: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000077a"),
Position: fault.NewPosition(0, 0),
},
}
canonicalProvider := fault.NewAlphabetProvider(canonical, uint64(maxDepth))
disputedProvider := fault.NewAlphabetProvider(disputed, uint64(maxDepth))
// Create a solver with the canonical provider.
cannonicalSolver := fault.NewSolver(maxDepth, canonicalProvider)
disputedSolver := fault.NewSolver(maxDepth, disputedProvider)
// Print the initial state.
fmt.Println("Canonical state: ", canonical)
fmt.Println("Disputed state: ", disputed)
fmt.Println()
fmt.Println("Proceeding with the following moves:")
fmt.Println("go left to d, then right to x (cannonical is f), then left to e")
fmt.Println()
PrettyPrintAlphabetClaim("Root claim", root)
claim1, err := cannonicalSolver.NextMove(root, false)
if err != nil {
fmt.Printf("error getting claim from provider: %v", err)
}
PrettyPrintAlphabetClaim("Cannonical move", *claim1)
claim2, err := disputedSolver.NextMove(*claim1, false)
if err != nil {
fmt.Printf("error getting claim from provider: %v", err)
}
PrettyPrintAlphabetClaim("Disputed moved", *claim2)
claim3, err := cannonicalSolver.NextMove(*claim2, false)
if err != nil {
fmt.Printf("error getting claim from provider: %v", err)
}
PrettyPrintAlphabetClaim("Cannonical move", *claim3)
}
package main
import (
"github.com/ethereum-optimism/optimism/op-challenger/fault/cmd/examples"
)
func main() {
examples.FullGame()
// examples.SolverExampleOne()
// examples.PositionExampleOne()
// examples.PositionExampleTwo()
}
...@@ -26,14 +26,6 @@ type Game interface { ...@@ -26,14 +26,6 @@ type Game interface {
// IsDuplicate returns true if the provided [Claim] already exists in the game state. // IsDuplicate returns true if the provided [Claim] already exists in the game state.
IsDuplicate(claim Claim) bool IsDuplicate(claim Claim) bool
// PreStateClaim gets the claim which commits to the pre-state of this specific claim.
// This will return an error if it is called with a non-leaf claim.
PreStateClaim(claim Claim) (Claim, error)
// PostStateClaim gets the claim which commits to the post-state of this specific claim.
// This will return an error if it is called with a non-leaf claim.
PostStateClaim(claim Claim) (Claim, error)
// AgreeWithLevel returns if the game state agrees with the provided claim level. // AgreeWithLevel returns if the game state agrees with the provided claim level.
AgreeWithClaimLevel(claim Claim) bool AgreeWithClaimLevel(claim Claim) bool
} }
...@@ -140,45 +132,3 @@ func (g *gameState) getParent(claim Claim) (Claim, error) { ...@@ -140,45 +132,3 @@ func (g *gameState) getParent(claim Claim) (Claim, error) {
return parent.self, nil return parent.self, nil
} }
} }
func (g *gameState) PreStateClaim(claim Claim) (Claim, error) {
// Do checks in PreStateClaim because these do not hold while walking the tree
if claim.Depth() != int(g.depth) {
return Claim{}, errors.New("Only leaf claims have pre or post state")
}
// If the claim is the far left most claim, the pre-state is pulled from the contracts & we can supply at contract index.
if claim.IndexAtDepth() == 0 {
return Claim{
ContractIndex: -1,
}, nil
}
return g.preStateClaim(claim)
}
// preStateClaim is the internal tree walker which does not do error handling
func (g *gameState) preStateClaim(claim Claim) (Claim, error) {
parent, _ := g.getParent(claim)
if claim.DefendsParent() {
return parent, nil
} else {
return g.preStateClaim(parent)
}
}
func (g *gameState) PostStateClaim(claim Claim) (Claim, error) {
// Do checks in PostStateClaim because these do not hold while walking the tree
if claim.Depth() != int(g.depth) {
return Claim{}, errors.New("Only leaf claims have pre or post state")
}
return g.postStateClaim(claim)
}
// postStateClaim is the internal tree walker which does not do error handling
func (g *gameState) postStateClaim(claim Claim) (Claim, error) {
parent, _ := g.getParent(claim)
if claim.DefendsParent() {
return g.postStateClaim(parent)
} else {
return parent, nil
}
}
...@@ -195,46 +195,6 @@ func TestGame_ClaimPairs(t *testing.T) { ...@@ -195,46 +195,6 @@ func TestGame_ClaimPairs(t *testing.T) {
require.ElementsMatch(t, expected, claims) require.ElementsMatch(t, expected, claims)
} }
// TestPrePostStateOnlyOnLeafClaim tests that if PreStateClaim or PostStateClaim is called with an non-leaf claim
// those functions return an error.
func TestPrePostStateOnlyOnLeafClaim(t *testing.T) {
root, top, middle, bottom := createTestClaims()
g := NewGameState(false, root, testMaxDepth)
require.NoError(t, g.PutAll([]Claim{top, middle, bottom}))
_, err := g.PreStateClaim(middle)
require.Error(t, err)
_, err = g.PostStateClaim(middle)
require.Error(t, err)
}
func TestPreStateClaim(t *testing.T) {
root, top, middle, bottom := createTestClaims()
g := NewGameState(false, root, testMaxDepth)
require.NoError(t, g.Put(top))
require.NoError(t, g.Put(middle))
require.NoError(t, g.Put(bottom))
// Bottom trace index is 4. Pre trace index is then 3
pre, err := g.PreStateClaim(bottom)
require.NoError(t, err)
require.Equal(t, top, pre)
}
func TestPostStateClaim(t *testing.T) {
root, top, middle, bottom := createTestClaims()
g := NewGameState(false, root, testMaxDepth)
require.NoError(t, g.Put(top))
require.NoError(t, g.Put(middle))
require.NoError(t, g.Put(bottom))
// Bottom trace index is 4. Post trace index is then 5
post, err := g.PostStateClaim(bottom)
require.NoError(t, err)
require.Equal(t, middle, post)
}
func TestAgreeWithClaimLevelDisagreeWithOutput(t *testing.T) { func TestAgreeWithClaimLevelDisagreeWithOutput(t *testing.T) {
// Setup the game state. // Setup the game state.
root, top, middle, bottom := createTestClaims() root, top, middle, bottom := createTestClaims()
......
package fault
import (
"context"
"github.com/ethereum/go-ethereum/log"
)
type Orchestrator struct {
agents []Agent
claims []Claim
steps []StepCallData
// tracking when to exit
claimLen, stepLen, step int
}
func NewOrchestrator(maxDepth uint64, traces []TraceProvider, names []string, agreeWithProposedOutput []bool, root Claim) Orchestrator {
o := Orchestrator{
agents: make([]Agent, len(traces)),
claims: []Claim{root},
steps: make([]StepCallData, 0),
}
log.Info("Starting game", "root_letter", string(root.Value[31:]))
for i, trace := range traces {
o.agents[i] = NewAgent(&o, int(maxDepth), trace, &o, agreeWithProposedOutput[i], log.New("role", names[i]))
}
return o
}
func (o *Orchestrator) Respond(_ context.Context, response Claim) error {
response.ContractIndex = len(o.claims)
o.claims = append(o.claims, response)
return nil
}
func (o *Orchestrator) Step(_ context.Context, stepData StepCallData) error {
log.Info("Step recorded", "step", stepData)
o.steps = append(o.steps, stepData)
return nil
}
func (o *Orchestrator) FetchClaims(ctx context.Context) ([]Claim, error) {
c := make([]Claim, len(o.claims))
copy(c, o.claims)
return c, nil
}
func (o *Orchestrator) Start() {
for {
for _, a := range o.agents {
_ = a.Act()
}
if o.shouldExit() {
log.Info("exiting")
return
}
}
}
func (o *Orchestrator) shouldExit() bool {
cl := o.claimLen
sl := o.stepLen
o.claimLen = len(o.claims)
o.stepLen = len(o.steps)
noProgress := o.claimLen == cl && o.stepLen == sl
if noProgress {
o.step = o.step + 1
} else {
o.step = 0
}
return noProgress && o.step == 1
}
...@@ -36,27 +36,29 @@ type testNodeInfo struct { ...@@ -36,27 +36,29 @@ type testNodeInfo struct {
Depth int Depth int
IndexAtDepth int IndexAtDepth int
TraceIndex uint64 TraceIndex uint64
AttackGIndex uint64 // 0 indicates attack is not possible from this node
DefendGIndex uint64 // 0 indicates defend is not possible from this node
} }
var treeNodesMaxDepth4 = []testNodeInfo{ var treeNodesMaxDepth4 = []testNodeInfo{
{GIndex: 1, Depth: 0, IndexAtDepth: 0, TraceIndex: 15}, {GIndex: 1, Depth: 0, IndexAtDepth: 0, TraceIndex: 15, AttackGIndex: 2},
{GIndex: 2, Depth: 1, IndexAtDepth: 0, TraceIndex: 7}, {GIndex: 2, Depth: 1, IndexAtDepth: 0, TraceIndex: 7, AttackGIndex: 4, DefendGIndex: 6},
{GIndex: 3, Depth: 1, IndexAtDepth: 1, TraceIndex: 15}, {GIndex: 3, Depth: 1, IndexAtDepth: 1, TraceIndex: 15, AttackGIndex: 6},
{GIndex: 4, Depth: 2, IndexAtDepth: 0, TraceIndex: 3}, {GIndex: 4, Depth: 2, IndexAtDepth: 0, TraceIndex: 3, AttackGIndex: 8, DefendGIndex: 10},
{GIndex: 5, Depth: 2, IndexAtDepth: 1, TraceIndex: 7}, {GIndex: 5, Depth: 2, IndexAtDepth: 1, TraceIndex: 7, AttackGIndex: 10},
{GIndex: 6, Depth: 2, IndexAtDepth: 2, TraceIndex: 11}, {GIndex: 6, Depth: 2, IndexAtDepth: 2, TraceIndex: 11, AttackGIndex: 12, DefendGIndex: 14},
{GIndex: 7, Depth: 2, IndexAtDepth: 3, TraceIndex: 15}, {GIndex: 7, Depth: 2, IndexAtDepth: 3, TraceIndex: 15, AttackGIndex: 14},
{GIndex: 8, Depth: 3, IndexAtDepth: 0, TraceIndex: 1}, {GIndex: 8, Depth: 3, IndexAtDepth: 0, TraceIndex: 1, AttackGIndex: 16, DefendGIndex: 18},
{GIndex: 9, Depth: 3, IndexAtDepth: 1, TraceIndex: 3}, {GIndex: 9, Depth: 3, IndexAtDepth: 1, TraceIndex: 3, AttackGIndex: 18},
{GIndex: 10, Depth: 3, IndexAtDepth: 2, TraceIndex: 5}, {GIndex: 10, Depth: 3, IndexAtDepth: 2, TraceIndex: 5, AttackGIndex: 20, DefendGIndex: 22},
{GIndex: 11, Depth: 3, IndexAtDepth: 3, TraceIndex: 7}, {GIndex: 11, Depth: 3, IndexAtDepth: 3, TraceIndex: 7, AttackGIndex: 22},
{GIndex: 12, Depth: 3, IndexAtDepth: 4, TraceIndex: 9}, {GIndex: 12, Depth: 3, IndexAtDepth: 4, TraceIndex: 9, AttackGIndex: 24, DefendGIndex: 26},
{GIndex: 13, Depth: 3, IndexAtDepth: 5, TraceIndex: 11}, {GIndex: 13, Depth: 3, IndexAtDepth: 5, TraceIndex: 11, AttackGIndex: 26},
{GIndex: 14, Depth: 3, IndexAtDepth: 6, TraceIndex: 13}, {GIndex: 14, Depth: 3, IndexAtDepth: 6, TraceIndex: 13, AttackGIndex: 28, DefendGIndex: 30},
{GIndex: 15, Depth: 3, IndexAtDepth: 7, TraceIndex: 15}, {GIndex: 15, Depth: 3, IndexAtDepth: 7, TraceIndex: 15, AttackGIndex: 30},
{GIndex: 16, Depth: 4, IndexAtDepth: 0, TraceIndex: 0}, {GIndex: 16, Depth: 4, IndexAtDepth: 0, TraceIndex: 0},
{GIndex: 17, Depth: 4, IndexAtDepth: 1, TraceIndex: 1}, {GIndex: 17, Depth: 4, IndexAtDepth: 1, TraceIndex: 1},
...@@ -95,3 +97,25 @@ func TestTraceIndex(t *testing.T) { ...@@ -95,3 +97,25 @@ func TestTraceIndex(t *testing.T) {
require.Equal(t, test.TraceIndex, result) require.Equal(t, test.TraceIndex, result)
} }
} }
func TestAttack(t *testing.T) {
for _, test := range treeNodesMaxDepth4 {
if test.AttackGIndex == 0 {
continue
}
pos := NewPosition(test.Depth, test.IndexAtDepth)
result := pos.Attack()
require.Equalf(t, test.AttackGIndex, result.ToGIndex(), "Attack from GIndex %v", pos.ToGIndex())
}
}
func TestDefend(t *testing.T) {
for _, test := range treeNodesMaxDepth4 {
if test.DefendGIndex == 0 {
continue
}
pos := NewPosition(test.Depth, test.IndexAtDepth)
result := pos.Defend()
require.Equalf(t, test.DefendGIndex, result.ToGIndex(), "Defend from GIndex %v", pos.ToGIndex())
}
}
...@@ -64,9 +64,9 @@ func (s *Solver) handleMiddle(claim Claim) (*Claim, error) { ...@@ -64,9 +64,9 @@ func (s *Solver) handleMiddle(claim Claim) (*Claim, error) {
} }
type StepData struct { type StepData struct {
LeafClaim Claim LeafClaim Claim
IsAttack bool IsAttack bool
PreStateTraceIndex uint64 PreState []byte
} }
// AttemptStep determines what step should occur for a given leaf claim. // AttemptStep determines what step should occur for a given leaf claim.
...@@ -80,14 +80,25 @@ func (s *Solver) AttemptStep(claim Claim) (StepData, error) { ...@@ -80,14 +80,25 @@ func (s *Solver) AttemptStep(claim Claim) (StepData, error) {
return StepData{}, err return StepData{}, err
} }
index := claim.TraceIndex(s.gameDepth) index := claim.TraceIndex(s.gameDepth)
// TODO(CLI-4198): Handle case where we dispute trace index 0 var preState []byte
if !claimCorrect { // If we are attacking index 0, we provide the absolute pre-state, not an intermediate state
index -= 1 if index == 0 && !claimCorrect {
preState = s.AbsolutePreState()
} else {
// If attacking, get the state just before, other get the state after
if !claimCorrect {
index = index - 1
}
preState, err = s.GetPreimage(index)
if err != nil {
return StepData{}, err
}
} }
return StepData{ return StepData{
LeafClaim: claim, LeafClaim: claim,
IsAttack: !claimCorrect, IsAttack: !claimCorrect,
PreStateTraceIndex: index, PreState: preState,
}, nil }, nil
} }
......
...@@ -102,17 +102,27 @@ func TestAttemptStep(t *testing.T) { ...@@ -102,17 +102,27 @@ func TestAttemptStep(t *testing.T) {
maxDepth := 3 maxDepth := 3
canonicalProvider := NewAlphabetProvider("abcdefgh", uint64(maxDepth)) canonicalProvider := NewAlphabetProvider("abcdefgh", uint64(maxDepth))
solver := NewSolver(maxDepth, canonicalProvider) solver := NewSolver(maxDepth, canonicalProvider)
root, top, middle, bottom := createTestClaims() _, _, middle, bottom := createTestClaims()
g := NewGameState(false, root, testMaxDepth)
require.NoError(t, g.Put(top)) zero := Claim{
require.NoError(t, g.Put(middle)) ClaimData: ClaimData{
require.NoError(t, g.Put(bottom)) // Zero value is a purposely disagree with claim value "a"
Position: NewPosition(3, 0),
},
}
step, err := solver.AttemptStep(bottom) step, err := solver.AttemptStep(bottom)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, bottom, step.LeafClaim) require.Equal(t, bottom, step.LeafClaim)
require.True(t, step.IsAttack) require.True(t, step.IsAttack)
require.Equal(t, step.PreState, BuildAlphabetPreimage(3, "d"))
_, err = solver.AttemptStep(middle) _, err = solver.AttemptStep(middle)
require.Error(t, err) require.Error(t, err)
step, err = solver.AttemptStep(zero)
require.NoError(t, err)
require.Equal(t, zero, step.LeafClaim)
require.True(t, step.IsAttack)
require.Equal(t, canonicalProvider.AbsolutePreState(), step.PreState)
} }
...@@ -22,10 +22,12 @@ type StepCallData struct { ...@@ -22,10 +22,12 @@ type StepCallData struct {
// TraceProvider is a generic way to get a claim value at a specific // TraceProvider is a generic way to get a claim value at a specific
// step in the trace. // step in the trace.
// The [AlphabetProvider] is a minimal implementation of this interface. // Get(i) = Keccak256(GetPreimage(i))
// AbsolutePreState is the value of the trace that transitions to the trace value at index 0
type TraceProvider interface { type TraceProvider interface {
Get(i uint64) (common.Hash, error) Get(i uint64) (common.Hash, error)
GetPreimage(i uint64) ([]byte, error) GetPreimage(i uint64) ([]byte, error)
AbsolutePreState() []byte
} }
// ClaimData is the core of a claim. It must be unique inside a specific game. // ClaimData is the core of a claim. It must be unique inside a specific game.
......
...@@ -76,7 +76,7 @@ func TestERC20BridgeDeposits(t *testing.T) { ...@@ -76,7 +76,7 @@ func TestERC20BridgeDeposits(t *testing.T) {
// Approve WETH9 with the bridge // Approve WETH9 with the bridge
tx, err = WETH9.Approve(opts, predeploys.DevL1StandardBridgeAddr, new(big.Int).SetUint64(math.MaxUint64)) tx, err = WETH9.Approve(opts, predeploys.DevL1StandardBridgeAddr, new(big.Int).SetUint64(math.MaxUint64))
require.NoError(t, err) require.NoError(t, err)
_, err = waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) _, err = waitForTransaction(tx.Hash(), l1Client, 6*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.NoError(t, err) require.NoError(t, err)
// Bridge the WETH9 // Bridge the WETH9
......
...@@ -300,23 +300,25 @@ func createGethNode(l2 bool, nodeCfg *node.Config, ethCfg *ethconfig.Config, pri ...@@ -300,23 +300,25 @@ func createGethNode(l2 bool, nodeCfg *node.Config, ethCfg *ethconfig.Config, pri
return nil, nil, err return nil, nil, err
} }
keydir := n.KeyStoreDir() if !l2 {
scryptN := 2 keydir := n.KeyStoreDir()
scryptP := 1 scryptN := 2
n.AccountManager().AddBackend(keystore.NewKeyStore(keydir, scryptN, scryptP)) scryptP := 1
ks := n.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) n.AccountManager().AddBackend(keystore.NewKeyStore(keydir, scryptN, scryptP))
ks := n.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
password := "foobar"
for _, pk := range privateKeys { password := "foobar"
act, err := ks.ImportECDSA(pk, password) for _, pk := range privateKeys {
if err != nil { act, err := ks.ImportECDSA(pk, password)
n.Close() if err != nil {
return nil, nil, err n.Close()
} return nil, nil, err
err = ks.Unlock(act, password) }
if err != nil { err = ks.Unlock(act, password)
n.Close() if err != nil {
return nil, nil, err n.Close()
return nil, nil, err
}
} }
} }
...@@ -341,5 +343,4 @@ func createGethNode(l2 bool, nodeCfg *node.Config, ethCfg *ethconfig.Config, pri ...@@ -341,5 +343,4 @@ func createGethNode(l2 bool, nodeCfg *node.Config, ethCfg *ethconfig.Config, pri
} }
} }
return n, backend, nil return n, backend, nil
} }
...@@ -1279,7 +1279,7 @@ func TestStopStartBatcher(t *testing.T) { ...@@ -1279,7 +1279,7 @@ func TestStopStartBatcher(t *testing.T) {
receipt := sendTx() receipt := sendTx()
// wait until the block the tx was first included in shows up in the safe chain on the verifier // wait until the block the tx was first included in shows up in the safe chain on the verifier
safeBlockInclusionDuration := time.Duration(3*cfg.DeployConfig.L1BlockTime) * time.Second safeBlockInclusionDuration := time.Duration(6*cfg.DeployConfig.L1BlockTime) * time.Second
_, err = waitForBlock(receipt.BlockNumber, l2Verif, safeBlockInclusionDuration) _, err = waitForBlock(receipt.BlockNumber, l2Verif, safeBlockInclusionDuration)
require.Nil(t, err, "Waiting for block on verifier") require.Nil(t, err, "Waiting for block on verifier")
......
...@@ -59,7 +59,11 @@ func (cfg *L2EndpointConfig) Setup(ctx context.Context, log log.Logger, rollupCf ...@@ -59,7 +59,11 @@ func (cfg *L2EndpointConfig) Setup(ctx context.Context, log log.Logger, rollupCf
return nil, nil, err return nil, nil, err
} }
auth := rpc.WithHTTPAuth(gn.NewJWTAuth(cfg.L2EngineJWTSecret)) auth := rpc.WithHTTPAuth(gn.NewJWTAuth(cfg.L2EngineJWTSecret))
l2Node, err := client.NewRPC(ctx, log, cfg.L2EngineAddr, client.WithGethRPCOptions(auth)) opts := []client.RPCOption{
client.WithGethRPCOptions(auth),
client.WithDialBackoff(10),
}
l2Node, err := client.NewRPC(ctx, log, cfg.L2EngineAddr, opts...)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
......
...@@ -56,7 +56,9 @@ RUN apt-get update && \ ...@@ -56,7 +56,9 @@ RUN apt-get update && \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.48.0 && \ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.48.0 && \
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh | bash curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh | bash
RUN echo "downloading pnpm" && npm i -g pnpm # We need to isntall yarn because a bespoke dependency installed from github https://codeload.github.com/Saw-mon-and-Natalie/clones-with-immutable-arg needs it
# it is installed from github which means it's postpack script which uses yarn is ran when unpacked into node_modules
RUN echo "downloading pnpm and yarn" && npm i -g pnpm && npm i -g yarn@1 && pnpm --version && yarn --version
RUN echo "downloading solidity compilers" && \ RUN echo "downloading solidity compilers" && \
curl -o solc-linux-amd64-v0.5.17+commit.d19bba13 -sL https://binaries.soliditylang.org/linux-amd64/solc-linux-amd64-v0.5.17+commit.d19bba13 && \ curl -o solc-linux-amd64-v0.5.17+commit.d19bba13 -sL https://binaries.soliditylang.org/linux-amd64/solc-linux-amd64-v0.5.17+commit.d19bba13 && \
......
...@@ -7,7 +7,7 @@ import { ...@@ -7,7 +7,7 @@ import {
} from '@eth-optimism/common-ts' } from '@eth-optimism/common-ts'
import { Provider } from '@ethersproject/abstract-provider' import { Provider } from '@ethersproject/abstract-provider'
import { ethers } from 'ethers' import { ethers } from 'ethers'
import * as DrippieArtifact from '@eth-optimism/contracts-periphery/artifacts/contracts/universal/drippie/Drippie.sol/Drippie.json' import * as DrippieArtifact from '@eth-optimism/contracts-bedrock/forge-artifacts/Drippie.sol/Drippie.json'
import { version } from '../../package.json' import { version } from '../../package.json'
......
This diff is collapsed.
...@@ -59,7 +59,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver { ...@@ -59,7 +59,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
Claim _absolutePrestate, Claim _absolutePrestate,
uint256 _maxGameDepth, uint256 _maxGameDepth,
IBigStepper _vm IBigStepper _vm
) Semver(0, 0, 2) { ) Semver(0, 0, 3) {
ABSOLUTE_PRESTATE = _absolutePrestate; ABSOLUTE_PRESTATE = _absolutePrestate;
MAX_GAME_DEPTH = _maxGameDepth; MAX_GAME_DEPTH = _maxGameDepth;
VM = _vm; VM = _vm;
...@@ -92,7 +92,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver { ...@@ -92,7 +92,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// Determine the expected pre & post states of the step. // Determine the expected pre & post states of the step.
Claim preStateClaim; Claim preStateClaim;
Claim postStateClaim; ClaimData storage postState;
if (_isAttack) { if (_isAttack) {
if (stepPos.indexAtDepth() == 0) { if (stepPos.indexAtDepth() == 0) {
// If the step position's index at depth is 0, the prestate is the absolute // If the step position's index at depth is 0, the prestate is the absolute
...@@ -104,16 +104,16 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver { ...@@ -104,16 +104,16 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
preStateClaim = findTraceAncestor( preStateClaim = findTraceAncestor(
Position.wrap(Position.unwrap(parentPos) - 1), Position.wrap(Position.unwrap(parentPos) - 1),
parent.parentIndex parent.parentIndex
); ).claim;
} }
// For all attacks, the poststate is the parent claim. // For all attacks, the poststate is the parent claim.
postStateClaim = parent.claim; postState = parent;
} else { } else {
// If the step is a defense, the poststate exists elsewhere in the game state, // If the step is a defense, the poststate exists elsewhere in the game state,
// and the parent claim is the expected pre-state. // and the parent claim is the expected pre-state.
preStateClaim = parent.claim; preStateClaim = parent.claim;
postStateClaim = findTraceAncestor( postState = findTraceAncestor(
Position.wrap(Position.unwrap(parentPos) + 1), Position.wrap(Position.unwrap(parentPos) + 1),
parent.parentIndex parent.parentIndex
); );
...@@ -123,10 +123,21 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver { ...@@ -123,10 +123,21 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// preimage of the prestate claim hash. // preimage of the prestate claim hash.
if (keccak256(_stateData) != Claim.unwrap(preStateClaim)) revert InvalidPrestate(); if (keccak256(_stateData) != Claim.unwrap(preStateClaim)) revert InvalidPrestate();
// INVARIANT: A VM step can never counter a parent claim unless it produces a poststate // INVARIANT: If a step is an attack, the poststate is valid if the step produces
// that is not equal to the claim at `_parentIndex` if the step is an attack, // the same poststate hash as the parent claim's value.
// or the claim at `_stateIndex` if the step is a defense. // If a step is a defense:
if (VM.step(_stateData, _proof) == Claim.unwrap(postStateClaim)) revert ValidStep(); // 1. If the parent claim and the found post state agree with each other
// (depth diff % 2 == 0), the step is valid if it produces the same
// state hash as the post state's claim.
// 2. If the parent claim and the found post state disagree with each other
// (depth diff % 2 != 0), the parent cannot be countered unless the step
// produces the same state hash as `postState.claim`.
// SAFETY: While the `attack` path does not need an extra check for the post
// state's depth in relation to the parent, we don't need another
// branch because (n - n) % 2 == 0.
bool validStep = VM.step(_stateData, _proof) == Claim.unwrap(postState.claim);
bool parentPostAgree = (parentPos.depth() - postState.position.depth()) % 2 == 0;
if ((parentPostAgree && validStep) || (!parentPostAgree && !validStep)) revert ValidStep();
// Set the parent claim as countered. We do not need to append a new claim to the game; // Set the parent claim as countered. We do not need to append a new claim to the game;
// instead, we can just set the existing parent as countered. // instead, we can just set the existing parent as countered.
...@@ -384,17 +395,16 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver { ...@@ -384,17 +395,16 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
function findTraceAncestor(Position _pos, uint256 _start) function findTraceAncestor(Position _pos, uint256 _start)
internal internal
view view
returns (Claim ancestor_) returns (ClaimData storage ancestor_)
{ {
// Grab the trace ancestor's expected position. // Grab the trace ancestor's expected position.
Position preStateTraceAncestor = _pos.traceAncestor(); Position preStateTraceAncestor = _pos.traceAncestor();
// Walk up the DAG to find a claim that commits to the same trace index as `_pos`. It is // Walk up the DAG to find a claim that commits to the same trace index as `_pos`. It is
// guaranteed that such a claim exists. // guaranteed that such a claim exists.
ClaimData storage ancestor = claimData[_start]; ancestor_ = claimData[_start];
while (Position.unwrap(ancestor.position) != Position.unwrap(preStateTraceAncestor)) { while (Position.unwrap(ancestor_.position) != Position.unwrap(preStateTraceAncestor)) {
ancestor = claimData[ancestor.parentIndex]; ancestor_ = claimData[ancestor_.parentIndex];
} }
ancestor_ = ancestor.claim;
} }
} }
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { AssetReceiver } from "../AssetReceiver.sol"; import { AssetReceiver } from "../AssetReceiver.sol";
import { IDripCheck } from "./IDripCheck.sol"; import { IDripCheck } from "./IDripCheck.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { IDripCheck } from "../IDripCheck.sol"; import { IDripCheck } from "../IDripCheck.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { IDripCheck } from "../IDripCheck.sol"; import { IDripCheck } from "../IDripCheck.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { IDripCheck } from "../IDripCheck.sol"; import { IDripCheck } from "../IDripCheck.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { IDripCheck } from "../IDripCheck.sol"; import { IDripCheck } from "../IDripCheck.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol"; import { Semver } from "../../universal/Semver.sol";
/** /**
* @title AttestationStation * @title AttestationStation
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol"; import { Semver } from "../../universal/Semver.sol";
import { import {
ERC721BurnableUpgradeable ERC721BurnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; } from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol"; import { Semver } from "../../universal/Semver.sol";
import { AttestationStation } from "./AttestationStation.sol"; import { AttestationStation } from "./AttestationStation.sol";
import { OptimistConstants } from "./libraries/OptimistConstants.sol"; import { OptimistConstants } from "./libraries/OptimistConstants.sol";
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { OptimistConstants } from "./libraries/OptimistConstants.sol"; import { OptimistConstants } from "./libraries/OptimistConstants.sol";
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol"; import { Semver } from "../../universal/Semver.sol";
import { AttestationStation } from "./AttestationStation.sol"; import { AttestationStation } from "./AttestationStation.sol";
import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import { import {
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AdminFaucetAuthModule } from "../universal/faucet/authmodules/AdminFaucetAuthModule.sol"; import { AdminFaucetAuthModule } from "../periphery/faucet/authmodules/AdminFaucetAuthModule.sol";
import { Faucet } from "../universal/faucet/Faucet.sol"; import { Faucet } from "../periphery/faucet/Faucet.sol";
import { FaucetHelper } from "../testing/helpers/FaucetHelper.sol"; import { FaucetHelper } from "./Helpers.sol";
/** /**
* @title AdminFaucetAuthModuleTest * @title AdminFaucetAuthModuleTest
...@@ -104,7 +104,7 @@ contract AdminFaucetAuthModuleTest is Test { ...@@ -104,7 +104,7 @@ contract AdminFaucetAuthModuleTest is Test {
/** /**
* @notice assert that verify returns true for valid proofs signed by admins. * @notice assert that verify returns true for valid proofs signed by admins.
*/ */
function test_adminProof_verify_returnsTrue() external { function test_adminProof_verify_succeeds() external {
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver"); address fundsReceiver = makeAddr("fundsReceiver");
bytes memory proof = issueProofWithEIP712Domain( bytes memory proof = issueProofWithEIP712Domain(
...@@ -132,7 +132,7 @@ contract AdminFaucetAuthModuleTest is Test { ...@@ -132,7 +132,7 @@ contract AdminFaucetAuthModuleTest is Test {
/** /**
* @notice assert that verify returns false for proofs signed by nonadmins. * @notice assert that verify returns false for proofs signed by nonadmins.
*/ */
function test_nonAdminProof_verify_returnsFalse() external { function test_nonAdminProof_verify_succeeds() external {
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver"); address fundsReceiver = makeAddr("fundsReceiver");
bytes memory proof = issueProofWithEIP712Domain( bytes memory proof = issueProofWithEIP712Domain(
...@@ -161,7 +161,7 @@ contract AdminFaucetAuthModuleTest is Test { ...@@ -161,7 +161,7 @@ contract AdminFaucetAuthModuleTest is Test {
* @notice assert that verify returns false for proofs where the id in the proof is different * @notice assert that verify returns false for proofs where the id in the proof is different
* than the id in the call to verify. * than the id in the call to verify.
*/ */
function test_proofWithWrongId_verify_returnsFalse() external { function test_proofWithWrongId_verify_succeeds() external {
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver"); address fundsReceiver = makeAddr("fundsReceiver");
address randomAddress = makeAddr("randomAddress"); address randomAddress = makeAddr("randomAddress");
......
...@@ -3,9 +3,9 @@ pragma solidity 0.8.15; ...@@ -3,9 +3,9 @@ pragma solidity 0.8.15;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { TestERC20 } from "../testing/helpers/TestERC20.sol"; import { TestERC20 } from "./Helpers.sol";
import { TestERC721 } from "../testing/helpers/TestERC721.sol"; import { TestERC721 } from "./Helpers.sol";
import { AssetReceiver } from "../universal/AssetReceiver.sol"; import { AssetReceiver } from "../periphery/AssetReceiver.sol";
contract AssetReceiver_Initializer is Test { contract AssetReceiver_Initializer is Test {
address alice = address(128); address alice = address(128);
...@@ -54,12 +54,12 @@ contract AssetReceiver_Initializer is Test { ...@@ -54,12 +54,12 @@ contract AssetReceiver_Initializer is Test {
contract AssetReceiverTest is AssetReceiver_Initializer { contract AssetReceiverTest is AssetReceiver_Initializer {
// Tests if the owner was set correctly during deploy // Tests if the owner was set correctly during deploy
function test_constructor() external { function test_constructor_succeeds() external {
assertEq(address(alice), assetReceiver.owner()); assertEq(address(alice), assetReceiver.owner());
} }
// Tests that receive works as inteded // Tests that receive works as inteded
function test_receive() external { function test_receive_succeeds() external {
// Check that contract balance is 0 initially // Check that contract balance is 0 initially
assertEq(address(assetReceiver).balance, 0); assertEq(address(assetReceiver).balance, 0);
...@@ -75,7 +75,7 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -75,7 +75,7 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// Tests withdrawETH function with only an address as argument, called by owner // Tests withdrawETH function with only an address as argument, called by owner
function test_withdrawETH() external { function test_withdrawETH_succeeds() external {
// Check contract initial balance // Check contract initial balance
assertEq(address(assetReceiver).balance, 0); assertEq(address(assetReceiver).balance, 0);
// Fund contract with 1 eth and check caller and contract balances // Fund contract with 1 eth and check caller and contract balances
...@@ -97,14 +97,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -97,14 +97,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// withdrawETH should fail if called by non-owner // withdrawETH should fail if called by non-owner
function testFail_withdrawETH() external { function test_withdrawETH_unauthorized_reverts() external {
vm.deal(address(assetReceiver), 1 ether); vm.deal(address(assetReceiver), 1 ether);
assetReceiver.withdrawETH(payable(alice));
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawETH(payable(alice));
} }
// Similar as withdrawETH but specify amount to withdraw // Similar as withdrawETH but specify amount to withdraw
function test_withdrawETHwithAmount() external { function test_withdrawETHwithAmount_succeeds() external {
assertEq(address(assetReceiver).balance, 0); assertEq(address(assetReceiver).balance, 0);
vm.deal(address(assetReceiver), 1 ether); vm.deal(address(assetReceiver), 1 ether);
...@@ -125,14 +125,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -125,14 +125,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// withdrawETH with address and amount as arguments called by non-owner // withdrawETH with address and amount as arguments called by non-owner
function testFail_withdrawETHwithAmount() external { function test_withdrawETHwithAmount_unauthorized_reverts() external {
vm.deal(address(assetReceiver), 1 ether); vm.deal(address(assetReceiver), 1 ether);
assetReceiver.withdrawETH(payable(alice), 0.5 ether);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawETH(payable(alice), 0.5 ether);
} }
// Test withdrawERC20 with token and address arguments, from owner // Test withdrawERC20 with token and address arguments, from owner
function test_withdrawERC20() external { function test_withdrawERC20_succeeds() external {
// check balances before the call // check balances before the call
assertEq(testERC20.balanceOf(address(assetReceiver)), 0); assertEq(testERC20.balanceOf(address(assetReceiver)), 0);
...@@ -153,14 +153,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -153,14 +153,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// Same as withdrawERC20 but call from non-owner // Same as withdrawERC20 but call from non-owner
function testFail_withdrawERC20() external { function test_withdrawERC20_unauthorized_reverts() external {
deal(address(testERC20), address(assetReceiver), 100_000); deal(address(testERC20), address(assetReceiver), 100_000);
assetReceiver.withdrawERC20(testERC20, alice);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawERC20(testERC20, alice);
} }
// Similar as withdrawERC20 but specify amount to withdraw // Similar as withdrawERC20 but specify amount to withdraw
function test_withdrawERC20withAmount() external { function test_withdrawERC20withAmount_succeeds() external {
// check balances before the call // check balances before the call
assertEq(testERC20.balanceOf(address(assetReceiver)), 0); assertEq(testERC20.balanceOf(address(assetReceiver)), 0);
...@@ -181,14 +181,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -181,14 +181,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// Similar as withdrawERC20 with amount but call from non-owner // Similar as withdrawERC20 with amount but call from non-owner
function testFail_withdrawERC20withAmount() external { function test_withdrawERC20withAmount_unauthorized_reverts() external {
deal(address(testERC20), address(assetReceiver), 100_000); deal(address(testERC20), address(assetReceiver), 100_000);
assetReceiver.withdrawERC20(testERC20, alice, 50_000);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawERC20(testERC20, alice, 50_000);
} }
// Test withdrawERC721 from owner // Test withdrawERC721 from owner
function test_withdrawERC721() external { function test_withdrawERC721_succeeds() external {
// Check owner of the token before calling withdrawERC721 // Check owner of the token before calling withdrawERC721
assertEq(testERC721.ownerOf(DEFAULT_TOKEN_ID), alice); assertEq(testERC721.ownerOf(DEFAULT_TOKEN_ID), alice);
...@@ -209,10 +209,10 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -209,10 +209,10 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// Similar as withdrawERC721 but call from non-owner // Similar as withdrawERC721 but call from non-owner
function testFail_withdrawERC721() external { function test_withdrawERC721_unauthorized_reverts() external {
vm.prank(alice); vm.prank(alice);
testERC721.transferFrom(alice, address(assetReceiver), DEFAULT_TOKEN_ID); testERC721.transferFrom(alice, address(assetReceiver), DEFAULT_TOKEN_ID);
assetReceiver.withdrawERC721(testERC721, alice, DEFAULT_TOKEN_ID);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawERC721(testERC721, alice, DEFAULT_TOKEN_ID);
} }
} }
...@@ -3,7 +3,7 @@ pragma solidity 0.8.15; ...@@ -3,7 +3,7 @@ pragma solidity 0.8.15;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol"; import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
contract AttestationStation_Initializer is Test { contract AttestationStation_Initializer is Test {
address alice_attestor = address(128); address alice_attestor = address(128);
...@@ -28,7 +28,7 @@ contract AttestationStationTest is AttestationStation_Initializer { ...@@ -28,7 +28,7 @@ contract AttestationStationTest is AttestationStation_Initializer {
bytes val bytes val
); );
function test_attest_individual() external { function test_attest_individual_succeeds() external {
AttestationStation attestationStation = new AttestationStation(); AttestationStation attestationStation = new AttestationStation();
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
...@@ -38,7 +38,7 @@ contract AttestationStationTest is AttestationStation_Initializer { ...@@ -38,7 +38,7 @@ contract AttestationStationTest is AttestationStation_Initializer {
attestationStation.attest({ _about: bob, _key: bytes32("foo"), _val: bytes("bar") }); attestationStation.attest({ _about: bob, _key: bytes32("foo"), _val: bytes("bar") });
} }
function test_attest_single() external { function test_attest_single_succeeds() external {
AttestationStation attestationStation = new AttestationStation(); AttestationStation attestationStation = new AttestationStation();
AttestationStation.AttestationData[] AttestationStation.AttestationData[]
...@@ -100,7 +100,7 @@ contract AttestationStationTest is AttestationStation_Initializer { ...@@ -100,7 +100,7 @@ contract AttestationStationTest is AttestationStation_Initializer {
); );
} }
function test_attest_bulk() external { function test_attest_bulk_succeeds() external {
AttestationStation attestationStation = new AttestationStation(); AttestationStation attestationStation = new AttestationStation();
vm.prank(alice_attestor); vm.prank(alice_attestor);
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { CheckBalanceHigh } from "../universal/drippie/dripchecks/CheckBalanceHigh.sol"; import { CheckBalanceHigh } from "../periphery/drippie/dripchecks/CheckBalanceHigh.sol";
/** /**
* @title CheckBalanceHighTest * @title CheckBalanceHighTest
...@@ -43,7 +43,7 @@ contract CheckBalanceHighTest is Test { ...@@ -43,7 +43,7 @@ contract CheckBalanceHighTest is Test {
* @notice Fuzz the `check` function and assert that it always returns false * @notice Fuzz the `check` function and assert that it always returns false
* when the target's balance is smaller than the threshold. * when the target's balance is smaller than the threshold.
*/ */
function testFuzz_check_fails(address _target, uint256 _threshold) external { function testFuzz_check_lowBalance_fails(address _target, uint256 _threshold) external {
CheckBalanceHigh.Params memory p = CheckBalanceHigh.Params({ CheckBalanceHigh.Params memory p = CheckBalanceHigh.Params({
target: _target, target: _target,
threshold: _threshold threshold: _threshold
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { CheckBalanceLow } from "../universal/drippie/dripchecks/CheckBalanceLow.sol"; import { CheckBalanceLow } from "../periphery/drippie/dripchecks/CheckBalanceLow.sol";
/** /**
* @title CheckBalanceLowTest * @title CheckBalanceLowTest
...@@ -41,7 +41,7 @@ contract CheckBalanceLowTest is Test { ...@@ -41,7 +41,7 @@ contract CheckBalanceLowTest is Test {
* @notice Fuzz the `check` function and assert that it always returns false * @notice Fuzz the `check` function and assert that it always returns false
* when the target's balance is larger than the threshold. * when the target's balance is larger than the threshold.
*/ */
function testFuzz_check_fails(address _target, uint256 _threshold) external { function testFuzz_check_highBalance_fails(address _target, uint256 _threshold) external {
CheckBalanceLow.Params memory p = CheckBalanceLow.Params({ CheckBalanceLow.Params memory p = CheckBalanceLow.Params({
target: _target, target: _target,
threshold: _threshold threshold: _threshold
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { import {
CheckGelatoLow, CheckGelatoLow,
IGelatoTreasury IGelatoTreasury
} from "../universal/drippie/dripchecks/CheckGelatoLow.sol"; } from "../periphery/drippie/dripchecks/CheckGelatoLow.sol";
/** /**
* @title MockGelatoTreasury * @title MockGelatoTreasury
...@@ -78,7 +78,7 @@ contract CheckGelatoLowTest is Test { ...@@ -78,7 +78,7 @@ contract CheckGelatoLowTest is Test {
* when the user's balance in the treasury is greater than or equal * when the user's balance in the treasury is greater than or equal
* to the threshold. * to the threshold.
*/ */
function testFuzz_check_fails(uint256 _threshold, address _recipient) external { function testFuzz_check_highBalance_fails(uint256 _threshold, address _recipient) external {
CheckGelatoLow.Params memory p = CheckGelatoLow.Params({ CheckGelatoLow.Params memory p = CheckGelatoLow.Params({
treasury: address(gelato), treasury: address(gelato),
threshold: _threshold, threshold: _threshold,
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { CheckTrue } from "../universal/drippie/dripchecks/CheckTrue.sol"; import { CheckTrue } from "../periphery/drippie/dripchecks/CheckTrue.sol";
/** /**
* @title CheckTrueTest * @title CheckTrueTest
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { Drippie } from "../universal/drippie/Drippie.sol"; import { Drippie } from "../periphery/drippie/Drippie.sol";
import { IDripCheck } from "../universal/drippie/IDripCheck.sol"; import { IDripCheck } from "../periphery/drippie/IDripCheck.sol";
import { CheckTrue } from "../universal/drippie/dripchecks/CheckTrue.sol"; import { CheckTrue } from "../periphery/drippie/dripchecks/CheckTrue.sol";
import { SimpleStorage } from "../testing/helpers/SimpleStorage.sol"; import { SimpleStorage } from "./Helpers.sol";
/** /**
* @title TestDrippie * @title TestDrippie
...@@ -149,7 +149,7 @@ contract Drippie_Test is Test { ...@@ -149,7 +149,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Creates a drip and asserts that it was configured as expected. * @notice Creates a drip and asserts that it was configured as expected.
*/ */
function test_create_success() external { function test_create_succeeds() external {
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
emit DripCreated(dripName, dripName, cfg); emit DripCreated(dripName, dripName, cfg);
...@@ -188,7 +188,7 @@ contract Drippie_Test is Test { ...@@ -188,7 +188,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Ensures that the same drip cannot be created two times. * @notice Ensures that the same drip cannot be created two times.
*/ */
function test_create_fails_twice() external { function test_create_calledTwice_reverts() external {
vm.startPrank(drippie.owner()); vm.startPrank(drippie.owner());
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
drippie.create(dripName, cfg); drippie.create(dripName, cfg);
...@@ -200,7 +200,7 @@ contract Drippie_Test is Test { ...@@ -200,7 +200,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Ensures that only the owner of Drippie can create a drip. * @notice Ensures that only the owner of Drippie can create a drip.
*/ */
function testFuzz_fails_unauthorized(address caller) external { function testFuzz_owner_unauthorized_reverts(address caller) external {
vm.assume(caller != drippie.owner()); vm.assume(caller != drippie.owner());
vm.prank(caller); vm.prank(caller);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
...@@ -210,7 +210,7 @@ contract Drippie_Test is Test { ...@@ -210,7 +210,7 @@ contract Drippie_Test is Test {
/** /**
* @notice The owner should be able to set the status of the drip. * @notice The owner should be able to set the status of the drip.
*/ */
function test_set_status_success() external { function test_set_status_succeeds() external {
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
emit DripCreated(dripName, dripName, _defaultConfig()); emit DripCreated(dripName, dripName, _defaultConfig());
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
...@@ -258,7 +258,7 @@ contract Drippie_Test is Test { ...@@ -258,7 +258,7 @@ contract Drippie_Test is Test {
/** /**
* @notice The drip status cannot be set back to NONE after it is created. * @notice The drip status cannot be set back to NONE after it is created.
*/ */
function test_set_status_none_fails() external { function test_set_statusNone_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -272,7 +272,7 @@ contract Drippie_Test is Test { ...@@ -272,7 +272,7 @@ contract Drippie_Test is Test {
* @notice The owner cannot set the status of the drip to the status that * @notice The owner cannot set the status of the drip to the status that
* it is already set as. * it is already set as.
*/ */
function test_set_status_same_fails() external { function test_set_statusSame_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -286,7 +286,7 @@ contract Drippie_Test is Test { ...@@ -286,7 +286,7 @@ contract Drippie_Test is Test {
* @notice The owner should be able to archive the drip if it is in the * @notice The owner should be able to archive the drip if it is in the
* paused state. * paused state.
*/ */
function test_should_archive_if_paused_success() external { function test_shouldArchive_ifPaused_succeeds() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
address owner = drippie.owner(); address owner = drippie.owner();
...@@ -310,7 +310,7 @@ contract Drippie_Test is Test { ...@@ -310,7 +310,7 @@ contract Drippie_Test is Test {
* @notice The owner should not be able to archive the drip if it is in the * @notice The owner should not be able to archive the drip if it is in the
* active state. * active state.
*/ */
function test_should_not_archive_if_active_fails() external { function test_shouldNotArchive_ifActive_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -327,7 +327,7 @@ contract Drippie_Test is Test { ...@@ -327,7 +327,7 @@ contract Drippie_Test is Test {
* @notice The owner should not be allowed to pause the drip if it * @notice The owner should not be allowed to pause the drip if it
* has already been archived. * has already been archived.
*/ */
function test_should_not_allow_paused_if_archived_fails() external { function test_shouldNotAllowPaused_ifArchived_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
_notAllowFromArchive(dripName, Drippie.DripStatus.PAUSED); _notAllowFromArchive(dripName, Drippie.DripStatus.PAUSED);
...@@ -337,7 +337,7 @@ contract Drippie_Test is Test { ...@@ -337,7 +337,7 @@ contract Drippie_Test is Test {
* @notice The owner should not be allowed to make the drip active again if * @notice The owner should not be allowed to make the drip active again if
* it has already been archived. * it has already been archived.
*/ */
function test_should_not_allow_active_if_archived_fails() external { function test_shouldNotAllowActive_ifArchived_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
_notAllowFromArchive(dripName, Drippie.DripStatus.ACTIVE); _notAllowFromArchive(dripName, Drippie.DripStatus.ACTIVE);
...@@ -361,7 +361,7 @@ contract Drippie_Test is Test { ...@@ -361,7 +361,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Attempt to update a drip that does not exist. * @notice Attempt to update a drip that does not exist.
*/ */
function test_name_not_exist_fails() external { function test_name_notExist_reverts() external {
string memory otherName = "bar"; string memory otherName = "bar";
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -376,7 +376,7 @@ contract Drippie_Test is Test { ...@@ -376,7 +376,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Expect a revert when attempting to set the status when not the owner. * @notice Expect a revert when attempting to set the status when not the owner.
*/ */
function test_status_unauthorized_fails() external { function test_status_unauthorized_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
...@@ -386,7 +386,7 @@ contract Drippie_Test is Test { ...@@ -386,7 +386,7 @@ contract Drippie_Test is Test {
/** /**
* @notice The drip should execute and be able to transfer value. * @notice The drip should execute and be able to transfer value.
*/ */
function test_drip_amount() external { function test_drip_amount_succeeds() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -418,7 +418,7 @@ contract Drippie_Test is Test { ...@@ -418,7 +418,7 @@ contract Drippie_Test is Test {
/** /**
* @notice A single DripAction should be able to make a state modifying call. * @notice A single DripAction should be able to make a state modifying call.
*/ */
function test_trigger_one_function() external { function test_trigger_oneFunction_succeeds() external {
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
bytes32 key = bytes32(uint256(2)); bytes32 key = bytes32(uint256(2));
...@@ -455,7 +455,7 @@ contract Drippie_Test is Test { ...@@ -455,7 +455,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Multiple drip actions should be able to be triggered with the same check. * @notice Multiple drip actions should be able to be triggered with the same check.
*/ */
function test_trigger_two_functions() external { function test_trigger_twoFunctions_succeeds() external {
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
Drippie.DripAction[] memory actions = new Drippie.DripAction[](2); Drippie.DripAction[] memory actions = new Drippie.DripAction[](2);
...@@ -516,7 +516,7 @@ contract Drippie_Test is Test { ...@@ -516,7 +516,7 @@ contract Drippie_Test is Test {
* trigger the same drip multiple times in the same interval. Then * trigger the same drip multiple times in the same interval. Then
* move forward to the next interval and it should trigger. * move forward to the next interval and it should trigger.
*/ */
function test_twice_in_one_interval_fails() external { function test_twice_inOneInterval_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -551,7 +551,7 @@ contract Drippie_Test is Test { ...@@ -551,7 +551,7 @@ contract Drippie_Test is Test {
* @notice It should revert if attempting to trigger a drip that does not exist. * @notice It should revert if attempting to trigger a drip that does not exist.
* Note that the drip was never created at the beginning of the test. * Note that the drip was never created at the beginning of the test.
*/ */
function test_drip_not_exist_fails() external { function test_drip_notExist_reverts() external {
vm.prank(drippie.owner()); vm.prank(drippie.owner());
vm.expectRevert("Drippie: selected drip does not exist or is not currently active"); vm.expectRevert("Drippie: selected drip does not exist or is not currently active");
...@@ -562,7 +562,7 @@ contract Drippie_Test is Test { ...@@ -562,7 +562,7 @@ contract Drippie_Test is Test {
/** /**
* @notice The owner cannot trigger the drip when it is paused. * @notice The owner cannot trigger the drip when it is paused.
*/ */
function test_not_active_fails() external { function test_not_active_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
Drippie.DripStatus status = drippie.dripStatus(dripName); Drippie.DripStatus status = drippie.dripStatus(dripName);
...@@ -598,7 +598,7 @@ contract Drippie_Test is Test { ...@@ -598,7 +598,7 @@ contract Drippie_Test is Test {
* @notice A non zero interval when reentrant is true will cause a revert * @notice A non zero interval when reentrant is true will cause a revert
* when creating a drip. * when creating a drip.
*/ */
function test_reentrant_fails() external { function test_drip_reentrant_reverts() external {
address owner = drippie.owner(); address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
cfg.reentrant = true; cfg.reentrant = true;
...@@ -614,7 +614,7 @@ contract Drippie_Test is Test { ...@@ -614,7 +614,7 @@ contract Drippie_Test is Test {
* @notice If reentrant is false and the interval is 0 then it should * @notice If reentrant is false and the interval is 0 then it should
* revert when the drip is created. * revert when the drip is created.
*/ */
function test_non_reentrant_zero_interval_fails() external { function test_notReentrant_zeroInterval_reverts() external {
address owner = drippie.owner(); address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
cfg.reentrant = false; cfg.reentrant = false;
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { Faucet } from "../universal/faucet/Faucet.sol"; import { Faucet } from "../periphery/faucet/Faucet.sol";
import { AdminFaucetAuthModule } from "../universal/faucet/authmodules/AdminFaucetAuthModule.sol"; import { AdminFaucetAuthModule } from "../periphery/faucet/authmodules/AdminFaucetAuthModule.sol";
import { FaucetHelper } from "../testing/helpers/FaucetHelper.sol"; import { FaucetHelper } from "./Helpers.sol";
contract Faucet_Initializer is Test { contract Faucet_Initializer is Test {
event Drip( event Drip(
...@@ -126,7 +126,7 @@ contract Faucet_Initializer is Test { ...@@ -126,7 +126,7 @@ contract Faucet_Initializer is Test {
} }
contract FaucetTest is Faucet_Initializer { contract FaucetTest is Faucet_Initializer {
function test_initialize() external { function test_initialize_succeeds() external {
assertEq(faucet.ADMIN(), faucetContractAdmin); assertEq(faucet.ADMIN(), faucetContractAdmin);
} }
...@@ -181,7 +181,7 @@ contract FaucetTest is Faucet_Initializer { ...@@ -181,7 +181,7 @@ contract FaucetTest is Faucet_Initializer {
); );
} }
function test_drip_optimistNft_sendsCorrectAmount() external { function test_drip_optimistNftSendsCorrectAmount_succeeds() external {
_enableFaucetAuthModules(); _enableFaucetAuthModules();
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
bytes memory signature = issueProofWithEIP712Domain( bytes memory signature = issueProofWithEIP712Domain(
...@@ -213,7 +213,7 @@ contract FaucetTest is Faucet_Initializer { ...@@ -213,7 +213,7 @@ contract FaucetTest is Faucet_Initializer {
); );
} }
function test_drip_github_sendsCorrectAmount() external { function test_drip_githubSendsCorrectAmount_succeeds() external {
_enableFaucetAuthModules(); _enableFaucetAuthModules();
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
bytes memory signature = issueProofWithEIP712Domain( bytes memory signature = issueProofWithEIP712Domain(
...@@ -241,7 +241,7 @@ contract FaucetTest is Faucet_Initializer { ...@@ -241,7 +241,7 @@ contract FaucetTest is Faucet_Initializer {
); );
} }
function test_drip_emitsEvent() external { function test_drip_emitsEvent_succeeds() external {
_enableFaucetAuthModules(); _enableFaucetAuthModules();
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
bytes memory signature = issueProofWithEIP712Domain( bytes memory signature = issueProofWithEIP712Domain(
...@@ -300,7 +300,7 @@ contract FaucetTest is Faucet_Initializer { ...@@ -300,7 +300,7 @@ contract FaucetTest is Faucet_Initializer {
vm.stopPrank(); vm.stopPrank();
} }
function test_drip_preventsReplayAttacks() external { function test_drip_preventsReplayAttacks_succeeds() external {
_enableFaucetAuthModules(); _enableFaucetAuthModules();
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
bytes memory signature = issueProofWithEIP712Domain( bytes memory signature = issueProofWithEIP712Domain(
...@@ -423,7 +423,7 @@ contract FaucetTest is Faucet_Initializer { ...@@ -423,7 +423,7 @@ contract FaucetTest is Faucet_Initializer {
vm.stopPrank(); vm.stopPrank();
} }
function test_withdraw_nonAdmin_fails() external { function test_withdraw_nonAdmin_reverts() external {
vm.prank(nonAdmin); vm.prank(nonAdmin);
vm.expectRevert("Faucet: function can only be called by admin"); vm.expectRevert("Faucet: function can only be called by admin");
faucet.withdraw(payable(fundsReceiver), 2 ether); faucet.withdraw(payable(fundsReceiver), 2 ether);
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity ^0.8.0;
import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
import { ERC721 } from "@rari-capital/solmate/src/tokens/ERC721.sol";
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import {
ECDSAUpgradeable
} from "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
import { AdminFaucetAuthModule } from "../periphery/faucet/authmodules/AdminFaucetAuthModule.sol";
import { OptimistInviter } from "../../universal/op-nft/OptimistInviter.sol"; contract TestERC20 is ERC20 {
constructor() ERC20("TEST", "TST", 18) {}
function mint(address to, uint256 value) public {
_mint(to, value);
}
}
contract TestERC721 is ERC721 {
constructor() ERC721("TEST", "TST") {}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function tokenURI(uint256) public pure virtual override returns (string memory) {}
}
contract CallRecorder {
struct CallInfo {
address sender;
bytes data;
uint256 gas;
uint256 value;
}
CallInfo public lastCall;
function record() public payable {
lastCall.sender = msg.sender;
lastCall.data = msg.data;
lastCall.gas = gasleft();
lastCall.value = msg.value;
}
}
contract Reverter {
function doRevert() public pure {
revert("Reverter reverted");
}
}
contract SimpleStorage {
mapping(bytes32 => bytes32) public db;
function set(bytes32 _key, bytes32 _value) public payable {
db[_key] = _value;
}
function get(bytes32 _key) public view returns (bytes32) {
return db[_key];
}
}
/** /**
* Simple helper contract that helps with testing flow and signature for OptimistInviter contract. * Simple helper contract that helps with testing flow and signature for OptimistInviter contract.
...@@ -144,3 +205,106 @@ contract OptimistInviterHelper { ...@@ -144,3 +205,106 @@ contract OptimistInviterHelper {
ECDSA.toTypedDataHash(domainSeparator, getClaimableInviteStructHash(_claimableInvite)); ECDSA.toTypedDataHash(domainSeparator, getClaimableInviteStructHash(_claimableInvite));
} }
} }
// solhint-disable max-line-length
/**
* Simple ERC1271 wallet that can be used to test the ERC1271 signature checker.
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/mocks/ERC1271WalletMock.sol
*/
contract TestERC1271Wallet is Ownable, IERC1271 {
constructor(address originalOwner) {
transferOwnership(originalOwner);
}
function isValidSignature(bytes32 hash, bytes memory signature)
public
view
override
returns (bytes4 magicValue)
{
return
ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0);
}
}
/**
* Simple helper contract that helps with testing the Faucet contract.
*/
contract FaucetHelper {
/**
* @notice EIP712 typehash for the Proof type.
*/
bytes32 public constant PROOF_TYPEHASH =
keccak256("Proof(address recipient,bytes32 nonce,bytes32 id)");
/**
* @notice EIP712 typehash for the EIP712Domain type that is included as part of the signature.
*/
bytes32 public constant EIP712_DOMAIN_TYPEHASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
/**
* @notice Keeps track of current nonce to generate new nonces for each drip.
*/
uint256 public currentNonce;
/**
* @notice Returns a bytes32 nonce that should change everytime. In practice, people should use
* pseudorandom nonces.
*
* @return Nonce that should be used as part of drip parameters.
*/
function consumeNonce() public returns (bytes32) {
return bytes32(keccak256(abi.encode(currentNonce++)));
}
/**
* @notice Returns the hash of the struct Proof.
*
* @param _proof Proof struct to hash.
*
* @return EIP-712 typed struct hash.
*/
function getProofStructHash(AdminFaucetAuthModule.Proof memory _proof)
public
pure
returns (bytes32)
{
return keccak256(abi.encode(PROOF_TYPEHASH, _proof.recipient, _proof.nonce, _proof.id));
}
/**
* @notice Computes the EIP712 digest with the given domain parameters.
* Used for testing that different domain parameters fail.
*
* @param _proof Proof struct to hash.
* @param _name Contract name to use in the EIP712 domain.
* @param _version Contract version to use in the EIP712 domain.
* @param _chainid Chain ID to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
*
* @return EIP-712 compatible digest.
*/
function getDigestWithEIP712Domain(
AdminFaucetAuthModule.Proof memory _proof,
bytes memory _name,
bytes memory _version,
uint256 _chainid,
address _verifyingContract
) public pure returns (bytes32) {
bytes32 domainSeparator = keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(_name),
keccak256(_version),
_chainid,
_verifyingContract
)
);
return ECDSAUpgradeable.toTypedDataHash(domainSeparator, getProofStructHash(_proof));
}
}
...@@ -3,11 +3,11 @@ pragma solidity 0.8.15; ...@@ -3,11 +3,11 @@ pragma solidity 0.8.15;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol"; import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { OptimistAllowlist } from "../universal/op-nft/OptimistAllowlist.sol"; import { OptimistAllowlist } from "../periphery/op-nft/OptimistAllowlist.sol";
import { OptimistInviter } from "../universal/op-nft/OptimistInviter.sol"; import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { OptimistInviterHelper } from "../testing/helpers/OptimistInviterHelper.sol"; import { OptimistInviterHelper } from "./Helpers.sol";
import { OptimistConstants } from "../universal/op-nft/libraries/OptimistConstants.sol"; import { OptimistConstants } from "../periphery/op-nft/libraries/OptimistConstants.sol";
contract OptimistAllowlist_Initializer is Test { contract OptimistAllowlist_Initializer is Test {
event AttestationCreated( event AttestationCreated(
......
...@@ -3,13 +3,13 @@ pragma solidity 0.8.15; ...@@ -3,13 +3,13 @@ pragma solidity 0.8.15;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol"; import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { OptimistInviter } from "../universal/op-nft/OptimistInviter.sol"; import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { Optimist } from "../universal/op-nft/Optimist.sol"; import { Optimist } from "../periphery/op-nft/Optimist.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { TestERC1271Wallet } from "../testing/helpers/TestERC1271Wallet.sol"; import { TestERC1271Wallet } from "./Helpers.sol";
import { OptimistInviterHelper } from "../testing/helpers/OptimistInviterHelper.sol"; import { OptimistInviterHelper } from "./Helpers.sol";
import { OptimistConstants } from "../universal/op-nft/libraries/OptimistConstants.sol"; import { OptimistConstants } from "../periphery/op-nft/libraries/OptimistConstants.sol";
contract OptimistInviter_Initializer is Test { contract OptimistInviter_Initializer is Test {
event InviteClaimed(address indexed issuer, address indexed claimer); event InviteClaimed(address indexed issuer, address indexed claimer);
...@@ -260,7 +260,7 @@ contract OptimistInviter_Initializer is Test { ...@@ -260,7 +260,7 @@ contract OptimistInviter_Initializer is Test {
} }
contract OptimistInviterTest is OptimistInviter_Initializer { contract OptimistInviterTest is OptimistInviter_Initializer {
function test_initialize() external { function test_initialize_succeeds() external {
// expect attestationStation to be set // expect attestationStation to be set
assertEq(address(optimistInviter.ATTESTATION_STATION()), address(attestationStation)); assertEq(address(optimistInviter.ATTESTATION_STATION()), address(attestationStation));
assertEq(optimistInviter.INVITE_GRANTER(), alice_inviteGranter); assertEq(optimistInviter.INVITE_GRANTER(), alice_inviteGranter);
......
...@@ -3,9 +3,9 @@ pragma solidity 0.8.15; ...@@ -3,9 +3,9 @@ pragma solidity 0.8.15;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { CallRecorder } from "../testing/helpers/CallRecorder.sol"; import { CallRecorder } from "./Helpers.sol";
import { Reverter } from "../testing/helpers/Reverter.sol"; import { Reverter } from "./Helpers.sol";
import { Transactor } from "../universal/Transactor.sol"; import { Transactor } from "../periphery/Transactor.sol";
contract Transactor_Initializer is Test { contract Transactor_Initializer is Test {
address alice = address(128); address alice = address(128);
...@@ -35,12 +35,12 @@ contract Transactor_Initializer is Test { ...@@ -35,12 +35,12 @@ contract Transactor_Initializer is Test {
contract TransactorTest is Transactor_Initializer { contract TransactorTest is Transactor_Initializer {
// Tests if the owner was set correctly during deploy // Tests if the owner was set correctly during deploy
function test_constructor() external { function test_constructor_succeeds() external {
assertEq(address(alice), transactor.owner()); assertEq(address(alice), transactor.owner());
} }
// Tests CALL, should do a call to target // Tests CALL, should do a call to target
function test_CALL() external { function test_call_succeeds() external {
// Initialize call data // Initialize call data
bytes memory data = abi.encodeWithSelector(callRecorded.record.selector); bytes memory data = abi.encodeWithSelector(callRecorded.record.selector);
// Run CALL // Run CALL
...@@ -50,16 +50,16 @@ contract TransactorTest is Transactor_Initializer { ...@@ -50,16 +50,16 @@ contract TransactorTest is Transactor_Initializer {
} }
// It should revert if called by non-owner // It should revert if called by non-owner
function testFail_CALL() external { function test_call_unauthorized_reverts() external {
// Initialize call data // Initialize call data
bytes memory data = abi.encodeWithSelector(callRecorded.record.selector); bytes memory data = abi.encodeWithSelector(callRecorded.record.selector);
// Run CALL // Run CALL
vm.prank(bob); vm.prank(bob);
transactor.CALL(address(callRecorded), data, 200_000 wei);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
transactor.CALL(address(callRecorded), data, 200_000 wei);
} }
function test_DELEGATECALL() external { function test_delegateCall_succeeds() external {
// Initialize call data // Initialize call data
bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector); bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector);
// Run CALL // Run CALL
...@@ -69,12 +69,12 @@ contract TransactorTest is Transactor_Initializer { ...@@ -69,12 +69,12 @@ contract TransactorTest is Transactor_Initializer {
} }
// It should revert if called by non-owner // It should revert if called by non-owner
function testFail_DELEGATECALLL() external { function test_delegateCall_unauthorized_reverts() external {
// Initialize call data // Initialize call data
bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector); bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector);
// Run CALL // Run CALL
vm.prank(bob); vm.prank(bob);
transactor.DELEGATECALL(address(reverter), data);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
transactor.DELEGATECALL(address(reverter), data);
} }
} }
...@@ -44,6 +44,6 @@ ...@@ -44,6 +44,6 @@
"l1GenesisBlockTimestamp": "0x64935846", "l1GenesisBlockTimestamp": "0x64935846",
"l1StartingBlockTag": "earliest", "l1StartingBlockTag": "earliest",
"l2GenesisRegolithTimeOffset": "0x0", "l2GenesisRegolithTimeOffset": "0x0",
"faultGameAbsolutePrestate": 15, "faultGameAbsolutePrestate": 140,
"faultGameMaxDepth": 4 "faultGameMaxDepth": 4
} }
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment