diff --git a/op-service/txmgr/cli.go b/op-service/txmgr/cli.go index d4ab7b650..d1b8ba91a 100644 --- a/op-service/txmgr/cli.go +++ b/op-service/txmgr/cli.go @@ -266,3 +266,34 @@ type Config struct { Signer opcrypto.SignerFn From common.Address } + +func (m Config) Check() error { + if m.Backend == nil { + return errors.New("must provide the Backend") + } + if m.NumConfirmations == 0 { + return errors.New("NumConfirmations must not be 0") + } + if m.NetworkTimeout == 0 { + return errors.New("must provide NetworkTimeout") + } + if m.ResubmissionTimeout == 0 { + return errors.New("must provide ResubmissionTimeout") + } + if m.ReceiptQueryInterval == 0 { + return errors.New("must provide ReceiptQueryInterval") + } + if m.TxNotInMempoolTimeout == 0 { + return errors.New("must provide TxNotInMempoolTimeout") + } + if m.SafeAbortNonceTooLowCount == 0 { + return errors.New("SafeAbortNonceTooLowCount must not be 0") + } + if m.Signer == nil { + return errors.New("must provide the Signer") + } + if m.ChainID == nil { + return errors.New("must provide the ChainID") + } + return nil +} diff --git a/op-service/txmgr/txmgr.go b/op-service/txmgr/txmgr.go index cb5e058cd..38a6bbd21 100644 --- a/op-service/txmgr/txmgr.go +++ b/op-service/txmgr/txmgr.go @@ -101,7 +101,14 @@ func NewSimpleTxManager(name string, l log.Logger, m metrics.TxMetricer, cfg CLI if err != nil { return nil, err } + return NewSimpleTxManagerFromConfig(name, l, m, conf) +} +// NewSimpleTxManager initializes a new SimpleTxManager with the passed Config. +func NewSimpleTxManagerFromConfig(name string, l log.Logger, m metrics.TxMetricer, conf Config) (*SimpleTxManager, error) { + if err := conf.Check(); err != nil { + return nil, fmt.Errorf("invalid config: %w", err) + } return &SimpleTxManager{ chainID: conf.ChainID, name: name, @@ -125,6 +132,8 @@ type TxCandidate struct { To *common.Address // GasLimit is the gas limit to be used in the constructed tx. GasLimit uint64 + // Value is the value to be used in the constructed tx. + Value *big.Int } // Send is used to publish a transaction with incrementally higher gas prices @@ -187,6 +196,7 @@ func (m *SimpleTxManager) craftTx(ctx context.Context, candidate TxCandidate) (* GasTipCap: gasTipCap, GasFeeCap: gasFeeCap, Data: candidate.TxData, + Value: candidate.Value, } m.l.Info("creating tx", "to", rawTx.To, "from", m.cfg.From) @@ -202,6 +212,7 @@ func (m *SimpleTxManager) craftTx(ctx context.Context, candidate TxCandidate) (* GasFeeCap: gasFeeCap, GasTipCap: gasTipCap, Data: rawTx.Data, + Value: rawTx.Value, }) if err != nil { return nil, fmt.Errorf("failed to estimate gas: %w", err) diff --git a/op-service/txmgr/txmgr_test.go b/op-service/txmgr/txmgr_test.go index fe2fc1e31..69bc1a306 100644 --- a/op-service/txmgr/txmgr_test.go +++ b/op-service/txmgr/txmgr_test.go @@ -598,12 +598,21 @@ func TestWaitMinedMultipleConfs(t *testing.T) { require.Equal(t, txHash, receipt.TxHash) } +// TestManagerErrsOnZeroCLIConfs ensures that the NewSimpleTxManager will error +// when attempting to configure with NumConfirmations set to zero. +func TestManagerErrsOnZeroCLIConfs(t *testing.T) { + t.Parallel() + + _, err := NewSimpleTxManager("TEST", testlog.Logger(t, log.LvlCrit), &metrics.NoopTxMetrics{}, CLIConfig{}) + require.Error(t, err) +} + // TestManagerErrsOnZeroConfs ensures that the NewSimpleTxManager will error // when attempting to configure with NumConfirmations set to zero. func TestManagerErrsOnZeroConfs(t *testing.T) { t.Parallel() - _, err := NewSimpleTxManager("TEST", testlog.Logger(t, log.LvlCrit), &metrics.NoopTxMetrics{}, CLIConfig{}) + _, err := NewSimpleTxManagerFromConfig("TEST", testlog.Logger(t, log.LvlCrit), &metrics.NoopTxMetrics{}, Config{}) require.Error(t, err) } diff --git a/packages/chain-mon/src/wd-mon/service.ts b/packages/chain-mon/src/wd-mon/service.ts index 259c34b49..0ff2190c0 100644 --- a/packages/chain-mon/src/wd-mon/service.ts +++ b/packages/chain-mon/src/wd-mon/service.ts @@ -9,7 +9,7 @@ import { import { CrossChainMessenger } from '@eth-optimism/sdk' import { getChainId, sleep } from '@eth-optimism/core-utils' import { Provider } from '@ethersproject/abstract-provider' -import { Event } from 'ethers' +import { ethers, Event } from 'ethers' import dateformat from 'dateformat' import { version } from '../../package.json' @@ -19,6 +19,7 @@ type Options = { l2RpcProvider: Provider startBlockNumber: number sleepTimeMs: number + optimismPortalAddress: string } type Metrics = { @@ -65,6 +66,11 @@ export class WithdrawalMonitor extends BaseServiceV2 { desc: 'Time in ms to sleep when waiting for a node', public: true, }, + optimismPortalAddress: { + validator: validators.str, + desc: 'overridden optimism portal address', + default: '', + }, }, metricsSpec: { withdrawalsValidated: { @@ -98,12 +104,35 @@ export class WithdrawalMonitor extends BaseServiceV2 { name: 'L2', }) - this.state.messenger = new CrossChainMessenger({ - l1SignerOrProvider: this.options.l1RpcProvider, - l2SignerOrProvider: this.options.l2RpcProvider, - l1ChainId: await getChainId(this.options.l1RpcProvider), - l2ChainId: await getChainId(this.options.l2RpcProvider), - }) + if (this.options.optimismPortalAddress) { + this.state.messenger = new CrossChainMessenger({ + l1SignerOrProvider: this.options.l1RpcProvider, + l2SignerOrProvider: this.options.l2RpcProvider, + l1ChainId: await getChainId(this.options.l1RpcProvider), + l2ChainId: await getChainId(this.options.l2RpcProvider), + bedrock: true, + contracts: { + l1: { + AddressManager: ethers.constants.AddressZero, + L1CrossDomainMessenger: ethers.constants.AddressZero, + L1StandardBridge: ethers.constants.AddressZero, + StateCommitmentChain: ethers.constants.AddressZero, + CanonicalTransactionChain: ethers.constants.AddressZero, + BondManager: ethers.constants.AddressZero, + OptimismPortal: this.options.optimismPortalAddress, + L2OutputOracle: ethers.constants.AddressZero, + }, + }, + }) + } else { + this.state.messenger = new CrossChainMessenger({ + l1SignerOrProvider: this.options.l1RpcProvider, + l2SignerOrProvider: this.options.l2RpcProvider, + l1ChainId: await getChainId(this.options.l1RpcProvider), + l2ChainId: await getChainId(this.options.l2RpcProvider), + bedrock: true, + }) + } // Not detected by default. this.state.forgeryDetected = false