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

Merge branch 'develop' into sc/cmon-init

parents 4ee0efca 70fd8913
---
'@eth-optimism/common-ts': minor
---
Add option to configure body parser
.github .github
.vscode
node_modules node_modules
**/node_modules
.env .env
**/.env **/.env
......
...@@ -3,21 +3,18 @@ package batcher ...@@ -3,21 +3,18 @@ package batcher
import ( import (
"context" "context"
"fmt" "fmt"
"math/big"
_ "net/http/pprof" _ "net/http/pprof"
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
"time" "time"
"github.com/urfave/cli"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
opsigner "github.com/ethereum-optimism/optimism/op-signer/client"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/urfave/cli"
) )
const ( const (
...@@ -30,98 +27,75 @@ const ( ...@@ -30,98 +27,75 @@ const (
// closure that executes the service and blocks until the service exits. The use // closure that executes the service and blocks until the service exits. The use
// of a closure allows the parameters bound to the top-level main package, e.g. // of a closure allows the parameters bound to the top-level main package, e.g.
// GitVersion, to be captured and used once the function is executed. // GitVersion, to be captured and used once the function is executed.
func Main(version string) func(cliCtx *cli.Context) error { func Main(version string, cliCtx *cli.Context) error {
return func(cliCtx *cli.Context) error { cfg := NewConfig(cliCtx)
cfg := NewConfig(cliCtx) if err := cfg.Check(); err != nil {
if err := cfg.Check(); err != nil { return fmt.Errorf("invalid CLI flags: %w", err)
return fmt.Errorf("invalid CLI flags: %w", err) }
}
l := oplog.NewLogger(cfg.LogConfig)
l.Info("Initializing Batch Submitter")
var batchSubmitter *BatchSubmitter l := oplog.NewLogger(cfg.LogConfig)
if !cfg.SignerConfig.Enabled() { l.Info("Initializing Batch Submitter")
bs, err := NewBatchSubmitter(cfg, l)
if err != nil {
l.Error("Unable to create Batch Submitter", "error", err)
return err
}
batchSubmitter = bs
} else {
signerClient, err := opsigner.NewSignerClientFromConfig(l, cfg.SignerConfig)
if err != nil {
l.Error("Unable to create Signer Client", "error", err)
return err
}
signer := func(chainID *big.Int) SignerFn {
return func(ctx context.Context, rawTx types.TxData) (*types.Transaction, error) {
tx := types.NewTx(rawTx)
return signerClient.SignTransaction(ctx, chainID, tx)
}
}
bs, err := NewBatchSubmitterWithSigner(cfg, common.HexToAddress(cfg.SignerConfig.Address), signer, l)
if err != nil {
l.Error("Unable to create Batch Submitter with signer", "error", err)
return err
}
batchSubmitter = bs
}
l.Info("Starting Batch Submitter") batchSubmitter, err := NewBatchSubmitterFromCLIConfig(cfg, l)
if err != nil {
l.Error("Unable to create Batch Submitter", "error", err)
return err
}
if err := batchSubmitter.Start(); err != nil { l.Info("Starting Batch Submitter")
l.Error("Unable to start Batch Submitter", "error", err)
return err
}
defer batchSubmitter.Stop()
ctx, cancel := context.WithCancel(context.Background()) if err := batchSubmitter.Start(); err != nil {
l.Error("Unable to start Batch Submitter", "error", err)
return err
}
defer batchSubmitter.Stop()
l.Info("Batch Submitter started") ctx, cancel := context.WithCancel(context.Background())
pprofConfig := cfg.PprofConfig
if pprofConfig.Enabled {
l.Info("starting pprof", "addr", pprofConfig.ListenAddr, "port", pprofConfig.ListenPort)
go func() {
if err := oppprof.ListenAndServe(ctx, pprofConfig.ListenAddr, pprofConfig.ListenPort); err != nil {
l.Error("error starting pprof", "err", err)
}
}()
}
registry := opmetrics.NewRegistry() l.Info("Batch Submitter started")
metricsCfg := cfg.MetricsConfig pprofConfig := cfg.PprofConfig
if metricsCfg.Enabled { if pprofConfig.Enabled {
l.Info("starting metrics server", "addr", metricsCfg.ListenAddr, "port", metricsCfg.ListenPort) l.Info("starting pprof", "addr", pprofConfig.ListenAddr, "port", pprofConfig.ListenPort)
go func() { go func() {
if err := opmetrics.ListenAndServe(ctx, registry, metricsCfg.ListenAddr, metricsCfg.ListenPort); err != nil { if err := oppprof.ListenAndServe(ctx, pprofConfig.ListenAddr, pprofConfig.ListenPort); err != nil {
l.Error("error starting metrics server", err) l.Error("error starting pprof", "err", err)
} }
}() }()
opmetrics.LaunchBalanceMetrics(ctx, l, registry, "", batchSubmitter.cfg.L1Client, batchSubmitter.addr) }
}
rpcCfg := cfg.RPCConfig registry := opmetrics.NewRegistry()
server := oprpc.NewServer( metricsCfg := cfg.MetricsConfig
rpcCfg.ListenAddr, if metricsCfg.Enabled {
rpcCfg.ListenPort, l.Info("starting metrics server", "addr", metricsCfg.ListenAddr, "port", metricsCfg.ListenPort)
version, go func() {
) if err := opmetrics.ListenAndServe(ctx, registry, metricsCfg.ListenAddr, metricsCfg.ListenPort); err != nil {
if err := server.Start(); err != nil { l.Error("error starting metrics server", err)
cancel() }
return fmt.Errorf("error starting RPC server: %w", err) }()
} opmetrics.LaunchBalanceMetrics(ctx, l, registry, "", batchSubmitter.L1Client, batchSubmitter.From)
}
interruptChannel := make(chan os.Signal, 1) rpcCfg := cfg.RPCConfig
signal.Notify(interruptChannel, []os.Signal{ server := oprpc.NewServer(
os.Interrupt, rpcCfg.ListenAddr,
os.Kill, rpcCfg.ListenPort,
syscall.SIGTERM, version,
syscall.SIGQUIT, )
}...) if err := server.Start(); err != nil {
<-interruptChannel
cancel() cancel()
_ = server.Stop() return fmt.Errorf("error starting RPC server: %w", err)
return nil
} }
interruptChannel := make(chan os.Signal, 1)
signal.Notify(interruptChannel, []os.Signal{
os.Interrupt,
os.Kill,
syscall.SIGTERM,
syscall.SIGQUIT,
}...)
<-interruptChannel
cancel()
_ = server.Stop()
return nil
} }
package batcher package batcher
import ( import (
"math/big"
"time" "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/ethereum-optimism/optimism/op-batcher/flags" "github.com/ethereum-optimism/optimism/op-batcher/flags"
"github.com/ethereum-optimism/optimism/op-node/sources"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
opsigner "github.com/ethereum-optimism/optimism/op-signer/client" opsigner "github.com/ethereum-optimism/optimism/op-signer/client"
) )
type Config struct { type Config struct {
log log.Logger
L1Client *ethclient.Client
L2Client *ethclient.Client
RollupNode *sources.RollupClient
PollInterval time.Duration
TxManagerConfig txmgr.Config
From common.Address
SignerFnFactory opcrypto.SignerFactory
ChainID *big.Int
// Where to send the batch txs to.
BatchInboxAddress common.Address
// Channel creation parameters
Channel ChannelConfig
}
type CLIConfig struct {
/* Required Params */ /* Required Params */
// L1EthRpc is the HTTP provider URL for L1. // L1EthRpc is the HTTP provider URL for L1.
...@@ -89,7 +114,7 @@ type Config struct { ...@@ -89,7 +114,7 @@ type Config struct {
SignerConfig opsigner.CLIConfig SignerConfig opsigner.CLIConfig
} }
func (c Config) Check() error { func (c CLIConfig) Check() error {
if err := c.RPCConfig.Check(); err != nil { if err := c.RPCConfig.Check(); err != nil {
return err return err
} }
...@@ -109,8 +134,8 @@ func (c Config) Check() error { ...@@ -109,8 +134,8 @@ func (c Config) Check() error {
} }
// NewConfig parses the Config from the provided flags or environment variables. // NewConfig parses the Config from the provided flags or environment variables.
func NewConfig(ctx *cli.Context) Config { func NewConfig(ctx *cli.Context) CLIConfig {
return Config{ return CLIConfig{
/* Required Flags */ /* Required Flags */
L1EthRpc: ctx.GlobalString(flags.L1EthRpcFlag.Name), L1EthRpc: ctx.GlobalString(flags.L1EthRpcFlag.Name),
L2EthRpc: ctx.GlobalString(flags.L2EthRpcFlag.Name), L2EthRpc: ctx.GlobalString(flags.L2EthRpcFlag.Name),
......
...@@ -2,34 +2,28 @@ package batcher ...@@ -2,34 +2,28 @@ package batcher
import ( import (
"context" "context"
"crypto/ecdsa"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"strings" _ "net/http/pprof"
"sync" "sync"
"time" "time"
hdwallet "github.com/ethereum-optimism/go-ethereum-hdwallet"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
// BatchSubmitter encapsulates a service responsible for submitting L2 tx // BatchSubmitter encapsulates a service responsible for submitting L2 tx
// batches to L1 for availability. // batches to L1 for availability.
type BatchSubmitter struct { type BatchSubmitter struct {
Config // directly embed the config + sources
txMgr *TransactionManager txMgr *TransactionManager
addr common.Address
cfg DriverConfig
wg sync.WaitGroup wg sync.WaitGroup
done chan struct{} done chan struct{}
log log.Logger
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
...@@ -40,63 +34,16 @@ type BatchSubmitter struct { ...@@ -40,63 +34,16 @@ type BatchSubmitter struct {
state *channelManager state *channelManager
} }
// NewBatchSubmitter initializes the BatchSubmitter, gathering any resources // NewBatchSubmitterFromCLIConfig initializes the BatchSubmitter, gathering any resources
// that will be needed during operation. // that will be needed during operation.
func NewBatchSubmitter(cfg Config, l log.Logger) (*BatchSubmitter, error) { func NewBatchSubmitterFromCLIConfig(cfg CLIConfig, l log.Logger) (*BatchSubmitter, error) {
var err error ctx := context.Background()
var sequencerPrivKey *ecdsa.PrivateKey
var addr common.Address
if cfg.PrivateKey != "" && cfg.Mnemonic != "" {
return nil, errors.New("cannot specify both a private key and a mnemonic")
}
if cfg.PrivateKey == "" {
// Parse wallet private key that will be used to submit L2 txs to the batch
// inbox address.
wallet, err := hdwallet.NewFromMnemonic(cfg.Mnemonic)
if err != nil {
return nil, err
}
acc := accounts.Account{
URL: accounts.URL{
Path: cfg.SequencerHDPath,
},
}
addr, err = wallet.Address(acc)
if err != nil {
return nil, err
}
sequencerPrivKey, err = wallet.PrivateKey(acc)
if err != nil {
return nil, err
}
} else {
sequencerPrivKey, err = crypto.HexToECDSA(strings.TrimPrefix(cfg.PrivateKey, "0x"))
if err != nil {
return nil, err
}
addr = crypto.PubkeyToAddress(sequencerPrivKey.PublicKey)
}
signer := func(chainID *big.Int) SignerFn { signer, fromAddress, err := opcrypto.SignerFactoryFromConfig(l, cfg.PrivateKey, cfg.Mnemonic, cfg.SequencerHDPath, cfg.SignerConfig)
s := types.LatestSignerForChainID(chainID) if err != nil {
return func(_ context.Context, rawTx types.TxData) (*types.Transaction, error) { return nil, err
return types.SignNewTx(sequencerPrivKey, s, rawTx)
}
} }
return NewBatchSubmitterWithSigner(cfg, addr, signer, l)
}
type SignerFactory func(chainID *big.Int) SignerFn
func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerFactory, l log.Logger) (*BatchSubmitter, error) {
ctx := context.Background()
batchInboxAddress, err := parseAddress(cfg.SequencerBatchInboxAddress) batchInboxAddress, err := parseAddress(cfg.SequencerBatchInboxAddress)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -124,13 +71,6 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF ...@@ -124,13 +71,6 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF
return nil, err return nil, err
} }
sequencerBalance, err := l1Client.BalanceAt(ctx, addr, nil)
if err != nil {
return nil, err
}
log.Info("starting batch submitter", "submitter_addr", addr, "submitter_bal", sequencerBalance)
txManagerConfig := txmgr.Config{ txManagerConfig := txmgr.Config{
Log: l, Log: l,
Name: "Batch Submitter", Name: "Batch Submitter",
...@@ -140,12 +80,15 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF ...@@ -140,12 +80,15 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF
SafeAbortNonceTooLowCount: cfg.SafeAbortNonceTooLowCount, SafeAbortNonceTooLowCount: cfg.SafeAbortNonceTooLowCount,
} }
batcherCfg := DriverConfig{ batcherCfg := Config{
Log: l,
Name: "Batch Submitter",
L1Client: l1Client, L1Client: l1Client,
L2Client: l2Client, L2Client: l2Client,
RollupNode: rollupClient, RollupNode: rollupClient,
ChainID: chainID,
PollInterval: cfg.PollInterval,
TxManagerConfig: txManagerConfig,
From: fromAddress,
SignerFnFactory: signer,
BatchInboxAddress: batchInboxAddress, BatchInboxAddress: batchInboxAddress,
Channel: ChannelConfig{ Channel: ChannelConfig{
ChannelTimeout: cfg.ChannelTimeout, ChannelTimeout: cfg.ChannelTimeout,
...@@ -154,24 +97,36 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF ...@@ -154,24 +97,36 @@ func NewBatchSubmitterWithSigner(cfg Config, addr common.Address, signer SignerF
TargetNumFrames: cfg.TargetNumFrames, TargetNumFrames: cfg.TargetNumFrames,
ApproxComprRatio: cfg.ApproxComprRatio, ApproxComprRatio: cfg.ApproxComprRatio,
}, },
ChainID: chainID,
PollInterval: cfg.PollInterval,
} }
return NewBatchSubmitter(batcherCfg, l)
}
// NewBatchSubmitter initializes the BatchSubmitter, gathering any resources
// that will be needed during operation.
func NewBatchSubmitter(cfg Config, l log.Logger) (*BatchSubmitter, error) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
balance, err := cfg.L1Client.BalanceAt(ctx, cfg.From, nil)
if err != nil {
cancel()
return nil, err
}
cfg.log = l
cfg.log.Info("creating batch submitter", "submitter_addr", cfg.From, "submitter_bal", balance)
return &BatchSubmitter{ return &BatchSubmitter{
cfg: batcherCfg, Config: cfg,
addr: addr, txMgr: NewTransactionManager(l, cfg.TxManagerConfig, cfg.BatchInboxAddress, cfg.ChainID, cfg.From, cfg.L1Client, cfg.SignerFnFactory(cfg.ChainID)),
txMgr: NewTransactionManager(l, txManagerConfig, batchInboxAddress, chainID, addr, l1Client, signer(chainID)), done: make(chan struct{}),
done: make(chan struct{}),
log: l,
state: NewChannelManager(l, batcherCfg.Channel),
// TODO: this context only exists because the event loop doesn't reach done // TODO: this context only exists because the event loop doesn't reach done
// if the tx manager is blocking forever due to e.g. insufficient balance. // if the tx manager is blocking forever due to e.g. insufficient balance.
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
state: NewChannelManager(l, cfg.Channel),
}, nil }, nil
} }
func (l *BatchSubmitter) Start() error { func (l *BatchSubmitter) Start() error {
...@@ -218,7 +173,7 @@ func (l *BatchSubmitter) loadBlocksIntoState(ctx context.Context) { ...@@ -218,7 +173,7 @@ func (l *BatchSubmitter) loadBlocksIntoState(ctx context.Context) {
// loadBlockIntoState fetches & stores a single block into `state`. It returns the block it loaded. // loadBlockIntoState fetches & stores a single block into `state`. It returns the block it loaded.
func (l *BatchSubmitter) loadBlockIntoState(ctx context.Context, blockNumber uint64) (eth.BlockID, error) { func (l *BatchSubmitter) loadBlockIntoState(ctx context.Context, blockNumber uint64) (eth.BlockID, error) {
ctx, cancel := context.WithTimeout(ctx, networkTimeout) ctx, cancel := context.WithTimeout(ctx, networkTimeout)
block, err := l.cfg.L2Client.BlockByNumber(ctx, new(big.Int).SetUint64(blockNumber)) block, err := l.L2Client.BlockByNumber(ctx, new(big.Int).SetUint64(blockNumber))
cancel() cancel()
if err != nil { if err != nil {
return eth.BlockID{}, err return eth.BlockID{}, err
...@@ -236,7 +191,7 @@ func (l *BatchSubmitter) loadBlockIntoState(ctx context.Context, blockNumber uin ...@@ -236,7 +191,7 @@ func (l *BatchSubmitter) loadBlockIntoState(ctx context.Context, blockNumber uin
func (l *BatchSubmitter) calculateL2BlockRangeToStore(ctx context.Context) (eth.BlockID, eth.BlockID, error) { func (l *BatchSubmitter) calculateL2BlockRangeToStore(ctx context.Context) (eth.BlockID, eth.BlockID, error) {
childCtx, cancel := context.WithTimeout(ctx, networkTimeout) childCtx, cancel := context.WithTimeout(ctx, networkTimeout)
defer cancel() defer cancel()
syncStatus, err := l.cfg.RollupNode.SyncStatus(childCtx) syncStatus, err := l.RollupNode.SyncStatus(childCtx)
// Ensure that we have the sync status // Ensure that we have the sync status
if err != nil { if err != nil {
return eth.BlockID{}, eth.BlockID{}, fmt.Errorf("failed to get sync status: %w", err) return eth.BlockID{}, eth.BlockID{}, fmt.Errorf("failed to get sync status: %w", err)
...@@ -277,7 +232,7 @@ func (l *BatchSubmitter) calculateL2BlockRangeToStore(ctx context.Context) (eth. ...@@ -277,7 +232,7 @@ func (l *BatchSubmitter) calculateL2BlockRangeToStore(ctx context.Context) (eth.
func (l *BatchSubmitter) loop() { func (l *BatchSubmitter) loop() {
defer l.wg.Done() defer l.wg.Done()
ticker := time.NewTicker(l.cfg.PollInterval) ticker := time.NewTicker(l.PollInterval)
defer ticker.Stop() defer ticker.Stop()
for { for {
select { select {
......
package batcher
import (
"math/big"
"time"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)
type DriverConfig struct {
Log log.Logger
Name string
// API to submit txs to
L1Client *ethclient.Client
// API to hit for batch data
L2Client *ethclient.Client
RollupNode *sources.RollupClient
// Where to send the batch txs to.
BatchInboxAddress common.Address
// Channel creation parameters
Channel ChannelConfig
// Chain ID of the L1 chain to submit txs to.
ChainID *big.Int
PollInterval time.Duration
}
...@@ -13,12 +13,12 @@ import ( ...@@ -13,12 +13,12 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
) )
const networkTimeout = 2 * time.Second // How long a single network request can take. TODO: put in a config somewhere const networkTimeout = 2 * time.Second // How long a single network request can take. TODO: put in a config somewhere
type SignerFn func(ctx context.Context, rawTx types.TxData) (*types.Transaction, error)
// TransactionManager wraps the simple txmgr package to make it easy to send & wait for transactions // TransactionManager wraps the simple txmgr package to make it easy to send & wait for transactions
type TransactionManager struct { type TransactionManager struct {
// Config // Config
...@@ -28,11 +28,11 @@ type TransactionManager struct { ...@@ -28,11 +28,11 @@ type TransactionManager struct {
// Outside world // Outside world
txMgr txmgr.TxManager txMgr txmgr.TxManager
l1Client *ethclient.Client l1Client *ethclient.Client
signerFn SignerFn signerFn opcrypto.SignerFn
log log.Logger log log.Logger
} }
func NewTransactionManager(log log.Logger, txMgrConfg txmgr.Config, batchInboxAddress common.Address, chainID *big.Int, senderAddress common.Address, l1Client *ethclient.Client, signerFn SignerFn) *TransactionManager { func NewTransactionManager(log log.Logger, txMgrConfg txmgr.Config, batchInboxAddress common.Address, chainID *big.Int, senderAddress common.Address, l1Client *ethclient.Client, signerFn opcrypto.SignerFn) *TransactionManager {
t := &TransactionManager{ t := &TransactionManager{
batchInboxAddress: batchInboxAddress, batchInboxAddress: batchInboxAddress,
senderAddress: senderAddress, senderAddress: senderAddress,
...@@ -132,7 +132,8 @@ func (t *TransactionManager) CraftTx(ctx context.Context, data []byte) (*types.T ...@@ -132,7 +132,8 @@ func (t *TransactionManager) CraftTx(ctx context.Context, data []byte) (*types.T
ctx, cancel = context.WithTimeout(ctx, networkTimeout) ctx, cancel = context.WithTimeout(ctx, networkTimeout)
defer cancel() defer cancel()
return t.signerFn(ctx, rawTx) tx := types.NewTx(rawTx)
return t.signerFn(ctx, t.senderAddress, tx)
} }
// UpdateGasPrice signs an otherwise identical txn to the one provided but with // UpdateGasPrice signs an otherwise identical txn to the one provided but with
...@@ -157,5 +158,6 @@ func (t *TransactionManager) UpdateGasPrice(ctx context.Context, tx *types.Trans ...@@ -157,5 +158,6 @@ func (t *TransactionManager) UpdateGasPrice(ctx context.Context, tx *types.Trans
// Only log the new tip/fee cap because the updateGasPrice closure reuses the same initial transaction // Only log the new tip/fee cap because the updateGasPrice closure reuses the same initial transaction
t.log.Trace("updating gas price", "tip_cap", gasTipCap, "fee_cap", gasFeeCap) t.log.Trace("updating gas price", "tip_cap", gasTipCap, "fee_cap", gasFeeCap)
return t.signerFn(ctx, rawTx) finalTx := types.NewTx(rawTx)
return t.signerFn(ctx, t.senderAddress, finalTx)
} }
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
) )
var ( var (
Version = "v0.10.11" Version = "v0.10.12"
GitCommit = "" GitCommit = ""
GitDate = "" GitDate = ""
) )
...@@ -29,9 +29,17 @@ func main() { ...@@ -29,9 +29,17 @@ func main() {
app.Description = "Service for generating and submitting L2 tx batches " + app.Description = "Service for generating and submitting L2 tx batches " +
"to L1" "to L1"
app.Action = batcher.Main(Version) app.Action = curryMain(Version)
err := app.Run(os.Args) err := app.Run(os.Args)
if err != nil { if err != nil {
log.Crit("Application failed", "message", err) log.Crit("Application failed", "message", err)
} }
} }
// curryMain transforms the batcher.Main function into an app.Action
// This is done to capture the Version of the batcher.
func curryMain(version string) func(ctx *cli.Context) error {
return func(ctx *cli.Context) error {
return batcher.Main(version, ctx)
}
}
...@@ -3,9 +3,8 @@ module github.com/ethereum-optimism/optimism/op-batcher ...@@ -3,9 +3,8 @@ module github.com/ethereum-optimism/optimism/op-batcher
go 1.18 go 1.18
require ( require (
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 github.com/ethereum-optimism/optimism/op-node v0.10.12
github.com/ethereum-optimism/optimism/op-node v0.10.11 github.com/ethereum-optimism/optimism/op-service v0.10.12
github.com/ethereum-optimism/optimism/op-service v0.10.11
github.com/ethereum-optimism/optimism/op-signer v0.1.0 github.com/ethereum-optimism/optimism/op-signer v0.1.0
github.com/ethereum/go-ethereum v1.10.26 github.com/ethereum/go-ethereum v1.10.26
github.com/urfave/cli v1.22.9 github.com/urfave/cli v1.22.9
...@@ -24,7 +23,8 @@ require ( ...@@ -24,7 +23,8 @@ require (
github.com/deckarep/golang-set v1.8.0 // indirect github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/dyson/certman v0.3.0 // indirect github.com/dyson/certman v0.3.0 // indirect
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 // indirect github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 // indirect
github.com/ethereum-optimism/optimism/op-bindings v0.10.12 // indirect
github.com/fjl/memsize v0.0.1 // indirect github.com/fjl/memsize v0.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
......
...@@ -109,12 +109,12 @@ github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z ...@@ -109,12 +109,12 @@ github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 h1:RDiRyHo0G/UuxHZQdMJyqIuHtWvpionuFNfczNaWCcM= github.com/ethereum-optimism/optimism/op-bindings v0.10.12 h1:/B1gaCLwZYy9Rja3MiceV3R642bygp937kZjnYwRxA0=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c= github.com/ethereum-optimism/optimism/op-bindings v0.10.12/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-node v0.10.11 h1:ED72b68ainzcXr5/cLOYRwv+LdE4hRDnkq3SmNRY1+Q= github.com/ethereum-optimism/optimism/op-node v0.10.12 h1:yOxMThwwz1rEDDM0xTjS+6jqJwgKRtrYM6h4Pdf0zno=
github.com/ethereum-optimism/optimism/op-node v0.10.11/go.mod h1:/CDpkMxc3mDklZ1nqz2lmxfeUyAUz7yC/OLmX8egAUw= github.com/ethereum-optimism/optimism/op-node v0.10.12/go.mod h1:z+DiFb82Vnn5zM3VEwc2OXK2V/JBg6MLg7ejTbsxye8=
github.com/ethereum-optimism/optimism/op-service v0.10.11 h1:o+SazhFXlE3EM9Re5KIPEQklZ9uTI8rNkjl0h5OwRtU= github.com/ethereum-optimism/optimism/op-service v0.10.12 h1:Y7pR3/b8eeHYkmo2V5z7sj8jaraYqm2Azyph5lbiIxo=
github.com/ethereum-optimism/optimism/op-service v0.10.11/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c= github.com/ethereum-optimism/optimism/op-service v0.10.12/go.mod h1:Ibbun+aic0rjQBV8yBf9kohqIj6mQ8nSTWbZjHv+Q7Q=
github.com/ethereum-optimism/optimism/op-signer v0.1.0 h1:wH44Deai43YQWO0pEd44pDm3BahdAtSmrOHKiPvTB8Y= github.com/ethereum-optimism/optimism/op-signer v0.1.0 h1:wH44Deai43YQWO0pEd44pDm3BahdAtSmrOHKiPvTB8Y=
github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8= github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
...@@ -391,7 +391,7 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w ...@@ -391,7 +391,7 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d h1:vmirMegf1vqPJ+lDBxLQ0MAt3tz+JL57UPxu44JBOjA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
......
...@@ -3,7 +3,7 @@ module github.com/ethereum-optimism/optimism/op-chain-ops ...@@ -3,7 +3,7 @@ module github.com/ethereum-optimism/optimism/op-chain-ops
go 1.18 go 1.18
require ( require (
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 github.com/ethereum-optimism/optimism/op-bindings v0.10.12
github.com/ethereum-optimism/optimism/op-node v0.10.1 github.com/ethereum-optimism/optimism/op-node v0.10.1
github.com/ethereum/go-ethereum v1.10.26 github.com/ethereum/go-ethereum v1.10.26
github.com/holiman/uint256 v1.2.0 github.com/holiman/uint256 v1.2.0
...@@ -23,7 +23,7 @@ require ( ...@@ -23,7 +23,7 @@ require (
github.com/deckarep/golang-set v1.8.0 // indirect github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/ethereum-optimism/optimism/op-service v0.10.11 // indirect github.com/ethereum-optimism/optimism/op-service v0.10.12 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/go-kit/kit v0.10.0 // indirect github.com/go-kit/kit v0.10.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
...@@ -49,7 +49,7 @@ require ( ...@@ -49,7 +49,7 @@ require (
github.com/rogpeppe/go-internal v1.8.1 // indirect github.com/rogpeppe/go-internal v1.8.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 // indirect github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.5.0 // indirect github.com/tklauser/numcpus v0.5.0 // indirect
......
...@@ -79,20 +79,20 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m ...@@ -79,20 +79,20 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 h1:RDiRyHo0G/UuxHZQdMJyqIuHtWvpionuFNfczNaWCcM= github.com/ethereum-optimism/optimism/op-bindings v0.10.12 h1:/B1gaCLwZYy9Rja3MiceV3R642bygp937kZjnYwRxA0=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c= github.com/ethereum-optimism/optimism/op-bindings v0.10.12/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-node v0.10.1 h1:kVBaOEOYLV22XEHRhB7dfdmoXepO0kx/RsZQK+Bpk1Y= github.com/ethereum-optimism/optimism/op-node v0.10.1 h1:kVBaOEOYLV22XEHRhB7dfdmoXepO0kx/RsZQK+Bpk1Y=
github.com/ethereum-optimism/optimism/op-node v0.10.1/go.mod h1:pup7wiiUs9g8cZKwXeB5tEGCqwUUwFVmej9MmSIm6S8= github.com/ethereum-optimism/optimism/op-node v0.10.1/go.mod h1:pup7wiiUs9g8cZKwXeB5tEGCqwUUwFVmej9MmSIm6S8=
github.com/ethereum-optimism/optimism/op-service v0.10.11 h1:o+SazhFXlE3EM9Re5KIPEQklZ9uTI8rNkjl0h5OwRtU= github.com/ethereum-optimism/optimism/op-service v0.10.12 h1:Y7pR3/b8eeHYkmo2V5z7sj8jaraYqm2Azyph5lbiIxo=
github.com/ethereum-optimism/optimism/op-service v0.10.11/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c= github.com/ethereum-optimism/optimism/op-service v0.10.12/go.mod h1:Ibbun+aic0rjQBV8yBf9kohqIj6mQ8nSTWbZjHv+Q7Q=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
...@@ -377,8 +377,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO ...@@ -377,8 +377,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d h1:vmirMegf1vqPJ+lDBxLQ0MAt3tz+JL57UPxu44JBOjA=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d/go.mod h1:97vT0Rym0wCnK4B++hNA3nCetr0Mh1KXaVxzSt1arjg=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
......
...@@ -18,11 +18,11 @@ type MockL1OriginSelector struct { ...@@ -18,11 +18,11 @@ type MockL1OriginSelector struct {
originOverride eth.L1BlockRef // override which origin gets picked originOverride eth.L1BlockRef // override which origin gets picked
} }
func (m *MockL1OriginSelector) FindL1Origin(ctx context.Context, l1Head eth.L1BlockRef, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) { func (m *MockL1OriginSelector) FindL1Origin(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) {
if m.originOverride != (eth.L1BlockRef{}) { if m.originOverride != (eth.L1BlockRef{}) {
return m.originOverride, nil return m.originOverride, nil
} }
return m.actual.FindL1Origin(ctx, l1Head, l2Head) return m.actual.FindL1Origin(ctx, l2Head)
} }
// L2Sequencer is an actor that functions like a rollup node, // L2Sequencer is an actor that functions like a rollup node,
...@@ -40,8 +40,9 @@ type L2Sequencer struct { ...@@ -40,8 +40,9 @@ type L2Sequencer struct {
func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, eng L2API, cfg *rollup.Config, seqConfDepth uint64) *L2Sequencer { func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, eng L2API, cfg *rollup.Config, seqConfDepth uint64) *L2Sequencer {
ver := NewL2Verifier(t, log, l1, eng, cfg) ver := NewL2Verifier(t, log, l1, eng, cfg)
attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, eng) attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, eng)
seqConfDepthL1 := driver.NewConfDepth(seqConfDepth, ver.l1State.L1Head, l1)
l1OriginSelector := &MockL1OriginSelector{ l1OriginSelector := &MockL1OriginSelector{
actual: driver.NewL1OriginSelector(log, cfg, l1, seqConfDepth), actual: driver.NewL1OriginSelector(log, cfg, seqConfDepthL1),
} }
return &L2Sequencer{ return &L2Sequencer{
L2Verifier: *ver, L2Verifier: *ver,
...@@ -62,7 +63,7 @@ func (s *L2Sequencer) ActL2StartBlock(t Testing) { ...@@ -62,7 +63,7 @@ func (s *L2Sequencer) ActL2StartBlock(t Testing) {
return return
} }
err := s.sequencer.StartBuildingBlock(t.Ctx(), s.l1State.L1Head()) err := s.sequencer.StartBuildingBlock(t.Ctx())
require.NoError(t, err, "failed to start block building") require.NoError(t, err, "failed to start block building")
s.l2Building = true s.l2Building = true
...@@ -106,7 +107,7 @@ func (s *L2Sequencer) ActBuildToL1Head(t Testing) { ...@@ -106,7 +107,7 @@ func (s *L2Sequencer) ActBuildToL1Head(t Testing) {
func (s *L2Sequencer) ActBuildToL1HeadExcl(t Testing) { func (s *L2Sequencer) ActBuildToL1HeadExcl(t Testing) {
for { for {
s.ActL2PipelineFull(t) s.ActL2PipelineFull(t)
nextOrigin, err := s.mockL1OriginSelector.FindL1Origin(t.Ctx(), s.l1State.L1Head(), s.derivation.UnsafeL2Head()) nextOrigin, err := s.mockL1OriginSelector.FindL1Origin(t.Ctx(), s.derivation.UnsafeL2Head())
require.NoError(t, err) require.NoError(t, err)
if nextOrigin.Number >= s.l1State.L1Head().Number { if nextOrigin.Number >= s.l1State.L1Head().Number {
break break
......
...@@ -10,12 +10,12 @@ require ( ...@@ -10,12 +10,12 @@ require (
github.com/docker/docker v20.10.21+incompatible github.com/docker/docker v20.10.21+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3
github.com/ethereum-optimism/optimism/op-batcher v0.10.11 github.com/ethereum-optimism/optimism/op-batcher v0.10.12
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 github.com/ethereum-optimism/optimism/op-bindings v0.10.12
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11 github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12
github.com/ethereum-optimism/optimism/op-node v0.10.11 github.com/ethereum-optimism/optimism/op-node v0.10.12
github.com/ethereum-optimism/optimism/op-proposer v0.10.11 github.com/ethereum-optimism/optimism/op-proposer v0.10.12
github.com/ethereum-optimism/optimism/op-service v0.10.11 github.com/ethereum-optimism/optimism/op-service v0.10.12
github.com/ethereum/go-ethereum v1.10.26 github.com/ethereum/go-ethereum v1.10.26
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8 github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8
github.com/libp2p/go-libp2p v0.23.3 github.com/libp2p/go-libp2p v0.23.3
......
...@@ -161,18 +161,18 @@ github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z ...@@ -161,18 +161,18 @@ github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-batcher v0.10.11 h1:aqTOE3UnTrX/rngXruT815CyRhcKi9kvZ4xJllW9l6I= github.com/ethereum-optimism/optimism/op-batcher v0.10.12 h1:Vyb2oEujqokXiybaC64l+T5e0NpEMOC6rhXqIFIN8Oo=
github.com/ethereum-optimism/optimism/op-batcher v0.10.11/go.mod h1:HIsxM0YihXGGImsUuPdI0T+L1LuS8UXgZnaZweXUGug= github.com/ethereum-optimism/optimism/op-batcher v0.10.12/go.mod h1:ai4nZjD0aOOHWhLZj7R8KFttG9+EFsdxiELDuqwzrO4=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 h1:RDiRyHo0G/UuxHZQdMJyqIuHtWvpionuFNfczNaWCcM= github.com/ethereum-optimism/optimism/op-bindings v0.10.12 h1:/B1gaCLwZYy9Rja3MiceV3R642bygp937kZjnYwRxA0=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c= github.com/ethereum-optimism/optimism/op-bindings v0.10.12/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11 h1:6ihrVPJYN1HvD4KG0Fk1zIJCM4ZB109kCu9fq81jznQ= github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12 h1:gRX5oIk0hboTOZ65y5MpEdM5+nmaad87QZP1donrHXo=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11/go.mod h1:6mub7Tx1cC4gDrfX9o9n+kA4R2qLlYvfWkG8es21EQI= github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12/go.mod h1:x98mGAxXIhyYM4WsnbgziJCAk+qA4JX0wvaE+azBg48=
github.com/ethereum-optimism/optimism/op-node v0.10.11 h1:ED72b68ainzcXr5/cLOYRwv+LdE4hRDnkq3SmNRY1+Q= github.com/ethereum-optimism/optimism/op-node v0.10.12 h1:yOxMThwwz1rEDDM0xTjS+6jqJwgKRtrYM6h4Pdf0zno=
github.com/ethereum-optimism/optimism/op-node v0.10.11/go.mod h1:/CDpkMxc3mDklZ1nqz2lmxfeUyAUz7yC/OLmX8egAUw= github.com/ethereum-optimism/optimism/op-node v0.10.12/go.mod h1:z+DiFb82Vnn5zM3VEwc2OXK2V/JBg6MLg7ejTbsxye8=
github.com/ethereum-optimism/optimism/op-proposer v0.10.11 h1:uG+CXcac1LVRAnivv+3q7qJZDTgdKLv0D3mbu2o7nKI= github.com/ethereum-optimism/optimism/op-proposer v0.10.12 h1:4K61QLg1mF38zwsaTQKOJnDqc65DKKsO33X20cLrhmk=
github.com/ethereum-optimism/optimism/op-proposer v0.10.11/go.mod h1:O/BolDMRNanlblBQKwq2UGwnl7hTdKrnVlmXfijG7vw= github.com/ethereum-optimism/optimism/op-proposer v0.10.12/go.mod h1:JBB9oVfhx9VjrBgcE5KIxCdQPnr7ma/xLBLYg2EFo9I=
github.com/ethereum-optimism/optimism/op-service v0.10.11 h1:o+SazhFXlE3EM9Re5KIPEQklZ9uTI8rNkjl0h5OwRtU= github.com/ethereum-optimism/optimism/op-service v0.10.12 h1:Y7pR3/b8eeHYkmo2V5z7sj8jaraYqm2Azyph5lbiIxo=
github.com/ethereum-optimism/optimism/op-service v0.10.11/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c= github.com/ethereum-optimism/optimism/op-service v0.10.12/go.mod h1:Ibbun+aic0rjQBV8yBf9kohqIj6mQ8nSTWbZjHv+Q7Q=
github.com/ethereum-optimism/optimism/op-signer v0.1.0 h1:wH44Deai43YQWO0pEd44pDm3BahdAtSmrOHKiPvTB8Y= github.com/ethereum-optimism/optimism/op-signer v0.1.0 h1:wH44Deai43YQWO0pEd44pDm3BahdAtSmrOHKiPvTB8Y=
github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8= github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
......
...@@ -319,7 +319,7 @@ func TestMigration(t *testing.T) { ...@@ -319,7 +319,7 @@ func TestMigration(t *testing.T) {
require.NoError(t, rollupNode.Close()) require.NoError(t, rollupNode.Close())
}) })
batcher, err := bss.NewBatchSubmitter(bss.Config{ batcher, err := bss.NewBatchSubmitterFromCLIConfig(bss.CLIConfig{
L1EthRpc: forkedL1URL, L1EthRpc: forkedL1URL,
L2EthRpc: gethNode.WSEndpoint(), L2EthRpc: gethNode.WSEndpoint(),
RollupRpc: rollupNode.HTTPEndpoint(), RollupRpc: rollupNode.HTTPEndpoint(),
......
...@@ -522,7 +522,7 @@ func (cfg SystemConfig) Start() (*System, error) { ...@@ -522,7 +522,7 @@ func (cfg SystemConfig) Start() (*System, error) {
} }
// Batch Submitter // Batch Submitter
sys.BatchSubmitter, err = bss.NewBatchSubmitter(bss.Config{ sys.BatchSubmitter, err = bss.NewBatchSubmitterFromCLIConfig(bss.CLIConfig{
L1EthRpc: sys.Nodes["l1"].WSEndpoint(), L1EthRpc: sys.Nodes["l1"].WSEndpoint(),
L2EthRpc: sys.Nodes["sequencer"].WSEndpoint(), L2EthRpc: sys.Nodes["sequencer"].WSEndpoint(),
RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(), RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(),
......
...@@ -6,9 +6,9 @@ require ( ...@@ -6,9 +6,9 @@ require (
github.com/btcsuite/btcd v0.23.3 github.com/btcsuite/btcd v0.23.3
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 github.com/ethereum-optimism/optimism/op-bindings v0.10.12
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11 github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12
github.com/ethereum-optimism/optimism/op-service v0.10.11 github.com/ethereum-optimism/optimism/op-service v0.10.12
github.com/ethereum/go-ethereum v1.10.26 github.com/ethereum/go-ethereum v1.10.26
github.com/golang/snappy v0.0.4 github.com/golang/snappy v0.0.4
github.com/google/go-cmp v0.5.8 github.com/google/go-cmp v0.5.8
...@@ -52,8 +52,7 @@ require ( ...@@ -52,8 +52,7 @@ require (
github.com/fjl/memsize v0.0.1 // indirect github.com/fjl/memsize v0.0.1 // indirect
github.com/flynn/noise v1.0.0 // indirect github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect github.com/go-stack/stack v1.8.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
...@@ -137,7 +136,6 @@ require ( ...@@ -137,7 +136,6 @@ require (
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.5.0 // indirect github.com/tklauser/numcpus v0.5.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa // indirect github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa // indirect
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
...@@ -151,7 +149,6 @@ require ( ...@@ -151,7 +149,6 @@ require (
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 // indirect
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
golang.org/x/tools v0.1.12 // indirect golang.org/x/tools v0.1.12 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
......
...@@ -145,12 +145,12 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m ...@@ -145,12 +145,12 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 h1:RDiRyHo0G/UuxHZQdMJyqIuHtWvpionuFNfczNaWCcM= github.com/ethereum-optimism/optimism/op-bindings v0.10.12 h1:/B1gaCLwZYy9Rja3MiceV3R642bygp937kZjnYwRxA0=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c= github.com/ethereum-optimism/optimism/op-bindings v0.10.12/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11 h1:6ihrVPJYN1HvD4KG0Fk1zIJCM4ZB109kCu9fq81jznQ= github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12 h1:gRX5oIk0hboTOZ65y5MpEdM5+nmaad87QZP1donrHXo=
github.com/ethereum-optimism/optimism/op-chain-ops v0.10.11/go.mod h1:6mub7Tx1cC4gDrfX9o9n+kA4R2qLlYvfWkG8es21EQI= github.com/ethereum-optimism/optimism/op-chain-ops v0.10.12/go.mod h1:x98mGAxXIhyYM4WsnbgziJCAk+qA4JX0wvaE+azBg48=
github.com/ethereum-optimism/optimism/op-service v0.10.11 h1:o+SazhFXlE3EM9Re5KIPEQklZ9uTI8rNkjl0h5OwRtU= github.com/ethereum-optimism/optimism/op-service v0.10.12 h1:Y7pR3/b8eeHYkmo2V5z7sj8jaraYqm2Azyph5lbiIxo=
github.com/ethereum-optimism/optimism/op-service v0.10.11/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c= github.com/ethereum-optimism/optimism/op-service v0.10.12/go.mod h1:Ibbun+aic0rjQBV8yBf9kohqIj6mQ8nSTWbZjHv+Q7Q=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
...@@ -160,10 +160,10 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn ...@@ -160,10 +160,10 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
...@@ -587,7 +587,7 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w ...@@ -587,7 +587,7 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d h1:vmirMegf1vqPJ+lDBxLQ0MAt3tz+JL57UPxu44JBOjA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
...@@ -613,7 +613,6 @@ github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hM ...@@ -613,7 +613,6 @@ github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hM
github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A= github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A=
github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo= github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw= github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
...@@ -846,6 +845,7 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc ...@@ -846,6 +845,7 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4= golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
...@@ -865,7 +865,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb ...@@ -865,7 +865,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
......
...@@ -66,10 +66,10 @@ type L1StateIface interface { ...@@ -66,10 +66,10 @@ type L1StateIface interface {
} }
type SequencerIface interface { type SequencerIface interface {
StartBuildingBlock(ctx context.Context, l1Head eth.L1BlockRef) error StartBuildingBlock(ctx context.Context) error
CompleteBuildingBlock(ctx context.Context) (*eth.ExecutionPayload, error) CompleteBuildingBlock(ctx context.Context) (*eth.ExecutionPayload, error)
PlanNextSequencerAction() time.Duration PlanNextSequencerAction() time.Duration
RunNextSequencerAction(ctx context.Context, l1Head eth.L1BlockRef) *eth.ExecutionPayload RunNextSequencerAction(ctx context.Context) *eth.ExecutionPayload
BuildingOnto() eth.L2BlockRef BuildingOnto() eth.L2BlockRef
} }
...@@ -81,7 +81,8 @@ type Network interface { ...@@ -81,7 +81,8 @@ type Network interface {
// NewDriver composes an events handler that tracks L1 state, triggers L2 derivation, and optionally sequences new L2 blocks. // NewDriver composes an events handler that tracks L1 state, triggers L2 derivation, and optionally sequences new L2 blocks.
func NewDriver(driverCfg *Config, cfg *rollup.Config, l2 L2Chain, l1 L1Chain, network Network, log log.Logger, snapshotLog log.Logger, metrics Metrics) *Driver { func NewDriver(driverCfg *Config, cfg *rollup.Config, l2 L2Chain, l1 L1Chain, network Network, log log.Logger, snapshotLog log.Logger, metrics Metrics) *Driver {
l1State := NewL1State(log, metrics) l1State := NewL1State(log, metrics)
findL1Origin := NewL1OriginSelector(log, cfg, l1, driverCfg.SequencerConfDepth) sequencerConfDepth := NewConfDepth(driverCfg.SequencerConfDepth, l1State.L1Head, l1)
findL1Origin := NewL1OriginSelector(log, cfg, sequencerConfDepth)
verifConfDepth := NewConfDepth(driverCfg.VerifierConfDepth, l1State.L1Head, l1) verifConfDepth := NewConfDepth(driverCfg.VerifierConfDepth, l1State.L1Head, l1)
derivationPipeline := derive.NewDerivationPipeline(log, cfg, verifConfDepth, l2, metrics) derivationPipeline := derive.NewDerivationPipeline(log, cfg, verifConfDepth, l2, metrics)
attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, l2) attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, l2)
......
...@@ -2,7 +2,10 @@ package driver ...@@ -2,7 +2,10 @@ package driver
import ( import (
"context" "context"
"errors"
"fmt"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
...@@ -19,63 +22,49 @@ type L1OriginSelector struct { ...@@ -19,63 +22,49 @@ type L1OriginSelector struct {
log log.Logger log log.Logger
cfg *rollup.Config cfg *rollup.Config
l1 L1Blocks l1 L1Blocks
sequencingConfDepth uint64
} }
func NewL1OriginSelector(log log.Logger, cfg *rollup.Config, l1 L1Blocks, sequencingConfDepth uint64) *L1OriginSelector { func NewL1OriginSelector(log log.Logger, cfg *rollup.Config, l1 L1Blocks) *L1OriginSelector {
return &L1OriginSelector{ return &L1OriginSelector{
log: log, log: log,
cfg: cfg, cfg: cfg,
l1: l1, l1: l1,
sequencingConfDepth: sequencingConfDepth,
} }
} }
// FindL1Origin determines what the next L1 Origin should be. // FindL1Origin determines what the next L1 Origin should be.
// The L1 Origin is either the L2 Head's Origin, or the following L1 block // The L1 Origin is either the L2 Head's Origin, or the following L1 block
// if the next L2 block's time is greater than or equal to the L2 Head's Origin. // if the next L2 block's time is greater than or equal to the L2 Head's Origin.
func (los *L1OriginSelector) FindL1Origin(ctx context.Context, l1Head eth.L1BlockRef, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) { func (los *L1OriginSelector) FindL1Origin(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) {
// If we are at the head block, don't do a lookup. // Grab a reference to the current L1 origin block. This call is by hash and thus easily cached.
if l2Head.L1Origin.Hash == l1Head.Hash {
return l1Head, nil
}
// Grab a reference to the current L1 origin block.
currentOrigin, err := los.l1.L1BlockRefByHash(ctx, l2Head.L1Origin.Hash) currentOrigin, err := los.l1.L1BlockRefByHash(ctx, l2Head.L1Origin.Hash)
if err != nil { if err != nil {
return eth.L1BlockRef{}, err return eth.L1BlockRef{}, err
} }
log := los.log.New("current", currentOrigin, "current_time", currentOrigin.Time,
"l2_head", l2Head, "l2_head_time", l2Head.Time)
// If we are past the sequencer depth, we may want to advance the origin, but need to still // If we are past the sequencer depth, we may want to advance the origin, but need to still
// check the time of the next origin. // check the time of the next origin.
pastSeqDrift := l2Head.Time+los.cfg.BlockTime > currentOrigin.Time+los.cfg.MaxSequencerDrift pastSeqDrift := l2Head.Time+los.cfg.BlockTime > currentOrigin.Time+los.cfg.MaxSequencerDrift
if pastSeqDrift { if pastSeqDrift {
log.Info("Next L2 block time is past the sequencer drift + current origin time", log.Warn("Next L2 block time is past the sequencer drift + current origin time")
"current", currentOrigin, "current_time", currentOrigin.Time,
"l1_head", l1Head, "l1_head_time", l1Head.Time,
"l2_head", l2Head, "l2_head_time", l2Head.Time,
"depth", los.sequencingConfDepth)
}
if !pastSeqDrift && currentOrigin.Number+1+los.sequencingConfDepth > l1Head.Number {
// TODO: we can decide to ignore confirmation depth if we would be forced
// to make an empty block (only deposits) by staying on the current origin.
log.Info("sequencing with old origin to preserve conf depth",
"current", currentOrigin, "current_time", currentOrigin.Time,
"l1_head", l1Head, "l1_head_time", l1Head.Time,
"l2_head", l2Head, "l2_head_time", l2Head.Time,
"depth", los.sequencingConfDepth)
return currentOrigin, nil
} }
// Attempt to find the next L1 origin block, where the next origin is the immediate child of // Attempt to find the next L1 origin block, where the next origin is the immediate child of
// the current origin block. // the current origin block.
// The L1 source can be shimmed to hide new L1 blocks and enforce a sequencer confirmation distance.
nextOrigin, err := los.l1.L1BlockRefByNumber(ctx, currentOrigin.Number+1) nextOrigin, err := los.l1.L1BlockRefByNumber(ctx, currentOrigin.Number+1)
if err != nil { if err != nil {
// TODO: this could result in a bad origin being selected if we are past the seq if pastSeqDrift {
// drift & should instead advance to the next origin. return eth.L1BlockRef{}, fmt.Errorf("cannot build next L2 block past current L1 origin %s by more than sequencer time drift, and failed to find next L1 origin: %w", currentOrigin, err)
log.Error("Failed to get next origin. Falling back to current origin", "err", err) }
if errors.Is(err, ethereum.NotFound) {
log.Debug("No next L1 block found, repeating current origin")
} else {
log.Error("Failed to get next origin. Falling back to current origin", "err", err)
}
return currentOrigin, nil return currentOrigin, nil
} }
......
...@@ -27,6 +27,7 @@ func TestOriginSelectorAdvances(t *testing.T) { ...@@ -27,6 +27,7 @@ func TestOriginSelectorAdvances(t *testing.T) {
BlockTime: 2, BlockTime: 2,
} }
l1 := &testutils.MockL1Source{} l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{ a := eth.L1BlockRef{
Hash: common.Hash{'a'}, Hash: common.Hash{'a'},
Number: 10, Number: 10,
...@@ -46,9 +47,8 @@ func TestOriginSelectorAdvances(t *testing.T) { ...@@ -46,9 +47,8 @@ func TestOriginSelectorAdvances(t *testing.T) {
l1.ExpectL1BlockRefByHash(a.Hash, a, nil) l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil) l1.ExpectL1BlockRefByNumber(b.Number, b, nil)
s := NewL1OriginSelector(log, cfg, l1, 0) s := NewL1OriginSelector(log, cfg, l1)
next, err := s.FindL1Origin(context.Background(), l2Head)
next, err := s.FindL1Origin(context.Background(), b, l2Head)
require.Nil(t, err) require.Nil(t, err)
require.Equal(t, b, next) require.Equal(t, b, next)
} }
...@@ -68,6 +68,7 @@ func TestOriginSelectorRespectsOriginTiming(t *testing.T) { ...@@ -68,6 +68,7 @@ func TestOriginSelectorRespectsOriginTiming(t *testing.T) {
BlockTime: 2, BlockTime: 2,
} }
l1 := &testutils.MockL1Source{} l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{ a := eth.L1BlockRef{
Hash: common.Hash{'a'}, Hash: common.Hash{'a'},
Number: 10, Number: 10,
...@@ -87,15 +88,14 @@ func TestOriginSelectorRespectsOriginTiming(t *testing.T) { ...@@ -87,15 +88,14 @@ func TestOriginSelectorRespectsOriginTiming(t *testing.T) {
l1.ExpectL1BlockRefByHash(a.Hash, a, nil) l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil) l1.ExpectL1BlockRefByNumber(b.Number, b, nil)
s := NewL1OriginSelector(log, cfg, l1, 0) s := NewL1OriginSelector(log, cfg, l1)
next, err := s.FindL1Origin(context.Background(), l2Head)
next, err := s.FindL1Origin(context.Background(), b, l2Head)
require.Nil(t, err) require.Nil(t, err)
require.Equal(t, a, next) require.Equal(t, a, next)
} }
// TestOriginSelectorRespectsConfDepth ensures that the origin selector // TestOriginSelectorRespectsConfDepth ensures that the origin selector
// will respects the confirmation depth requirement // will respect the confirmation depth requirement
// //
// There are 2 L1 blocks at time 20 & 25. The L2 Head is at time 27. // There are 2 L1 blocks at time 20 & 25. The L2 Head is at time 27.
// The next L2 time is 29 which enough to normally select block `b` // The next L2 time is 29 which enough to normally select block `b`
...@@ -108,6 +108,7 @@ func TestOriginSelectorRespectsConfDepth(t *testing.T) { ...@@ -108,6 +108,7 @@ func TestOriginSelectorRespectsConfDepth(t *testing.T) {
BlockTime: 2, BlockTime: 2,
} }
l1 := &testutils.MockL1Source{} l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{ a := eth.L1BlockRef{
Hash: common.Hash{'a'}, Hash: common.Hash{'a'},
Number: 10, Number: 10,
...@@ -125,33 +126,32 @@ func TestOriginSelectorRespectsConfDepth(t *testing.T) { ...@@ -125,33 +126,32 @@ func TestOriginSelectorRespectsConfDepth(t *testing.T) {
} }
l1.ExpectL1BlockRefByHash(a.Hash, a, nil) l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil) confDepthL1 := NewConfDepth(10, func() eth.L1BlockRef { return b }, l1)
s := NewL1OriginSelector(log, cfg, confDepthL1)
s := NewL1OriginSelector(log, cfg, l1, 10)
next, err := s.FindL1Origin(context.Background(), b, l2Head) next, err := s.FindL1Origin(context.Background(), l2Head)
require.Nil(t, err) require.Nil(t, err)
require.Equal(t, a, next) require.Equal(t, a, next)
} }
// TestOriginSelectorRespectsMaxSeqDrift ensures that the origin selector // TestOriginSelectorStrictConfDepth ensures that the origin selector will maintain the sequencer conf depth,
// will advance if the time delta between the current L1 origin and the next // even while the time delta between the current L1 origin and the next
// L2 block is greater than the sequencer drift. This needs to occur even // L2 block is greater than the sequencer drift.
// if conf depth needs to be ignored // It's more important to maintain safety with an empty block than to maintain liveness with poor conf depth.
// //
// There are 2 L1 blocks at time 20 & 25. The L2 Head is at time 27. // There are 2 L1 blocks at time 20 & 25. The L2 Head is at time 27.
// The next L2 time is 29. The sequencer drift is 8 so the L2 head is // The next L2 time is 29. The sequencer drift is 8 so the L2 head is
// valid with origin `a`, but the next L2 block is not valid with origin `b.` // valid with origin `a`, but the next L2 block is not valid with origin `b.`
// This is because 29 (next L2 time) > 20 (origin) + 8 (seq drift) => invalid block. // This is because 29 (next L2 time) > 20 (origin) + 8 (seq drift) => invalid block.
// Even though the LOS would normally refuse to advance because block `b` does not // We maintain confirmation distance, even though we would shift to the next origin if we could.
// have enough confirmations, it should in this instance. func TestOriginSelectorStrictConfDepth(t *testing.T) {
func TestOriginSelectorRespectsMaxSeqDrift(t *testing.T) {
log := testlog.Logger(t, log.LvlCrit) log := testlog.Logger(t, log.LvlCrit)
cfg := &rollup.Config{ cfg := &rollup.Config{
MaxSequencerDrift: 8, MaxSequencerDrift: 8,
BlockTime: 2, BlockTime: 2,
} }
l1 := &testutils.MockL1Source{} l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{ a := eth.L1BlockRef{
Hash: common.Hash{'a'}, Hash: common.Hash{'a'},
Number: 10, Number: 10,
...@@ -169,13 +169,11 @@ func TestOriginSelectorRespectsMaxSeqDrift(t *testing.T) { ...@@ -169,13 +169,11 @@ func TestOriginSelectorRespectsMaxSeqDrift(t *testing.T) {
} }
l1.ExpectL1BlockRefByHash(a.Hash, a, nil) l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil) confDepthL1 := NewConfDepth(10, func() eth.L1BlockRef { return b }, l1)
s := NewL1OriginSelector(log, cfg, confDepthL1)
s := NewL1OriginSelector(log, cfg, l1, 10)
next, err := s.FindL1Origin(context.Background(), b, l2Head) _, err := s.FindL1Origin(context.Background(), l2Head)
require.Nil(t, err) require.ErrorContains(t, err, "sequencer time drift")
require.Equal(t, b, next)
} }
// TestOriginSelectorSeqDriftRespectsNextOriginTime // TestOriginSelectorSeqDriftRespectsNextOriginTime
...@@ -191,6 +189,7 @@ func TestOriginSelectorSeqDriftRespectsNextOriginTime(t *testing.T) { ...@@ -191,6 +189,7 @@ func TestOriginSelectorSeqDriftRespectsNextOriginTime(t *testing.T) {
BlockTime: 2, BlockTime: 2,
} }
l1 := &testutils.MockL1Source{} l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{ a := eth.L1BlockRef{
Hash: common.Hash{'a'}, Hash: common.Hash{'a'},
Number: 10, Number: 10,
...@@ -210,9 +209,76 @@ func TestOriginSelectorSeqDriftRespectsNextOriginTime(t *testing.T) { ...@@ -210,9 +209,76 @@ func TestOriginSelectorSeqDriftRespectsNextOriginTime(t *testing.T) {
l1.ExpectL1BlockRefByHash(a.Hash, a, nil) l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil) l1.ExpectL1BlockRefByNumber(b.Number, b, nil)
s := NewL1OriginSelector(log, cfg, l1, 10) s := NewL1OriginSelector(log, cfg, l1)
next, err := s.FindL1Origin(context.Background(), l2Head)
next, err := s.FindL1Origin(context.Background(), b, l2Head)
require.Nil(t, err) require.Nil(t, err)
require.Equal(t, a, next) require.Equal(t, a, next)
} }
// TestOriginSelectorHandlesLateL1Blocks tests the forced repeat of the previous origin,
// but with a conf depth that first prevents it from learning about the need to repeat.
//
// There are 2 L1 blocks at time 20 & 100. The L2 Head is at time 27.
// The next L2 time is 29. Even though the next L2 time is past the seq
// drift, the origin should remain on block `a` because the next origin's
// time is greater than the next L2 time.
// Due to a conf depth of 2, block `b` is not immediately visible,
// and the origin selection should fail until it is visible, by waiting for block `c`.
func TestOriginSelectorHandlesLateL1Blocks(t *testing.T) {
log := testlog.Logger(t, log.LvlCrit)
cfg := &rollup.Config{
MaxSequencerDrift: 8,
BlockTime: 2,
}
l1 := &testutils.MockL1Source{}
defer l1.AssertExpectations(t)
a := eth.L1BlockRef{
Hash: common.Hash{'a'},
Number: 10,
Time: 20,
}
b := eth.L1BlockRef{
Hash: common.Hash{'b'},
Number: 11,
Time: 100,
ParentHash: a.Hash,
}
c := eth.L1BlockRef{
Hash: common.Hash{'c'},
Number: 12,
Time: 150,
ParentHash: b.Hash,
}
d := eth.L1BlockRef{
Hash: common.Hash{'d'},
Number: 13,
Time: 200,
ParentHash: c.Hash,
}
l2Head := eth.L2BlockRef{
L1Origin: a.ID(),
Time: 27,
}
// l2 head does not change, so we start at the same origin again and again until we meet the conf depth
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByHash(a.Hash, a, nil)
l1.ExpectL1BlockRefByNumber(b.Number, b, nil)
l1Head := b
confDepthL1 := NewConfDepth(2, func() eth.L1BlockRef { return l1Head }, l1)
s := NewL1OriginSelector(log, cfg, confDepthL1)
_, err := s.FindL1Origin(context.Background(), l2Head)
require.ErrorContains(t, err, "sequencer time drift")
l1Head = c
_, err = s.FindL1Origin(context.Background(), l2Head)
require.ErrorContains(t, err, "sequencer time drift")
l1Head = d
next, err := s.FindL1Origin(context.Background(), l2Head)
require.Nil(t, err)
require.Equal(t, a, next, "must stay on a because the L1 time may not be higher than the L2 time")
}
...@@ -20,7 +20,7 @@ type Downloader interface { ...@@ -20,7 +20,7 @@ type Downloader interface {
} }
type L1OriginSelectorIface interface { type L1OriginSelectorIface interface {
FindL1Origin(ctx context.Context, l1Head eth.L1BlockRef, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) FindL1Origin(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error)
} }
// Sequencer implements the sequencing interface of the driver: it starts and completes block building jobs. // Sequencer implements the sequencing interface of the driver: it starts and completes block building jobs.
...@@ -51,11 +51,11 @@ func NewSequencer(log log.Logger, cfg *rollup.Config, engine derive.EngineContro ...@@ -51,11 +51,11 @@ func NewSequencer(log log.Logger, cfg *rollup.Config, engine derive.EngineContro
} }
// StartBuildingBlock initiates a block building job on top of the given L2 head, safe and finalized blocks, and using the provided l1Origin. // StartBuildingBlock initiates a block building job on top of the given L2 head, safe and finalized blocks, and using the provided l1Origin.
func (d *Sequencer) StartBuildingBlock(ctx context.Context, l1Head eth.L1BlockRef) error { func (d *Sequencer) StartBuildingBlock(ctx context.Context) error {
l2Head := d.engine.UnsafeL2Head() l2Head := d.engine.UnsafeL2Head()
// Figure out which L1 origin block we're going to be building on top of. // Figure out which L1 origin block we're going to be building on top of.
l1Origin, err := d.l1OriginSelector.FindL1Origin(ctx, l1Head, l2Head) l1Origin, err := d.l1OriginSelector.FindL1Origin(ctx, l2Head)
if err != nil { if err != nil {
d.log.Error("Error finding next L1 Origin", "err", err) d.log.Error("Error finding next L1 Origin", "err", err)
return err return err
...@@ -159,7 +159,7 @@ func (d *Sequencer) BuildingOnto() eth.L2BlockRef { ...@@ -159,7 +159,7 @@ func (d *Sequencer) BuildingOnto() eth.L2BlockRef {
// RunNextSequencerAction starts new block building work, or seals existing work, // RunNextSequencerAction starts new block building work, or seals existing work,
// and is best timed by first awaiting the delay returned by PlanNextSequencerAction. // and is best timed by first awaiting the delay returned by PlanNextSequencerAction.
// If a new block is successfully sealed, it will be returned for publishing, nil otherwise. // If a new block is successfully sealed, it will be returned for publishing, nil otherwise.
func (d *Sequencer) RunNextSequencerAction(ctx context.Context, l1Head eth.L1BlockRef) *eth.ExecutionPayload { func (d *Sequencer) RunNextSequencerAction(ctx context.Context) *eth.ExecutionPayload {
if _, buildingID, _ := d.engine.BuildingPayload(); buildingID != (eth.PayloadID{}) { if _, buildingID, _ := d.engine.BuildingPayload(); buildingID != (eth.PayloadID{}) {
payload, err := d.CompleteBuildingBlock(ctx) payload, err := d.CompleteBuildingBlock(ctx)
if err != nil { if err != nil {
...@@ -174,7 +174,7 @@ func (d *Sequencer) RunNextSequencerAction(ctx context.Context, l1Head eth.L1Blo ...@@ -174,7 +174,7 @@ func (d *Sequencer) RunNextSequencerAction(ctx context.Context, l1Head eth.L1Blo
return payload return payload
} }
} else { } else {
err := d.StartBuildingBlock(ctx, l1Head) err := d.StartBuildingBlock(ctx)
if err != nil { if err != nil {
d.log.Error("sequencer failed to start building new block", "err", err) d.log.Error("sequencer failed to start building new block", "err", err)
d.nextAction = d.timeNow().Add(time.Second) d.nextAction = d.timeNow().Add(time.Second)
......
...@@ -132,10 +132,10 @@ func (fn testAttrBuilderFn) PreparePayloadAttributes(ctx context.Context, l2Pare ...@@ -132,10 +132,10 @@ func (fn testAttrBuilderFn) PreparePayloadAttributes(ctx context.Context, l2Pare
var _ derive.AttributesBuilder = (testAttrBuilderFn)(nil) var _ derive.AttributesBuilder = (testAttrBuilderFn)(nil)
type testOriginSelectorFn func(ctx context.Context, l1Head eth.L1BlockRef, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) type testOriginSelectorFn func(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error)
func (fn testOriginSelectorFn) FindL1Origin(ctx context.Context, l1Head eth.L1BlockRef, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) { func (fn testOriginSelectorFn) FindL1Origin(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) {
return fn(ctx, l1Head, l2Head) return fn(ctx, l2Head)
} }
var _ L1OriginSelectorIface = (testOriginSelectorFn)(nil) var _ L1OriginSelectorIface = (testOriginSelectorFn)(nil)
...@@ -262,7 +262,7 @@ func TestSequencerChaosMonkey(t *testing.T) { ...@@ -262,7 +262,7 @@ func TestSequencerChaosMonkey(t *testing.T) {
maxL1BlockTimeGap := uint64(100) maxL1BlockTimeGap := uint64(100)
// The origin selector just generates random L1 blocks based on RNG // The origin selector just generates random L1 blocks based on RNG
var originErr error var originErr error
originSelector := testOriginSelectorFn(func(ctx context.Context, l1Head eth.L1BlockRef, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) { originSelector := testOriginSelectorFn(func(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) {
if originErr != nil { if originErr != nil {
return eth.L1BlockRef{}, originErr return eth.L1BlockRef{}, originErr
} }
...@@ -298,8 +298,6 @@ func TestSequencerChaosMonkey(t *testing.T) { ...@@ -298,8 +298,6 @@ func TestSequencerChaosMonkey(t *testing.T) {
seq := NewSequencer(log, cfg, engControl, attrBuilder, originSelector) seq := NewSequencer(log, cfg, engControl, attrBuilder, originSelector)
seq.timeNow = clockFn seq.timeNow = clockFn
l1Head := eth.L1BlockRef{} // TODO this is getting removed
// try to build 1000 blocks, with 5x as many planning attempts, to handle errors and clock problems // try to build 1000 blocks, with 5x as many planning attempts, to handle errors and clock problems
desiredBlocks := 1000 desiredBlocks := 1000
for i := 0; i < 5*desiredBlocks && engControl.totalBuiltBlocks < desiredBlocks; i++ { for i := 0; i < 5*desiredBlocks && engControl.totalBuiltBlocks < desiredBlocks; i++ {
...@@ -339,7 +337,7 @@ func TestSequencerChaosMonkey(t *testing.T) { ...@@ -339,7 +337,7 @@ func TestSequencerChaosMonkey(t *testing.T) {
default: default:
// no error // no error
} }
payload := seq.RunNextSequencerAction(context.Background(), l1Head) payload := seq.RunNextSequencerAction(context.Background())
if payload != nil { if payload != nil {
require.Equal(t, engControl.UnsafeL2Head().ID(), payload.ID(), "head must stay in sync with emitted payloads") require.Equal(t, engControl.UnsafeL2Head().ID(), payload.ID(), "head must stay in sync with emitted payloads")
var tx types.Transaction var tx types.Transaction
......
...@@ -212,7 +212,7 @@ func (s *Driver) eventLoop() { ...@@ -212,7 +212,7 @@ func (s *Driver) eventLoop() {
select { select {
case <-sequencerCh: case <-sequencerCh:
payload := s.sequencer.RunNextSequencerAction(ctx, s.l1State.L1Head()) payload := s.sequencer.RunNextSequencerAction(ctx)
if s.network != nil && payload != nil { if s.network != nil && payload != nil {
// Publishing of unsafe data via p2p is optional. // Publishing of unsafe data via p2p is optional.
// Errors are not severe enough to change/halt sequencing but should be logged and metered. // Errors are not severe enough to change/halt sequencing but should be logged and metered.
......
package version package version
var ( var (
Version = "v0.10.11" Version = "v0.10.12"
Meta = "dev" Meta = "dev"
) )
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
) )
var ( var (
Version = "v0.10.11" Version = "v0.10.12"
GitCommit = "" GitCommit = ""
GitDate = "" GitDate = ""
) )
......
...@@ -3,9 +3,9 @@ module github.com/ethereum-optimism/optimism/op-proposer ...@@ -3,9 +3,9 @@ module github.com/ethereum-optimism/optimism/op-proposer
go 1.18 go 1.18
require ( require (
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 github.com/ethereum-optimism/optimism/op-bindings v0.10.12
github.com/ethereum-optimism/optimism/op-node v0.10.11 github.com/ethereum-optimism/optimism/op-node v0.10.12
github.com/ethereum-optimism/optimism/op-service v0.10.11 github.com/ethereum-optimism/optimism/op-service v0.10.12
github.com/ethereum-optimism/optimism/op-signer v0.1.0 github.com/ethereum-optimism/optimism/op-signer v0.1.0
github.com/ethereum/go-ethereum v1.10.26 github.com/ethereum/go-ethereum v1.10.26
github.com/urfave/cli v1.22.9 github.com/urfave/cli v1.22.9
...@@ -15,12 +15,16 @@ require ( ...@@ -15,12 +15,16 @@ require (
github.com/VictoriaMetrics/fastcache v1.10.0 // indirect github.com/VictoriaMetrics/fastcache v1.10.0 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcd v0.23.3 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/btcsuite/btcd/btcutil v1.1.0 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/dyson/certman v0.3.0 // indirect github.com/dyson/certman v0.3.0 // indirect
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 // indirect
github.com/fjl/memsize v0.0.1 // indirect github.com/fjl/memsize v0.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
...@@ -80,6 +84,7 @@ require ( ...@@ -80,6 +84,7 @@ require (
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.5.0 // indirect github.com/tklauser/numcpus v0.5.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa // indirect github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
......
...@@ -36,6 +36,7 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym ...@@ -36,6 +36,7 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY=
github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
...@@ -49,10 +50,27 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 ...@@ -49,10 +50,27 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
github.com/btcsuite/btcd v0.23.3 h1:4KH/JKy9WiCd+iUS9Mu0Zp7Dnj17TGdKrg9xc/FGj24= github.com/btcsuite/btcd v0.23.3 h1:4KH/JKy9WiCd+iUS9Mu0Zp7Dnj17TGdKrg9xc/FGj24=
github.com/btcsuite/btcd v0.23.3/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=
github.com/btcsuite/btcd/btcutil v1.1.0 h1:MO4klnGY+EWJdoWF12Wkuf4AWDBPMpZNeN/jRLrklUU=
github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
...@@ -67,14 +85,18 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX ...@@ -67,14 +85,18 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dyson/certman v0.3.0 h1:S7WCUim5faT/OiBhiY3u5cMaiC9MNKiA+8PJDXLaIYQ= github.com/dyson/certman v0.3.0 h1:S7WCUim5faT/OiBhiY3u5cMaiC9MNKiA+8PJDXLaIYQ=
github.com/dyson/certman v0.3.0/go.mod h1:RMWlyA9op6D9SxOBRRX3sxnParehv9gf52WWUJPd1JA= github.com/dyson/certman v0.3.0/go.mod h1:RMWlyA9op6D9SxOBRRX3sxnParehv9gf52WWUJPd1JA=
...@@ -83,14 +105,16 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF ...@@ -83,14 +105,16 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468 h1:7KgjBYDji5AKi42eRYI+n8Gs+ZJVilSASL3WBu82c3M=
github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY= github.com/ethereum-optimism/op-geth v0.0.0-20221216190603-60b51d600468/go.mod h1:p0Yox74PhYlq1HvijrCBCD9A3cI7rXco7hT6KrQr+rY=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11 h1:RDiRyHo0G/UuxHZQdMJyqIuHtWvpionuFNfczNaWCcM= github.com/ethereum-optimism/optimism/op-bindings v0.10.12 h1:/B1gaCLwZYy9Rja3MiceV3R642bygp937kZjnYwRxA0=
github.com/ethereum-optimism/optimism/op-bindings v0.10.11/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c= github.com/ethereum-optimism/optimism/op-bindings v0.10.12/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c=
github.com/ethereum-optimism/optimism/op-node v0.10.11 h1:ED72b68ainzcXr5/cLOYRwv+LdE4hRDnkq3SmNRY1+Q= github.com/ethereum-optimism/optimism/op-node v0.10.12 h1:yOxMThwwz1rEDDM0xTjS+6jqJwgKRtrYM6h4Pdf0zno=
github.com/ethereum-optimism/optimism/op-node v0.10.11/go.mod h1:/CDpkMxc3mDklZ1nqz2lmxfeUyAUz7yC/OLmX8egAUw= github.com/ethereum-optimism/optimism/op-node v0.10.12/go.mod h1:z+DiFb82Vnn5zM3VEwc2OXK2V/JBg6MLg7ejTbsxye8=
github.com/ethereum-optimism/optimism/op-service v0.10.11 h1:o+SazhFXlE3EM9Re5KIPEQklZ9uTI8rNkjl0h5OwRtU= github.com/ethereum-optimism/optimism/op-service v0.10.12 h1:Y7pR3/b8eeHYkmo2V5z7sj8jaraYqm2Azyph5lbiIxo=
github.com/ethereum-optimism/optimism/op-service v0.10.11/go.mod h1:wbtHqi1fv00B3agj7a2zdP3OFanEfGZ23zPgGgFCF/c= github.com/ethereum-optimism/optimism/op-service v0.10.12/go.mod h1:Ibbun+aic0rjQBV8yBf9kohqIj6mQ8nSTWbZjHv+Q7Q=
github.com/ethereum-optimism/optimism/op-signer v0.1.0 h1:wH44Deai43YQWO0pEd44pDm3BahdAtSmrOHKiPvTB8Y= github.com/ethereum-optimism/optimism/op-signer v0.1.0 h1:wH44Deai43YQWO0pEd44pDm3BahdAtSmrOHKiPvTB8Y=
github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8= github.com/ethereum-optimism/optimism/op-signer v0.1.0/go.mod h1:u8sN6X/c20pP9F1Ey7jH3fi19D08Y+T9ep3PGJfdyi8=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
...@@ -214,7 +238,10 @@ github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc= ...@@ -214,7 +238,10 @@ github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw= github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
...@@ -225,6 +252,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V ...@@ -225,6 +252,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0= github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
...@@ -294,11 +322,15 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn ...@@ -294,11 +322,15 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
...@@ -359,7 +391,7 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w ...@@ -359,7 +391,7 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d h1:vmirMegf1vqPJ+lDBxLQ0MAt3tz+JL57UPxu44JBOjA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
...@@ -378,6 +410,7 @@ github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hM ...@@ -378,6 +410,7 @@ github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hM
github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A= github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A=
github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo= github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw= github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q=
...@@ -395,6 +428,7 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= ...@@ -395,6 +428,7 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
...@@ -433,6 +467,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB ...@@ -433,6 +467,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
...@@ -462,6 +497,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ ...@@ -462,6 +497,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
...@@ -523,10 +559,12 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w ...@@ -523,10 +559,12 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
......
...@@ -124,6 +124,7 @@ export abstract class BaseServiceV2< ...@@ -124,6 +124,7 @@ export abstract class BaseServiceV2<
metricsSpec: MetricsSpec<TMetrics> metricsSpec: MetricsSpec<TMetrics>
options?: Partial<TOptions & StandardOptions> options?: Partial<TOptions & StandardOptions>
loop?: boolean loop?: boolean
bodyParserParams?: bodyParser.OptionsJson
} }
) { ) {
this.loop = params.loop !== undefined ? params.loop : true this.loop = params.loop !== undefined ? params.loop : true
...@@ -330,6 +331,7 @@ export abstract class BaseServiceV2< ...@@ -330,6 +331,7 @@ export abstract class BaseServiceV2<
verify: (req, res, buf, encoding) => { verify: (req, res, buf, encoding) => {
;(req as any).rawBody = buf?.toString(encoding || 'utf8') || '' ;(req as any).rawBody = buf?.toString(encoding || 'utf8') || ''
}, },
...(this.params.bodyParserParams ?? {}),
}) })
) )
......
...@@ -9,13 +9,13 @@ GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 88513) ...@@ -9,13 +9,13 @@ GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 88513)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 74998) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 74998)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 36156) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 36156)
GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 167187) GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 167187)
Bytes_Test:test_slice_acrossMultipleWords_works() (gas: 9391) Bytes_slice_Test:test_slice_acrossMultipleWords_works() (gas: 9357)
Bytes_Test:test_slice_acrossWords_works() (gas: 1397) Bytes_slice_Test:test_slice_acrossWords_works() (gas: 1396)
Bytes_Test:test_slice_fromNonZeroIdx_works() (gas: 17218) Bytes_slice_Test:test_slice_fromNonZeroIdx_works() (gas: 17154)
Bytes_Test:test_slice_fromZeroIdx_works() (gas: 20826) Bytes_slice_Test:test_slice_fromZeroIdx_works() (gas: 20671)
Bytes_Test:test_toNibbles_expectedResult128Bytes_works() (gas: 129885) Bytes_toNibbles_Test:test_toNibbles_expectedResult128Bytes_works() (gas: 129830)
Bytes_Test:test_toNibbles_expectedResult5Bytes_works() (gas: 6132) Bytes_toNibbles_Test:test_toNibbles_expectedResult5Bytes_works() (gas: 6088)
Bytes_Test:test_toNibbles_zeroLengthInput_works() (gas: 966) Bytes_toNibbles_Test:test_toNibbles_zeroLengthInput_works() (gas: 944)
CrossDomainMessenger_BaseGas_Test:test_baseGas_succeeds() (gas: 20120) CrossDomainMessenger_BaseGas_Test:test_baseGas_succeeds() (gas: 20120)
CrossDomainOwnableThroughPortal_Test:test_depositTransaction_crossDomainOwner_succeeds() (gas: 61882) CrossDomainOwnableThroughPortal_Test:test_depositTransaction_crossDomainOwner_succeeds() (gas: 61882)
CrossDomainOwnable_Test:test_onlyOwner_notOwner_reverts() (gas: 10530) CrossDomainOwnable_Test:test_onlyOwner_notOwner_reverts() (gas: 10530)
...@@ -46,7 +46,7 @@ GovernanceToken_Test:test_mint_fromNotOwner_reverts() (gas: 17052) ...@@ -46,7 +46,7 @@ GovernanceToken_Test:test_mint_fromNotOwner_reverts() (gas: 17052)
GovernanceToken_Test:test_mint_fromOwner_succeeds() (gas: 108547) GovernanceToken_Test:test_mint_fromOwner_succeeds() (gas: 108547)
GovernanceToken_Test:test_transferFrom_succeeds() (gas: 146295) GovernanceToken_Test:test_transferFrom_succeeds() (gas: 146295)
GovernanceToken_Test:test_transfer_succeeds() (gas: 138085) GovernanceToken_Test:test_transfer_succeeds() (gas: 138085)
Hashing_Test:test_hashDepositSource_succeeds() (gas: 650) Hashing_hashDepositSource_Test:test_hashDepositSource_succeeds() (gas: 566)
L1BlockTest:test_basefee_succeeds() (gas: 7553) L1BlockTest:test_basefee_succeeds() (gas: 7553)
L1BlockTest:test_hash_succeeds() (gas: 7510) L1BlockTest:test_hash_succeeds() (gas: 7510)
L1BlockTest:test_number_succeeds() (gas: 7584) L1BlockTest:test_number_succeeds() (gas: 7584)
......
...@@ -4,7 +4,10 @@ pragma solidity 0.8.15; ...@@ -4,7 +4,10 @@ pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol"; import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol";
contract AddressAliasHelper_Test is Test { contract AddressAliasHelper_applyAndUndo_Test is Test {
/**
* @notice Tests that applying and then undoing an alias results in the original address.
*/
function testFuzz_applyAndUndo_succeeds(address _address) external { function testFuzz_applyAndUndo_succeeds(address _address) external {
address aliased = AddressAliasHelper.applyL1ToL2Alias(_address); address aliased = AddressAliasHelper.applyL1ToL2Alias(_address);
address unaliased = AddressAliasHelper.undoL1ToL2Alias(aliased); address unaliased = AddressAliasHelper.undoL1ToL2Alias(aliased);
......
...@@ -3,10 +3,10 @@ pragma solidity 0.8.15; ...@@ -3,10 +3,10 @@ pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { Bytes } from "../libraries/Bytes.sol"; import { Bytes } from "../libraries/Bytes.sol";
/// @title BytesTest contract Bytes_slice_Test is Test {
contract Bytes_Test is Test { /**
/// @dev Tests that the `slice` function works as expected when starting from * @notice Tests that the `slice` function works as expected when starting from index 0.
/// index 0. */
function test_slice_fromZeroIdx_works() public { function test_slice_fromZeroIdx_works() public {
bytes memory input = hex"11223344556677889900"; bytes memory input = hex"11223344556677889900";
...@@ -24,8 +24,10 @@ contract Bytes_Test is Test { ...@@ -24,8 +24,10 @@ contract Bytes_Test is Test {
assertEq(Bytes.slice(input, 0, 10), hex"11223344556677889900"); assertEq(Bytes.slice(input, 0, 10), hex"11223344556677889900");
} }
/// @dev Tests that the `slice` function works as expected when starting from /**
/// indexes [1, 9] with lengths [1, 9], in reverse order. * @notice Tests that the `slice` function works as expected when starting from indices [1, 9]
* with lengths [1, 9], in reverse order.
*/
function test_slice_fromNonZeroIdx_works() public { function test_slice_fromNonZeroIdx_works() public {
bytes memory input = hex"11223344556677889900"; bytes memory input = hex"11223344556677889900";
...@@ -42,10 +44,11 @@ contract Bytes_Test is Test { ...@@ -42,10 +44,11 @@ contract Bytes_Test is Test {
assertEq(Bytes.slice(input, 1, 9), hex"223344556677889900"); assertEq(Bytes.slice(input, 1, 9), hex"223344556677889900");
} }
/// @dev Tests that the `slice` function works as expected when slicing between /**
/// multiple words in memory. In this case, we test that a 2 byte slice between * @notice Tests that the `slice` function works as expected when slicing between multiple words
/// the 32nd byte of the first word and the 1st byte of the second word is * in memory. In this case, we test that a 2 byte slice between the 32nd byte of the
/// correct. * first word and the 1st byte of the second word is correct.
*/
function test_slice_acrossWords_works() public { function test_slice_acrossWords_works() public {
bytes bytes
memory input = hex"00000000000000000000000000000000000000000000000000000000000000112200000000000000000000000000000000000000000000000000000000000000"; memory input = hex"00000000000000000000000000000000000000000000000000000000000000112200000000000000000000000000000000000000000000000000000000000000";
...@@ -53,9 +56,11 @@ contract Bytes_Test is Test { ...@@ -53,9 +56,11 @@ contract Bytes_Test is Test {
assertEq(Bytes.slice(input, 31, 2), hex"1122"); assertEq(Bytes.slice(input, 31, 2), hex"1122");
} }
/// @dev Tests that the `slice` function works as expected when slicing between /**
/// multiple words in memory. In this case, we test that a 34 byte slice between * @notice Tests that the `slice` function works as expected when slicing between multiple
/// 3 separate words returns the correct result. * words in memory. In this case, we test that a 34 byte slice between 3 separate words
* returns the correct result.
*/
function test_slice_acrossMultipleWords_works() public { function test_slice_acrossMultipleWords_works() public {
bytes bytes
memory input = hex"000000000000000000000000000000000000000000000000000000000000001122FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1100000000000000000000000000000000000000000000000000000000000000"; memory input = hex"000000000000000000000000000000000000000000000000000000000000001122FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1100000000000000000000000000000000000000000000000000000000000000";
...@@ -65,8 +70,10 @@ contract Bytes_Test is Test { ...@@ -65,8 +70,10 @@ contract Bytes_Test is Test {
assertEq(Bytes.slice(input, 31, 34), expected); assertEq(Bytes.slice(input, 31, 34), expected);
} }
/// @dev Tests that, when given an input bytes array of length `n`, /**
/// the `slice` function will always revert if `_start + _length > n`. * @notice Tests that, when given an input bytes array of length `n`, the `slice` function will
* always revert if `_start + _length > n`.
*/
function testFuzz_slice_outOfBounds_reverts( function testFuzz_slice_outOfBounds_reverts(
bytes memory _input, bytes memory _input,
uint256 _start, uint256 _start,
...@@ -81,8 +88,10 @@ contract Bytes_Test is Test { ...@@ -81,8 +88,10 @@ contract Bytes_Test is Test {
Bytes.slice(_input, _start, _length); Bytes.slice(_input, _start, _length);
} }
/// @dev Tests that, when given a length `n` that is greater than `type(uint256).max - 31`, /**
/// the `slice` function reverts. * @notice Tests that, when given a length `n` that is greater than `type(uint256).max - 31`,
* the `slice` function reverts.
*/
function testFuzz_slice_lengthOverflows_reverts( function testFuzz_slice_lengthOverflows_reverts(
bytes memory _input, bytes memory _input,
uint256 _start, uint256 _start,
...@@ -95,8 +104,10 @@ contract Bytes_Test is Test { ...@@ -95,8 +104,10 @@ contract Bytes_Test is Test {
Bytes.slice(_input, _start, _length); Bytes.slice(_input, _start, _length);
} }
/// @dev Tests that, when given a length `n` that is greater than `type(uint256).max - 31`, /**
/// the `slice` function reverts. * @notice Tests that, when given a start index `n` that is greater than
* `type(uint256).max - n`, the `slice` function reverts.
*/
function testFuzz_slice_rangeOverflows_reverts( function testFuzz_slice_rangeOverflows_reverts(
bytes memory _input, bytes memory _input,
uint256 _start, uint256 _start,
...@@ -111,9 +122,56 @@ contract Bytes_Test is Test { ...@@ -111,9 +122,56 @@ contract Bytes_Test is Test {
vm.expectRevert("slice_overflow"); vm.expectRevert("slice_overflow");
Bytes.slice(_input, _start, _length); Bytes.slice(_input, _start, _length);
} }
}
contract Bytes_toNibbles_Test is Test {
/**
* @notice Diffs the test Solidity version of `toNibbles` against the Yul version.
*
* @param _bytes The `bytes` array to convert to nibbles.
*
* @return Yul version of `toNibbles` applied to `_bytes`.
*/
function _toNibblesYul(bytes memory _bytes) internal pure returns (bytes memory) {
// Allocate memory for the `nibbles` array.
bytes memory nibbles = new bytes(_bytes.length << 1);
assembly {
// Load the length of the passed bytes array from memory
let bytesLength := mload(_bytes)
// Store the memory offset of the _bytes array's contents on the stack
let bytesStart := add(_bytes, 0x20)
/// @dev Tests that, given an input of 5 bytes, the `toNibbles` function returns // Store the memory offset of the nibbles array's contents on the stack
/// an array of 10 nibbles corresponding to the input data. let nibblesStart := add(nibbles, 0x20)
// Loop through each byte in the input array
for {
let i := 0x00
} lt(i, bytesLength) {
i := add(i, 0x01)
} {
// Get the starting offset of the next 2 bytes in the nibbles array
let offset := add(nibblesStart, shl(0x01, i))
// Load the byte at the current index within the `_bytes` array
let b := byte(0x00, mload(add(bytesStart, i)))
// Pull out the first nibble and store it in the new array
mstore8(offset, shr(0x04, b))
// Pull out the second nibble and store it in the new array
mstore8(add(offset, 0x01), and(b, 0x0F))
}
}
return nibbles;
}
/**
* @notice Tests that, given an input of 5 bytes, the `toNibbles` function returns an array of
* 10 nibbles corresponding to the input data.
*/
function test_toNibbles_expectedResult5Bytes_works() public { function test_toNibbles_expectedResult5Bytes_works() public {
bytes memory input = hex"1234567890"; bytes memory input = hex"1234567890";
bytes memory expected = hex"01020304050607080900"; bytes memory expected = hex"01020304050607080900";
...@@ -124,10 +182,11 @@ contract Bytes_Test is Test { ...@@ -124,10 +182,11 @@ contract Bytes_Test is Test {
assertEq(actual, expected); assertEq(actual, expected);
} }
/// @dev Tests that, given an input of 128 bytes, the `toNibbles` function returns /**
/// an array of 256 nibbles corresponding to the input data. * @notice Tests that, given an input of 128 bytes, the `toNibbles` function returns an array
/// This test exists to ensure that, given a large input, the `toNibbles` function * of 256 nibbles corresponding to the input data. This test exists to ensure that,
/// works as expected. * given a large input, the `toNibbles` function works as expected.
*/
function test_toNibbles_expectedResult128Bytes_works() public { function test_toNibbles_expectedResult128Bytes_works() public {
bytes bytes
memory input = hex"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"; memory input = hex"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f";
...@@ -140,8 +199,10 @@ contract Bytes_Test is Test { ...@@ -140,8 +199,10 @@ contract Bytes_Test is Test {
assertEq(actual, expected); assertEq(actual, expected);
} }
/// @dev Tests that, given an input of 0 bytes, the `toNibbles` function returns /**
/// a zero length array. * @notice Tests that, given an input of 0 bytes, the `toNibbles` function returns a zero
* length array.
*/
function test_toNibbles_zeroLengthInput_works() public { function test_toNibbles_zeroLengthInput_works() public {
bytes memory input = hex""; bytes memory input = hex"";
bytes memory expected = hex""; bytes memory expected = hex"";
...@@ -153,30 +214,24 @@ contract Bytes_Test is Test { ...@@ -153,30 +214,24 @@ contract Bytes_Test is Test {
assertEq(actual, expected); assertEq(actual, expected);
} }
/// @dev Test that the `toNibbles` function in the `Bytes` library is equivalent to the /**
/// Yul implementation. * @notice Test that the `toNibbles` function in the `Bytes` library is equivalent to the Yul
* implementation.
*/
function testDiff_toNibbles_succeeds(bytes memory _input) public { function testDiff_toNibbles_succeeds(bytes memory _input) public {
assertEq(Bytes.toNibbles(_input), toNibblesYul(_input)); assertEq(Bytes.toNibbles(_input), _toNibblesYul(_input));
}
/// @dev Test that the `equal` function in the `Bytes` library returns `false` if given
/// two non-equal byte arrays.
function testFuzz_equal_notEqual_works(bytes memory _a, bytes memory _b) public {
vm.assume(!manualEq(_a, _b));
assertFalse(Bytes.equal(_a, _b));
} }
}
/// @dev Test whether or not the `equal` function in the `Bytes` library is equivalent contract Bytes_equal_Test is Test {
/// to manually checking equality of the two dynamic `bytes` arrays in memory. /**
function testDiff_equal_works(bytes memory _a, bytes memory _b) public { * @notice Manually checks equality of two dynamic `bytes` arrays in memory.
assertEq(Bytes.equal(_a, _b), manualEq(_a, _b)); *
} * @param _a The first `bytes` array to compare.
* @param _b The second `bytes` array to compare.
//////////////////////////////////////////////////////////////// *
// HELPERS // * @return True if the two `bytes` arrays are equal in memory.
//////////////////////////////////////////////////////////////// */
/// @dev Utility function to manually check equality of two dynamic `bytes` arrays in memory.
function manualEq(bytes memory _a, bytes memory _b) internal pure returns (bool) { function manualEq(bytes memory _a, bytes memory _b) internal pure returns (bool) {
bool _eq; bool _eq;
assembly { assembly {
...@@ -191,40 +246,20 @@ contract Bytes_Test is Test { ...@@ -191,40 +246,20 @@ contract Bytes_Test is Test {
return _eq; return _eq;
} }
/// @dev Utility function to diff test Solidity version of `toNibbles` /**
function toNibblesYul(bytes memory _bytes) internal pure returns (bytes memory) { * @notice Tests that the `equal` function in the `Bytes` library returns `false` if given two
// Allocate memory for the `nibbles` array. * non-equal byte arrays.
bytes memory nibbles = new bytes(_bytes.length << 1); */
function testFuzz_equal_notEqual_works(bytes memory _a, bytes memory _b) public {
assembly { vm.assume(!manualEq(_a, _b));
// Load the length of the passed bytes array from memory assertFalse(Bytes.equal(_a, _b));
let bytesLength := mload(_bytes) }
// Store the memory offset of the _bytes array's contents on the stack
let bytesStart := add(_bytes, 0x20)
// Store the memory offset of the nibbles array's contents on the stack
let nibblesStart := add(nibbles, 0x20)
// Loop through each byte in the input array
for {
let i := 0x00
} lt(i, bytesLength) {
i := add(i, 0x01)
} {
// Get the starting offset of the next 2 bytes in the nibbles array
let offset := add(nibblesStart, shl(0x01, i))
// Load the byte at the current index within the `_bytes` array
let b := byte(0x00, mload(add(bytesStart, i)))
// Pull out the first nibble and store it in the new array
mstore8(offset, shr(0x04, b))
// Pull out the second nibble and store it in the new array
mstore8(add(offset, 0x01), and(b, 0x0F))
}
}
return nibbles; /**
* @notice Test whether or not the `equal` function in the `Bytes` library is equivalent to
* manually checking equality of the two dynamic `bytes` arrays in memory.
*/
function testDiff_equal_works(bytes memory _a, bytes memory _b) public {
assertEq(Bytes.equal(_a, _b), manualEq(_a, _b));
} }
} }
...@@ -6,20 +6,33 @@ import { Types } from "../libraries/Types.sol"; ...@@ -6,20 +6,33 @@ import { Types } from "../libraries/Types.sol";
import { Hashing } from "../libraries/Hashing.sol"; import { Hashing } from "../libraries/Hashing.sol";
import { Encoding } from "../libraries/Encoding.sol"; import { Encoding } from "../libraries/Encoding.sol";
contract Hashing_Test is CommonTest { contract Hashing_hashDepositSource_Test is CommonTest {
function setUp() external { function setUp() external {
_setUp(); _setUp();
} }
/**
* @notice Tests that hashDepositSource returns the correct hash in a simple case.
*/
function test_hashDepositSource_succeeds() external { function test_hashDepositSource_succeeds() external {
bytes32 sourceHash = Hashing.hashDepositSource( assertEq(
0xd25df7858efc1778118fb133ac561b138845361626dfb976699c5287ed0f4959, Hashing.hashDepositSource(
0x1 0xd25df7858efc1778118fb133ac561b138845361626dfb976699c5287ed0f4959,
0x1
),
0xf923fb07134d7d287cb52c770cc619e17e82606c21a875c92f4c63b65280a5cc
); );
}
}
assertEq(sourceHash, 0xf923fb07134d7d287cb52c770cc619e17e82606c21a875c92f4c63b65280a5cc); contract Hashing_hashCrossDomainMessage_Test is CommonTest {
function setUp() external {
_setUp();
} }
/**
* @notice Tests that hashCrossDomainMessage returns the correct hash in a simple case.
*/
function testDiff_hashCrossDomainMessage_succeeds( function testDiff_hashCrossDomainMessage_succeeds(
uint240 _nonce, uint240 _nonce,
uint16 _version, uint16 _version,
...@@ -29,31 +42,25 @@ contract Hashing_Test is CommonTest { ...@@ -29,31 +42,25 @@ contract Hashing_Test is CommonTest {
uint256 _gasLimit, uint256 _gasLimit,
bytes memory _data bytes memory _data
) external { ) external {
// Ensure the version is valid // Ensure the version is valid.
uint16 version = uint16(bound(uint256(_version), 0, 1)); uint16 version = uint16(bound(uint256(_version), 0, 1));
uint256 nonce = Encoding.encodeVersionedNonce(_nonce, version); uint256 nonce = Encoding.encodeVersionedNonce(_nonce, version);
bytes32 _hash = ffi.hashCrossDomainMessage( assertEq(
nonce, Hashing.hashCrossDomainMessage(nonce, _sender, _target, _value, _gasLimit, _data),
_sender, ffi.hashCrossDomainMessage(nonce, _sender, _target, _value, _gasLimit, _data)
_target,
_value,
_gasLimit,
_data
);
bytes32 hash = Hashing.hashCrossDomainMessage(
nonce,
_sender,
_target,
_value,
_gasLimit,
_data
); );
}
}
assertEq(hash, _hash); contract Hashing_hashWithdrawal_Test is CommonTest {
function setUp() external {
_setUp();
} }
/**
* @notice Tests that hashWithdrawal returns the correct hash in a simple case.
*/
function testDiff_hashWithdrawal_succeeds( function testDiff_hashWithdrawal_succeeds(
uint256 _nonce, uint256 _nonce,
address _sender, address _sender,
...@@ -62,42 +69,56 @@ contract Hashing_Test is CommonTest { ...@@ -62,42 +69,56 @@ contract Hashing_Test is CommonTest {
uint256 _gasLimit, uint256 _gasLimit,
bytes memory _data bytes memory _data
) external { ) external {
bytes32 hash = Hashing.hashWithdrawal( assertEq(
Types.WithdrawalTransaction(_nonce, _sender, _target, _value, _gasLimit, _data) Hashing.hashWithdrawal(
Types.WithdrawalTransaction(_nonce, _sender, _target, _value, _gasLimit, _data)
),
ffi.hashWithdrawal(_nonce, _sender, _target, _value, _gasLimit, _data)
); );
}
}
bytes32 _hash = ffi.hashWithdrawal(_nonce, _sender, _target, _value, _gasLimit, _data); contract Hashing_hashOutputRootProof_Test is CommonTest {
function setUp() external {
assertEq(hash, _hash); _setUp();
} }
/**
* @notice Tests that hashOutputRootProof returns the correct hash in a simple case.
*/
function testDiff_hashOutputRootProof_succeeds( function testDiff_hashOutputRootProof_succeeds(
bytes32 _version, bytes32 _version,
bytes32 _stateRoot, bytes32 _stateRoot,
bytes32 _messagePasserStorageRoot, bytes32 _messagePasserStorageRoot,
bytes32 _latestBlockhash bytes32 _latestBlockhash
) external { ) external {
Types.OutputRootProof memory proof = Types.OutputRootProof({ assertEq(
version: _version, Hashing.hashOutputRootProof(
stateRoot: _stateRoot, Types.OutputRootProof({
messagePasserStorageRoot: _messagePasserStorageRoot, version: _version,
latestBlockhash: _latestBlockhash stateRoot: _stateRoot,
}); messagePasserStorageRoot: _messagePasserStorageRoot,
latestBlockhash: _latestBlockhash
bytes32 hash = Hashing.hashOutputRootProof(proof); })
),
bytes32 _hash = ffi.hashOutputRootProof( ffi.hashOutputRootProof(
_version, _version,
_stateRoot, _stateRoot,
_messagePasserStorageRoot, _messagePasserStorageRoot,
_latestBlockhash _latestBlockhash
)
); );
}
}
assertEq(hash, _hash); contract Hashing_hashDepositTransaction_Test is CommonTest {
function setUp() external {
_setUp();
} }
// TODO(tynes): foundry bug cannot serialize /**
// bytes32 as strings with vm.toString * @notice Tests that hashDepositTransaction returns the correct hash in a simple case.
*/
function testDiff_hashDepositTransaction_succeeds( function testDiff_hashDepositTransaction_succeeds(
address _from, address _from,
address _to, address _to,
...@@ -107,30 +128,21 @@ contract Hashing_Test is CommonTest { ...@@ -107,30 +128,21 @@ contract Hashing_Test is CommonTest {
bytes memory _data, bytes memory _data,
uint256 _logIndex uint256 _logIndex
) external { ) external {
bytes32 hash = Hashing.hashDepositTransaction( assertEq(
Types.UserDepositTransaction( Hashing.hashDepositTransaction(
_from, Types.UserDepositTransaction(
_to, _from,
false, // isCreate _to,
_value, false, // isCreate
_mint, _value,
_gas, _mint,
_data, _gas,
bytes32(uint256(0)), _data,
_logIndex bytes32(uint256(0)),
) _logIndex
)
),
ffi.hashDepositTransaction(_from, _to, _mint, _value, _gas, _data, _logIndex)
); );
bytes32 _hash = ffi.hashDepositTransaction(
_from,
_to,
_mint,
_value,
_gas,
_data,
_logIndex
);
assertEq(hash, _hash);
} }
} }
...@@ -13,6 +13,34 @@ AssetReceiverTest:test_withdrawETHwithAmount() (gas: 26108) ...@@ -13,6 +13,34 @@ AssetReceiverTest:test_withdrawETHwithAmount() (gas: 26108)
AssetReceiverTest:test_attest_bulk() (gas: 611440) AssetReceiverTest:test_attest_bulk() (gas: 611440)
AssetReceiverTest:test_attest_individual() (gas: 538514) AssetReceiverTest:test_attest_individual() (gas: 538514)
AssetReceiverTest:test_attest_single() (gas: 558962) AssetReceiverTest:test_attest_single() (gas: 558962)
CheckBalanceHighTest:testFuzz_check_fails(address,uint256) (runs: 256, μ: 12352, ~: 12382)
CheckBalanceHighTest:testFuzz_check_succeeds(address,uint256) (runs: 256, μ: 10284, ~: 10284)
CheckBalanceLowTest:testFuzz_check_fails(address,uint256) (runs: 256, μ: 10262, ~: 10262)
CheckBalanceLowTest:testFuzz_check_succeeds(address,uint256) (runs: 256, μ: 12374, ~: 12404)
CheckGelatoLowTest:testFuzz_check_fails(uint256,address) (runs: 256, μ: 34938, ~: 35871)
CheckGelatoLowTest:testFuzz_check_succeeds(uint256,address) (runs: 256, μ: 18800, ~: 18800)
CheckTrueTest:testFuzz_always_true_succeeds(bytes) (runs: 256, μ: 6539, ~: 6486)
Drippie_Test:testFuzz_fails_unauthorized(address) (runs: 256, μ: 17073, ~: 17073)
Drippie_Test:test_create_fails_twice() (gas: 169499)
Drippie_Test:test_create_success() (gas: 184013)
Drippie_Test:test_drip_amount() (gas: 286156)
Drippie_Test:test_drip_not_exist_fails() (gas: 15136)
Drippie_Test:test_name_not_exist_fails() (gas: 16157)
Drippie_Test:test_non_reentrant_zero_interval_fails() (gas: 19090)
Drippie_Test:test_not_active_fails() (gas: 171861)
Drippie_Test:test_reentrant_fails() (gas: 19129)
Drippie_Test:test_reentrant_succeeds() (gas: 180769)
Drippie_Test:test_set_status_none_fails() (gas: 169439)
Drippie_Test:test_set_status_same_fails() (gas: 169939)
Drippie_Test:test_set_status_success() (gas: 199270)
Drippie_Test:test_should_archive_if_paused_success() (gas: 177922)
Drippie_Test:test_should_not_allow_active_if_archived_fails() (gas: 175362)
Drippie_Test:test_should_not_allow_paused_if_archived_fails() (gas: 175383)
Drippie_Test:test_should_not_archive_if_active_fails() (gas: 176512)
Drippie_Test:test_status_unauthorized_fails() (gas: 167971)
Drippie_Test:test_trigger_one_function() (gas: 339137)
Drippie_Test:test_trigger_two_functions() (gas: 493184)
Drippie_Test:test_twice_in_one_interval_fails() (gas: 305202)
OptimistTest:test_optimist_baseURI() (gas: 116809) OptimistTest:test_optimist_baseURI() (gas: 116809)
OptimistTest:test_optimist_burn() (gas: 77526) OptimistTest:test_optimist_burn() (gas: 77526)
OptimistTest:test_optimist_initialize() (gas: 23095) OptimistTest:test_optimist_initialize() (gas: 23095)
......
import { DeployConfig } from '../../src'
const config: DeployConfig = {
ddd: '0x9C6373dE60c2D3297b18A8f964618ac46E011B58',
l2ProxyOwnerAddress: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistName: 'Optimist',
optimistSymbol: 'OPTIMIST',
attestorAddress: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
}
export default config
import { ethers } from 'ethers'
import { DrippieConfig, Time } from '../../src'
const config: DrippieConfig = {
BatcherBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckBalanceLow',
checkparams: {
target: '0x6887246668a3b87f54deb3b94ba47a6f63f32985',
threshold: ethers.utils.parseEther('75'),
},
actions: [
{
target: '0x6887246668a3b87f54deb3b94ba47a6f63f32985',
value: ethers.utils.parseEther('125'),
},
],
},
ProposerBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckBalanceLow',
checkparams: {
target: '0x473300df21d047806a082244b417f96b32f13a33',
threshold: ethers.utils.parseEther('50'),
},
actions: [
{
target: '0x473300df21d047806a082244b417f96b32f13a33',
value: ethers.utils.parseEther('100'),
},
],
},
GelatoBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckGelatoLow',
checkparams: {
treasury: '0x2807B4aE232b624023f87d0e237A3B1bf200Fd99',
recipient: '0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
threshold: ethers.utils.parseEther('0.1'),
},
actions: [
{
target: '0x2807B4aE232b624023f87d0e237A3B1bf200Fd99',
value: ethers.utils.parseEther('1'),
data: {
fn: 'depositFunds',
args: [
// receiver
'0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
// token
'0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
// amount
ethers.utils.parseEther('1'),
],
},
},
],
},
}
export default config
//SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import { Test } from "forge-std/Test.sol";
import { CheckBalanceHigh } from "../universal/drippie/dripchecks/CheckBalanceHigh.sol";
/**
* @title CheckBalanceHighTest
* @notice Tests the CheckBalanceHigh contract via fuzzing both the success case
* and the failure case.
*/
contract CheckBalanceHighTest is Test {
/**
* @notice An instance of the CheckBalanceHigh contract.
*/
CheckBalanceHigh c;
/**
* @notice Deploy the `CheckTrue` contract.
*/
function setUp() external {
c = new CheckBalanceHigh();
}
/**
* @notice Fuzz the `check` function and assert that it always returns true
* when the target's balance is larger than the threshold.
*/
function testFuzz_check_succeeds(address _target, uint256 _threshold) external {
CheckBalanceHigh.Params memory p = CheckBalanceHigh.Params({
target: _target,
threshold: _threshold
});
// prevent overflows
vm.assume(_threshold != type(uint256).max);
vm.deal(_target, _threshold + 1);
assertEq(c.check(abi.encode(p)), true);
}
/**
* @notice Fuzz the `check` function and assert that it always returns false
* when the target's balance is smaller than the threshold.
*/
function testFuzz_check_fails(address _target, uint256 _threshold) external {
CheckBalanceHigh.Params memory p = CheckBalanceHigh.Params({
target: _target,
threshold: _threshold
});
vm.assume(_target.balance < _threshold);
assertEq(c.check(abi.encode(p)), false);
}
}
//SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import { Test } from "forge-std/Test.sol";
import { CheckBalanceLow } from "../universal/drippie/dripchecks/CheckBalanceLow.sol";
/**
* @title CheckBalanceLowTest
* @notice Tests the CheckBalanceLow contract via fuzzing both the success case
* and the failure case.
*/
contract CheckBalanceLowTest is Test {
/**
* @notice An instance of the CheckBalanceLow contract.
*/
CheckBalanceLow c;
/**
* @notice Deploy the `CheckBalanceLow` contract.
*/
function setUp() external {
c = new CheckBalanceLow();
}
/**
* @notice Fuzz the `check` function and assert that it always returns true
* when the target's balance is smaller than the threshold.
*/
function testFuzz_check_succeeds(address _target, uint256 _threshold) external {
CheckBalanceLow.Params memory p = CheckBalanceLow.Params({
target: _target,
threshold: _threshold
});
vm.assume(_target.balance < _threshold);
assertEq(c.check(abi.encode(p)), true);
}
/**
* @notice Fuzz the `check` function and assert that it always returns false
* when the target's balance is larger than the threshold.
*/
function testFuzz_check_fails(address _target, uint256 _threshold) external {
CheckBalanceLow.Params memory p = CheckBalanceLow.Params({
target: _target,
threshold: _threshold
});
// prevent overflows
vm.assume(_threshold != type(uint256).max);
vm.deal(_target, _threshold + 1);
assertEq(c.check(abi.encode(p)), false);
}
}
//SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import { Test } from "forge-std/Test.sol";
import {
CheckGelatoLow,
IGelatoTreasury
} from "../universal/drippie/dripchecks/CheckGelatoLow.sol";
/**
* @title MockGelatoTreasury
* @notice Mocks the Gelato treasury for testing purposes. Allows arbitrary
* setting of user balances.
*/
contract MockGelatoTreasury is IGelatoTreasury {
mapping(address => mapping(address => uint256)) private tokenBalances;
function setTokenBalance(
address _user,
address _token,
uint256 _balance
) external {
tokenBalances[_token][_user] = _balance;
}
function userTokenBalance(address _user, address _token) external view returns (uint256) {
return tokenBalances[_token][_user];
}
}
/**
* @title CheckGelatoLowTest
* @notice Tests the CheckBalanceHigh contract via fuzzing both the success case
* and the failure case.
*/
contract CheckGelatoLowTest is Test {
/**
* @notice An instance of the CheckGelatoLow contract.
*/
CheckGelatoLow c;
/**
* @notice An instance of the MockGelatoTreasury contract.
*/
MockGelatoTreasury gelato;
/**
* @notice The account Gelato uses to represent ether
*/
address internal constant eth = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/**
* @notice Deploy the `CheckGelatoLow` and `MockGelatoTreasury` contracts.
*/
function setUp() external {
c = new CheckGelatoLow();
gelato = new MockGelatoTreasury();
}
/**
* @notice Fuzz the `check` function and assert that it always returns true
* when the user's balance in the treasury is less than the threshold.
*/
function testFuzz_check_succeeds(uint256 _threshold, address _recipient) external {
CheckGelatoLow.Params memory p = CheckGelatoLow.Params({
treasury: address(gelato),
threshold: _threshold,
recipient: _recipient
});
vm.assume(gelato.userTokenBalance(_recipient, eth) < _threshold);
assertEq(c.check(abi.encode(p)), true);
}
/**
* @notice Fuzz the `check` function and assert that it always returns false
* when the user's balance in the treasury is greater than or equal
* to the threshold.
*/
function testFuzz_check_fails(uint256 _threshold, address _recipient) external {
CheckGelatoLow.Params memory p = CheckGelatoLow.Params({
treasury: address(gelato),
threshold: _threshold,
recipient: _recipient
});
gelato.setTokenBalance(_recipient, eth, _threshold);
assertEq(c.check(abi.encode(p)), false);
}
}
//SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import { Test } from "forge-std/Test.sol";
import { CheckTrue } from "../universal/drippie/dripchecks/CheckTrue.sol";
/**
* @title CheckTrueTest
* @notice Ensures that the CheckTrue DripCheck contract always returns true.
*/
contract CheckTrueTest is Test {
/**
* @notice An instance of the CheckTrue contract.
*/
CheckTrue c;
/**
* @notice Deploy the `CheckTrue` contract.
*/
function setUp() external {
c = new CheckTrue();
}
/**
* @notice Fuzz the `check` function and assert that it always returns true.
*/
function testFuzz_always_true_succeeds(bytes memory input) external {
assertEq(c.check(input), true);
}
}
//SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import { Test } from "forge-std/Test.sol";
import { Drippie } from "../universal/drippie/Drippie.sol";
import { IDripCheck } from "../universal/drippie/IDripCheck.sol";
import { CheckTrue } from "../universal/drippie/dripchecks/CheckTrue.sol";
import { SimpleStorage } from "../testing/helpers/SimpleStorage.sol";
/**
* @title TestDrippie
* @notice This is a wrapper contract around Drippie used for testing.
* Returning an entire `Drippie.DripState` causes stack too
* deep errors without `--vir-ir` which causes the compile time
* to go up by ~4x. Each of the methods is a simple getter around
* parts of the `DripState`.
*/
contract TestDrippie is Drippie {
constructor(address owner) Drippie(owner) {}
function dripStatus(string memory name) external view returns (Drippie.DripStatus) {
return drips[name].status;
}
function dripStateLast(string memory name) external view returns (uint256) {
return drips[name].last;
}
function dripConfig(string memory name) external view returns (Drippie.DripConfig memory) {
return drips[name].config;
}
function dripConfigActions(string memory name)
external
view
returns (Drippie.DripAction[] memory)
{
return drips[name].config.actions;
}
function dripConfigCheckParams(string memory name) external view returns (bytes memory) {
return drips[name].config.checkparams;
}
function dripConfigCheckAddress(string memory name) external view returns (address) {
return address(drips[name].config.dripcheck);
}
}
/**
* @title Drippie_Test
* @notice Test coverage of the Drippie contract.
*/
contract Drippie_Test is Test {
/**
* @notice Emitted when a drip is executed.
*/
event DripExecuted(string indexed nameref, string name, address executor, uint256 timestamp);
/**
* @notice Emitted when a drip's status is updated.
*/
event DripStatusUpdated(string indexed nameref, string name, Drippie.DripStatus status);
/**
* @notice Emitted when a drip is created.
*/
event DripCreated(string indexed nameref, string name, Drippie.DripConfig config);
/**
* @notice Address of the test DripCheck. CheckTrue is deployed
* here so it always returns true.
*/
IDripCheck check;
/**
* @notice Address of a SimpleStorage contract. Used to test that
* calls are actually made by Drippie.
*/
SimpleStorage simpleStorage;
/**
* @notice Address of the Drippie contract.
*/
TestDrippie drippie;
/**
* @notice Address of the Drippie owner
*/
address constant alice = address(0x42);
/**
* @notice The name of the default drip
*/
string constant dripName = "foo";
/**
* @notice Set up the test suite by deploying a CheckTrue DripCheck.
* This is a mock that always returns true. Alice is the owner
* and also give drippie 1 ether so that it can balance transfer.
*/
function setUp() external {
check = IDripCheck(new CheckTrue());
simpleStorage = new SimpleStorage();
drippie = new TestDrippie(alice);
vm.deal(address(drippie), 1 ether);
}
/**
* @notice Builds a default Drippie.DripConfig. Uses CheckTrue as the
* dripcheck so it will always be able to do its DripActions.
* Gives a dummy DripAction that does a simple transfer to
* a dummy address.
*/
function _defaultConfig() internal view returns (Drippie.DripConfig memory) {
Drippie.DripAction[] memory actions = new Drippie.DripAction[](1);
actions[0] = Drippie.DripAction({ target: payable(address(0x44)), data: hex"", value: 1 });
return
Drippie.DripConfig({
interval: 100,
dripcheck: check,
reentrant: false,
checkparams: hex"",
actions: actions
});
}
/**
* @notice Creates a default drip using the default drip config.
*/
function _createDefaultDrip(string memory name) internal {
address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig();
vm.prank(owner);
drippie.create(name, cfg);
}
/**
* @notice Moves the block's timestamp forward so that it is
* possible to execute a drip.
*/
function _warpToExecutable(string memory name) internal {
Drippie.DripConfig memory config = drippie.dripConfig(name);
vm.warp(config.interval + drippie.dripStateLast(name));
}
/**
* @notice Creates a drip and asserts that it was configured as expected.
*/
function test_create_success() external {
Drippie.DripConfig memory cfg = _defaultConfig();
vm.expectEmit(true, true, true, true);
emit DripCreated(dripName, dripName, cfg);
if (cfg.reentrant) {
assertEq(cfg.interval, 0);
} else {
assertTrue(cfg.interval > 0);
}
vm.prank(drippie.owner());
drippie.create(dripName, cfg);
Drippie.DripStatus status = drippie.dripStatus(dripName);
Drippie.DripConfig memory config = drippie.dripConfig(dripName);
assertEq(uint256(status), uint256(Drippie.DripStatus.PAUSED));
assertEq(config.interval, cfg.interval);
assertEq(config.reentrant, cfg.reentrant);
assertEq(address(config.dripcheck), address(cfg.dripcheck));
assertEq(config.checkparams, cfg.checkparams);
assertEq(config.actions.length, cfg.actions.length);
for (uint256 i; i < config.actions.length; i++) {
Drippie.DripAction memory a = config.actions[i];
Drippie.DripAction memory b = cfg.actions[i];
assertEq(a.target, b.target);
assertEq(a.data, b.data);
assertEq(a.value, b.value);
}
}
/**
* @notice Ensures that the same drip cannot be created two times.
*/
function test_create_fails_twice() external {
vm.startPrank(drippie.owner());
Drippie.DripConfig memory cfg = _defaultConfig();
drippie.create(dripName, cfg);
vm.expectRevert("Drippie: drip with that name already exists");
drippie.create(dripName, cfg);
vm.stopPrank();
}
/**
* @notice Ensures that only the owner of Drippie can create a drip.
*/
function testFuzz_fails_unauthorized(address caller) external {
vm.assume(caller != drippie.owner());
vm.prank(caller);
vm.expectRevert("UNAUTHORIZED");
drippie.create(dripName, _defaultConfig());
}
/**
* @notice The owner should be able to set the status of the drip.
*/
function test_set_status_success() external {
vm.expectEmit(true, true, true, true);
emit DripCreated(dripName, dripName, _defaultConfig());
_createDefaultDrip(dripName);
address owner = drippie.owner();
{
Drippie.DripStatus status = drippie.dripStatus(dripName);
assertEq(uint256(status), uint256(Drippie.DripStatus.PAUSED));
}
vm.prank(owner);
vm.expectEmit(true, true, true, true);
emit DripStatusUpdated({
nameref: dripName,
name: dripName,
status: Drippie.DripStatus.ACTIVE
});
drippie.status(dripName, Drippie.DripStatus.ACTIVE);
{
Drippie.DripStatus status = drippie.dripStatus(dripName);
assertEq(uint256(status), uint256(Drippie.DripStatus.ACTIVE));
}
vm.prank(owner);
vm.expectEmit(true, true, true, true);
emit DripStatusUpdated({
nameref: dripName,
name: dripName,
status: Drippie.DripStatus.PAUSED
});
drippie.status(dripName, Drippie.DripStatus.PAUSED);
{
Drippie.DripStatus status = drippie.dripStatus(dripName);
assertEq(uint256(status), uint256(Drippie.DripStatus.PAUSED));
}
}
/**
* @notice The drip status cannot be set back to NONE after it is created.
*/
function test_set_status_none_fails() external {
_createDefaultDrip(dripName);
vm.prank(drippie.owner());
vm.expectRevert("Drippie: drip status can never be set back to NONE after creation");
drippie.status(dripName, Drippie.DripStatus.NONE);
}
/**
* @notice The owner cannot set the status of the drip to the status that
* it is already set as.
*/
function test_set_status_same_fails() external {
_createDefaultDrip(dripName);
vm.prank(drippie.owner());
vm.expectRevert("Drippie: cannot set drip status to the same status as its current status");
drippie.status(dripName, Drippie.DripStatus.PAUSED);
}
/**
* @notice The owner should be able to archive the drip if it is in the
* paused state.
*/
function test_should_archive_if_paused_success() external {
_createDefaultDrip(dripName);
address owner = drippie.owner();
vm.prank(owner);
vm.expectEmit(true, true, true, true);
emit DripStatusUpdated({
nameref: dripName,
name: dripName,
status: Drippie.DripStatus.ARCHIVED
});
drippie.status(dripName, Drippie.DripStatus.ARCHIVED);
Drippie.DripStatus status = drippie.dripStatus(dripName);
assertEq(uint256(status), uint256(Drippie.DripStatus.ARCHIVED));
}
/**
* @notice The owner should not be able to archive the drip if it is in the
* active state.
*/
function test_should_not_archive_if_active_fails() external {
_createDefaultDrip(dripName);
vm.prank(drippie.owner());
drippie.status(dripName, Drippie.DripStatus.ACTIVE);
vm.prank(drippie.owner());
vm.expectRevert("Drippie: drip must first be paused before being archived");
drippie.status(dripName, Drippie.DripStatus.ARCHIVED);
}
/**
* @notice The owner should not be allowed to pause the drip if it
* has already been archived.
*/
function test_should_not_allow_paused_if_archived_fails() external {
_createDefaultDrip(dripName);
_notAllowFromArchive(dripName, Drippie.DripStatus.PAUSED);
}
/**
* @notice The owner should not be allowed to make the drip active again if
* it has already been archived.
*/
function test_should_not_allow_active_if_archived_fails() external {
_createDefaultDrip(dripName);
_notAllowFromArchive(dripName, Drippie.DripStatus.ACTIVE);
}
/**
* @notice Archive the drip and then attempt to set the status to the passed
* in status.
*/
function _notAllowFromArchive(string memory name, Drippie.DripStatus status) internal {
address owner = drippie.owner();
vm.prank(owner);
drippie.status(name, Drippie.DripStatus.ARCHIVED);
vm.expectRevert("Drippie: drip with that name has been archived and cannot be updated");
vm.prank(owner);
drippie.status(name, status);
}
/**
* @notice Attempt to update a drip that does not exist.
*/
function test_name_not_exist_fails() external {
string memory otherName = "bar";
vm.prank(drippie.owner());
vm.expectRevert("Drippie: drip with that name does not exist and cannot be updated");
assertFalse(keccak256(abi.encode(dripName)) == keccak256(abi.encode(otherName)));
drippie.status(otherName, Drippie.DripStatus.ARCHIVED);
}
/**
* @notice Expect a revert when attempting to set the status when not the owner.
*/
function test_status_unauthorized_fails() external {
_createDefaultDrip(dripName);
vm.expectRevert("UNAUTHORIZED");
drippie.status(dripName, Drippie.DripStatus.ACTIVE);
}
/**
* @notice The drip should execute and be able to transfer value.
*/
function test_drip_amount() external {
_createDefaultDrip(dripName);
vm.prank(drippie.owner());
drippie.status(dripName, Drippie.DripStatus.ACTIVE);
_warpToExecutable(dripName);
vm.expectEmit(true, true, true, true);
emit DripExecuted({
nameref: dripName,
name: dripName,
executor: address(this),
timestamp: block.timestamp
});
Drippie.DripAction[] memory actions = drippie.dripConfigActions(dripName);
assertEq(actions.length, 1);
vm.expectCall(
drippie.dripConfigCheckAddress(dripName),
drippie.dripConfigCheckParams(dripName)
);
vm.expectCall(actions[0].target, actions[0].value, actions[0].data);
drippie.drip(dripName);
}
/**
* @notice A single DripAction should be able to make a state modifying call.
*/
function test_trigger_one_function() external {
Drippie.DripConfig memory cfg = _defaultConfig();
bytes32 key = bytes32(uint256(2));
bytes32 value = bytes32(uint256(3));
// Add in an action
cfg.actions[0] = Drippie.DripAction({
target: payable(address(simpleStorage)),
data: abi.encodeWithSelector(SimpleStorage.set.selector, key, value),
value: 0
});
vm.prank(drippie.owner());
drippie.create(dripName, cfg);
_warpToExecutable(dripName);
vm.prank(drippie.owner());
drippie.status(dripName, Drippie.DripStatus.ACTIVE);
vm.expectCall(
address(simpleStorage),
0,
abi.encodeWithSelector(SimpleStorage.set.selector, key, value)
);
vm.expectEmit(true, true, true, true, address(drippie));
emit DripExecuted(dripName, dripName, address(this), block.timestamp);
drippie.drip(dripName);
assertEq(simpleStorage.get(key), value);
}
/**
* @notice Multiple drip actions should be able to be triggered with the same check.
*/
function test_trigger_two_functions() external {
Drippie.DripConfig memory cfg = _defaultConfig();
Drippie.DripAction[] memory actions = new Drippie.DripAction[](2);
bytes32 keyOne = bytes32(uint256(2));
bytes32 valueOne = bytes32(uint256(3));
actions[0] = Drippie.DripAction({
target: payable(address(simpleStorage)),
data: abi.encodeWithSelector(simpleStorage.set.selector, keyOne, valueOne),
value: 0
});
bytes32 keyTwo = bytes32(uint256(4));
bytes32 valueTwo = bytes32(uint256(5));
actions[1] = Drippie.DripAction({
target: payable(address(simpleStorage)),
data: abi.encodeWithSelector(simpleStorage.set.selector, keyTwo, valueTwo),
value: 0
});
cfg.actions = actions;
vm.prank(drippie.owner());
drippie.create(dripName, cfg);
_warpToExecutable(dripName);
vm.prank(drippie.owner());
drippie.status(dripName, Drippie.DripStatus.ACTIVE);
vm.expectCall(
drippie.dripConfigCheckAddress(dripName),
drippie.dripConfigCheckParams(dripName)
);
vm.expectCall(
address(simpleStorage),
0,
abi.encodeWithSelector(SimpleStorage.set.selector, keyOne, valueOne)
);
vm.expectCall(
address(simpleStorage),
0,
abi.encodeWithSelector(SimpleStorage.set.selector, keyTwo, valueTwo)
);
vm.expectEmit(true, true, true, true, address(drippie));
emit DripExecuted(dripName, dripName, address(this), block.timestamp);
drippie.drip(dripName);
assertEq(simpleStorage.get(keyOne), valueOne);
assertEq(simpleStorage.get(keyTwo), valueTwo);
}
/**
* @notice The drips can only be triggered once per interval. Attempt to
* trigger the same drip multiple times in the same interval. Then
* move forward to the next interval and it should trigger.
*/
function test_twice_in_one_interval_fails() external {
_createDefaultDrip(dripName);
vm.prank(drippie.owner());
drippie.status(dripName, Drippie.DripStatus.ACTIVE);
_warpToExecutable(dripName);
vm.prank(drippie.owner());
drippie.drip(dripName);
vm.prank(drippie.owner());
vm.expectRevert("Drippie: drip interval has not elapsed since last drip");
drippie.drip(dripName);
_warpToExecutable(dripName);
vm.expectEmit(true, true, true, true, address(drippie));
emit DripExecuted({
nameref: dripName,
name: dripName,
executor: address(this),
timestamp: block.timestamp
});
drippie.drip(dripName);
}
/**
* @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.
*/
function test_drip_not_exist_fails() external {
vm.prank(drippie.owner());
vm.expectRevert("Drippie: selected drip does not exist or is not currently active");
drippie.drip(dripName);
}
/**
* @notice The owner cannot trigger the drip when it is paused.
*/
function test_not_active_fails() external {
_createDefaultDrip(dripName);
Drippie.DripStatus status = drippie.dripStatus(dripName);
assertEq(uint256(status), uint256(Drippie.DripStatus.PAUSED));
vm.prank(drippie.owner());
vm.expectRevert("Drippie: selected drip does not exist or is not currently active");
drippie.drip(dripName);
}
/**
* @notice The interval must be 0 if reentrant is set on the config.
*/
function test_reentrant_succeeds() external {
address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig();
cfg.reentrant = true;
cfg.interval = 0;
vm.prank(owner);
vm.expectEmit(true, true, true, true, address(drippie));
emit DripCreated(dripName, dripName, cfg);
drippie.create(dripName, cfg);
Drippie.DripConfig memory _cfg = drippie.dripConfig(dripName);
assertEq(_cfg.reentrant, true);
assertEq(_cfg.interval, 0);
}
/**
* @notice A non zero interval when reentrant is true will cause a revert
* when creating a drip.
*/
function test_reentrant_fails() external {
address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig();
cfg.reentrant = true;
cfg.interval = 1;
vm.prank(owner);
vm.expectRevert("Drippie: if allowing reentrant drip, must set interval to zero");
drippie.create(dripName, cfg);
}
/**
* @notice If reentrant is false and the interval is 0 then it should
* revert when the drip is created.
*/
function test_non_reentrant_zero_interval_fails() external {
address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig();
cfg.reentrant = false;
cfg.interval = 0;
vm.prank(owner);
vm.expectRevert("Drippie: interval must be greater than zero if drip is not reentrant");
drippie.create(dripName, cfg);
}
}
{ {
"address": "0xd5F62980C9d1bAa2A983bF16F8874A92F0050C48", "address": "0x7eC64a8a591bFf829ff6C8be76074D540ACb813F",
"abi": [ "abi": [
{ {
"anonymous": false, "anonymous": false,
...@@ -46,21 +46,62 @@ ...@@ -46,21 +46,62 @@
"type": "function" "type": "function"
} }
], ],
"transactionHash": "0x29af2bb56b520b9f7115dd3f4deda3dec0d6db0dfe45ef6a440a1f1b678242be",
"receipt": {
"to": "0x4e59b44847b379578588920cA78FbF26c0B4956C",
"from": "0x9C6373dE60c2D3297b18A8f964618ac46E011B58",
"contractAddress": null,
"transactionIndex": 158,
"gasUsed": "176628",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"blockHash": "0x64d24a3fac9011c7cb71b7811a78d0220251808bd5b4c5c71ac234ca77e1f792",
"transactionHash": "0x29af2bb56b520b9f7115dd3f4deda3dec0d6db0dfe45ef6a440a1f1b678242be",
"logs": [],
"blockNumber": 16485623,
"cumulativeGasUsed": "13944967",
"status": 1,
"byzantium": true
},
"args": [], "args": [],
"numDeployments": 1, "numDeployments": 2,
"solcInputHash": "b09909e91a3ff9823ceba49a3a845230", "solcInputHash": "2373b7ba869baea4fec58e6e7f7b8988",
"metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct CheckBalanceHigh.Params\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"_EventToExposeStructInABI__Params\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_params\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"CheckBalanceHigh\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"DripCheck for checking if an account's balance is above a given threshold.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol\":\"CheckBalanceHigh\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x73db6ada63ed1f0eba24efd36099139e66908aa45c79c0d1defe2a59a9e9eb9d\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\n/**\\n * @title CheckBalanceHigh\\n * @notice DripCheck for checking if an account's balance is above a given threshold.\\n */\\ncontract CheckBalanceHigh is IDripCheck {\\n event _EventToExposeStructInABI__Params(Params params);\\n struct Params {\\n address target;\\n uint256 threshold;\\n }\\n\\n function check(bytes memory _params) external view returns (bool) {\\n Params memory params = abi.decode(_params, (Params));\\n\\n // Check target balance is above threshold.\\n return params.target.balance > params.threshold;\\n }\\n}\\n\",\"keccak256\":\"0x517f69b75b62b7b74d3d4fceb45ecacb9cf1d68b62a8517e2985a6e0da0a7575\",\"license\":\"MIT\"}},\"version\":1}", "metadata": "{\"compiler\":{\"version\":\"0.8.16+commit.07a7930e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct CheckBalanceHigh.Params\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"_EventToExposeStructInABI__Params\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_params\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"_EventToExposeStructInABI__Params((address,uint256))\":{\"params\":{\"params\":\"Parameters to encode.\"}}},\"kind\":\"dev\",\"methods\":{\"check(bytes)\":{\"params\":{\"_params\":\"Encoded parameters for the drip check.\"},\"returns\":{\"_0\":\"Whether the drip should be executed.\"}}},\"title\":\"CheckBalanceHigh\",\"version\":1},\"userdoc\":{\"events\":{\"_EventToExposeStructInABI__Params((address,uint256))\":{\"notice\":\"External event used to help client-side tooling encode parameters.\"}},\"kind\":\"user\",\"methods\":{\"check(bytes)\":{\"notice\":\"Checks whether a drip should be executable.\"}},\"notice\":\"DripCheck for checking if an account's balance is above a given threshold.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol\":\"CheckBalanceHigh\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n /**\\n * @notice Checks whether a drip should be executable.\\n *\\n * @param _params Encoded parameters for the drip check.\\n *\\n * @return Whether the drip should be executed.\\n */\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xb52c89360566b2963dfd82cb2cc23f0c3ce4503a69e8563878e8aa80b6c60b3f\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.16;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\n/**\\n * @title CheckBalanceHigh\\n * @notice DripCheck for checking if an account's balance is above a given threshold.\\n */\\ncontract CheckBalanceHigh is IDripCheck {\\n struct Params {\\n address target;\\n uint256 threshold;\\n }\\n\\n /**\\n * @notice External event used to help client-side tooling encode parameters.\\n *\\n * @param params Parameters to encode.\\n */\\n event _EventToExposeStructInABI__Params(Params params);\\n\\n /**\\n * @inheritdoc IDripCheck\\n */\\n function check(bytes memory _params) external view returns (bool) {\\n Params memory params = abi.decode(_params, (Params));\\n\\n // Check target balance is above threshold.\\n return params.target.balance > params.threshold;\\n }\\n}\\n\",\"keccak256\":\"0xcb27d9e50a7c32406872b8fdc4ca62ee0d27372eb9077657f6d16f3cd3b58c85\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b50610239806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631119392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea2646970667358221220c3948eadf9cbb80bb928bc392291d583593cefbaff6536ec1485a7602e7f6b7f64736f6c63430008090033", "bytecode": "0x608060405234801561001057600080fd5b50610239806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631119392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea26469706673582212203818d112b628fa60d8cffe88e7198c860e268b9375b8b118dacdbf531c397ef864736f6c63430008100033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631119392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea2646970667358221220c3948eadf9cbb80bb928bc392291d583593cefbaff6536ec1485a7602e7f6b7f64736f6c63430008090033", "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631119392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea26469706673582212203818d112b628fa60d8cffe88e7198c860e268b9375b8b118dacdbf531c397ef864736f6c63430008100033",
"devdoc": { "devdoc": {
"events": {
"_EventToExposeStructInABI__Params((address,uint256))": {
"params": {
"params": "Parameters to encode."
}
}
},
"kind": "dev", "kind": "dev",
"methods": {}, "methods": {
"check(bytes)": {
"params": {
"_params": "Encoded parameters for the drip check."
},
"returns": {
"_0": "Whether the drip should be executed."
}
}
},
"title": "CheckBalanceHigh", "title": "CheckBalanceHigh",
"version": 1 "version": 1
}, },
"userdoc": { "userdoc": {
"events": {
"_EventToExposeStructInABI__Params((address,uint256))": {
"notice": "External event used to help client-side tooling encode parameters."
}
},
"kind": "user", "kind": "user",
"methods": {}, "methods": {
"check(bytes)": {
"notice": "Checks whether a drip should be executable."
}
},
"notice": "DripCheck for checking if an account's balance is above a given threshold.", "notice": "DripCheck for checking if an account's balance is above a given threshold.",
"version": 1 "version": 1
}, },
......
{ {
"address": "0x00B1D6438A4E7E3733Bd9fCe4A068b07A0E47620", "address": "0x381a4eFC2A2C914eA1889722bB4B44Fa6BD5b640",
"abi": [ "abi": [
{ {
"anonymous": false, "anonymous": false,
...@@ -46,37 +46,62 @@ ...@@ -46,37 +46,62 @@
"type": "function" "type": "function"
} }
], ],
"transactionHash": "0x65f0d04160b33d020aed8bfc4207f169d230549d8cff494f600b104fe0e689a1", "transactionHash": "0x914ed8cd67ba7ae6117f48f54d28a8bc95c024bcf81892fb5e3ef7cc3e6816bf",
"receipt": { "receipt": {
"to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C",
"from": "0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5", "from": "0x9C6373dE60c2D3297b18A8f964618ac46E011B58",
"contractAddress": null, "contractAddress": null,
"transactionIndex": 81, "transactionIndex": 142,
"gasUsed": "176640", "gasUsed": "176640",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"blockHash": "0xb1ddf0d044777738b0a1e53a28129e5d58076dbaa9b190843b76354706d8880b", "blockHash": "0x1146150967938fa2bc31b565eec819de4993de51c9f26921139c6c5251316d68",
"transactionHash": "0x65f0d04160b33d020aed8bfc4207f169d230549d8cff494f600b104fe0e689a1", "transactionHash": "0x914ed8cd67ba7ae6117f48f54d28a8bc95c024bcf81892fb5e3ef7cc3e6816bf",
"logs": [], "logs": [],
"blockNumber": 14981100, "blockNumber": 16485625,
"cumulativeGasUsed": "5262258", "cumulativeGasUsed": "11747659",
"status": 1, "status": 1,
"byzantium": true "byzantium": true
}, },
"args": [], "args": [],
"numDeployments": 1, "numDeployments": 2,
"solcInputHash": "b09909e91a3ff9823ceba49a3a845230", "solcInputHash": "2373b7ba869baea4fec58e6e7f7b8988",
"metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct CheckBalanceLow.Params\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"_EventToExposeStructInABI__Params\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_params\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"CheckBalanceLow\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"DripCheck for checking if an account's balance is below a given threshold.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol\":\"CheckBalanceLow\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x73db6ada63ed1f0eba24efd36099139e66908aa45c79c0d1defe2a59a9e9eb9d\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\n/**\\n * @title CheckBalanceLow\\n * @notice DripCheck for checking if an account's balance is below a given threshold.\\n */\\ncontract CheckBalanceLow is IDripCheck {\\n event _EventToExposeStructInABI__Params(Params params);\\n struct Params {\\n address target;\\n uint256 threshold;\\n }\\n\\n function check(bytes memory _params) external view returns (bool) {\\n Params memory params = abi.decode(_params, (Params));\\n\\n // Check target ETH balance is below threshold.\\n return params.target.balance < params.threshold;\\n }\\n}\\n\",\"keccak256\":\"0xd6d8e6abcc1428666132e9d8140243fff23c564b6474927e18f30fe078801842\",\"license\":\"MIT\"}},\"version\":1}", "metadata": "{\"compiler\":{\"version\":\"0.8.16+commit.07a7930e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct CheckBalanceLow.Params\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"_EventToExposeStructInABI__Params\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_params\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"_EventToExposeStructInABI__Params((address,uint256))\":{\"params\":{\"params\":\"Parameters to encode.\"}}},\"kind\":\"dev\",\"methods\":{\"check(bytes)\":{\"params\":{\"_params\":\"Encoded parameters for the drip check.\"},\"returns\":{\"_0\":\"Whether the drip should be executed.\"}}},\"title\":\"CheckBalanceLow\",\"version\":1},\"userdoc\":{\"events\":{\"_EventToExposeStructInABI__Params((address,uint256))\":{\"notice\":\"External event used to help client-side tooling encode parameters.\"}},\"kind\":\"user\",\"methods\":{\"check(bytes)\":{\"notice\":\"Checks whether a drip should be executable.\"}},\"notice\":\"DripCheck for checking if an account's balance is below a given threshold.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol\":\"CheckBalanceLow\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n /**\\n * @notice Checks whether a drip should be executable.\\n *\\n * @param _params Encoded parameters for the drip check.\\n *\\n * @return Whether the drip should be executed.\\n */\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xb52c89360566b2963dfd82cb2cc23f0c3ce4503a69e8563878e8aa80b6c60b3f\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.16;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\n/**\\n * @title CheckBalanceLow\\n * @notice DripCheck for checking if an account's balance is below a given threshold.\\n */\\ncontract CheckBalanceLow is IDripCheck {\\n struct Params {\\n address target;\\n uint256 threshold;\\n }\\n\\n /**\\n * @notice External event used to help client-side tooling encode parameters.\\n *\\n * @param params Parameters to encode.\\n */\\n event _EventToExposeStructInABI__Params(Params params);\\n\\n /**\\n * @inheritdoc IDripCheck\\n */\\n function check(bytes memory _params) external view returns (bool) {\\n Params memory params = abi.decode(_params, (Params));\\n\\n // Check target ETH balance is below threshold.\\n return params.target.balance < params.threshold;\\n }\\n}\\n\",\"keccak256\":\"0x6a1187a80093770931296d3360b1ecc7d17f69157fe88f628989b257548b564b\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b50610239806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea264697066735822122075d8f6816a6709f5b54613834c7be6979cb3af4abf6a1d38244135be431d562b64736f6c63430008090033", "bytecode": "0x608060405234801561001057600080fd5b50610239806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea2646970667358221220cc86d01120737597addcccffd841244801dcb64ce402d73b8d8569a52348996464736f6c63430008100033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea264697066735822122075d8f6816a6709f5b54613834c7be6979cb3af4abf6a1d38244135be431d562b64736f6c63430008090033", "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea2646970667358221220cc86d01120737597addcccffd841244801dcb64ce402d73b8d8569a52348996464736f6c63430008100033",
"devdoc": { "devdoc": {
"events": {
"_EventToExposeStructInABI__Params((address,uint256))": {
"params": {
"params": "Parameters to encode."
}
}
},
"kind": "dev", "kind": "dev",
"methods": {}, "methods": {
"check(bytes)": {
"params": {
"_params": "Encoded parameters for the drip check."
},
"returns": {
"_0": "Whether the drip should be executed."
}
}
},
"title": "CheckBalanceLow", "title": "CheckBalanceLow",
"version": 1 "version": 1
}, },
"userdoc": { "userdoc": {
"events": {
"_EventToExposeStructInABI__Params((address,uint256))": {
"notice": "External event used to help client-side tooling encode parameters."
}
},
"kind": "user", "kind": "user",
"methods": {}, "methods": {
"check(bytes)": {
"notice": "Checks whether a drip should be executable."
}
},
"notice": "DripCheck for checking if an account's balance is below a given threshold.", "notice": "DripCheck for checking if an account's balance is below a given threshold.",
"version": 1 "version": 1
}, },
......
{ {
"address": "0x81d70959f29872A9e597a54658A93962F7D9B597", "address": "0x4f7CFc43f6D262a085F3b946cAC69E7a8E39BBAa",
"abi": [ "abi": [
{ {
"anonymous": false, "anonymous": false,
...@@ -51,37 +51,62 @@ ...@@ -51,37 +51,62 @@
"type": "function" "type": "function"
} }
], ],
"transactionHash": "0x4f3db725a79a177062c8ddbbedb005a96ecb8eab6e71c4172c1b37fa1c708688", "transactionHash": "0x18d80365aa0edda05af40c91fa32c610df2101f8c388d274cb50b882f5147167",
"receipt": { "receipt": {
"to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C",
"from": "0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5", "from": "0x9C6373dE60c2D3297b18A8f964618ac46E011B58",
"contractAddress": null, "contractAddress": null,
"transactionIndex": 53, "transactionIndex": 47,
"gasUsed": "225248", "gasUsed": "222032",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"blockHash": "0xae292ed733027c5232a5775cd788ce31394cf4e7a068b7f2edbf8bd142e40d8f", "blockHash": "0xe3b313c0071bf10c41546a0f95ad53cda542f1b487fe1452e137ef652a0089a1",
"transactionHash": "0x4f3db725a79a177062c8ddbbedb005a96ecb8eab6e71c4172c1b37fa1c708688", "transactionHash": "0x18d80365aa0edda05af40c91fa32c610df2101f8c388d274cb50b882f5147167",
"logs": [], "logs": [],
"blockNumber": 14981104, "blockNumber": 16485627,
"cumulativeGasUsed": "5063510", "cumulativeGasUsed": "5224175",
"status": 1, "status": 1,
"byzantium": true "byzantium": true
}, },
"args": [], "args": [],
"numDeployments": 1, "numDeployments": 2,
"solcInputHash": "b09909e91a3ff9823ceba49a3a845230", "solcInputHash": "2373b7ba869baea4fec58e6e7f7b8988",
"metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"treasury\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct CheckGelatoLow.Params\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"_EventToExposeStructInABI__Params\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_params\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"CheckGelatoLow\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"DripCheck for checking if an account's Gelato ETH balance is below some threshold.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol\":\"CheckGelatoLow\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x73db6ada63ed1f0eba24efd36099139e66908aa45c79c0d1defe2a59a9e9eb9d\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\ninterface IGelatoTreasury {\\n function userTokenBalance(address _user, address _token) external view returns (uint256);\\n}\\n\\n/**\\n * @title CheckGelatoLow\\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\\n */\\ncontract CheckGelatoLow is IDripCheck {\\n event _EventToExposeStructInABI__Params(Params params);\\n struct Params {\\n address treasury;\\n uint256 threshold;\\n address recipient;\\n }\\n\\n function check(bytes memory _params) external view returns (bool) {\\n Params memory params = abi.decode(_params, (Params));\\n\\n // Check GelatoTreasury ETH balance is below threshold.\\n return\\n IGelatoTreasury(params.treasury).userTokenBalance(\\n params.recipient,\\n // Gelato represents ETH as 0xeeeee....eeeee\\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\n ) < params.threshold;\\n }\\n}\\n\",\"keccak256\":\"0x8d936bc5e037a1b05225f2cd208ef6899b0d29cd3b91c73e5c16762eb242e5ef\",\"license\":\"MIT\"}},\"version\":1}", "metadata": "{\"compiler\":{\"version\":\"0.8.16+commit.07a7930e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"treasury\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct CheckGelatoLow.Params\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"_EventToExposeStructInABI__Params\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_params\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"events\":{\"_EventToExposeStructInABI__Params((address,uint256,address))\":{\"params\":{\"params\":\"Parameters to encode.\"}}},\"kind\":\"dev\",\"methods\":{\"check(bytes)\":{\"params\":{\"_params\":\"Encoded parameters for the drip check.\"},\"returns\":{\"_0\":\"Whether the drip should be executed.\"}}},\"title\":\"CheckGelatoLow\",\"version\":1},\"userdoc\":{\"events\":{\"_EventToExposeStructInABI__Params((address,uint256,address))\":{\"notice\":\"External event used to help client-side tooling encode parameters.\"}},\"kind\":\"user\",\"methods\":{\"check(bytes)\":{\"notice\":\"Checks whether a drip should be executable.\"}},\"notice\":\"DripCheck for checking if an account's Gelato ETH balance is below some threshold.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol\":\"CheckGelatoLow\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n /**\\n * @notice Checks whether a drip should be executable.\\n *\\n * @param _params Encoded parameters for the drip check.\\n *\\n * @return Whether the drip should be executed.\\n */\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xb52c89360566b2963dfd82cb2cc23f0c3ce4503a69e8563878e8aa80b6c60b3f\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.16;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\ninterface IGelatoTreasury {\\n function userTokenBalance(address _user, address _token) external view returns (uint256);\\n}\\n\\n/**\\n * @title CheckGelatoLow\\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\\n */\\ncontract CheckGelatoLow is IDripCheck {\\n struct Params {\\n address treasury;\\n uint256 threshold;\\n address recipient;\\n }\\n\\n /**\\n * @notice External event used to help client-side tooling encode parameters.\\n *\\n * @param params Parameters to encode.\\n */\\n event _EventToExposeStructInABI__Params(Params params);\\n\\n /**\\n * @inheritdoc IDripCheck\\n */\\n function check(bytes memory _params) external view returns (bool) {\\n Params memory params = abi.decode(_params, (Params));\\n\\n // Check GelatoTreasury ETH balance is below threshold.\\n return\\n IGelatoTreasury(params.treasury).userTokenBalance(\\n params.recipient,\\n // Gelato represents ETH as 0xeeeee....eeeee\\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\n ) < params.threshold;\\n }\\n}\\n\",\"keccak256\":\"0x1a127a2c8955525cc2e5cd3c6703edc785c662a79222f524df4574cf47ddd864\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b5061031b806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e36600461016f565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610267565b6020810151815160408084015190517fb47064c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6024820152939450919291169063b47064c89060440160206040518083038186803b15801561010057600080fd5b505afa158015610114573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061013891906102cc565b109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561018157600080fd5b813567ffffffffffffffff8082111561019957600080fd5b818401915084601f8301126101ad57600080fd5b8135818111156101bf576101bf610140565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561020557610205610140565b8160405282815287602084870101111561021e57600080fd5b826020860160208301376000928101602001929092525095945050505050565b805173ffffffffffffffffffffffffffffffffffffffff8116811461026257600080fd5b919050565b60006060828403121561027957600080fd5b6040516060810181811067ffffffffffffffff8211171561029c5761029c610140565b6040526102a88361023e565b8152602083015160208201526102c06040840161023e565b60408201529392505050565b6000602082840312156102de57600080fd5b505191905056fea2646970667358221220e4e865f160af7ad5bd6e586c93c567a5f9a5ee5a652397683119d14d6f5e658464736f6c63430008090033", "bytecode": "0x608060405234801561001057600080fd5b5061030c806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e366004610160565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610258565b6020810151815160408084015190517fb47064c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6024820152939450919291169063b47064c890604401602060405180830381865afa158015610105573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061012991906102bd565b109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561017257600080fd5b813567ffffffffffffffff8082111561018a57600080fd5b818401915084601f83011261019e57600080fd5b8135818111156101b0576101b0610131565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101f6576101f6610131565b8160405282815287602084870101111561020f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b805173ffffffffffffffffffffffffffffffffffffffff8116811461025357600080fd5b919050565b60006060828403121561026a57600080fd5b6040516060810181811067ffffffffffffffff8211171561028d5761028d610131565b6040526102998361022f565b8152602083015160208201526102b16040840161022f565b60408201529392505050565b6000602082840312156102cf57600080fd5b505191905056fea2646970667358221220d5d7b760af134f89109f20dbf88fd89e78bb4b81bed97f9aa45772b3775b388964736f6c63430008100033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e36600461016f565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610267565b6020810151815160408084015190517fb47064c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6024820152939450919291169063b47064c89060440160206040518083038186803b15801561010057600080fd5b505afa158015610114573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061013891906102cc565b109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561018157600080fd5b813567ffffffffffffffff8082111561019957600080fd5b818401915084601f8301126101ad57600080fd5b8135818111156101bf576101bf610140565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561020557610205610140565b8160405282815287602084870101111561021e57600080fd5b826020860160208301376000928101602001929092525095945050505050565b805173ffffffffffffffffffffffffffffffffffffffff8116811461026257600080fd5b919050565b60006060828403121561027957600080fd5b6040516060810181811067ffffffffffffffff8211171561029c5761029c610140565b6040526102a88361023e565b8152602083015160208201526102c06040840161023e565b60408201529392505050565b6000602082840312156102de57600080fd5b505191905056fea2646970667358221220e4e865f160af7ad5bd6e586c93c567a5f9a5ee5a652397683119d14d6f5e658464736f6c63430008090033", "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e366004610160565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610258565b6020810151815160408084015190517fb47064c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6024820152939450919291169063b47064c890604401602060405180830381865afa158015610105573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061012991906102bd565b109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561017257600080fd5b813567ffffffffffffffff8082111561018a57600080fd5b818401915084601f83011261019e57600080fd5b8135818111156101b0576101b0610131565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101f6576101f6610131565b8160405282815287602084870101111561020f57600080fd5b826020860160208301376000928101602001929092525095945050505050565b805173ffffffffffffffffffffffffffffffffffffffff8116811461025357600080fd5b919050565b60006060828403121561026a57600080fd5b6040516060810181811067ffffffffffffffff8211171561028d5761028d610131565b6040526102998361022f565b8152602083015160208201526102b16040840161022f565b60408201529392505050565b6000602082840312156102cf57600080fd5b505191905056fea2646970667358221220d5d7b760af134f89109f20dbf88fd89e78bb4b81bed97f9aa45772b3775b388964736f6c63430008100033",
"devdoc": { "devdoc": {
"events": {
"_EventToExposeStructInABI__Params((address,uint256,address))": {
"params": {
"params": "Parameters to encode."
}
}
},
"kind": "dev", "kind": "dev",
"methods": {}, "methods": {
"check(bytes)": {
"params": {
"_params": "Encoded parameters for the drip check."
},
"returns": {
"_0": "Whether the drip should be executed."
}
}
},
"title": "CheckGelatoLow", "title": "CheckGelatoLow",
"version": 1 "version": 1
}, },
"userdoc": { "userdoc": {
"events": {
"_EventToExposeStructInABI__Params((address,uint256,address))": {
"notice": "External event used to help client-side tooling encode parameters."
}
},
"kind": "user", "kind": "user",
"methods": {}, "methods": {
"check(bytes)": {
"notice": "Checks whether a drip should be executable."
}
},
"notice": "DripCheck for checking if an account's Gelato ETH balance is below some threshold.", "notice": "DripCheck for checking if an account's Gelato ETH balance is below some threshold.",
"version": 1 "version": 1
}, },
......
{ {
"address": "0x7e2B28af043c347C18fc37f62B5D001df6BFa26c", "address": "0x5c741a38cb11424711231777D71689C458eE835D",
"abi": [ "abi": [
{ {
"inputs": [ "inputs": [
...@@ -21,37 +21,50 @@ ...@@ -21,37 +21,50 @@
"type": "function" "type": "function"
} }
], ],
"transactionHash": "0x02af8af4f6eda0944e437af66082a71b3a0c9c52f3ab2ac4e4929538f94d9411", "transactionHash": "0xf9c55443c3afb82190503b06ac5914eb3ea85179ec1572a0f22d781452f624dd",
"receipt": { "receipt": {
"to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C",
"from": "0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5", "from": "0x9C6373dE60c2D3297b18A8f964618ac46E011B58",
"contractAddress": null, "contractAddress": null,
"transactionIndex": 6, "transactionIndex": 129,
"gasUsed": "139230", "gasUsed": "139230",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"blockHash": "0xbf599dc7b5468b1291bd41db9290db892c3e883c7f24cfa123f0ce4fa19d8bf3", "blockHash": "0x5a37331d49bcc789cd37c2dd45be47bb35724fd974aab0573e8b6eb58f1690e5",
"transactionHash": "0x02af8af4f6eda0944e437af66082a71b3a0c9c52f3ab2ac4e4929538f94d9411", "transactionHash": "0xf9c55443c3afb82190503b06ac5914eb3ea85179ec1572a0f22d781452f624dd",
"logs": [], "logs": [],
"blockNumber": 14981108, "blockNumber": 16485630,
"cumulativeGasUsed": "630300", "cumulativeGasUsed": "13196107",
"status": 1, "status": 1,
"byzantium": true "byzantium": true
}, },
"args": [], "args": [],
"numDeployments": 1, "numDeployments": 2,
"solcInputHash": "b09909e91a3ff9823ceba49a3a845230", "solcInputHash": "2373b7ba869baea4fec58e6e7f7b8988",
"metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"CheckTrue\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"DripCheck that always returns true.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckTrue.sol\":\"CheckTrue\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x73db6ada63ed1f0eba24efd36099139e66908aa45c79c0d1defe2a59a9e9eb9d\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckTrue.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\n/**\\n * @title CheckTrue\\n * @notice DripCheck that always returns true.\\n */\\ncontract CheckTrue is IDripCheck {\\n function check(bytes memory) external pure returns (bool) {\\n return true;\\n }\\n}\\n\",\"keccak256\":\"0x2ed60821a4302130b567da45f15dce5a7c41e5d5b016c32ec09c92d4fb5ba6e6\",\"license\":\"MIT\"}},\"version\":1}", "metadata": "{\"compiler\":{\"version\":\"0.8.16+commit.07a7930e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"check(bytes)\":{\"params\":{\"_params\":\"Encoded parameters for the drip check.\"},\"returns\":{\"_0\":\"Whether the drip should be executed.\"}}},\"title\":\"CheckTrue\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"check(bytes)\":{\"notice\":\"Checks whether a drip should be executable.\"}},\"notice\":\"DripCheck that always returns true.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckTrue.sol\":\"CheckTrue\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n /**\\n * @notice Checks whether a drip should be executable.\\n *\\n * @param _params Encoded parameters for the drip check.\\n *\\n * @return Whether the drip should be executed.\\n */\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xb52c89360566b2963dfd82cb2cc23f0c3ce4503a69e8563878e8aa80b6c60b3f\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckTrue.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.16;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\n/**\\n * @title CheckTrue\\n * @notice DripCheck that always returns true.\\n */\\ncontract CheckTrue is IDripCheck {\\n /**\\n * @inheritdoc IDripCheck\\n */\\n function check(bytes memory) external pure returns (bool) {\\n return true;\\n }\\n}\\n\",\"keccak256\":\"0xf2f5474f12983c30ca4fe9d19e7f88e6d2262e4a6f779e86b4a2117498fdbea5\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b5061018c806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004461003e366004610087565b50600190565b604051901515815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561009957600080fd5b813567ffffffffffffffff808211156100b157600080fd5b818401915084601f8301126100c557600080fd5b8135818111156100d7576100d7610058565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561011d5761011d610058565b8160405282815287602084870101111561013657600080fd5b82602086016020830137600092810160200192909252509594505050505056fea26469706673582212207179cc803626c6d5a28bb5725d572d164ec9b64d4f37f10f220761ee045840fc64736f6c63430008090033", "bytecode": "0x608060405234801561001057600080fd5b5061018c806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004461003e366004610087565b50600190565b604051901515815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561009957600080fd5b813567ffffffffffffffff808211156100b157600080fd5b818401915084601f8301126100c557600080fd5b8135818111156100d7576100d7610058565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561011d5761011d610058565b8160405282815287602084870101111561013657600080fd5b82602086016020830137600092810160200192909252509594505050505056fea26469706673582212200bb899cb0e5f9dce180ebe72a1dfade46ffc5ec3cab398d1f2af09e8b9ce76d164736f6c63430008100033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004461003e366004610087565b50600190565b604051901515815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561009957600080fd5b813567ffffffffffffffff808211156100b157600080fd5b818401915084601f8301126100c557600080fd5b8135818111156100d7576100d7610058565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561011d5761011d610058565b8160405282815287602084870101111561013657600080fd5b82602086016020830137600092810160200192909252509594505050505056fea26469706673582212207179cc803626c6d5a28bb5725d572d164ec9b64d4f37f10f220761ee045840fc64736f6c63430008090033", "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004461003e366004610087565b50600190565b604051901515815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561009957600080fd5b813567ffffffffffffffff808211156100b157600080fd5b818401915084601f8301126100c557600080fd5b8135818111156100d7576100d7610058565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561011d5761011d610058565b8160405282815287602084870101111561013657600080fd5b82602086016020830137600092810160200192909252509594505050505056fea26469706673582212200bb899cb0e5f9dce180ebe72a1dfade46ffc5ec3cab398d1f2af09e8b9ce76d164736f6c63430008100033",
"devdoc": { "devdoc": {
"kind": "dev", "kind": "dev",
"methods": {}, "methods": {
"check(bytes)": {
"params": {
"_params": "Encoded parameters for the drip check."
},
"returns": {
"_0": "Whether the drip should be executed."
}
}
},
"title": "CheckTrue", "title": "CheckTrue",
"version": 1 "version": 1
}, },
"userdoc": { "userdoc": {
"kind": "user", "kind": "user",
"methods": {}, "methods": {
"check(bytes)": {
"notice": "Checks whether a drip should be executable."
}
},
"notice": "DripCheck that always returns true.", "notice": "DripCheck that always returns true.",
"version": 1 "version": 1
}, },
......
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"language": "Solidity",
"sources": {
"contracts/testing/helpers/TestERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\n\ncontract TestERC20 is ERC20 {\n constructor() ERC20(\"TEST\", \"TST\", 18) {}\n\n function mint(address to, uint256 value) public {\n _mint(to, value);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n uint8 public immutable decimals;\n\n /*//////////////////////////////////////////////////////////////\n ERC20 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 public totalSupply;\n\n mapping(address => uint256) public balanceOf;\n\n mapping(address => mapping(address => uint256)) public allowance;\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal immutable INITIAL_CHAIN_ID;\n\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n mapping(address => uint256) public nonces;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals\n ) {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n INITIAL_CHAIN_ID = block.chainid;\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 amount) public virtual returns (bool) {\n allowance[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n\n return true;\n }\n\n function transfer(address to, uint256 amount) public virtual returns (bool) {\n balanceOf[msg.sender] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(msg.sender, to, amount);\n\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual returns (bool) {\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n balanceOf[from] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual {\n require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n // Unchecked because the only math done is incrementing\n // the owner's nonce which cannot realistically overflow.\n unchecked {\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n allowance[recoveredAddress][spender] = value;\n }\n\n emit Approval(owner, spender, value);\n }\n\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n }\n\n function computeDomainSeparator() internal view virtual returns (bytes32) {\n return\n keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(name)),\n keccak256(\"1\"),\n block.chainid,\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 amount) internal virtual {\n totalSupply += amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal virtual {\n balanceOf[from] -= amount;\n\n // Cannot underflow because a user's balance\n // will never be larger than the total supply.\n unchecked {\n totalSupply -= amount;\n }\n\n emit Transfer(from, address(0), amount);\n }\n}\n"
},
"contracts/universal/AssetReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\nimport { Transactor } from \"./Transactor.sol\";\n\n/**\n * @title AssetReceiver\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\n */\ncontract AssetReceiver is Transactor {\n /**\n * @notice Emitted when ETH is received by this address.\n *\n * @param from Address that sent ETH to this contract.\n * @param amount Amount of ETH received.\n */\n event ReceivedETH(address indexed from, uint256 amount);\n\n /**\n * @notice Emitted when ETH is withdrawn from this address.\n *\n * @param withdrawer Address that triggered the withdrawal.\n * @param recipient Address that received the withdrawal.\n * @param amount ETH amount withdrawn.\n */\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\n\n /**\n * @notice Emitted when ERC20 tokens are withdrawn from this address.\n *\n * @param withdrawer Address that triggered the withdrawal.\n * @param recipient Address that received the withdrawal.\n * @param asset Address of the token being withdrawn.\n * @param amount ERC20 amount withdrawn.\n */\n event WithdrewERC20(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 amount\n );\n\n /**\n * @notice Emitted when ERC20 tokens are withdrawn from this address.\n *\n * @param withdrawer Address that triggered the withdrawal.\n * @param recipient Address that received the withdrawal.\n * @param asset Address of the token being withdrawn.\n * @param id Token ID being withdrawn.\n */\n event WithdrewERC721(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 id\n );\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Transactor(_owner) {}\n\n /**\n * @notice Make sure we can receive ETH.\n */\n receive() external payable {\n emit ReceivedETH(msg.sender, msg.value);\n }\n\n /**\n * @notice Withdraws full ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n */\n function withdrawETH(address payable _to) external onlyOwner {\n withdrawETH(_to, address(this).balance);\n }\n\n /**\n * @notice Withdraws partial ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n * @param _amount Amount of ETH to withdraw.\n */\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\n // slither-disable-next-line reentrancy-unlimited-gas\n (bool success, ) = _to.call{ value: _amount }(\"\");\n emit WithdrewETH(msg.sender, _to, _amount);\n }\n\n /**\n * @notice Withdraws full ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n */\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\n }\n\n /**\n * @notice Withdraws partial ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n * @param _amount Amount of ERC20 to withdraw.\n */\n function withdrawERC20(\n ERC20 _asset,\n address _to,\n uint256 _amount\n ) public onlyOwner {\n // slither-disable-next-line unchecked-transfer\n _asset.transfer(_to, _amount);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\n }\n\n /**\n * @notice Withdraws ERC721 token to the recipient.\n *\n * @param _asset ERC721 token to withdraw.\n * @param _to Address to receive the ERC721 token.\n * @param _id Token ID of the ERC721 token to withdraw.\n */\n function withdrawERC721(\n ERC721 _asset,\n address _to,\n uint256 _id\n ) external onlyOwner {\n _asset.transferFrom(address(this), _to, _id);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _ownerOf;\n\n mapping(address => uint256) internal _balanceOf;\n\n function ownerOf(uint256 id) public view virtual returns (address owner) {\n require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n }\n\n function balanceOf(address owner) public view virtual returns (uint256) {\n require(owner != address(0), \"ZERO_ADDRESS\");\n\n return _balanceOf[owner];\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) public getApproved;\n\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public virtual {\n address owner = _ownerOf[id];\n\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n require(from == _ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender's balance is impossible because we check for\n // ownership above and the recipient's balance can't realistically overflow.\n unchecked {\n _balanceOf[from]--;\n\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n delete getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes calldata data\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n unchecked {\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = _ownerOf[id];\n\n require(owner != address(0), \"NOT_MINTED\");\n\n // Ownership check above ensures no underflow.\n unchecked {\n _balanceOf[owner]--;\n }\n\n delete _ownerOf[id];\n\n delete getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(\n address to,\n uint256 id,\n bytes memory data\n ) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721TokenReceiver {\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/universal/Transactor.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Owned } from \"@rari-capital/solmate/src/auth/Owned.sol\";\n\n/**\n * @title Transactor\n * @notice Transactor is a minimal contract that can send transactions.\n */\ncontract Transactor is Owned {\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Owned(_owner) {}\n\n /**\n * Sends a CALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _value ETH value to send with the call.\n *\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function CALL(\n address _target,\n bytes memory _data,\n uint256 _value\n ) external payable onlyOwner returns (bool, bytes memory) {\n return _target.call{ value: _value }(_data);\n }\n\n /**\n * Sends a DELEGATECALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n *\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function DELEGATECALL(address _target, bytes memory _data)\n external\n payable\n onlyOwner\n returns (bool, bytes memory)\n {\n // slither-disable-next-line controlled-delegatecall\n return _target.delegatecall(_data);\n }\n}\n"
},
"@rari-capital/solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnerUpdated(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnerUpdated(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setOwner(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnerUpdated(msg.sender, newOwner);\n }\n}\n"
},
"contracts/universal/drippie/Drippie.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { AssetReceiver } from \"../AssetReceiver.sol\";\nimport { IDripCheck } from \"./IDripCheck.sol\";\n\n/**\n * @title Drippie\n * @notice Drippie is a system for managing automated contract interactions. A specific interaction\n * is called a \"drip\" and can be executed according to some condition (called a dripcheck)\n * and an execution interval. Drips cannot be executed faster than the execution interval.\n * Drips can trigger arbitrary contract calls where the calling contract is this contract\n * address. Drips can also send ETH value, which makes them ideal for keeping addresses\n * sufficiently funded with ETH. Drippie is designed to be connected with smart contract\n * automation services so that drips can be executed automatically. However, Drippie is\n * specifically designed to be separated from these services so that trust assumptions are\n * better compartmentalized.\n */\ncontract Drippie is AssetReceiver {\n /**\n * @notice Enum representing different status options for a given drip.\n *\n * @custom:value NONE Drip does not exist.\n * @custom:value PAUSED Drip is paused and cannot be executed until reactivated.\n * @custom:value ACTIVE Drip is active and can be executed.\n * @custom:value ARCHIVED Drip is archived and can no longer be executed or reactivated.\n */\n enum DripStatus {\n NONE,\n PAUSED,\n ACTIVE,\n ARCHIVED\n }\n\n /**\n * @notice Represents a drip action.\n */\n struct DripAction {\n address payable target;\n bytes data;\n uint256 value;\n }\n\n /**\n * @notice Represents the configuration for a given drip.\n */\n struct DripConfig {\n bool reentrant;\n uint256 interval;\n IDripCheck dripcheck;\n bytes checkparams;\n DripAction[] actions;\n }\n\n /**\n * @notice Represents the state of an active drip.\n */\n struct DripState {\n DripStatus status;\n DripConfig config;\n uint256 last;\n uint256 count;\n }\n\n /**\n * @notice Emitted when a new drip is created.\n *\n * @param nameref Indexed name parameter (hashed).\n * @param name Unindexed name parameter (unhashed).\n * @param config Config for the created drip.\n */\n event DripCreated(\n // Emit name twice because indexed version is hashed.\n string indexed nameref,\n string name,\n DripConfig config\n );\n\n /**\n * @notice Emitted when a drip status is updated.\n *\n * @param nameref Indexed name parameter (hashed).\n * @param name Unindexed name parameter (unhashed).\n * @param status New drip status.\n */\n event DripStatusUpdated(\n // Emit name twice because indexed version is hashed.\n string indexed nameref,\n string name,\n DripStatus status\n );\n\n /**\n * @notice Emitted when a drip is executed.\n *\n * @param nameref Indexed name parameter (hashed).\n * @param name Unindexed name parameter (unhashed).\n * @param executor Address that executed the drip.\n * @param timestamp Time when the drip was executed.\n */\n event DripExecuted(\n // Emit name twice because indexed version is hashed.\n string indexed nameref,\n string name,\n address executor,\n uint256 timestamp\n );\n\n /**\n * @notice Maps from drip names to drip states.\n */\n mapping(string => DripState) public drips;\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) AssetReceiver(_owner) {}\n\n /**\n * @notice Creates a new drip with the given name and configuration. Once created, drips cannot\n * be modified in any way (this is a security measure). If you want to update a drip,\n * simply pause (and potentially archive) the existing drip and create a new one.\n *\n * @param _name Name of the drip.\n * @param _config Configuration for the drip.\n */\n function create(string calldata _name, DripConfig calldata _config) external onlyOwner {\n // Make sure this drip doesn't already exist. We *must* guarantee that no other function\n // will ever set the status of a drip back to NONE after it's been created. This is why\n // archival is a separate status.\n require(\n drips[_name].status == DripStatus.NONE,\n \"Drippie: drip with that name already exists\"\n );\n\n // Validate the drip interval, only allowing an interval of zero if the drip has explicitly\n // been marked as reentrant. Prevents client-side bugs making a drip infinitely executable\n // within the same block (of course, restricted by gas limits).\n if (_config.reentrant) {\n require(\n _config.interval == 0,\n \"Drippie: if allowing reentrant drip, must set interval to zero\"\n );\n } else {\n require(\n _config.interval > 0,\n \"Drippie: interval must be greater than zero if drip is not reentrant\"\n );\n }\n\n // We initialize this way because Solidity won't let us copy arrays into storage yet.\n DripState storage state = drips[_name];\n state.status = DripStatus.PAUSED;\n state.config.reentrant = _config.reentrant;\n state.config.interval = _config.interval;\n state.config.dripcheck = _config.dripcheck;\n state.config.checkparams = _config.checkparams;\n\n // Solidity doesn't let us copy arrays into storage, so we push each array one by one.\n for (uint256 i = 0; i < _config.actions.length; i++) {\n state.config.actions.push(_config.actions[i]);\n }\n\n // Tell the world!\n emit DripCreated(_name, _name, _config);\n }\n\n /**\n * @notice Sets the status for a given drip. The behavior of this function depends on the\n * status that the user is trying to set. A drip can always move between ACTIVE and\n * PAUSED, but it can never move back to NONE and once ARCHIVED, it can never move back\n * to ACTIVE or PAUSED.\n *\n * @param _name Name of the drip to update.\n * @param _status New drip status.\n */\n function status(string calldata _name, DripStatus _status) external onlyOwner {\n // Make sure we can never set drip status back to NONE. A simple security measure to\n // prevent accidental overwrites if this code is ever updated down the line.\n require(\n _status != DripStatus.NONE,\n \"Drippie: drip status can never be set back to NONE after creation\"\n );\n\n // Load the drip status once to avoid unnecessary SLOADs.\n DripStatus curr = drips[_name].status;\n\n // Make sure the drip in question actually exists. Not strictly necessary but there doesn't\n // seem to be any clear reason why you would want to do this, and it may save some gas in\n // the case of a front-end bug.\n require(\n curr != DripStatus.NONE,\n \"Drippie: drip with that name does not exist and cannot be updated\"\n );\n\n // Once a drip has been archived, it cannot be un-archived. This is, after all, the entire\n // point of archiving a drip.\n require(\n curr != DripStatus.ARCHIVED,\n \"Drippie: drip with that name has been archived and cannot be updated\"\n );\n\n // Although not strictly necessary, we make sure that the status here is actually changing.\n // This may save the client some gas if there's a front-end bug and the user accidentally\n // tries to \"change\" the status to the same value as before.\n require(\n curr != _status,\n \"Drippie: cannot set drip status to the same status as its current status\"\n );\n\n // If the user is trying to archive this drip, make sure the drip has been paused. We do\n // not allow users to archive active drips so that the effects of this action are more\n // abundantly clear.\n if (_status == DripStatus.ARCHIVED) {\n require(\n curr == DripStatus.PAUSED,\n \"Drippie: drip must first be paused before being archived\"\n );\n }\n\n // If we made it here then we can safely update the status.\n drips[_name].status = _status;\n emit DripStatusUpdated(_name, _name, _status);\n }\n\n /**\n * @notice Checks if a given drip is executable.\n *\n * @param _name Drip to check.\n *\n * @return True if the drip is executable, reverts otherwise.\n */\n function executable(string calldata _name) public view returns (bool) {\n DripState storage state = drips[_name];\n\n // Only allow active drips to be executed, an obvious security measure.\n require(\n state.status == DripStatus.ACTIVE,\n \"Drippie: selected drip does not exist or is not currently active\"\n );\n\n // Don't drip if the drip interval has not yet elapsed since the last time we dripped. This\n // is a safety measure that prevents a malicious recipient from, e.g., spending all of\n // their funds and repeatedly requesting new drips. Limits the potential impact of a\n // compromised recipient to just a single drip interval, after which the drip can be paused\n // by the owner address.\n require(\n state.last + state.config.interval <= block.timestamp,\n \"Drippie: drip interval has not elapsed since last drip\"\n );\n\n // Make sure we're allowed to execute this drip.\n require(\n state.config.dripcheck.check(state.config.checkparams),\n \"Drippie: dripcheck failed so drip is not yet ready to be triggered\"\n );\n\n // Alright, we're good to execute.\n return true;\n }\n\n /**\n * @notice Triggers a drip. This function is deliberately left as a public function because the\n * assumption being made here is that setting the drip to ACTIVE is an affirmative\n * signal that the drip should be executable according to the drip parameters, drip\n * check, and drip interval. Note that drip parameters are read entirely from the state\n * and are not supplied as user input, so there should not be any way for a\n * non-authorized user to influence the behavior of the drip. Note that the drip check\n * is executed only **once** at the beginning of the call to the drip function and will\n * not be executed again between the drip actions within this call.\n *\n * @param _name Name of the drip to trigger.\n */\n function drip(string calldata _name) external {\n DripState storage state = drips[_name];\n\n // Make sure the drip can be executed. Since executable reverts if the drip is not ready to\n // be executed, we don't need to do an assertion that the returned value is true.\n executable(_name);\n\n // Update the last execution time for this drip before the call. Note that it's entirely\n // possible for a drip to be executed multiple times per block or even multiple times\n // within the same transaction (via re-entrancy) if the drip interval is set to zero. Users\n // should set a drip interval of 1 if they'd like the drip to be executed only once per\n // block (since this will then prevent re-entrancy).\n state.last = block.timestamp;\n\n // Update the number of times this drip has been executed. Although this increases the cost\n // of using Drippie, it slightly simplifies the client-side by not having to worry about\n // counting drips via events. Useful for monitoring the rate of drip execution.\n state.count++;\n\n // Execute each action in the drip. We allow drips to have multiple actions because there\n // are scenarios in which a contract must do multiple things atomically. For example, the\n // contract may need to withdraw ETH from one account and then deposit that ETH into\n // another account within the same transaction.\n uint256 len = state.config.actions.length;\n for (uint256 i = 0; i < len; i++) {\n // Must be marked as \"storage\" because copying structs into memory is not yet supported\n // by Solidity. Won't significantly reduce gas costs but at least makes it easier to\n // read what the rest of this section is doing.\n DripAction storage action = state.config.actions[i];\n\n // Actually execute the action. We could use ExcessivelySafeCall here but not strictly\n // necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this\n // will ever happen in practice). Could save a marginal amount of gas to ignore the\n // returndata.\n // slither-disable-next-line calls-loop\n (bool success, ) = action.target.call{ value: action.value }(action.data);\n\n // Generally should not happen, but could if there's a misconfiguration (e.g., passing\n // the wrong data to the target contract), the recipient is not payable, or\n // insufficient gas was supplied to this transaction. We revert so the drip can be\n // fixed and triggered again later. Means we cannot emit an event to alert of the\n // failure, but can reasonably be detected by off-chain services even without an event.\n // Note that this forces the drip executor to supply sufficient gas to the call\n // (assuming there is some sufficient gas limit that exists, otherwise the drip will\n // not execute).\n require(\n success,\n \"Drippie: drip was unsuccessful, please check your configuration for mistakes\"\n );\n }\n\n emit DripExecuted(_name, _name, msg.sender, block.timestamp);\n }\n}\n"
},
"contracts/universal/drippie/IDripCheck.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IDripCheck {\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\n // possible to easily encode parameters on the client side. Solidity does not support generics\n // so it's not possible to do this with explicit typing.\n\n /**\n * @notice Checks whether a drip should be executable.\n *\n * @param _params Encoded parameters for the drip check.\n *\n * @return Whether the drip should be executed.\n */\n function check(bytes memory _params) external view returns (bool);\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckTrue.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckTrue\n * @notice DripCheck that always returns true.\n */\ncontract CheckTrue is IDripCheck {\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory) external pure returns (bool) {\n return true;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\ninterface IGelatoTreasury {\n function userTokenBalance(address _user, address _token) external view returns (uint256);\n}\n\n/**\n * @title CheckGelatoLow\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\n */\ncontract CheckGelatoLow is IDripCheck {\n struct Params {\n address treasury;\n uint256 threshold;\n address recipient;\n }\n\n /**\n * @notice External event used to help client-side tooling encode parameters.\n *\n * @param params Parameters to encode.\n */\n event _EventToExposeStructInABI__Params(Params params);\n\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check GelatoTreasury ETH balance is below threshold.\n return\n IGelatoTreasury(params.treasury).userTokenBalance(\n params.recipient,\n // Gelato represents ETH as 0xeeeee....eeeee\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\n ) < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceLow\n * @notice DripCheck for checking if an account's balance is below a given threshold.\n */\ncontract CheckBalanceLow is IDripCheck {\n struct Params {\n address target;\n uint256 threshold;\n }\n\n /**\n * @notice External event used to help client-side tooling encode parameters.\n *\n * @param params Parameters to encode.\n */\n event _EventToExposeStructInABI__Params(Params params);\n\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target ETH balance is below threshold.\n return params.target.balance < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceHigh\n * @notice DripCheck for checking if an account's balance is above a given threshold.\n */\ncontract CheckBalanceHigh is IDripCheck {\n struct Params {\n address target;\n uint256 threshold;\n }\n\n /**\n * @notice External event used to help client-side tooling encode parameters.\n *\n * @param params Parameters to encode.\n */\n event _EventToExposeStructInABI__Params(Params params);\n\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target balance is above threshold.\n return params.target.balance > params.threshold;\n }\n}\n"
},
"contracts/testing/helpers/TestERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\n\ncontract TestERC721 is ERC721 {\n constructor() ERC721(\"TEST\", \"TST\") {}\n\n function mint(address to, uint256 tokenId) public {\n _mint(to, tokenId);\n }\n\n function tokenURI(uint256) public pure virtual override returns (string memory) {}\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
...@@ -54,7 +54,6 @@ ...@@ -54,7 +54,6 @@
"url": "https://github.com/ethereum-optimism/optimism.git" "url": "https://github.com/ethereum-optimism/optimism.git"
}, },
"devDependencies": { "devDependencies": {
"@defi-wonderland/smock": "^2.0.7",
"@eth-optimism/contracts-bedrock": "0.11.3", "@eth-optimism/contracts-bedrock": "0.11.3",
"@eth-optimism/core-utils": "^0.12.0", "@eth-optimism/core-utils": "^0.12.0",
"@eth-optimism/hardhat-deploy-config": "^0.2.5", "@eth-optimism/hardhat-deploy-config": "^0.2.5",
......
import hre from 'hardhat'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { Contract } from 'ethers'
import { toRpcHexString } from '@eth-optimism/core-utils'
import { expect } from '../../../setup'
import { deploy } from '../../../helpers'
describe('Drippie', () => {
const DEFAULT_DRIP_NAME = 'drippity drip drip'
const DEFAULT_DRIP_CONFIG = {
interval: hre.ethers.BigNumber.from(100),
dripcheck: '', // Gets added in setup
checkparams: '0x',
actions: [
{
target: '0x' + '11'.repeat(20),
data: '0x',
value: hre.ethers.BigNumber.from(1),
},
],
}
let signer1: SignerWithAddress
let signer2: SignerWithAddress
before('signer setup', async () => {
;[signer1, signer2] = await hre.ethers.getSigners()
})
before('deploy default dripcheck', async () => {
DEFAULT_DRIP_CONFIG.dripcheck = (await deploy('CheckTrue')).address
})
let SimpleStorage: Contract
let Drippie: Contract
beforeEach('deploy contracts', async () => {
SimpleStorage = await deploy('SimpleStorage')
Drippie = await deploy('Drippie', {
signer: signer1,
args: [signer1.address],
})
})
beforeEach('balance setup', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
Drippie.address,
toRpcHexString(DEFAULT_DRIP_CONFIG.actions[0].value.mul(100000)),
])
await hre.ethers.provider.send('hardhat_setBalance', [
DEFAULT_DRIP_CONFIG.actions[0].target,
'0x0',
])
})
describe('create', () => {
describe('when called by authorized address', () => {
it('should create a drip with the given name', async () => {
await expect(
Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
).to.emit(Drippie, 'DripCreated')
const drip = await Drippie.drips(DEFAULT_DRIP_NAME)
expect(drip.status).to.equal(1) // PAUSED
expect(drip.last).to.deep.equal(hre.ethers.BigNumber.from(0))
expect(drip.config.interval).to.deep.equal(DEFAULT_DRIP_CONFIG.interval)
expect(drip.config.dripcheck).to.deep.equal(
DEFAULT_DRIP_CONFIG.dripcheck
)
expect(drip.config.checkparams).to.deep.equal(
DEFAULT_DRIP_CONFIG.checkparams
)
expect(drip.config.actions[0][0]).to.deep.equal(
DEFAULT_DRIP_CONFIG.actions[0].target
)
expect(drip.config.actions[0][1]).to.deep.equal(
DEFAULT_DRIP_CONFIG.actions[0].data
)
expect(drip.config.actions[0][2]).to.deep.equal(
DEFAULT_DRIP_CONFIG.actions[0].value
)
})
it('should not be able to create the same drip twice', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await expect(
Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
).to.be.revertedWith('Drippie: drip with that name already exists')
})
})
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
Drippie.connect(signer2).create(
DEFAULT_DRIP_NAME,
DEFAULT_DRIP_CONFIG
)
).to.be.revertedWith('UNAUTHORIZED')
})
})
})
describe('status', () => {
describe('when called by authorized address', () => {
it('should allow setting between PAUSED and ACTIVE', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
expect((await Drippie.drips(DEFAULT_DRIP_NAME)).status).to.equal(1) // PAUSED
await Drippie.status(DEFAULT_DRIP_NAME, 2) // ACTIVE
expect((await Drippie.drips(DEFAULT_DRIP_NAME)).status).to.equal(2) // ACTIVE
await Drippie.status(DEFAULT_DRIP_NAME, 1) // PAUSED
expect((await Drippie.drips(DEFAULT_DRIP_NAME)).status).to.equal(1) // PAUSED
})
it('should not allow setting status to NONE', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await expect(Drippie.status(DEFAULT_DRIP_NAME, 0)).to.be.revertedWith(
'Drippie: drip status can never be set back to NONE after creation'
)
})
it('should not allow setting status to same status as before', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await expect(Drippie.status(DEFAULT_DRIP_NAME, 1)).to.be.revertedWith(
'Drippie: cannot set drip status to the same status as its current status'
)
})
it('should allow setting status to ARCHIVED if PAUSED', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 3) // ARCHIVED
expect((await Drippie.drips(DEFAULT_DRIP_NAME)).status).to.equal(3) // ARCHIVED
})
it('should not allow setting status to ARCHIVED if ACTIVE', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 2) // ACTIVE
await expect(Drippie.status(DEFAULT_DRIP_NAME, 3)).to.be.revertedWith(
'Drippie: drip must first be paused before being archived'
)
})
it('should not allow setting status to PAUSED if ARCHIVED', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 3) // ARCHIVED
await expect(Drippie.status(DEFAULT_DRIP_NAME, 2)).to.be.revertedWith(
'Drippie: drip with that name has been archived'
)
})
it('should not allow setting status to ACTIVE if ARCHIVED', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 3) // ARCHIVED
await expect(Drippie.status(DEFAULT_DRIP_NAME, 1)).to.be.revertedWith(
'Drippie: drip with that name has been archived'
)
})
it('should revert if the drip does not exist yet', async () => {
await expect(Drippie.status(DEFAULT_DRIP_NAME, 1)).to.be.revertedWith(
'Drippie: drip with that name does not exist'
)
})
})
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
Drippie.connect(signer2).status(DEFAULT_DRIP_NAME, 1)
).to.be.revertedWith('UNAUTHORIZED')
})
})
})
describe('drip', () => {
it('should drip the amount', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 2) // ACTIVE
await expect(Drippie.drip(DEFAULT_DRIP_NAME)).to.emit(
Drippie,
'DripExecuted'
)
expect(
await signer1.provider.getBalance(DEFAULT_DRIP_CONFIG.actions[0].target)
).to.equal(DEFAULT_DRIP_CONFIG.actions[0].value)
})
it('should be able to trigger one function', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, {
...DEFAULT_DRIP_CONFIG,
actions: [
{
target: SimpleStorage.address,
data: SimpleStorage.interface.encodeFunctionData('set', [
'0x' + '33'.repeat(32),
'0x' + '44'.repeat(32),
]),
value: hre.ethers.BigNumber.from(0),
},
],
})
await Drippie.status(DEFAULT_DRIP_NAME, 2) // ACTIVE
await Drippie.drip(DEFAULT_DRIP_NAME)
expect(await SimpleStorage.get('0x' + '33'.repeat(32))).to.equal(
'0x' + '44'.repeat(32)
)
})
it('should be able to trigger two functions', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, {
...DEFAULT_DRIP_CONFIG,
actions: [
{
target: SimpleStorage.address,
data: SimpleStorage.interface.encodeFunctionData('set', [
'0x' + '33'.repeat(32),
'0x' + '44'.repeat(32),
]),
value: hre.ethers.BigNumber.from(0),
},
{
target: SimpleStorage.address,
data: SimpleStorage.interface.encodeFunctionData('set', [
'0x' + '44'.repeat(32),
'0x' + '55'.repeat(32),
]),
value: hre.ethers.BigNumber.from(0),
},
],
})
await Drippie.status(DEFAULT_DRIP_NAME, 2) // ACTIVE
await Drippie.drip(DEFAULT_DRIP_NAME)
expect(await SimpleStorage.get('0x' + '33'.repeat(32))).to.equal(
'0x' + '44'.repeat(32)
)
expect(await SimpleStorage.get('0x' + '44'.repeat(32))).to.equal(
'0x' + '55'.repeat(32)
)
})
it('should revert if dripping twice in one interval', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await Drippie.status(DEFAULT_DRIP_NAME, 2) // ACTIVE
await Drippie.drip(DEFAULT_DRIP_NAME)
await expect(Drippie.drip(DEFAULT_DRIP_NAME)).to.be.revertedWith(
'Drippie: drip interval has not elapsed'
)
await hre.ethers.provider.send('evm_increaseTime', [
DEFAULT_DRIP_CONFIG.interval.add(1).toHexString(),
])
await expect(Drippie.drip(DEFAULT_DRIP_NAME)).to.not.be.reverted
})
it('should revert when the drip does not exist', async () => {
await expect(Drippie.drip(DEFAULT_DRIP_NAME)).to.be.revertedWith(
'Drippie: selected drip does not exist or is not currently active'
)
})
it('should revert when the drip is not active', async () => {
await Drippie.create(DEFAULT_DRIP_NAME, DEFAULT_DRIP_CONFIG)
await expect(Drippie.drip(DEFAULT_DRIP_NAME)).to.be.revertedWith(
'Drippie: selected drip does not exist or is not currently active'
)
})
})
})
import hre from 'hardhat'
import { Contract } from 'ethers'
import { toRpcHexString } from '@eth-optimism/core-utils'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
import { encodeDripCheckParams } from '../../../../../src'
describe('CheckBalanceHigh', () => {
const RECIPIENT = '0x' + '11'.repeat(20)
const THRESHOLD = 100
let CheckBalanceHigh: Contract
before(async () => {
CheckBalanceHigh = await deploy('CheckBalanceHigh')
})
describe('check', () => {
it('should return true when balance is above threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD + 1),
])
expect(
await CheckBalanceHigh.check(
encodeDripCheckParams(CheckBalanceHigh.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(true)
})
it('should return false when balance is below threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD - 1),
])
expect(
await CheckBalanceHigh.check(
encodeDripCheckParams(CheckBalanceHigh.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(false)
})
})
})
import hre from 'hardhat'
import { Contract } from 'ethers'
import { toRpcHexString } from '@eth-optimism/core-utils'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
import { encodeDripCheckParams } from '../../../../../src'
describe('CheckBalanceLow', () => {
const RECIPIENT = '0x' + '11'.repeat(20)
const THRESHOLD = 100
let CheckBalanceLow: Contract
before(async () => {
CheckBalanceLow = await deploy('CheckBalanceLow')
})
describe('check', () => {
it('should return true when balance is below threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD - 1),
])
expect(
await CheckBalanceLow.check(
encodeDripCheckParams(CheckBalanceLow.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(true)
})
it('should return false when balance is above threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD + 1),
])
expect(
await CheckBalanceLow.check(
encodeDripCheckParams(CheckBalanceLow.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(false)
})
})
})
import { Contract } from 'ethers'
import { smock, FakeContract } from '@defi-wonderland/smock'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
import { encodeDripCheckParams } from '../../../../../src'
describe('CheckGelatoLow', () => {
const RECIPIENT = '0x' + '11'.repeat(20)
const THRESHOLD = 100
let CheckGelatoLow: Contract
let FakeGelatoTresury: FakeContract<Contract>
before(async () => {
CheckGelatoLow = await deploy('CheckGelatoLow')
FakeGelatoTresury = await smock.fake('IGelatoTreasury')
})
describe('check', () => {
it('should return true when balance is below threshold', async () => {
FakeGelatoTresury.userTokenBalance.returns(THRESHOLD - 1)
expect(
await CheckGelatoLow.check(
encodeDripCheckParams(CheckGelatoLow.interface, {
treasury: FakeGelatoTresury.address,
threshold: THRESHOLD,
recipient: RECIPIENT,
})
)
).to.equal(true)
})
it('should return false when balance is above threshold', async () => {
FakeGelatoTresury.userTokenBalance.returns(THRESHOLD + 1)
expect(
await CheckGelatoLow.check(
encodeDripCheckParams(CheckGelatoLow.interface, {
treasury: FakeGelatoTresury.address,
threshold: THRESHOLD,
recipient: RECIPIENT,
})
)
).to.equal(false)
})
})
})
import { Contract } from 'ethers'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
describe('CheckTrue', () => {
let CheckTrue: Contract
before(async () => {
CheckTrue = await deploy('CheckTrue')
})
describe('check', () => {
it('should return true', async () => {
expect(await CheckTrue.check('0x')).to.equal(true)
})
})
})
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