diff --git a/.circleci/config.yml b/.circleci/config.yml index ac858b59b79be..802343d720e34 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -121,6 +121,15 @@ commands: install-contracts-dependencies: description: "Install the dependencies for the smart contracts" steps: + - run: + name: Install SVM compilers + command: | + # Have to wipe out the SVM directory to avoid issues with the SVM version + rm -rf ~/.svm/* + svm install 0.8.15 + svm install 0.8.19 + svm install 0.8.25 + svm install 0.8.28 - run: name: Install dependencies command: | diff --git a/go.mod b/go.mod index 4d839b84604e0..c53509066b275 100644 --- a/go.mod +++ b/go.mod @@ -256,7 +256,7 @@ require ( rsc.io/tmplfunc v0.0.3 // indirect ) -replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101500.2-rc.1 +replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101500.2-rc.2 //replace github.com/ethereum/go-ethereum => ../op-geth diff --git a/go.sum b/go.sum index a6dd712478e2e..dbaf85d5d45fa 100644 --- a/go.sum +++ b/go.sum @@ -192,8 +192,8 @@ github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/u github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= 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 v1.101500.2-rc.1 h1:CCQtyKKobjMbK9jYd676YbH6Xcvntdn6jIOxFTCb5B8= -github.com/ethereum-optimism/op-geth v1.101500.2-rc.1/go.mod h1:OMpyVMMy5zpAAHlR5s/aGbXRk+7cIKczUEIJj54APbY= +github.com/ethereum-optimism/op-geth v1.101500.2-rc.2 h1:sUPXJ07X4Ud0QCtVWFeuhWe0y9WP5QXEduo8ZRVOeXs= +github.com/ethereum-optimism/op-geth v1.101500.2-rc.2/go.mod h1:OMpyVMMy5zpAAHlR5s/aGbXRk+7cIKczUEIJj54APbY= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20250205201532-8ff62ada16e1 h1:OqRYDcjiOx5QCLn5krpd3BK1CW+VfSZx7YIa6zY9ePE= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20250205201532-8ff62ada16e1/go.mod h1:NZ816PzLU1TLv1RdAvYAb6KWOj4Zm5aInT0YpDVml2Y= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= diff --git a/op-chain-ops/genesis/config.go b/op-chain-ops/genesis/config.go index be37cb440304a..3cd7f9d677e0c 100644 --- a/op-chain-ops/genesis/config.go +++ b/op-chain-ops/genesis/config.go @@ -233,6 +233,10 @@ type GasPriceOracleDeployConfig struct { GasPriceOracleBaseFeeScalar uint32 `json:"gasPriceOracleBaseFeeScalar" evm:"basefeeScalar"` // GasPriceOracleBlobBaseFeeScalar represents the value of the blob base fee scalar used for fee calculations. GasPriceOracleBlobBaseFeeScalar uint32 `json:"gasPriceOracleBlobBaseFeeScalar" evm:"blobbasefeeScalar"` + // GasPriceOracleOperatorFeeScalar represents the value of the operator fee scalar used for fee calculations. + GasPriceOracleOperatorFeeScalar uint32 `json:"gasPriceOracleOperatorFeeScalar" evm:"operatorfeeScalar"` + // GasPriceOracleOperatorFeeConstant represents the value of the operator fee constant used for fee calculations. + GasPriceOracleOperatorFeeConstant uint64 `json:"gasPriceOracleOperatorFeeConstant" evm:"operatorfeeConstant"` } var _ ConfigChecker = (*GasPriceOracleDeployConfig)(nil) @@ -259,6 +263,14 @@ func (d *GasPriceOracleDeployConfig) FeeScalar() [32]byte { }) } +// OperatorFeeParams returns the raw serialized operator fee params. +func (d *GasPriceOracleDeployConfig) OperatorFeeParams() [32]byte { + return eth.EncodeOperatorFeeParams(eth.OperatorFeeParams{ + Scalar: d.GasPriceOracleOperatorFeeScalar, + Constant: d.GasPriceOracleOperatorFeeConstant, + }) +} + // GasTokenDeployConfig configures the optional custom gas token functionality. type GasTokenDeployConfig struct { // UseCustomGasToken is a flag to indicate that a custom gas token should be used @@ -1036,10 +1048,11 @@ func (d *DeployConfig) RollupConfig(l1StartBlock *types.Header, l2GenesisBlockHa // Overhead value is considered a noop. func (d *DeployConfig) GenesisSystemConfig() eth.SystemConfig { return eth.SystemConfig{ - BatcherAddr: d.BatchSenderAddress, - Overhead: eth.Bytes32(common.BigToHash(new(big.Int).SetUint64(d.GasPriceOracleOverhead))), - Scalar: d.FeeScalar(), - GasLimit: uint64(d.L2GenesisBlockGasLimit), + BatcherAddr: d.BatchSenderAddress, + Overhead: eth.Bytes32(common.BigToHash(new(big.Int).SetUint64(d.GasPriceOracleOverhead))), + Scalar: d.FeeScalar(), + GasLimit: uint64(d.L2GenesisBlockGasLimit), + OperatorFeeParams: d.OperatorFeeParams(), } } diff --git a/op-chain-ops/genesis/testdata/test-deploy-config-full.json b/op-chain-ops/genesis/testdata/test-deploy-config-full.json index 7fe9a78e71549..0f332842204f9 100644 --- a/op-chain-ops/genesis/testdata/test-deploy-config-full.json +++ b/op-chain-ops/genesis/testdata/test-deploy-config-full.json @@ -55,6 +55,8 @@ "protocolVersionsProxy": "0x0000000000000000000000000000000000000000", "gasPriceOracleBaseFeeScalar": 0, "gasPriceOracleBlobBaseFeeScalar": 0, + "gasPriceOracleOperatorFeeScalar": 0, + "gasPriceOracleOperatorFeeConstant": 0, "gasPriceOracleOverhead": 2100, "gasPriceOracleScalar": 1000000, "enableGovernance": true, diff --git a/op-deployer/pkg/deployer/opcm/opchain.go b/op-deployer/pkg/deployer/opcm/opchain.go index 632ca3a053e75..a9015044b9e7b 100644 --- a/op-deployer/pkg/deployer/opcm/opchain.go +++ b/op-deployer/pkg/deployer/opcm/opchain.go @@ -40,6 +40,9 @@ type DeployOPChainInput struct { DisputeClockExtension uint64 DisputeMaxClockDuration uint64 AllowCustomDisputeParameters bool + + OperatorFeeScalar uint32 + OperatorFeeConstant uint64 } func (input *DeployOPChainInput) InputSet() bool { diff --git a/op-deployer/pkg/deployer/pipeline/opchain.go b/op-deployer/pkg/deployer/pipeline/opchain.go index dadbb34820df5..03d5b375671d3 100644 --- a/op-deployer/pkg/deployer/pipeline/opchain.go +++ b/op-deployer/pkg/deployer/pipeline/opchain.go @@ -107,6 +107,8 @@ func makeDCI(intent *state.Intent, thisIntent *state.ChainIntent, chainID common DisputeClockExtension: proofParams.DisputeClockExtension, // 3 hours (input in seconds) DisputeMaxClockDuration: proofParams.DisputeMaxClockDuration, // 3.5 days (input in seconds) AllowCustomDisputeParameters: proofParams.DangerouslyAllowCustomDisputeParameters, + OperatorFeeScalar: thisIntent.OperatorFeeScalar, + OperatorFeeConstant: thisIntent.OperatorFeeConstant, }, nil } diff --git a/op-deployer/pkg/deployer/state/chain_intent.go b/op-deployer/pkg/deployer/state/chain_intent.go index aac1d27affe16..f374466ea41ca 100644 --- a/op-deployer/pkg/deployer/state/chain_intent.go +++ b/op-deployer/pkg/deployer/state/chain_intent.go @@ -47,6 +47,8 @@ type ChainIntent struct { DeployOverrides map[string]any `json:"deployOverrides" toml:"deployOverrides"` DangerousAltDAConfig genesis.AltDADeployConfig `json:"dangerousAltDAConfig,omitempty" toml:"dangerousAltDAConfig,omitempty"` AdditionalDisputeGames []AdditionalDisputeGame `json:"dangerousAdditionalDisputeGames" toml:"dangerousAdditionalDisputeGames,omitempty"` + OperatorFeeScalar uint32 `json:"operatorFeeScalar,omitempty" toml:"operatorFeeScalar,omitempty"` + OperatorFeeConstant uint64 `json:"operatorFeeConstant,omitempty" toml:"operatorFeeConstant,omitempty"` } type ChainRoles struct { diff --git a/op-deployer/pkg/deployer/state/deploy_config.go b/op-deployer/pkg/deployer/state/deploy_config.go index 1cf8fc913c84e..50b2f128415eb 100644 --- a/op-deployer/pkg/deployer/state/deploy_config.go +++ b/op-deployer/pkg/deployer/state/deploy_config.go @@ -67,8 +67,10 @@ func CombineDeployConfig(intent *Intent, chainIntent *ChainIntent, state *State, GovernanceTokenOwner: common.HexToAddress("0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAdDEad"), }, GasPriceOracleDeployConfig: genesis.GasPriceOracleDeployConfig{ - GasPriceOracleBaseFeeScalar: 1368, - GasPriceOracleBlobBaseFeeScalar: 810949, + GasPriceOracleBaseFeeScalar: 1368, + GasPriceOracleBlobBaseFeeScalar: 810949, + GasPriceOracleOperatorFeeScalar: chainIntent.OperatorFeeScalar, + GasPriceOracleOperatorFeeConstant: chainIntent.OperatorFeeConstant, }, EIP1559DeployConfig: genesis.EIP1559DeployConfig{ EIP1559Denominator: chainIntent.Eip1559Denominator, diff --git a/op-e2e/actions/proofs/operator_fee_test.go b/op-e2e/actions/proofs/operator_fee_test.go new file mode 100644 index 0000000000000..476d50b08577e --- /dev/null +++ b/op-e2e/actions/proofs/operator_fee_test.go @@ -0,0 +1,135 @@ +package proofs + +import ( + "math/big" + "testing" + + actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/bindings" + "github.com/ethereum-optimism/optimism/op-program/client/claim" + "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func Test_Operator_Fee_Constistency(gt *testing.T) { + + const testOperatorFeeScalar = uint32(20000) + const testOperatorFeeConstant = uint64(500) + + runIsthmusDerivationTest := func(gt *testing.T, testCfg *helpers.TestCfg[any]) { + t := actionsHelpers.NewDefaultTesting(gt) + + env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg()) + + balanceAt := func(a common.Address) *big.Int { + t.Helper() + bal, err := env.Engine.EthClient().BalanceAt(t.Ctx(), a, nil) + require.NoError(t, err) + return bal + } + + t.Logf("L2 Genesis Time: %d, IsthmusTime: %d ", env.Sequencer.RollupCfg.Genesis.L2Time, *env.Sequencer.RollupCfg.IsthmusTime) + + sysCfgContract, err := bindings.NewSystemConfig(env.Sd.RollupCfg.L1SystemConfigAddress, env.Miner.EthClient()) + require.NoError(t, err) + + sysCfgOwner, err := bind.NewKeyedTransactorWithChainID(env.Dp.Secrets.Deployer, env.Sd.RollupCfg.L1ChainID) + require.NoError(t, err) + + // Update the operator fee parameters + _, err = sysCfgContract.SetOperatorFeeScalars(sysCfgOwner, testOperatorFeeScalar, testOperatorFeeConstant) + require.NoError(t, err) + + env.Miner.ActL1StartBlock(12)(t) + env.Miner.ActL1IncludeTx(env.Dp.Addresses.Deployer)(t) + env.Miner.ActL1EndBlock(t) + + // sequence L2 blocks, and submit with new batcher + env.Sequencer.ActL1HeadSignal(t) + env.Sequencer.ActBuildToL1Head(t) + env.Batcher.ActSubmitAll(t) + env.Miner.ActL1StartBlock(12)(t) + env.Miner.ActL1EndBlock(t) + + aliceInitialBalance := balanceAt(env.Alice.Address()) + operatorFeeVaultInitialBalance := balanceAt(predeploys.OperatorFeeVaultAddr) + + require.Equal(t, operatorFeeVaultInitialBalance.Sign(), 0) + + env.Sequencer.ActL2StartBlock(t) + // Send an L2 tx + env.Alice.L2.ActResetTxOpts(t) + env.Alice.L2.ActSetTxToAddr(&env.Dp.Addresses.Bob) + env.Alice.L2.ActMakeTx(t) + env.Engine.ActL2IncludeTx(env.Alice.Address())(t) + env.Sequencer.ActL2EndBlock(t) + + receipt := env.Alice.L2.LastTxReceipt(t) + + // Check that the operator fee was applied + require.Equal(t, testOperatorFeeScalar, uint32(*receipt.OperatorFeeScalar)) + require.Equal(t, testOperatorFeeConstant, *receipt.OperatorFeeConstant) + + l1FeeVaultBalance := balanceAt(predeploys.L1FeeVaultAddr) + baseFeeVaultBalance := balanceAt(predeploys.BaseFeeVaultAddr) + sequencerFeeVaultBalance := balanceAt(predeploys.SequencerFeeVaultAddr) + operatorFeeVaultFinalBalance := balanceAt(predeploys.OperatorFeeVaultAddr) + aliceFinalBalance := balanceAt(env.Alice.Address()) + + require.True(t, aliceFinalBalance.Cmp(aliceInitialBalance) < 0, "Alice's balance should decrease") + + // Check that the operator fee sent to the vault is correct + require.Equal(t, + new(big.Int).Add( + new(big.Int).Div( + new(big.Int).Mul( + new(big.Int).SetUint64(receipt.GasUsed), + new(big.Int).SetUint64(uint64(testOperatorFeeScalar)), + ), + new(big.Int).SetUint64(1e6), + ), + new(big.Int).SetUint64(testOperatorFeeConstant), + ), + operatorFeeVaultFinalBalance, + ) + + // Check that no Ether has been minted or burned + // All vault balances are 0 at the beginning of the test + finalTotalBalance := new(big.Int).Add( + aliceFinalBalance, + new(big.Int).Add( + new(big.Int).Add(l1FeeVaultBalance, sequencerFeeVaultBalance), + new(big.Int).Add(operatorFeeVaultFinalBalance, baseFeeVaultBalance), + ), + ) + + require.Equal(t, aliceInitialBalance, finalTotalBalance) + + l2SafeHead := env.Sequencer.L2Safe() + + env.RunFaultProofProgram(t, l2SafeHead.Number, testCfg.CheckResult, testCfg.InputParams...) + } + + matrix := helpers.NewMatrix[any]() + defer matrix.Run(gt) + + matrix.AddTestCase( + "HonestClaim-OperatorFeeConstistency", + nil, + helpers.NewForkMatrix(helpers.Isthmus), + runIsthmusDerivationTest, + helpers.ExpectNoError(), + ) + + matrix.AddTestCase( + "JunkClaim-OperatorFeeConstistency", + nil, + helpers.NewForkMatrix(helpers.Isthmus), + runIsthmusDerivationTest, + helpers.ExpectError(claim.ErrClaimNotValid), + helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), + ) +} diff --git a/op-e2e/actions/upgrades/isthmus_fork_test.go b/op-e2e/actions/upgrades/isthmus_fork_test.go index ce774be1a1b43..2175970921006 100644 --- a/op-e2e/actions/upgrades/isthmus_fork_test.go +++ b/op-e2e/actions/upgrades/isthmus_fork_test.go @@ -6,11 +6,13 @@ import ( "testing" "time" + "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth" "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/predeploys" @@ -26,6 +28,12 @@ import ( "github.com/stretchr/testify/require" ) +var ( + isthmusL1BlockCodeHash = common.HexToHash("0xe59074b8d4c08924ce463087b05485b835650652528383a32ef009fb2b6d4050") + isthmusGasPriceOracleCodeHash = common.HexToHash("0x9279e9e0535a7b63939d670e7faec536256b63d4ff353eb521a3342c51ce26e5") + isthmusOperatorFeeVaultCodeHash = common.HexToHash("0x9ee0fa5ab86f13f58fcb8f798f3a74401a8493d99d1c5b3bad19a8dff4b3194f") +) + func TestIsthmusActivationAtGenesis(gt *testing.T) { t := helpers.NewDefaultTesting(gt) env := helpers.SetupEnv(t, helpers.WithActiveGenesisFork(rollup.Isthmus)) @@ -341,6 +349,16 @@ func TestIsthmusNetworkUpgradeTransactions(gt *testing.T) { sequencer.ActL2PipelineFull(t) verifier.ActL2PipelineFull(t) + // Get gas price from oracle + gasPriceOracle, err := bindings.NewGasPriceOracleCaller(predeploys.GasPriceOracleAddr, ethCl) + require.NoError(t, err) + + // Get current implementations addresses (by slot) for L1Block + GasPriceOracle + initialL1BlockAddress, err := ethCl.StorageAt(context.Background(), predeploys.L1BlockAddr, genesis.ImplementationSlot, nil) + require.NoError(t, err) + initialGasPriceOracleAddress, err := ethCl.StorageAt(context.Background(), predeploys.GasPriceOracleAddr, genesis.ImplementationSlot, nil) + require.NoError(t, err) + // Build to the isthmus block sequencer.ActBuildL2ToIsthmus(t) @@ -353,14 +371,47 @@ func TestIsthmusNetworkUpgradeTransactions(gt *testing.T) { // L1Block: 1 set-L1-info + 1 deploy // See [derive.IsthmusNetworkUpgradeTransactions] - require.Equal(t, 2, len(transactions)) + require.Equal(t, 9, len(transactions)) + + // All transactions are successful + for i := 1; i < 9; i++ { + txn := transactions[i] + receipt, err := ethCl.TransactionReceipt(context.Background(), txn.Hash()) + require.NoError(t, err) + require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status) + require.NotEmpty(t, txn.Data(), "upgrade tx must provide input data") + } + + expectedL1BlockAddress := crypto.CreateAddress(derive.L1BlockIsthmusDeployerAddress, 0) + + // L1 Block Proxy is updated + updatedL1BlockAddress, err := ethCl.StorageAt(context.Background(), predeploys.L1BlockAddr, genesis.ImplementationSlot, latestBlock.Number()) + require.NoError(t, err) + require.Equal(t, expectedL1BlockAddress, common.BytesToAddress(updatedL1BlockAddress)) + require.NotEqualf(t, initialL1BlockAddress, updatedL1BlockAddress, "Gas L1 Block address should have changed") + verifyCodeHashMatches(t, ethCl, expectedL1BlockAddress, isthmusL1BlockCodeHash) + + expectedGasPriceOracleAddress := crypto.CreateAddress(derive.GasPriceOracleIsthmusDeployerAddress, 0) + + // Gas Price Oracle Proxy is updated + updatedGasPriceOracleAddress, err := ethCl.StorageAt(context.Background(), predeploys.GasPriceOracleAddr, genesis.ImplementationSlot, latestBlock.Number()) + require.NoError(t, err) + require.Equal(t, expectedGasPriceOracleAddress, common.BytesToAddress(updatedGasPriceOracleAddress)) + require.NotEqualf(t, initialGasPriceOracleAddress, updatedGasPriceOracleAddress, "Gas Price Oracle Proxy address should have changed") + verifyCodeHashMatches(t, ethCl, expectedGasPriceOracleAddress, isthmusGasPriceOracleCodeHash) + + // Check that Isthmus was activated + isIsthmus, err := gasPriceOracle.IsIsthmus(nil) + require.NoError(t, err) + require.True(t, isIsthmus) + + expectedOperatorFeeVaultAddress := crypto.CreateAddress(derive.OperatorFeeVaultDeployerAddress, 0) - // Contract deployment transaction - txn := transactions[1] - receipt, err := ethCl.TransactionReceipt(context.Background(), txn.Hash()) + // Operator Fee vault is updated + updatedOperatorFeeVaultAddress, err := ethCl.StorageAt(context.Background(), predeploys.OperatorFeeVaultAddr, genesis.ImplementationSlot, latestBlock.Number()) require.NoError(t, err) - require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status, "block hashes deployment tx must pass") - require.NotEmpty(t, txn.Data(), "upgrade tx must provide input data") + require.Equal(t, expectedOperatorFeeVaultAddress, common.BytesToAddress(updatedOperatorFeeVaultAddress)) + verifyCodeHashMatches(t, ethCl, expectedOperatorFeeVaultAddress, isthmusOperatorFeeVaultCodeHash) // EIP-2935 contract is deployed expectedBlockHashAddress := crypto.CreateAddress(predeploys.EIP2935ContractDeployer, 0) diff --git a/op-e2e/bindings/gaspriceoracle.go b/op-e2e/bindings/gaspriceoracle.go index 00f3194cb6a44..c50bf674be9e0 100644 --- a/op-e2e/bindings/gaspriceoracle.go +++ b/op-e2e/bindings/gaspriceoracle.go @@ -30,8 +30,8 @@ var ( // GasPriceOracleMetaData contains all meta data concerning the GasPriceOracle contract. var GasPriceOracleMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"DECIMALS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"baseFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"baseFeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blobBaseFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blobBaseFeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decimals\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"gasPrice\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL1Fee\",\"inputs\":[{\"name\":\"_data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL1FeeUpperBound\",\"inputs\":[{\"name\":\"_unsignedTxSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL1GasUsed\",\"inputs\":[{\"name\":\"_data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isEcotone\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isFjord\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1BaseFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"overhead\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"scalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setEcotone\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setFjord\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"}]", - Bin: "0x608060405234801561001057600080fd5b506117f6806100206000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80636ef25c3a116100b2578063de26c4a111610081578063f45e65d811610066578063f45e65d81461025b578063f820614014610263578063fe173b971461020d57600080fd5b8063de26c4a114610235578063f1c7a58b1461024857600080fd5b80636ef25c3a1461020d5780638e98b10614610213578063960e3a231461021b578063c59859181461022d57600080fd5b806349948e0e11610109578063519b4bd3116100ee578063519b4bd31461019f57806354fd4d50146101a757806368d5dca6146101f057600080fd5b806349948e0e1461016f5780634ef6e2241461018257600080fd5b80630c18c1621461013b57806322b90ab3146101565780632e0f262514610160578063313ce56714610168575b600080fd5b61014361026b565b6040519081526020015b60405180910390f35b61015e61038c565b005b610143600681565b6006610143565b61014361017d3660046112a1565b610515565b60005461018f9060ff1681565b604051901515815260200161014d565b610143610552565b6101e36040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b60405161014d9190611370565b6101f86105b3565b60405163ffffffff909116815260200161014d565b48610143565b61015e610638565b60005461018f90610100900460ff1681565b6101f8610832565b6101436102433660046112a1565b610893565b6101436102563660046113e3565b61098d565b610143610a69565b610143610b5c565b6000805460ff1615610304576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f47617350726963654f7261636c653a206f76657268656164282920697320646560448201527f707265636174656400000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038791906113fc565b905090565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e2073657420697345636f746f6e6520666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a4016102fb565b60005460ff16156104e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a2045636f746f6e6520616c72656164792060448201527f616374697665000000000000000000000000000000000000000000000000000060648201526084016102fb565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60008054610100900460ff16156105355761052f82610bbd565b92915050565b60005460ff16156105495761052f82610bdc565b61052f82610c80565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16635cf249696040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103879190611415565b3373deaddeaddeaddeaddeaddeaddeaddeaddead0001146106db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e20736574206973466a6f726420666c61670060648201526084016102fb565b60005460ff1661076d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f47617350726963654f7261636c653a20466a6f72642063616e206f6e6c79206260448201527f65206163746976617465642061667465722045636f746f6e650000000000000060648201526084016102fb565b600054610100900460ff1615610804576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f47617350726963654f7261636c653a20466a6f726420616c726561647920616360448201527f746976650000000000000000000000000000000000000000000000000000000060648201526084016102fb565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663c59859186040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b60008054610100900460ff16156108da57620f42406108c56108b484610dd4565b516108c090604461146a565b6110f1565b6108d0906010611482565b61052f91906114bf565b60006108e583611150565b60005490915060ff16156108f95792915050565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610958573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097c91906113fc565b610986908261146a565b9392505050565b60008054610100900460ff16610a25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f47617350726963654f7261636c653a206765744c314665655570706572426f7560448201527f6e64206f6e6c7920737570706f72747320466a6f72640000000000000000000060648201526084016102fb565b6000610a3283604461146a565b90506000610a4160ff836114bf565b610a4b908361146a565b610a5690601061146a565b9050610a61816111e0565b949350505050565b6000805460ff1615610afd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a207363616c61722829206973206465707260448201527f656361746564000000000000000000000000000000000000000000000000000060648201526084016102fb565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600061052f610bcb83610dd4565b51610bd790604461146a565b6111e0565b600080610be883611150565b90506000610bf4610552565b610bfc610832565b610c079060106114fa565b63ffffffff16610c179190611482565b90506000610c23610b5c565b610c2b6105b3565b63ffffffff16610c3b9190611482565b90506000610c49828461146a565b610c539085611482565b9050610c616006600a611646565b610c6c906010611482565b610c7690826114bf565b9695505050505050565b600080610c8c83611150565b9050600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d1391906113fc565b610d1b610552565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9e91906113fc565b610da8908561146a565b610db29190611482565b610dbc9190611482565b9050610dca6006600a611646565b610a6190826114bf565b6060610f63565b818153600101919050565b600082840393505b838110156109865782810151828201511860001a1590930292600101610dee565b825b60208210610e5b578251610e26601f83610ddb565b52602092909201917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910190602101610e11565b8115610986578251610e706001840383610ddb565b520160010192915050565b60006001830392505b6101078210610ebc57610eae8360ff16610ea960fd610ea98760081c60e00189610ddb565b610ddb565b935061010682039150610e84565b60078210610ee957610ee28360ff16610ea960078503610ea98760081c60e00189610ddb565b9050610986565b610a618360ff16610ea98560081c8560051b0187610ddb565b610f5b828203610f3f610f2f84600081518060001a8160011a60081b178160021a60101b17915050919050565b639e3779b90260131c611fff1690565b8060021b6040510182815160e01c1860e01b8151188152505050565b600101919050565b6180003860405139618000604051016020830180600d8551820103826002015b81811015611096576000805b50508051604051600082901a600183901a60081b1760029290921a60101b91909117639e3779b9810260111c617ffc16909101805160e081811c878603811890911b90911890915284019081830390848410610feb5750611026565b600184019350611fff8211611020578251600081901a600182901a60081b1760029190911a60101b1781036110205750611026565b50610f8f565b838310611034575050611096565b600183039250858311156110525761104f8787888603610e0f565b96505b611066600985016003850160038501610de6565b9150611073878284610e7b565b96505061108b8461108686848601610f02565b610f02565b915050809350610f83565b50506110a88383848851850103610e0f565b925050506040519150618000820180820391508183526020830160005b838110156110dd5782810151828201526020016110c5565b506000920191825250602001604052919050565b60008061110183620cc394611482565b61112b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd763200611652565b905061113b6064620f42406116c6565b81121561052f576109866064620f42406116c6565b80516000908190815b818110156111d35784818151811061117357611173611782565b01602001517fff00000000000000000000000000000000000000000000000000000000000000166000036111b3576111ac60048461146a565b92506111c1565b6111be60108461146a565b92505b806111cb816117b1565b915050611159565b50610a618261044061146a565b6000806111ec836110f1565b905060006111f8610b5c565b6112006105b3565b63ffffffff166112109190611482565b611218610552565b611220610832565b61122b9060106114fa565b63ffffffff1661123b9190611482565b611245919061146a565b905061125360066002611482565b61125e90600a611646565b6112688284611482565b610a6191906114bf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156112b357600080fd5b813567ffffffffffffffff808211156112cb57600080fd5b818401915084601f8301126112df57600080fd5b8135818111156112f1576112f1611272565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561133757611337611272565b8160405282815287602084870101111561135057600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561139d57858101830151858201604001528201611381565b818111156113af576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000602082840312156113f557600080fd5b5035919050565b60006020828403121561140e57600080fd5b5051919050565b60006020828403121561142757600080fd5b815163ffffffff8116811461098657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561147d5761147d61143b565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156114ba576114ba61143b565b500290565b6000826114f5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600063ffffffff8083168185168183048111821515161561151d5761151d61143b565b02949350505050565b600181815b8085111561157f57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156115655761156561143b565b8085161561157257918102915b93841c939080029061152b565b509250929050565b6000826115965750600161052f565b816115a35750600061052f565b81600181146115b957600281146115c3576115df565b600191505061052f565b60ff8411156115d4576115d461143b565b50506001821b61052f565b5060208310610133831016604e8410600b8410161715611602575081810a61052f565b61160c8383611526565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561163e5761163e61143b565b029392505050565b60006109868383611587565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0384138115161561168c5761168c61143b565b827f80000000000000000000000000000000000000000000000000000000000000000384128116156116c0576116c061143b565b50500190565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000841360008413858304851182821616156117075761170761143b565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156117425761174261143b565b6000871292508782058712848416161561175e5761175e61143b565b878505871281841616156117745761177461143b565b505050929093029392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117e2576117e261143b565b506001019056fea164736f6c634300080f000a", + ABI: "[{\"inputs\":[],\"name\":\"DECIMALS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseFeeScalar\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blobBaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blobBaseFeeScalar\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_unsignedTxSize\",\"type\":\"uint256\"}],\"name\":\"getL1FeeUpperBound\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getL1GasUsed\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_gasUsed\",\"type\":\"uint256\"}],\"name\":\"getOperatorFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isEcotone\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isFjord\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isIsthmus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1BaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"overhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"scalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"setEcotone\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"setFjord\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"setIsthmus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50611c08806100206000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806368d5dca6116100d8578063c59859181161008c578063f45e65d811610066578063f45e65d8146102ca578063f8206140146102d2578063fe173b971461026957600080fd5b8063c59859181461029c578063de26c4a1146102a4578063f1c7a58b146102b757600080fd5b80638e98b106116100bd5780638e98b1061461026f578063960e3a2314610277578063b54501bc1461028957600080fd5b806368d5dca61461024c5780636ef25c3a1461026957600080fd5b8063313ce5671161012f5780634ef6e224116101145780634ef6e224146101de578063519b4bd3146101fb57806354fd4d501461020357600080fd5b8063313ce567146101c457806349948e0e146101cb57600080fd5b8063275aedd211610160578063275aedd2146101a1578063291b0383146101b45780632e0f2625146101bc57600080fd5b80630c18c1621461017c57806322b90ab314610197575b600080fd5b6101846102da565b6040519081526020015b60405180910390f35b61019f6103fb565b005b6101846101af36600461165a565b610584565b61019f6106db565b610184600681565b6006610184565b6101846101d93660046116a2565b610903565b6000546101eb9060ff1681565b604051901515815260200161018e565b61018461093a565b61023f6040518060400160405280600c81526020017f312e332e312d626574612e35000000000000000000000000000000000000000081525081565b60405161018e9190611771565b61025461099b565b60405163ffffffff909116815260200161018e565b48610184565b61019f610a20565b6000546101eb90610100900460ff1681565b6000546101eb9062010000900460ff1681565b610254610c1a565b6101846102b23660046116a2565b610c7b565b6101846102c536600461165a565b610d75565b610184610e51565b610184610f44565b6000805460ff1615610373576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f47617350726963654f7261636c653a206f76657268656164282920697320646560448201527f707265636174656400000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f691906117e4565b905090565b3373deaddeaddeaddeaddeaddeaddeaddeaddead0001146104c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e2073657420697345636f746f6e6520666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a40161036a565b60005460ff1615610557576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a2045636f746f6e6520616c72656164792060448201527f6163746976650000000000000000000000000000000000000000000000000000606482015260840161036a565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6000805462010000900460ff1661059d57506000919050565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166316d3bc7f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062091906117fd565b67ffffffffffffffff16620f424073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16634d5d9a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b19190611827565b6106c19063ffffffff168561187c565b6106cb91906118b9565b6106d591906118f4565b92915050565b3373deaddeaddeaddeaddeaddeaddeaddeaddead0001146107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e20736574206973497374686d757320666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a40161036a565b600054610100900460ff1661083b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f47617350726963654f7261636c653a20497374686d75732063616e206f6e6c7960448201527f2062652061637469766174656420616674657220466a6f726400000000000000606482015260840161036a565b60005462010000900460ff16156108d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a20497374686d757320616c72656164792060448201527f6163746976650000000000000000000000000000000000000000000000000000606482015260840161036a565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1662010000179055565b60008054610100900460ff161561091d576106d582610fa5565b60005460ff1615610931576106d582610fc4565b6106d582611068565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16635cf249696040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103d2573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f69190611827565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610ac3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e20736574206973466a6f726420666c616700606482015260840161036a565b60005460ff16610b55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f47617350726963654f7261636c653a20466a6f72642063616e206f6e6c79206260448201527f65206163746976617465642061667465722045636f746f6e6500000000000000606482015260840161036a565b600054610100900460ff1615610bec576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f47617350726963654f7261636c653a20466a6f726420616c726561647920616360448201527f7469766500000000000000000000000000000000000000000000000000000000606482015260840161036a565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663c59859186040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109fc573d6000803e3d6000fd5b60008054610100900460ff1615610cc257620f4240610cad610c9c846111bc565b51610ca89060446118f4565b6114d9565b610cb890601061187c565b6106d591906118b9565b6000610ccd83611538565b60005490915060ff1615610ce15792915050565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6491906117e4565b610d6e90826118f4565b9392505050565b60008054610100900460ff16610e0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f47617350726963654f7261636c653a206765744c314665655570706572426f7560448201527f6e64206f6e6c7920737570706f72747320466a6f726400000000000000000000606482015260840161036a565b6000610e1a8360446118f4565b90506000610e2960ff836118b9565b610e3390836118f4565b610e3e9060106118f4565b9050610e49816115c8565b949350505050565b6000805460ff1615610ee5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a207363616c61722829206973206465707260448201527f6563617465640000000000000000000000000000000000000000000000000000606482015260840161036a565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103d2573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103d2573d6000803e3d6000fd5b60006106d5610fb3836111bc565b51610fbf9060446118f4565b6115c8565b600080610fd083611538565b90506000610fdc61093a565b610fe4610c1a565b610fef90601061190c565b63ffffffff16610fff919061187c565b9050600061100b610f44565b61101361099b565b63ffffffff16611023919061187c565b9050600061103182846118f4565b61103b908561187c565b90506110496006600a611a58565b61105490601061187c565b61105e90826118b9565b9695505050505050565b60008061107483611538565b9050600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fb91906117e4565b61110361093a565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015611162573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118691906117e4565b61119090856118f4565b61119a919061187c565b6111a4919061187c565b90506111b26006600a611a58565b610e4990826118b9565b606061134b565b818153600101919050565b600082840393505b83811015610d6e5782810151828201511860001a15909302926001016111d6565b825b6020821061124357825161120e601f836111c3565b52602092909201917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909101906021016111f9565b8115610d6e57825161125860018403836111c3565b520160010192915050565b60006001830392505b61010782106112a4576112968360ff1661129160fd6112918760081c60e001896111c3565b6111c3565b93506101068203915061126c565b600782106112d1576112ca8360ff16611291600785036112918760081c60e001896111c3565b9050610d6e565b610e498360ff166112918560081c8560051b01876111c3565b61134382820361132761131784600081518060001a8160011a60081b178160021a60101b17915050919050565b639e3779b90260131c611fff1690565b8060021b6040510182815160e01c1860e01b8151188152505050565b600101919050565b6180003860405139618000604051016020830180600d8551820103826002015b8181101561147e576000805b50508051604051600082901a600183901a60081b1760029290921a60101b91909117639e3779b9810260111c617ffc16909101805160e081811c878603811890911b909118909152840190818303908484106113d3575061140e565b600184019350611fff8211611408578251600081901a600182901a60081b1760029190911a60101b178103611408575061140e565b50611377565b83831061141c57505061147e565b6001830392508583111561143a5761143787878886036111f7565b96505b61144e6009850160038501600385016111ce565b915061145b878284611263565b9650506114738461146e868486016112ea565b6112ea565b91505080935061136b565b505061149083838488518501036111f7565b925050506040519150618000820180820391508183526020830160005b838110156114c55782810151828201526020016114ad565b506000920191825250602001604052919050565b6000806114e983620cc39461187c565b611513907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd763200611a64565b90506115236064620f4240611ad8565b8112156106d557610d6e6064620f4240611ad8565b80516000908190815b818110156115bb5784818151811061155b5761155b611b94565b01602001517fff000000000000000000000000000000000000000000000000000000000000001660000361159b576115946004846118f4565b92506115a9565b6115a66010846118f4565b92505b806115b381611bc3565b915050611541565b50610e49826104406118f4565b6000806115d4836114d9565b905060006115e0610f44565b6115e861099b565b63ffffffff166115f8919061187c565b61160061093a565b611608610c1a565b61161390601061190c565b63ffffffff16611623919061187c565b61162d91906118f4565b905061163b6006600261187c565b61164690600a611a58565b611650828461187c565b610e4991906118b9565b60006020828403121561166c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156116b457600080fd5b813567ffffffffffffffff808211156116cc57600080fd5b818401915084601f8301126116e057600080fd5b8135818111156116f2576116f2611673565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561173857611738611673565b8160405282815287602084870101111561175157600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561179e57858101830151858201604001528201611782565b818111156117b0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000602082840312156117f657600080fd5b5051919050565b60006020828403121561180f57600080fd5b815167ffffffffffffffff81168114610d6e57600080fd5b60006020828403121561183957600080fd5b815163ffffffff81168114610d6e57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156118b4576118b461184d565b500290565b6000826118ef577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600082198211156119075761190761184d565b500190565b600063ffffffff8083168185168183048111821515161561192f5761192f61184d565b02949350505050565b600181815b8085111561199157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156119775761197761184d565b8085161561198457918102915b93841c939080029061193d565b509250929050565b6000826119a8575060016106d5565b816119b5575060006106d5565b81600181146119cb57600281146119d5576119f1565b60019150506106d5565b60ff8411156119e6576119e661184d565b50506001821b6106d5565b5060208310610133831016604e8410600b8410161715611a14575081810a6106d5565b611a1e8383611938565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611a5057611a5061184d565b029392505050565b6000610d6e8383611999565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03841381151615611a9e57611a9e61184d565b827f8000000000000000000000000000000000000000000000000000000000000000038412811615611ad257611ad261184d565b50500190565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600084136000841385830485118282161615611b1957611b1961184d565b7f80000000000000000000000000000000000000000000000000000000000000006000871286820588128184161615611b5457611b5461184d565b60008712925087820587128484161615611b7057611b7061184d565b87850587128184161615611b8657611b8661184d565b505050929093029392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611bf457611bf461184d565b506001019056fea164736f6c634300080f000a", } // GasPriceOracleABI is the input ABI used to generate the binding from. @@ -511,6 +511,37 @@ func (_GasPriceOracle *GasPriceOracleCallerSession) GetL1GasUsed(_data []byte) ( return _GasPriceOracle.Contract.GetL1GasUsed(&_GasPriceOracle.CallOpts, _data) } +// GetOperatorFee is a free data retrieval call binding the contract method 0x275aedd2. +// +// Solidity: function getOperatorFee(uint256 _gasUsed) view returns(uint256) +func (_GasPriceOracle *GasPriceOracleCaller) GetOperatorFee(opts *bind.CallOpts, _gasUsed *big.Int) (*big.Int, error) { + var out []interface{} + err := _GasPriceOracle.contract.Call(opts, &out, "getOperatorFee", _gasUsed) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetOperatorFee is a free data retrieval call binding the contract method 0x275aedd2. +// +// Solidity: function getOperatorFee(uint256 _gasUsed) view returns(uint256) +func (_GasPriceOracle *GasPriceOracleSession) GetOperatorFee(_gasUsed *big.Int) (*big.Int, error) { + return _GasPriceOracle.Contract.GetOperatorFee(&_GasPriceOracle.CallOpts, _gasUsed) +} + +// GetOperatorFee is a free data retrieval call binding the contract method 0x275aedd2. +// +// Solidity: function getOperatorFee(uint256 _gasUsed) view returns(uint256) +func (_GasPriceOracle *GasPriceOracleCallerSession) GetOperatorFee(_gasUsed *big.Int) (*big.Int, error) { + return _GasPriceOracle.Contract.GetOperatorFee(&_GasPriceOracle.CallOpts, _gasUsed) +} + // IsEcotone is a free data retrieval call binding the contract method 0x4ef6e224. // // Solidity: function isEcotone() view returns(bool) @@ -573,6 +604,37 @@ func (_GasPriceOracle *GasPriceOracleCallerSession) IsFjord() (bool, error) { return _GasPriceOracle.Contract.IsFjord(&_GasPriceOracle.CallOpts) } +// IsIsthmus is a free data retrieval call binding the contract method 0xb54501bc. +// +// Solidity: function isIsthmus() view returns(bool) +func (_GasPriceOracle *GasPriceOracleCaller) IsIsthmus(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _GasPriceOracle.contract.Call(opts, &out, "isIsthmus") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsIsthmus is a free data retrieval call binding the contract method 0xb54501bc. +// +// Solidity: function isIsthmus() view returns(bool) +func (_GasPriceOracle *GasPriceOracleSession) IsIsthmus() (bool, error) { + return _GasPriceOracle.Contract.IsIsthmus(&_GasPriceOracle.CallOpts) +} + +// IsIsthmus is a free data retrieval call binding the contract method 0xb54501bc. +// +// Solidity: function isIsthmus() view returns(bool) +func (_GasPriceOracle *GasPriceOracleCallerSession) IsIsthmus() (bool, error) { + return _GasPriceOracle.Contract.IsIsthmus(&_GasPriceOracle.CallOpts) +} + // L1BaseFee is a free data retrieval call binding the contract method 0x519b4bd3. // // Solidity: function l1BaseFee() view returns(uint256) @@ -738,3 +800,24 @@ func (_GasPriceOracle *GasPriceOracleSession) SetFjord() (*types.Transaction, er func (_GasPriceOracle *GasPriceOracleTransactorSession) SetFjord() (*types.Transaction, error) { return _GasPriceOracle.Contract.SetFjord(&_GasPriceOracle.TransactOpts) } + +// SetIsthmus is a paid mutator transaction binding the contract method 0x291b0383. +// +// Solidity: function setIsthmus() returns() +func (_GasPriceOracle *GasPriceOracleTransactor) SetIsthmus(opts *bind.TransactOpts) (*types.Transaction, error) { + return _GasPriceOracle.contract.Transact(opts, "setIsthmus") +} + +// SetIsthmus is a paid mutator transaction binding the contract method 0x291b0383. +// +// Solidity: function setIsthmus() returns() +func (_GasPriceOracle *GasPriceOracleSession) SetIsthmus() (*types.Transaction, error) { + return _GasPriceOracle.Contract.SetIsthmus(&_GasPriceOracle.TransactOpts) +} + +// SetIsthmus is a paid mutator transaction binding the contract method 0x291b0383. +// +// Solidity: function setIsthmus() returns() +func (_GasPriceOracle *GasPriceOracleTransactorSession) SetIsthmus() (*types.Transaction, error) { + return _GasPriceOracle.Contract.SetIsthmus(&_GasPriceOracle.TransactOpts) +} diff --git a/op-e2e/bindings/systemconfig.go b/op-e2e/bindings/systemconfig.go index a6ff5ce1480e6..05d74beadbeb5 100644 --- a/op-e2e/bindings/systemconfig.go +++ b/op-e2e/bindings/systemconfig.go @@ -46,12 +46,11 @@ type SystemConfigAddresses struct { DisputeGameFactory common.Address OptimismPortal common.Address OptimismMintableERC20Factory common.Address - GasPayingToken common.Address } // SystemConfigMetaData contains all meta data concerning the SystemConfig contract. var SystemConfigMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"BATCH_INBOX_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DISPUTE_GAME_FACTORY_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L1_CROSS_DOMAIN_MESSENGER_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L1_ERC_721_BRIDGE_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L1_STANDARD_BRIDGE_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPTIMISM_PORTAL_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"START_BLOCK_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UNSAFE_BLOCK_SIGNER_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"basefeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"batchInbox\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"batcherHash\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blobbasefeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disputeGameFactory\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eip1559Denominator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eip1559Elasticity\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasPayingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"decimals_\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasPayingTokenName\",\"inputs\":[],\"outputs\":[{\"name\":\"name_\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasPayingTokenSymbol\",\"inputs\":[],\"outputs\":[{\"name\":\"symbol_\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_basefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_blobbasefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_batcherHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_gasLimit\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"_unsafeBlockSigner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_config\",\"type\":\"tuple\",\"internalType\":\"structIResourceMetering.ResourceConfig\",\"components\":[{\"name\":\"maxResourceLimit\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"elasticityMultiplier\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"minimumBaseFee\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"systemTxMaxGas\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"maximumBaseFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"_batchInbox\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_addresses\",\"type\":\"tuple\",\"internalType\":\"structSystemConfig.Addresses\",\"components\":[{\"name\":\"l1CrossDomainMessenger\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"l1ERC721Bridge\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"l1StandardBridge\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"disputeGameFactory\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"optimismPortal\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"optimismMintableERC20Factory\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"gasPayingToken\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isCustomGasToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1CrossDomainMessenger\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1ERC721Bridge\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1StandardBridge\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maximumGasLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"minimumGasLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"optimismMintableERC20Factory\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"optimismPortal\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"overhead\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"resourceConfig\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIResourceMetering.ResourceConfig\",\"components\":[{\"name\":\"maxResourceLimit\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"elasticityMultiplier\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"minimumBaseFee\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"systemTxMaxGas\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"maximumBaseFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"scalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setBatcherHash\",\"inputs\":[{\"name\":\"_batcherHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setEIP1559Params\",\"inputs\":[{\"name\":\"_denominator\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_elasticity\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGasConfig\",\"inputs\":[{\"name\":\"_overhead\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_scalar\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGasConfigEcotone\",\"inputs\":[{\"name\":\"_basefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_blobbasefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGasLimit\",\"inputs\":[{\"name\":\"_gasLimit\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setUnsafeBlockSigner\",\"inputs\":[{\"name\":\"_unsafeBlockSigner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"startBlock\",\"inputs\":[],\"outputs\":[{\"name\":\"startBlock_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unsafeBlockSigner\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"event\",\"name\":\"ConfigUpdate\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"updateType\",\"type\":\"uint8\",\"indexed\":true,\"internalType\":\"enumSystemConfig.UpdateType\"},{\"name\":\"data\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BATCH_INBOX_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_GAME_FACTORY_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L1_CROSS_DOMAIN_MESSENGER_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L1_ERC_721_BRIDGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L1_STANDARD_BRIDGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OPTIMISM_PORTAL_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"START_BLOCK_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UNSAFE_BLOCK_SIGNER_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VERSION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"basefeeScalar\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchInbox\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batcherHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blobbasefeeScalar\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disputeGameFactory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eip1559Denominator\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eip1559Elasticity\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasLimit\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAddresses\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"l1CrossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1ERC721Bridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1StandardBridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"disputeGameFactory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"optimismPortal\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"optimismMintableERC20Factory\",\"type\":\"address\"}],\"internalType\":\"structSystemConfig.Addresses\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"_basefeeScalar\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_blobbasefeeScalar\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"_batcherHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"_gasLimit\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"_unsafeBlockSigner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxResourceLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"elasticityMultiplier\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"minimumBaseFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"systemTxMaxGas\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"maximumBaseFee\",\"type\":\"uint128\"}],\"internalType\":\"structIResourceMetering.ResourceConfig\",\"name\":\"_config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_batchInbox\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"l1CrossDomainMessenger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1ERC721Bridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1StandardBridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"disputeGameFactory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"optimismPortal\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"optimismMintableERC20Factory\",\"type\":\"address\"}],\"internalType\":\"structSystemConfig.Addresses\",\"name\":\"_addresses\",\"type\":\"tuple\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1CrossDomainMessenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1ERC721Bridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StandardBridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maximumGasLimit\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumGasLimit\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatorFeeConstant\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatorFeeScalar\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"optimismMintableERC20Factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"optimismPortal\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"overhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resourceConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxResourceLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"elasticityMultiplier\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"minimumBaseFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"systemTxMaxGas\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"maximumBaseFee\",\"type\":\"uint128\"}],\"internalType\":\"structIResourceMetering.ResourceConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"scalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_batcherHash\",\"type\":\"bytes32\"}],\"name\":\"setBatcherHash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_denominator\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_elasticity\",\"type\":\"uint32\"}],\"name\":\"setEIP1559Params\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_overhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_scalar\",\"type\":\"uint256\"}],\"name\":\"setGasConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_basefeeScalar\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_blobbasefeeScalar\",\"type\":\"uint32\"}],\"name\":\"setGasConfigEcotone\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_gasLimit\",\"type\":\"uint64\"}],\"name\":\"setGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_operatorFeeScalar\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"_operatorFeeConstant\",\"type\":\"uint64\"}],\"name\":\"setOperatorFeeScalars\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_unsafeBlockSigner\",\"type\":\"address\"}],\"name\":\"setUnsafeBlockSigner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"startBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"startBlock_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unsafeBlockSigner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"enumSystemConfig.UpdateType\",\"name\":\"updateType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ConfigUpdate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"}]", } // SystemConfigABI is the input ABI used to generate the binding from. @@ -758,142 +757,35 @@ func (_SystemConfig *SystemConfigCallerSession) GasLimit() (uint64, error) { return _SystemConfig.Contract.GasLimit(&_SystemConfig.CallOpts) } -// GasPayingToken is a free data retrieval call binding the contract method 0x4397dfef. +// GetAddresses is a free data retrieval call binding the contract method 0xa39fac12. // -// Solidity: function gasPayingToken() view returns(address addr_, uint8 decimals_) -func (_SystemConfig *SystemConfigCaller) GasPayingToken(opts *bind.CallOpts) (struct { - Addr common.Address - Decimals uint8 -}, error) { +// Solidity: function getAddresses() view returns((address,address,address,address,address,address)) +func (_SystemConfig *SystemConfigCaller) GetAddresses(opts *bind.CallOpts) (SystemConfigAddresses, error) { var out []interface{} - err := _SystemConfig.contract.Call(opts, &out, "gasPayingToken") + err := _SystemConfig.contract.Call(opts, &out, "getAddresses") - outstruct := new(struct { - Addr common.Address - Decimals uint8 - }) if err != nil { - return *outstruct, err + return *new(SystemConfigAddresses), err } - outstruct.Addr = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - outstruct.Decimals = *abi.ConvertType(out[1], new(uint8)).(*uint8) - - return *outstruct, err - -} - -// GasPayingToken is a free data retrieval call binding the contract method 0x4397dfef. -// -// Solidity: function gasPayingToken() view returns(address addr_, uint8 decimals_) -func (_SystemConfig *SystemConfigSession) GasPayingToken() (struct { - Addr common.Address - Decimals uint8 -}, error) { - return _SystemConfig.Contract.GasPayingToken(&_SystemConfig.CallOpts) -} - -// GasPayingToken is a free data retrieval call binding the contract method 0x4397dfef. -// -// Solidity: function gasPayingToken() view returns(address addr_, uint8 decimals_) -func (_SystemConfig *SystemConfigCallerSession) GasPayingToken() (struct { - Addr common.Address - Decimals uint8 -}, error) { - return _SystemConfig.Contract.GasPayingToken(&_SystemConfig.CallOpts) -} - -// GasPayingTokenName is a free data retrieval call binding the contract method 0xd8444715. -// -// Solidity: function gasPayingTokenName() view returns(string name_) -func (_SystemConfig *SystemConfigCaller) GasPayingTokenName(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _SystemConfig.contract.Call(opts, &out, "gasPayingTokenName") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) + out0 := *abi.ConvertType(out[0], new(SystemConfigAddresses)).(*SystemConfigAddresses) return out0, err } -// GasPayingTokenName is a free data retrieval call binding the contract method 0xd8444715. +// GetAddresses is a free data retrieval call binding the contract method 0xa39fac12. // -// Solidity: function gasPayingTokenName() view returns(string name_) -func (_SystemConfig *SystemConfigSession) GasPayingTokenName() (string, error) { - return _SystemConfig.Contract.GasPayingTokenName(&_SystemConfig.CallOpts) -} - -// GasPayingTokenName is a free data retrieval call binding the contract method 0xd8444715. -// -// Solidity: function gasPayingTokenName() view returns(string name_) -func (_SystemConfig *SystemConfigCallerSession) GasPayingTokenName() (string, error) { - return _SystemConfig.Contract.GasPayingTokenName(&_SystemConfig.CallOpts) -} - -// GasPayingTokenSymbol is a free data retrieval call binding the contract method 0x550fcdc9. -// -// Solidity: function gasPayingTokenSymbol() view returns(string symbol_) -func (_SystemConfig *SystemConfigCaller) GasPayingTokenSymbol(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _SystemConfig.contract.Call(opts, &out, "gasPayingTokenSymbol") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// GasPayingTokenSymbol is a free data retrieval call binding the contract method 0x550fcdc9. -// -// Solidity: function gasPayingTokenSymbol() view returns(string symbol_) -func (_SystemConfig *SystemConfigSession) GasPayingTokenSymbol() (string, error) { - return _SystemConfig.Contract.GasPayingTokenSymbol(&_SystemConfig.CallOpts) -} - -// GasPayingTokenSymbol is a free data retrieval call binding the contract method 0x550fcdc9. -// -// Solidity: function gasPayingTokenSymbol() view returns(string symbol_) -func (_SystemConfig *SystemConfigCallerSession) GasPayingTokenSymbol() (string, error) { - return _SystemConfig.Contract.GasPayingTokenSymbol(&_SystemConfig.CallOpts) -} - -// IsCustomGasToken is a free data retrieval call binding the contract method 0x21326849. -// -// Solidity: function isCustomGasToken() view returns(bool) -func (_SystemConfig *SystemConfigCaller) IsCustomGasToken(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _SystemConfig.contract.Call(opts, &out, "isCustomGasToken") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - +// Solidity: function getAddresses() view returns((address,address,address,address,address,address)) +func (_SystemConfig *SystemConfigSession) GetAddresses() (SystemConfigAddresses, error) { + return _SystemConfig.Contract.GetAddresses(&_SystemConfig.CallOpts) } -// IsCustomGasToken is a free data retrieval call binding the contract method 0x21326849. +// GetAddresses is a free data retrieval call binding the contract method 0xa39fac12. // -// Solidity: function isCustomGasToken() view returns(bool) -func (_SystemConfig *SystemConfigSession) IsCustomGasToken() (bool, error) { - return _SystemConfig.Contract.IsCustomGasToken(&_SystemConfig.CallOpts) -} - -// IsCustomGasToken is a free data retrieval call binding the contract method 0x21326849. -// -// Solidity: function isCustomGasToken() view returns(bool) -func (_SystemConfig *SystemConfigCallerSession) IsCustomGasToken() (bool, error) { - return _SystemConfig.Contract.IsCustomGasToken(&_SystemConfig.CallOpts) +// Solidity: function getAddresses() view returns((address,address,address,address,address,address)) +func (_SystemConfig *SystemConfigCallerSession) GetAddresses() (SystemConfigAddresses, error) { + return _SystemConfig.Contract.GetAddresses(&_SystemConfig.CallOpts) } // L1CrossDomainMessenger is a free data retrieval call binding the contract method 0xa7119869. @@ -1051,6 +943,68 @@ func (_SystemConfig *SystemConfigCallerSession) MinimumGasLimit() (uint64, error return _SystemConfig.Contract.MinimumGasLimit(&_SystemConfig.CallOpts) } +// OperatorFeeConstant is a free data retrieval call binding the contract method 0x16d3bc7f. +// +// Solidity: function operatorFeeConstant() view returns(uint64) +func (_SystemConfig *SystemConfigCaller) OperatorFeeConstant(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _SystemConfig.contract.Call(opts, &out, "operatorFeeConstant") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +// OperatorFeeConstant is a free data retrieval call binding the contract method 0x16d3bc7f. +// +// Solidity: function operatorFeeConstant() view returns(uint64) +func (_SystemConfig *SystemConfigSession) OperatorFeeConstant() (uint64, error) { + return _SystemConfig.Contract.OperatorFeeConstant(&_SystemConfig.CallOpts) +} + +// OperatorFeeConstant is a free data retrieval call binding the contract method 0x16d3bc7f. +// +// Solidity: function operatorFeeConstant() view returns(uint64) +func (_SystemConfig *SystemConfigCallerSession) OperatorFeeConstant() (uint64, error) { + return _SystemConfig.Contract.OperatorFeeConstant(&_SystemConfig.CallOpts) +} + +// OperatorFeeScalar is a free data retrieval call binding the contract method 0x4d5d9a2a. +// +// Solidity: function operatorFeeScalar() view returns(uint32) +func (_SystemConfig *SystemConfigCaller) OperatorFeeScalar(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _SystemConfig.contract.Call(opts, &out, "operatorFeeScalar") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// OperatorFeeScalar is a free data retrieval call binding the contract method 0x4d5d9a2a. +// +// Solidity: function operatorFeeScalar() view returns(uint32) +func (_SystemConfig *SystemConfigSession) OperatorFeeScalar() (uint32, error) { + return _SystemConfig.Contract.OperatorFeeScalar(&_SystemConfig.CallOpts) +} + +// OperatorFeeScalar is a free data retrieval call binding the contract method 0x4d5d9a2a. +// +// Solidity: function operatorFeeScalar() view returns(uint32) +func (_SystemConfig *SystemConfigCallerSession) OperatorFeeScalar() (uint32, error) { + return _SystemConfig.Contract.OperatorFeeScalar(&_SystemConfig.CallOpts) +} + // OptimismMintableERC20Factory is a free data retrieval call binding the contract method 0x9b7d7f0a. // // Solidity: function optimismMintableERC20Factory() view returns(address addr_) @@ -1330,23 +1284,23 @@ func (_SystemConfig *SystemConfigCallerSession) Version() (string, error) { return _SystemConfig.Contract.Version(&_SystemConfig.CallOpts) } -// Initialize is a paid mutator transaction binding the contract method 0xdb9040fa. +// Initialize is a paid mutator transaction binding the contract method 0xca407f0c. // -// Solidity: function initialize(address _owner, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address,address) _addresses) returns() +// Solidity: function initialize(address _owner, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address) _addresses) returns() func (_SystemConfig *SystemConfigTransactor) Initialize(opts *bind.TransactOpts, _owner common.Address, _basefeeScalar uint32, _blobbasefeeScalar uint32, _batcherHash [32]byte, _gasLimit uint64, _unsafeBlockSigner common.Address, _config IResourceMeteringResourceConfig, _batchInbox common.Address, _addresses SystemConfigAddresses) (*types.Transaction, error) { return _SystemConfig.contract.Transact(opts, "initialize", _owner, _basefeeScalar, _blobbasefeeScalar, _batcherHash, _gasLimit, _unsafeBlockSigner, _config, _batchInbox, _addresses) } -// Initialize is a paid mutator transaction binding the contract method 0xdb9040fa. +// Initialize is a paid mutator transaction binding the contract method 0xca407f0c. // -// Solidity: function initialize(address _owner, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address,address) _addresses) returns() +// Solidity: function initialize(address _owner, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address) _addresses) returns() func (_SystemConfig *SystemConfigSession) Initialize(_owner common.Address, _basefeeScalar uint32, _blobbasefeeScalar uint32, _batcherHash [32]byte, _gasLimit uint64, _unsafeBlockSigner common.Address, _config IResourceMeteringResourceConfig, _batchInbox common.Address, _addresses SystemConfigAddresses) (*types.Transaction, error) { return _SystemConfig.Contract.Initialize(&_SystemConfig.TransactOpts, _owner, _basefeeScalar, _blobbasefeeScalar, _batcherHash, _gasLimit, _unsafeBlockSigner, _config, _batchInbox, _addresses) } -// Initialize is a paid mutator transaction binding the contract method 0xdb9040fa. +// Initialize is a paid mutator transaction binding the contract method 0xca407f0c. // -// Solidity: function initialize(address _owner, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address,address) _addresses) returns() +// Solidity: function initialize(address _owner, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address) _addresses) returns() func (_SystemConfig *SystemConfigTransactorSession) Initialize(_owner common.Address, _basefeeScalar uint32, _blobbasefeeScalar uint32, _batcherHash [32]byte, _gasLimit uint64, _unsafeBlockSigner common.Address, _config IResourceMeteringResourceConfig, _batchInbox common.Address, _addresses SystemConfigAddresses) (*types.Transaction, error) { return _SystemConfig.Contract.Initialize(&_SystemConfig.TransactOpts, _owner, _basefeeScalar, _blobbasefeeScalar, _batcherHash, _gasLimit, _unsafeBlockSigner, _config, _batchInbox, _addresses) } @@ -1477,6 +1431,27 @@ func (_SystemConfig *SystemConfigTransactorSession) SetGasLimit(_gasLimit uint64 return _SystemConfig.Contract.SetGasLimit(&_SystemConfig.TransactOpts, _gasLimit) } +// SetOperatorFeeScalars is a paid mutator transaction binding the contract method 0x155b6c6f. +// +// Solidity: function setOperatorFeeScalars(uint32 _operatorFeeScalar, uint64 _operatorFeeConstant) returns() +func (_SystemConfig *SystemConfigTransactor) SetOperatorFeeScalars(opts *bind.TransactOpts, _operatorFeeScalar uint32, _operatorFeeConstant uint64) (*types.Transaction, error) { + return _SystemConfig.contract.Transact(opts, "setOperatorFeeScalars", _operatorFeeScalar, _operatorFeeConstant) +} + +// SetOperatorFeeScalars is a paid mutator transaction binding the contract method 0x155b6c6f. +// +// Solidity: function setOperatorFeeScalars(uint32 _operatorFeeScalar, uint64 _operatorFeeConstant) returns() +func (_SystemConfig *SystemConfigSession) SetOperatorFeeScalars(_operatorFeeScalar uint32, _operatorFeeConstant uint64) (*types.Transaction, error) { + return _SystemConfig.Contract.SetOperatorFeeScalars(&_SystemConfig.TransactOpts, _operatorFeeScalar, _operatorFeeConstant) +} + +// SetOperatorFeeScalars is a paid mutator transaction binding the contract method 0x155b6c6f. +// +// Solidity: function setOperatorFeeScalars(uint32 _operatorFeeScalar, uint64 _operatorFeeConstant) returns() +func (_SystemConfig *SystemConfigTransactorSession) SetOperatorFeeScalars(_operatorFeeScalar uint32, _operatorFeeConstant uint64) (*types.Transaction, error) { + return _SystemConfig.Contract.SetOperatorFeeScalars(&_SystemConfig.TransactOpts, _operatorFeeScalar, _operatorFeeConstant) +} + // SetUnsafeBlockSigner is a paid mutator transaction binding the contract method 0x18d13918. // // Solidity: function setUnsafeBlockSigner(address _unsafeBlockSigner) returns() diff --git a/op-e2e/config/init.go b/op-e2e/config/init.go index d2cd5728cfa96..b13a60023426d 100644 --- a/op-e2e/config/init.go +++ b/op-e2e/config/init.go @@ -396,6 +396,8 @@ func defaultIntent(root string, loc *artifacts.Locator, deployer common.Address, "gasPriceOracleScalar": 1000000, "gasPriceOracleBaseFeeScalar": 1368, "gasPriceOracleBlobBaseFeeScalar": 810949, + "gasPriceOracleOperatorFeeScalar": 0, + "gasPriceOracleOperatorFeeConstant": 0, "l1CancunTimeOffset": "0x0", "faultGameAbsolutePrestate": defaultPrestate.Hex(), "faultGameMaxDepth": 50, diff --git a/op-e2e/system/fees/fees_test.go b/op-e2e/system/fees/fees_test.go index 6296b0ee7ab4f..80f5febc19ebe 100644 --- a/op-e2e/system/fees/fees_test.go +++ b/op-e2e/system/fees/fees_test.go @@ -68,14 +68,27 @@ func TestFees(t *testing.T) { }) t.Run("fjord", func(t *testing.T) { op_e2e.InitParallel(t) - cfg := e2esys.DefaultSystemConfig(t) + cfg := e2esys.FjordSystemConfig(t, new(hexutil.Uint64)) cfg.DeployConfig.L1GenesisBlockBaseFeePerGas = (*hexutil.Big)(big.NewInt(7)) - cfg.DeployConfig.L2GenesisRegolithTimeOffset = new(hexutil.Uint64) - cfg.DeployConfig.L2GenesisCanyonTimeOffset = new(hexutil.Uint64) - cfg.DeployConfig.L2GenesisDeltaTimeOffset = new(hexutil.Uint64) - cfg.DeployConfig.L2GenesisEcotoneTimeOffset = new(hexutil.Uint64) - cfg.DeployConfig.L2GenesisFjordTimeOffset = new(hexutil.Uint64) + testFees(t, cfg) + }) + + t.Run("isthmus without operator fee", func(t *testing.T) { + op_e2e.InitParallel(t) + cfg := e2esys.IsthmusSystemConfig(t, new(hexutil.Uint64)) + cfg.DeployConfig.L1GenesisBlockBaseFeePerGas = (*hexutil.Big)(big.NewInt(7)) + + testFees(t, cfg) + }) + + t.Run("isthmus with operator fee", func(t *testing.T) { + op_e2e.InitParallel(t) + cfg := e2esys.IsthmusSystemConfig(t, new(hexutil.Uint64)) + cfg.DeployConfig.L1GenesisBlockBaseFeePerGas = (*hexutil.Big)(big.NewInt(7)) + cfg.DeployConfig.GasPriceOracleOperatorFeeScalar = 1439103868 + cfg.DeployConfig.GasPriceOracleOperatorFeeConstant = 12564178266093314607 + testFees(t, cfg) }) } @@ -88,6 +101,13 @@ func testFees(t *testing.T, cfg e2esys.SystemConfig) { l2Verif := sys.NodeClient("verifier") l1 := sys.NodeClient("l1") + balanceAt := func(a common.Address, blockNumber *big.Int) *big.Int { + t.Helper() + bal, err := l2Seq.BalanceAt(context.Background(), a, blockNumber) + require.NoError(t, err) + return bal + } + // Wait for first block after genesis. The genesis block has zero L1Block values and will throw off the GPO checks _, err = geth.WaitForBlock(big.NewInt(1), l2Verif) require.NoError(t, err) @@ -101,6 +121,7 @@ func testFees(t *testing.T, cfg e2esys.SystemConfig) { } l1CostFn := types.NewL1CostFunc(config, sga) + operatorFeeFn := types.NewOperatorCostFunc(config, sga) // Transactor Account ethPrivKey := cfg.Secrets.Alice @@ -134,26 +155,24 @@ func testFees(t *testing.T, cfg e2esys.SystemConfig) { require.Equal(t, decimals.Uint64(), uint64(6), "wrong gpo decimals") - // BaseFee Recipient - baseFeeRecipientStartBalance, err := l2Seq.BalanceAt(context.Background(), predeploys.BaseFeeVaultAddr, big.NewInt(rpc.EarliestBlockNumber.Int64())) - require.Nil(t, err) - - // L1Fee Recipient - l1FeeRecipientStartBalance, err := l2Seq.BalanceAt(context.Background(), predeploys.L1FeeVaultAddr, big.NewInt(rpc.EarliestBlockNumber.Int64())) - require.Nil(t, err) + baseFeeRecipientStartBalance := balanceAt(predeploys.BaseFeeVaultAddr, big.NewInt(rpc.EarliestBlockNumber.Int64())) + l1FeeRecipientStartBalance := balanceAt(predeploys.L1FeeVaultAddr, big.NewInt(rpc.EarliestBlockNumber.Int64())) + sequencerFeeVaultStartBalance := balanceAt(predeploys.SequencerFeeVaultAddr, big.NewInt(rpc.EarliestBlockNumber.Int64())) + operatorFeeVaultStartBalance := balanceAt(predeploys.OperatorFeeVaultAddr, big.NewInt(rpc.EarliestBlockNumber.Int64())) - sequencerFeeVaultStartBalance, err := l2Seq.BalanceAt(context.Background(), predeploys.SequencerFeeVaultAddr, big.NewInt(rpc.EarliestBlockNumber.Int64())) - require.Nil(t, err) + require.Equal(t, baseFeeRecipientStartBalance.Sign(), 0, "base fee vault should be empty") + require.Equal(t, l1FeeRecipientStartBalance.Sign(), 0, "l1 fee vault should be empty") + require.Equal(t, sequencerFeeVaultStartBalance.Sign(), 0, "sequencer fee vault should be empty") + require.Equal(t, operatorFeeVaultStartBalance.Sign(), 0, "operator fee vault should be empty") genesisBlock, err := l2Seq.BlockByNumber(context.Background(), big.NewInt(rpc.EarliestBlockNumber.Int64())) require.NoError(t, err) - coinbaseStartBalance, err := l2Seq.BalanceAt(context.Background(), genesisBlock.Coinbase(), big.NewInt(rpc.EarliestBlockNumber.Int64())) - require.NoError(t, err) + coinbaseStartBalance := balanceAt(genesisBlock.Coinbase(), big.NewInt(rpc.EarliestBlockNumber.Int64())) // Simple transfer from signer to random account - startBalance, err := l2Seq.BalanceAt(context.Background(), fromAddr, big.NewInt(rpc.EarliestBlockNumber.Int64())) - require.Nil(t, err) + startBalance := balanceAt(fromAddr, big.NewInt(rpc.EarliestBlockNumber.Int64())) + require.Greater(t, startBalance.Uint64(), big.NewInt(params.Ether).Uint64()) transferAmount := big.NewInt(params.Ether) @@ -172,38 +191,33 @@ func testFees(t *testing.T, cfg e2esys.SystemConfig) { header, err := l2Seq.HeaderByNumber(context.Background(), receipt.BlockNumber) require.Nil(t, err) - coinbaseEndBalance, err := l2Seq.BalanceAt(context.Background(), header.Coinbase, header.Number) - require.Nil(t, err) - - endBalance, err := l2Seq.BalanceAt(context.Background(), fromAddr, header.Number) - require.Nil(t, err) - - baseFeeRecipientEndBalance, err := l2Seq.BalanceAt(context.Background(), predeploys.BaseFeeVaultAddr, header.Number) - require.Nil(t, err) + coinbaseEndBalance := balanceAt(header.Coinbase, header.Number) + endBalance := balanceAt(fromAddr, header.Number) + baseFeeRecipientEndBalance := balanceAt(predeploys.BaseFeeVaultAddr, header.Number) l1Header, err := l1.HeaderByNumber(context.Background(), nil) require.Nil(t, err) - l1FeeRecipientEndBalance, err := l2Seq.BalanceAt(context.Background(), predeploys.L1FeeVaultAddr, header.Number) - require.Nil(t, err) - - sequencerFeeVaultEndBalance, err := l2Seq.BalanceAt(context.Background(), predeploys.SequencerFeeVaultAddr, header.Number) - require.Nil(t, err) + l1FeeRecipientEndBalance := balanceAt(predeploys.L1FeeVaultAddr, header.Number) + sequencerFeeVaultEndBalance := balanceAt(predeploys.SequencerFeeVaultAddr, header.Number) + operatorFeeVaultEndBalance := balanceAt(predeploys.OperatorFeeVaultAddr, header.Number) // Diff fee recipient + coinbase balances baseFeeRecipientDiff := new(big.Int).Sub(baseFeeRecipientEndBalance, baseFeeRecipientStartBalance) l1FeeRecipientDiff := new(big.Int).Sub(l1FeeRecipientEndBalance, l1FeeRecipientStartBalance) sequencerFeeVaultDiff := new(big.Int).Sub(sequencerFeeVaultEndBalance, sequencerFeeVaultStartBalance) + operatorFeeVaultDiff := new(big.Int).Sub(operatorFeeVaultEndBalance, operatorFeeVaultStartBalance) coinbaseDiff := new(big.Int).Sub(coinbaseEndBalance, coinbaseStartBalance) // Tally L2 Fee - l2Fee := gasTip.Mul(gasTip, new(big.Int).SetUint64(receipt.GasUsed)) + gasUsed := new(big.Int).SetUint64(receipt.GasUsed) + l2Fee := gasTip.Mul(gasTip, gasUsed) require.Equal(t, sequencerFeeVaultDiff, coinbaseDiff, "coinbase is always sequencer fee vault") require.Equal(t, l2Fee, coinbaseDiff, "l2 fee mismatch") require.Equal(t, l2Fee, sequencerFeeVaultDiff) // Tally BaseFee - baseFee := new(big.Int).Mul(header.BaseFee, new(big.Int).SetUint64(receipt.GasUsed)) + baseFee := new(big.Int).Mul(header.BaseFee, gasUsed) require.Equal(t, baseFee, baseFeeRecipientDiff, "base fee mismatch") // Tally L1 Fee @@ -215,6 +229,9 @@ func testFees(t *testing.T, cfg e2esys.SystemConfig) { l1Fee := l1CostFn(tx.RollupCostData(), header.Time) require.Equalf(t, l1Fee, l1FeeRecipientDiff, "L1 fee mismatch: start balance %v, end balance %v", l1FeeRecipientStartBalance, l1FeeRecipientEndBalance) + operatorFee := operatorFeeFn(receipt.GasUsed, header.Time) + require.True(t, operatorFeeVaultDiff.Cmp(operatorFee.ToBig()) == 0, "operator fee mismatch: start balance %v, end balance %v", operatorFeeVaultStartBalance, operatorFeeVaultEndBalance) + gpoEcotone, err := gpoContract.IsEcotone(nil) require.NoError(t, err) require.Equal(t, sys.RollupConfig.IsEcotone(header.Time), gpoEcotone, "GPO and chain must have same ecotone view") @@ -223,6 +240,10 @@ func testFees(t *testing.T, cfg e2esys.SystemConfig) { require.NoError(t, err) require.Equal(t, sys.RollupConfig.IsFjord(header.Time), gpoFjord, "GPO and chain must have same fjord view") + gpoIsthmus, err := gpoContract.IsIsthmus(nil) + require.NoError(t, err) + require.Equal(t, sys.RollupConfig.IsIsthmus(header.Time), gpoIsthmus, "GPO and chain must have same isthmus view") + gpoL1Fee, err := gpoContract.GetL1Fee(&bind.CallOpts{}, bytes) require.Nil(t, err) @@ -256,9 +277,36 @@ func testFees(t *testing.T, cfg e2esys.SystemConfig) { new(big.Float).SetInt(receipt.L1Fee), "fee field in receipt matches gas used times scalar times base fee") } + expectedOperatorFee := new(big.Int).Add( + new(big.Int).Div( + new(big.Int).Mul( + gasUsed, + new(big.Int).SetUint64(uint64(cfg.DeployConfig.GasPriceOracleOperatorFeeScalar)), + ), + new(big.Int).SetUint64(uint64(1e6)), + ), + new(big.Int).SetUint64(cfg.DeployConfig.GasPriceOracleOperatorFeeConstant), + ) + + if sys.RollupConfig.IsIsthmus(header.Time) { + require.True(t, expectedOperatorFee.Cmp(operatorFee.ToBig()) == 0, + "operator fee is correct", + ) + + if cfg.DeployConfig.GasPriceOracleOperatorFeeScalar == 0 && cfg.DeployConfig.GasPriceOracleOperatorFeeConstant == 0 { + // if both operator fee params are 0, they aren't added to receipts. + require.Nil(t, receipt.OperatorFeeScalar, "operator fee constant in receipt is nil") + require.Nil(t, receipt.OperatorFeeConstant, "operator fee constant in receipt is nil") + } else { + require.Equal(t, cfg.DeployConfig.GasPriceOracleOperatorFeeScalar, uint32(*receipt.OperatorFeeScalar), "operator fee constant in receipt is correct") + require.Equal(t, cfg.DeployConfig.GasPriceOracleOperatorFeeConstant, *receipt.OperatorFeeConstant, "operator fee constant in receipt is correct") + } + } + // Calculate total fee baseFeeRecipientDiff.Add(baseFeeRecipientDiff, coinbaseDiff) totalFee := new(big.Int).Add(baseFeeRecipientDiff, l1FeeRecipientDiff) + totalFee = new(big.Int).Add(totalFee, operatorFeeVaultDiff) balanceDiff := new(big.Int).Sub(startBalance, endBalance) balanceDiff.Sub(balanceDiff, transferAmount) require.Equal(t, balanceDiff, totalFee, "balances should add up") diff --git a/op-node/rollup/derive/isthmus_upgrade_transactions.go b/op-node/rollup/derive/isthmus_upgrade_transactions.go index 595bf50fd9427..31c575af46994 100644 --- a/op-node/rollup/derive/isthmus_upgrade_transactions.go +++ b/op-node/rollup/derive/isthmus_upgrade_transactions.go @@ -7,14 +7,170 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" ) var ( + // L1Block Parameters + deployIsthmusL1BlockSource = UpgradeDepositSource{Intent: "Isthmus: L1 Block Deployment"} + updateIsthmusL1BlockProxySource = UpgradeDepositSource{Intent: "Isthmus: L1 Block Proxy Update"} + L1BlockIsthmusDeployerAddress = common.HexToAddress("0x4210000000000000000000000000000000000003") + isthmusL1BlockAddress = crypto.CreateAddress(L1BlockIsthmusDeployerAddress, 0) + + // Gas Price Oracle Parameters + deployIsthmusGasPriceOracleSource = UpgradeDepositSource{Intent: "Isthmus: Gas Price Oracle Deployment"} + updateIsthmusGasPriceOracleSource = UpgradeDepositSource{Intent: "Isthmus: Gas Price Oracle Proxy Update"} + GasPriceOracleIsthmusDeployerAddress = common.HexToAddress("0x4210000000000000000000000000000000000004") + isthmusGasPriceOracleAddress = crypto.CreateAddress(GasPriceOracleIsthmusDeployerAddress, 0) + + // Operator fee vault Parameters + deployOperatorFeeVaultSource = UpgradeDepositSource{Intent: "Isthmus: Operator Fee Vault Deployment"} + updateOperatorFeeVaultSource = UpgradeDepositSource{Intent: "Isthmus: Operator Fee Vault Proxy Update"} + OperatorFeeVaultDeployerAddress = common.HexToAddress("0x4210000000000000000000000000000000000005") + OperatorFeeVaultAddress = crypto.CreateAddress(OperatorFeeVaultDeployerAddress, 0) + + // Bytecodes + l1BlockIsthmusDeploymentBytecode = common.FromHex("0x608060405234801561001057600080fd5b506106ae806100206000396000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c806364ca23ef116100d8578063b80777ea1161008c578063e591b28211610066578063e591b282146103b0578063e81b2c6d146103d2578063f8206140146103db57600080fd5b8063b80777ea14610337578063c598591814610357578063d84447151461037757600080fd5b80638381f58a116100bd5780638381f58a146103115780638b239f73146103255780639e8c49661461032e57600080fd5b806364ca23ef146102e157806368d5dca6146102f557600080fd5b80634397dfef1161013a57806354fd4d501161011457806354fd4d501461025d578063550fcdc91461029f5780635cf24969146102d857600080fd5b80634397dfef146101fc578063440a5e20146102245780634d5d9a2a1461022c57600080fd5b806309bd5a601161016b57806309bd5a60146101a457806316d3bc7f146101c057806321326849146101ed57600080fd5b8063015d8eb914610187578063098999be1461019c575b600080fd5b61019a6101953660046105bc565b6103e4565b005b61019a610523565b6101ad60025481565b6040519081526020015b60405180910390f35b6008546101d49067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101b7565b604051600081526020016101b7565b6040805173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee815260126020820152016101b7565b61019a61052d565b6008546102489068010000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016101b7565b60408051808201909152600c81527f312e352e312d626574612e37000000000000000000000000000000000000000060208201525b6040516101b7919061062e565b60408051808201909152600381527f45544800000000000000000000000000000000000000000000000000000000006020820152610292565b6101ad60015481565b6003546101d49067ffffffffffffffff1681565b6003546102489068010000000000000000900463ffffffff1681565b6000546101d49067ffffffffffffffff1681565b6101ad60055481565b6101ad60065481565b6000546101d49068010000000000000000900467ffffffffffffffff1681565b600354610248906c01000000000000000000000000900463ffffffff1681565b60408051808201909152600581527f45746865720000000000000000000000000000000000000000000000000000006020820152610292565b60405173deaddeaddeaddeaddeaddeaddeaddeaddead000181526020016101b7565b6101ad60045481565b6101ad60075481565b3373deaddeaddeaddeaddeaddeaddeaddeaddead00011461048b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4c31426c6f636b3a206f6e6c7920746865206465706f7369746f72206163636f60448201527f756e742063616e20736574204c3120626c6f636b2076616c7565730000000000606482015260840160405180910390fd5b6000805467ffffffffffffffff98891668010000000000000000027fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116998916999099179890981790975560019490945560029290925560038054919094167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009190911617909255600491909155600555600655565b61052b610535565b565b61052b610548565b61053d610548565b60a43560a01c600855565b73deaddeaddeaddeaddeaddeaddeaddeaddead000133811461057257633cc50b456000526004601cfd5b60043560801c60035560143560801c60005560243560015560443560075560643560025560843560045550565b803567ffffffffffffffff811681146105b757600080fd5b919050565b600080600080600080600080610100898b0312156105d957600080fd5b6105e28961059f565b97506105f060208a0161059f565b9650604089013595506060890135945061060c60808a0161059f565b979a969950949793969560a0850135955060c08501359460e001359350915050565b600060208083528351808285015260005b8181101561065b5785810183015185820160400152820161063f565b8181111561066d576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a") + gasPriceOracleIsthmusDeploymentBytecode = common.FromHex("0x608060405234801561001057600080fd5b50611c3c806100206000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806368d5dca6116100d8578063c59859181161008c578063f45e65d811610066578063f45e65d8146102ca578063f8206140146102d2578063fe173b971461026957600080fd5b8063c59859181461029c578063de26c4a1146102a4578063f1c7a58b146102b757600080fd5b80638e98b106116100bd5780638e98b1061461026f578063960e3a2314610277578063b54501bc1461028957600080fd5b806368d5dca61461024c5780636ef25c3a1461026957600080fd5b8063313ce5671161012f5780634ef6e224116101145780634ef6e224146101de578063519b4bd3146101fb57806354fd4d501461020357600080fd5b8063313ce567146101c457806349948e0e146101cb57600080fd5b8063275aedd211610160578063275aedd2146101a1578063291b0383146101b45780632e0f2625146101bc57600080fd5b80630c18c1621461017c57806322b90ab314610197575b600080fd5b6101846102da565b6040519081526020015b60405180910390f35b61019f6103fb565b005b6101846101af36600461168e565b610584565b61019f61070f565b610184600681565b6006610184565b6101846101d93660046116d6565b610937565b6000546101eb9060ff1681565b604051901515815260200161018e565b61018461096e565b61023f6040518060400160405280600c81526020017f312e332e312d626574612e35000000000000000000000000000000000000000081525081565b60405161018e91906117a5565b6102546109cf565b60405163ffffffff909116815260200161018e565b48610184565b61019f610a54565b6000546101eb90610100900460ff1681565b6000546101eb9062010000900460ff1681565b610254610c4e565b6101846102b23660046116d6565b610caf565b6101846102c536600461168e565b610da9565b610184610e85565b610184610f78565b6000805460ff1615610373576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f47617350726963654f7261636c653a206f76657268656164282920697320646560448201527f707265636174656400000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f69190611818565b905090565b3373deaddeaddeaddeaddeaddeaddeaddeaddead0001146104c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e2073657420697345636f746f6e6520666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a40161036a565b60005460ff1615610557576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a2045636f746f6e6520616c72656164792060448201527f6163746976650000000000000000000000000000000000000000000000000000606482015260840161036a565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6000805462010000900460ff1661059d57506000919050565b610709620f42406106668473420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16634d5d9a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062b9190611831565b63ffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821583830293840490921491909117011790565b6106709190611886565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166316d3bc7f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f391906118c1565b67ffffffffffffffff1681019081106000031790565b92915050565b3373deaddeaddeaddeaddeaddeaddeaddeaddead0001146107d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e20736574206973497374686d757320666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a40161036a565b600054610100900460ff1661086f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f47617350726963654f7261636c653a20497374686d75732063616e206f6e6c7960448201527f2062652061637469766174656420616674657220466a6f726400000000000000606482015260840161036a565b60005462010000900460ff1615610908576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a20497374686d757320616c72656164792060448201527f6163746976650000000000000000000000000000000000000000000000000000606482015260840161036a565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1662010000179055565b60008054610100900460ff16156109515761070982610fd9565b60005460ff16156109655761070982610ff8565b6107098261109c565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16635cf249696040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103d2573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a30573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f69190611831565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610af7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e20736574206973466a6f726420666c616700606482015260840161036a565b60005460ff16610b89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f47617350726963654f7261636c653a20466a6f72642063616e206f6e6c79206260448201527f65206163746976617465642061667465722045636f746f6e6500000000000000606482015260840161036a565b600054610100900460ff1615610c20576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f47617350726963654f7261636c653a20466a6f726420616c726561647920616360448201527f7469766500000000000000000000000000000000000000000000000000000000606482015260840161036a565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663c59859186040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a30573d6000803e3d6000fd5b60008054610100900460ff1615610cf657620f4240610ce1610cd0846111f0565b51610cdc9060446118eb565b61150d565b610cec906010611903565b6107099190611886565b6000610d018361156c565b60005490915060ff1615610d155792915050565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d989190611818565b610da290826118eb565b9392505050565b60008054610100900460ff16610e41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f47617350726963654f7261636c653a206765744c314665655570706572426f7560448201527f6e64206f6e6c7920737570706f72747320466a6f726400000000000000000000606482015260840161036a565b6000610e4e8360446118eb565b90506000610e5d60ff83611886565b610e6790836118eb565b610e729060106118eb565b9050610e7d816115fc565b949350505050565b6000805460ff1615610f19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a207363616c61722829206973206465707260448201527f6563617465640000000000000000000000000000000000000000000000000000606482015260840161036a565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103d2573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103d2573d6000803e3d6000fd5b6000610709610fe7836111f0565b51610ff39060446118eb565b6115fc565b6000806110048361156c565b9050600061101061096e565b611018610c4e565b611023906010611940565b63ffffffff166110339190611903565b9050600061103f610f78565b6110476109cf565b63ffffffff166110579190611903565b9050600061106582846118eb565b61106f9085611903565b905061107d6006600a611a8c565b611088906010611903565b6110929082611886565b9695505050505050565b6000806110a88361156c565b9050600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa15801561110b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112f9190611818565b61113761096e565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015611196573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ba9190611818565b6111c490856118eb565b6111ce9190611903565b6111d89190611903565b90506111e66006600a611a8c565b610e7d9082611886565b606061137f565b818153600101919050565b600082840393505b83811015610da25782810151828201511860001a159093029260010161120a565b825b60208210611277578251611242601f836111f7565b52602092909201917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09091019060210161122d565b8115610da257825161128c60018403836111f7565b520160010192915050565b60006001830392505b61010782106112d8576112ca8360ff166112c560fd6112c58760081c60e001896111f7565b6111f7565b9350610106820391506112a0565b60078210611305576112fe8360ff166112c5600785036112c58760081c60e001896111f7565b9050610da2565b610e7d8360ff166112c58560081c8560051b01876111f7565b61137782820361135b61134b84600081518060001a8160011a60081b178160021a60101b17915050919050565b639e3779b90260131c611fff1690565b8060021b6040510182815160e01c1860e01b8151188152505050565b600101919050565b6180003860405139618000604051016020830180600d8551820103826002015b818110156114b2576000805b50508051604051600082901a600183901a60081b1760029290921a60101b91909117639e3779b9810260111c617ffc16909101805160e081811c878603811890911b909118909152840190818303908484106114075750611442565b600184019350611fff821161143c578251600081901a600182901a60081b1760029190911a60101b17810361143c5750611442565b506113ab565b8383106114505750506114b2565b6001830392508583111561146e5761146b878788860361122b565b96505b611482600985016003850160038501611202565b915061148f878284611297565b9650506114a7846114a28684860161131e565b61131e565b91505080935061139f565b50506114c4838384885185010361122b565b925050506040519150618000820180820391508183526020830160005b838110156114f95782810151828201526020016114e1565b506000920191825250602001604052919050565b60008061151d83620cc394611903565b611547907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd763200611a98565b90506115576064620f4240611b0c565b81121561070957610da26064620f4240611b0c565b80516000908190815b818110156115ef5784818151811061158f5761158f611bc8565b01602001517fff00000000000000000000000000000000000000000000000000000000000000166000036115cf576115c86004846118eb565b92506115dd565b6115da6010846118eb565b92505b806115e781611bf7565b915050611575565b50610e7d826104406118eb565b6000806116088361150d565b90506000611614610f78565b61161c6109cf565b63ffffffff1661162c9190611903565b61163461096e565b61163c610c4e565b611647906010611940565b63ffffffff166116579190611903565b61166191906118eb565b905061166f60066002611903565b61167a90600a611a8c565b6116848284611903565b610e7d9190611886565b6000602082840312156116a057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156116e857600080fd5b813567ffffffffffffffff8082111561170057600080fd5b818401915084601f83011261171457600080fd5b813581811115611726576117266116a7565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561176c5761176c6116a7565b8160405282815287602084870101111561178557600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b818110156117d2578581018301518582016040015282016117b6565b818111156117e4576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60006020828403121561182a57600080fd5b5051919050565b60006020828403121561184357600080fd5b815163ffffffff81168114610da257600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000826118bc577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000602082840312156118d357600080fd5b815167ffffffffffffffff81168114610da257600080fd5b600082198211156118fe576118fe611857565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561193b5761193b611857565b500290565b600063ffffffff8083168185168183048111821515161561196357611963611857565b02949350505050565b600181815b808511156119c557817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156119ab576119ab611857565b808516156119b857918102915b93841c9390800290611971565b509250929050565b6000826119dc57506001610709565b816119e957506000610709565b81600181146119ff5760028114611a0957611a25565b6001915050610709565b60ff841115611a1a57611a1a611857565b50506001821b610709565b5060208310610133831016604e8410600b8410161715611a48575081810a610709565b611a52838361196c565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611a8457611a84611857565b029392505050565b6000610da283836119cd565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03841381151615611ad257611ad2611857565b827f8000000000000000000000000000000000000000000000000000000000000000038412811615611b0657611b06611857565b50500190565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600084136000841385830485118282161615611b4d57611b4d611857565b7f80000000000000000000000000000000000000000000000000000000000000006000871286820588128184161615611b8857611b88611857565b60008712925087820587128484161615611ba457611ba4611857565b87850587128184161615611bba57611bba611857565b505050929093029392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611c2857611c28611857565b506001019056fea164736f6c634300080f000a") + operatorFeeVaultDeploymentBytecode = common.FromHex("0x60e060405234801561001057600080fd5b5073420000000000000000000000000000000000001960a0526000608052600160c05260805160a05160c0516107ef6100a7600039600081816101b3015281816102450152818161044b015261048601526000818160b8015281816101800152818161039a01528181610429015281816104c201526105b70152600081816101ef01528181610279015261029d01526107ef6000f3fe60806040526004361061009a5760003560e01c806382356d8a1161006957806384411d651161004e57806384411d651461021d578063d0e12f9014610233578063d3e5792b1461026757600080fd5b806382356d8a146101a45780638312f149146101e057600080fd5b80630d9019e1146100a65780633ccfd60b1461010457806354fd4d501461011b57806366d003ac1461017157600080fd5b366100a157005b600080fd5b3480156100b257600080fd5b506100da7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561011057600080fd5b5061011961029b565b005b34801561012757600080fd5b506101646040518060400160405280600c81526020017f312e352e302d626574612e35000000000000000000000000000000000000000081525081565b6040516100fb9190610671565b34801561017d57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006100da565b3480156101b057600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516100fb919061074e565b3480156101ec57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040519081526020016100fb565b34801561022957600080fd5b5061020f60005481565b34801561023f57600080fd5b506101d37f000000000000000000000000000000000000000000000000000000000000000081565b34801561027357600080fd5b5061020f7f000000000000000000000000000000000000000000000000000000000000000081565b7f0000000000000000000000000000000000000000000000000000000000000000471015610376576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f4665655661756c743a207769746864726177616c20616d6f756e74206d75737460448201527f2062652067726561746572207468616e206d696e696d756d207769746864726160648201527f77616c20616d6f756e7400000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b60004790508060008082825461038c9190610762565b9091555050604080518281527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166020820152338183015290517fc8a211cc64b6ed1b50595a9fcb1932b6d1e5a6e8ef15b60e5b1f988ea9086bba9181900360600190a17f38e04cbeb8c10f8f568618aa75be0f10b6729b8b4237743b4de20cbcde2839ee817f0000000000000000000000000000000000000000000000000000000000000000337f000000000000000000000000000000000000000000000000000000000000000060405161047a94939291906107a1565b60405180910390a160017f000000000000000000000000000000000000000000000000000000000000000060018111156104b6576104b66106e4565b0361057a5760006104e77f000000000000000000000000000000000000000000000000000000000000000083610649565b905080610576576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4665655661756c743a206661696c656420746f2073656e642045544820746f2060448201527f4c322066656520726563697069656e7400000000000000000000000000000000606482015260840161036d565b5050565b6040517fc2b3e5ac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015262061a80602482015260606044820152600060648201527342000000000000000000000000000000000000169063c2b3e5ac9083906084016000604051808303818588803b15801561062d57600080fd5b505af1158015610641573d6000803e3d6000fd5b505050505050565b6000610656835a8461065d565b9392505050565b6000806000806000858888f1949350505050565b600060208083528351808285015260005b8181101561069e57858101830151858201604001528201610682565b818111156106b0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6002811061074a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6020810161075c8284610713565b92915050565b6000821982111561079c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b84815273ffffffffffffffffffffffffffffffffffffffff848116602083015283166040820152608081016107d96060830184610713565b9594505050505056fea164736f6c634300080f000a") + + // Enable Isthmus Parameters + enableIsthmusSource = UpgradeDepositSource{Intent: "Isthmus: Gas Price Oracle Set Isthmus"} + enableIsthmusInput = crypto.Keccak256([]byte("setIsthmus()"))[:4] + blockHashDeployerSource = UpgradeDepositSource{Intent: "Isthmus: EIP-2935 Contract Deployment"} blockHashDeploymentBytecode = common.FromHex("0x60538060095f395ff33373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500") ) func IsthmusNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { + upgradeTxns := make([]hexutil.Bytes, 0, 8) + + // Deploy L1 Block transaction + deployL1BlockTransaction, err := types.NewTx(&types.DepositTx{ + SourceHash: deployIsthmusL1BlockSource.SourceHash(), + From: L1BlockIsthmusDeployerAddress, + To: nil, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 425_000, + IsSystemTransaction: false, + Data: l1BlockIsthmusDeploymentBytecode, + }).MarshalBinary() + + if err != nil { + return nil, err + } + + upgradeTxns = append(upgradeTxns, deployL1BlockTransaction) + + // Deploy Gas Price Oracle transaction + deployGasPriceOracle, err := types.NewTx(&types.DepositTx{ + SourceHash: deployIsthmusGasPriceOracleSource.SourceHash(), + From: GasPriceOracleIsthmusDeployerAddress, + To: nil, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 1_625_000, + IsSystemTransaction: false, + Data: gasPriceOracleIsthmusDeploymentBytecode, + }).MarshalBinary() + + if err != nil { + return nil, err + } + + upgradeTxns = append(upgradeTxns, deployGasPriceOracle) + + // Deploy Operator Fee vault transaction + deployOperatorFeeVault, err := types.NewTx(&types.DepositTx{ + SourceHash: deployOperatorFeeVaultSource.SourceHash(), + From: OperatorFeeVaultDeployerAddress, + To: nil, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 500_000, + IsSystemTransaction: false, + Data: operatorFeeVaultDeploymentBytecode, + }).MarshalBinary() + + if err != nil { + return nil, err + } + + upgradeTxns = append(upgradeTxns, deployOperatorFeeVault) + + // Deploy L1 Block Proxy upgrade transaction + updateL1BlockProxy, err := types.NewTx(&types.DepositTx{ + SourceHash: updateIsthmusL1BlockProxySource.SourceHash(), + From: common.Address{}, + To: &predeploys.L1BlockAddr, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 50_000, + IsSystemTransaction: false, + Data: upgradeToCalldata(isthmusL1BlockAddress), + }).MarshalBinary() + + if err != nil { + return nil, err + } + + upgradeTxns = append(upgradeTxns, updateL1BlockProxy) + + // Deploy Gas Price Oracle Proxy upgrade transaction + updateGasPriceOracleProxy, err := types.NewTx(&types.DepositTx{ + SourceHash: updateIsthmusGasPriceOracleSource.SourceHash(), + From: common.Address{}, + To: &predeploys.GasPriceOracleAddr, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 50_000, + IsSystemTransaction: false, + Data: upgradeToCalldata(isthmusGasPriceOracleAddress), + }).MarshalBinary() + + if err != nil { + return nil, err + } + + upgradeTxns = append(upgradeTxns, updateGasPriceOracleProxy) + + // Deploy Operator Fee Vault Proxy upgrade transaction + updateOperatorFeeVaultProxy, err := types.NewTx(&types.DepositTx{ + SourceHash: updateOperatorFeeVaultSource.SourceHash(), + From: common.Address{}, + To: &predeploys.OperatorFeeVaultAddr, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 50_000, + IsSystemTransaction: false, + Data: upgradeToCalldata(OperatorFeeVaultAddress), + }).MarshalBinary() + + if err != nil { + return nil, err + } + + upgradeTxns = append(upgradeTxns, updateOperatorFeeVaultProxy) + + // Enable Isthmus transaction + enableIsthmus, err := types.NewTx(&types.DepositTx{ + SourceHash: enableIsthmusSource.SourceHash(), + From: L1InfoDepositerAddress, + To: &predeploys.GasPriceOracleAddr, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 90_000, + IsSystemTransaction: false, + Data: enableIsthmusInput, + }).MarshalBinary() + + if err != nil { + return nil, err + } + + upgradeTxns = append(upgradeTxns, enableIsthmus) + deployHistoricalBlockHashesContract, err := types.NewTx(&types.DepositTx{ SourceHash: blockHashDeployerSource.SourceHash(), From: predeploys.EIP2935ContractDeployer, @@ -30,5 +186,7 @@ func IsthmusNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { return nil, err } - return []hexutil.Bytes{deployHistoricalBlockHashesContract}, nil + upgradeTxns = append(upgradeTxns, deployHistoricalBlockHashesContract) + + return upgradeTxns, nil } diff --git a/op-node/rollup/derive/isthmus_upgrade_transactions_test.go b/op-node/rollup/derive/isthmus_upgrade_transactions_test.go index 5527e76e20e89..c005d57b16130 100644 --- a/op-node/rollup/derive/isthmus_upgrade_transactions_test.go +++ b/op-node/rollup/derive/isthmus_upgrade_transactions_test.go @@ -4,9 +4,8 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-service/predeploys" - "github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" ) func TestIsthmusSourcesMatchSpec(t *testing.T) { @@ -18,6 +17,34 @@ func TestIsthmusSourcesMatchSpec(t *testing.T) { source: blockHashDeployerSource, expectedHash: "0xbfb734dae514c5974ddf803e54c1bc43d5cdb4a48ae27e1d9b875a5a150b553a", }, + { + source: deployIsthmusL1BlockSource, + expectedHash: "0x3b2d0821ca2411ad5cd3595804d1213d15737188ae4cbd58aa19c821a6c211bf", + }, + { + source: deployIsthmusGasPriceOracleSource, + expectedHash: "0xfc70b48424763fa3fab9844253b4f8d508f91eb1f7cb11a247c9baec0afb8035", + }, + { + source: deployOperatorFeeVaultSource, + expectedHash: "0x107a570d3db75e6110817eb024f09f3172657e920634111ce9875d08a16daa96", + }, + { + source: updateIsthmusL1BlockProxySource, + expectedHash: "0xebe8b5cb10ca47e0d8bda8f5355f2d66711a54ddeb0ef1d30e29418c9bf17a0e", + }, + { + source: updateIsthmusGasPriceOracleSource, + expectedHash: "0xecf2d9161d26c54eda6b7bfdd9142719b1e1199a6e5641468d1bf705bc531ab0", + }, + { + source: updateOperatorFeeVaultSource, + expectedHash: "0xad74e1adb877ccbe176b8fa1cc559388a16e090ddbe8b512f5b37d07d887a927", + }, + { + source: enableIsthmusSource, + expectedHash: "0x3ddf4b1302548dd92939826e970f260ba36167f4c25f18390a5e8b194b295319", + }, } { require.Equal(t, common.HexToHash(test.expectedHash), test.source.SourceHash()) } @@ -26,9 +53,62 @@ func TestIsthmusSourcesMatchSpec(t *testing.T) { func TestIsthmusNetworkTransactions(t *testing.T) { upgradeTxns, err := IsthmusNetworkUpgradeTransactions() require.NoError(t, err) - require.Len(t, upgradeTxns, 1) + require.Len(t, upgradeTxns, 8) + + deployL1BlockSender, deployL1Block := toDepositTxn(t, upgradeTxns[0]) + require.Equal(t, deployL1BlockSender, common.HexToAddress("0x4210000000000000000000000000000000000003")) + require.Equal(t, deployIsthmusL1BlockSource.SourceHash(), deployL1Block.SourceHash()) + require.Nil(t, deployL1Block.To()) + require.Equal(t, uint64(425_000), deployL1Block.Gas()) // TODO + require.Equal(t, l1BlockIsthmusDeploymentBytecode, deployL1Block.Data()) + + deployGasPriceOracleSender, deployGasPriceOracle := toDepositTxn(t, upgradeTxns[1]) + require.Equal(t, deployGasPriceOracleSender, common.HexToAddress("0x4210000000000000000000000000000000000004")) + require.Equal(t, deployIsthmusGasPriceOracleSource.SourceHash(), deployGasPriceOracle.SourceHash()) + require.Nil(t, deployGasPriceOracle.To()) + require.Equal(t, uint64(1_625_000), deployGasPriceOracle.Gas()) + require.Equal(t, gasPriceOracleIsthmusDeploymentBytecode, deployGasPriceOracle.Data()) + + deployOperatorFeeVaultSender, deployOperatorFeeVault := toDepositTxn(t, upgradeTxns[2]) + require.Equal(t, deployOperatorFeeVaultSender, common.HexToAddress("0x4210000000000000000000000000000000000005")) + require.Equal(t, deployOperatorFeeVaultSource.SourceHash(), deployOperatorFeeVault.SourceHash()) + require.Nil(t, deployOperatorFeeVault.To()) + require.Equal(t, uint64(500_000), deployOperatorFeeVault.Gas()) + require.Equal(t, operatorFeeVaultDeploymentBytecode, deployOperatorFeeVault.Data()) + + updateL1BlockProxySender, updateL1BlockProxy := toDepositTxn(t, upgradeTxns[3]) + require.Equal(t, updateL1BlockProxySender, common.Address{}) + require.Equal(t, updateIsthmusL1BlockProxySource.SourceHash(), updateL1BlockProxy.SourceHash()) + require.NotNil(t, updateL1BlockProxy.To()) + require.Equal(t, *updateL1BlockProxy.To(), common.HexToAddress("0x4200000000000000000000000000000000000015")) + require.Equal(t, uint64(50_000), updateL1BlockProxy.Gas()) + require.Equal(t, common.FromHex("3659cfe6000000000000000000000000ff256497d61dcd71a9e9ff43967c13fde1f72d12"), updateL1BlockProxy.Data()) + + updateGasPriceOracleSender, updateGasPriceOracle := toDepositTxn(t, upgradeTxns[4]) + require.Equal(t, updateGasPriceOracleSender, common.Address{}) + require.Equal(t, updateIsthmusGasPriceOracleSource.SourceHash(), updateGasPriceOracle.SourceHash()) + require.NotNil(t, updateGasPriceOracle.To()) + require.Equal(t, *updateGasPriceOracle.To(), common.HexToAddress("0x420000000000000000000000000000000000000F")) + require.Equal(t, uint64(50_000), updateGasPriceOracle.Gas()) + require.Equal(t, common.FromHex("3659cfe600000000000000000000000093e57a196454cb919193fa9946f14943cf733845"), updateGasPriceOracle.Data()) + + updateOperatorFeeSender, updateOperatorFee := toDepositTxn(t, upgradeTxns[5]) + require.Equal(t, updateOperatorFeeSender, common.Address{}) + require.Equal(t, updateOperatorFeeVaultSource.SourceHash(), updateOperatorFee.SourceHash()) + require.NotNil(t, updateOperatorFee.To()) + require.Equal(t, *updateOperatorFee.To(), common.HexToAddress("0x420000000000000000000000000000000000001b")) + require.Equal(t, uint64(50_000), updateOperatorFee.Gas()) + require.Equal(t, common.FromHex("3659cfe60000000000000000000000004fa2be8cd41504037f1838bce3bcc93bc68ff537"), updateOperatorFee.Data()) + + gpoSetIsthmusSender, gpoSetIsthmus := toDepositTxn(t, upgradeTxns[6]) + require.Equal(t, gpoSetIsthmusSender, common.HexToAddress("0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001")) + require.Equal(t, enableIsthmusSource.SourceHash(), gpoSetIsthmus.SourceHash()) + require.NotNil(t, gpoSetIsthmus.To()) + require.Equal(t, *gpoSetIsthmus.To(), common.HexToAddress("0x420000000000000000000000000000000000000F")) + require.Equal(t, uint64(90_000), gpoSetIsthmus.Gas()) + require.Equal(t, common.FromHex("291b0383"), gpoSetIsthmus.Data()) - deployBlockHashesSender, deployBlockHashesContract := toDepositTxn(t, upgradeTxns[0]) + deployBlockHashesSender, deployBlockHashesContract := toDepositTxn(t, upgradeTxns[7]) require.Equal(t, deployBlockHashesSender, predeploys.EIP2935ContractDeployer) require.Equal(t, blockHashDeployerSource.SourceHash(), deployBlockHashesContract.SourceHash()) require.Nil(t, deployBlockHashesContract.To()) diff --git a/op-node/rollup/derive/l1_block_info.go b/op-node/rollup/derive/l1_block_info.go index a01fe5bca6b91..0fae5de81182e 100644 --- a/op-node/rollup/derive/l1_block_info.go +++ b/op-node/rollup/derive/l1_block_info.go @@ -20,12 +20,14 @@ import ( const ( L1InfoFuncBedrockSignature = "setL1BlockValues(uint64,uint64,uint256,bytes32,uint64,bytes32,uint256,uint256)" L1InfoFuncEcotoneSignature = "setL1BlockValuesEcotone()" + L1InfoFuncIsthmusSignature = "setL1BlockValuesIsthmus()" L1InfoFuncInteropSignature = "setL1BlockValuesInterop()" DepositsCompleteSignature = "depositsComplete()" L1InfoArguments = 8 L1InfoBedrockLen = 4 + 32*L1InfoArguments - L1InfoEcotoneLen = 4 + 32*5 // after Ecotone upgrade, args are packed into 5 32-byte slots - DepositsCompleteLen = 4 // only the selector + L1InfoEcotoneLen = 4 + 32*5 // after Ecotone upgrade, args are packed into 5 32-byte slots + L1InfoIsthmusLen = 4 + 32*5 + 4 + 8 // after Isthmus upgrade, additionally pack in operator fee scalar and constant + DepositsCompleteLen = 4 // only the selector // DepositsCompleteGas allocates 21k gas for intrinsic tx costs, and // an additional 15k to ensure that the DepositsComplete call does not run out of gas. // GasBenchMark_L1BlockInterop_DepositsComplete:test_depositsComplete_benchmark() (gas: 7768) @@ -37,11 +39,13 @@ const ( var ( L1InfoFuncBedrockBytes4 = crypto.Keccak256([]byte(L1InfoFuncBedrockSignature))[:4] L1InfoFuncEcotoneBytes4 = crypto.Keccak256([]byte(L1InfoFuncEcotoneSignature))[:4] + L1InfoFuncIsthmusBytes4 = crypto.Keccak256([]byte(L1InfoFuncIsthmusSignature))[:4] L1InfoFuncInteropBytes4 = crypto.Keccak256([]byte(L1InfoFuncInteropSignature))[:4] DepositsCompleteBytes4 = crypto.Keccak256([]byte(DepositsCompleteSignature))[:4] L1InfoDepositerAddress = common.HexToAddress("0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001") L1BlockAddress = predeploys.L1BlockAddr ErrInvalidFormat = errors.New("invalid ecotone l1 block info format") + ErrInvalidIsthmusFormat = errors.New("invalid isthmus l1 block info format") ) const ( @@ -66,6 +70,9 @@ type L1BlockInfo struct { BlobBaseFee *big.Int // added by Ecotone upgrade BaseFeeScalar uint32 // added by Ecotone upgrade BlobBaseFeeScalar uint32 // added by Ecotone upgrade + + OperatorFeeScalar uint32 // added by Isthmus upgrade + OperatorFeeConstant uint64 // added by Isthmus upgrade } // Bedrock Binary Format @@ -155,7 +162,7 @@ func (info *L1BlockInfo) unmarshalBinaryBedrock(data []byte) error { return nil } -// Interop & Ecotone Binary Format +// Ecotone Binary Format // +---------+--------------------------+ // | Bytes | Field | // +---------+--------------------------+ @@ -172,9 +179,111 @@ func (info *L1BlockInfo) unmarshalBinaryBedrock(data []byte) error { // +---------+--------------------------+ func (info *L1BlockInfo) marshalBinaryEcotone() ([]byte, error) { - out, err := marshalBinaryWithSignature(info, L1InfoFuncEcotoneBytes4) + w := bytes.NewBuffer(make([]byte, 0, L1InfoEcotoneLen)) // Ecotone and Interop have the same length + if err := solabi.WriteSignature(w, L1InfoFuncEcotoneBytes4); err != nil { + return nil, err + } + if err := binary.Write(w, binary.BigEndian, info.BaseFeeScalar); err != nil { + return nil, err + } + if err := binary.Write(w, binary.BigEndian, info.BlobBaseFeeScalar); err != nil { + return nil, err + } + if err := binary.Write(w, binary.BigEndian, info.SequenceNumber); err != nil { + return nil, err + } + if err := binary.Write(w, binary.BigEndian, info.Time); err != nil { + return nil, err + } + if err := binary.Write(w, binary.BigEndian, info.Number); err != nil { + return nil, err + } + if err := solabi.WriteUint256(w, info.BaseFee); err != nil { + return nil, err + } + blobBasefee := info.BlobBaseFee + if blobBasefee == nil { + blobBasefee = big.NewInt(1) // set to 1, to match the min blob basefee as defined in EIP-4844 + } + if err := solabi.WriteUint256(w, blobBasefee); err != nil { + return nil, err + } + if err := solabi.WriteHash(w, info.BlockHash); err != nil { + return nil, err + } + // ABI encoding will perform the left-padding with zeroes to 32 bytes, matching the "batcherHash" SystemConfig format and version 0 byte. + if err := solabi.WriteAddress(w, info.BatcherAddr); err != nil { + return nil, err + } + return w.Bytes(), nil +} + +func (info *L1BlockInfo) unmarshalBinaryEcotone(data []byte) error { + if len(data) != L1InfoEcotoneLen { + return fmt.Errorf("data is unexpected length: %d", len(data)) + } + r := bytes.NewReader(data) + + var err error + if _, err := solabi.ReadAndValidateSignature(r, L1InfoFuncEcotoneBytes4); err != nil { + return err + } + if err := binary.Read(r, binary.BigEndian, &info.BaseFeeScalar); err != nil { + return ErrInvalidFormat + } + if err := binary.Read(r, binary.BigEndian, &info.BlobBaseFeeScalar); err != nil { + return ErrInvalidFormat + } + if err := binary.Read(r, binary.BigEndian, &info.SequenceNumber); err != nil { + return ErrInvalidFormat + } + if err := binary.Read(r, binary.BigEndian, &info.Time); err != nil { + return ErrInvalidFormat + } + if err := binary.Read(r, binary.BigEndian, &info.Number); err != nil { + return ErrInvalidFormat + } + if info.BaseFee, err = solabi.ReadUint256(r); err != nil { + return err + } + if info.BlobBaseFee, err = solabi.ReadUint256(r); err != nil { + return err + } + if info.BlockHash, err = solabi.ReadHash(r); err != nil { + return err + } + // The "batcherHash" will be correctly parsed as address, since the version 0 and left-padding matches the ABI encoding format. + if info.BatcherAddr, err = solabi.ReadAddress(r); err != nil { + return err + } + if !solabi.EmptyReader(r) { + return errors.New("too many bytes") + } + return nil +} + +// Interop & Isthmus Binary Format +// +---------+--------------------------+ +// | Bytes | Field | +// +---------+--------------------------+ +// | 4 | Function signature | +// | 4 | BaseFeeScalar | +// | 4 | BlobBaseFeeScalar | +// | 8 | SequenceNumber | +// | 8 | Timestamp | +// | 8 | L1BlockNumber | +// | 32 | BaseFee | +// | 32 | BlobBaseFee | +// | 32 | BlockHash | +// | 32 | BatcherHash | +// | 4 | OperatorFeeScalar | +// | 8 | OperatorFeeConstant | +// +---------+--------------------------+ + +func (info *L1BlockInfo) marshalBinaryIsthmus() ([]byte, error) { + out, err := marshalBinaryWithSignature(info, L1InfoFuncIsthmusBytes4) if err != nil { - return nil, fmt.Errorf("failed to marshal Ecotone l1 block info: %w", err) + return nil, fmt.Errorf("failed to marshal Isthmus l1 block info: %w", err) } return out, nil } @@ -188,7 +297,7 @@ func (info *L1BlockInfo) marshalBinaryInterop() ([]byte, error) { } func marshalBinaryWithSignature(info *L1BlockInfo, signature []byte) ([]byte, error) { - w := bytes.NewBuffer(make([]byte, 0, L1InfoEcotoneLen)) // Ecotone and Interop have the same length + w := bytes.NewBuffer(make([]byte, 0, L1InfoIsthmusLen)) if err := solabi.WriteSignature(w, signature); err != nil { return nil, err } @@ -224,19 +333,21 @@ func marshalBinaryWithSignature(info *L1BlockInfo, signature []byte) ([]byte, er if err := solabi.WriteAddress(w, info.BatcherAddr); err != nil { return nil, err } + if err := binary.Write(w, binary.BigEndian, info.OperatorFeeScalar); err != nil { + return nil, err + } + if err := binary.Write(w, binary.BigEndian, info.OperatorFeeConstant); err != nil { + return nil, err + } return w.Bytes(), nil } -func (info *L1BlockInfo) unmarshalBinaryEcotone(data []byte) error { - return unmarshalBinaryWithSignatureAndData(info, L1InfoFuncEcotoneBytes4, data) -} - func (info *L1BlockInfo) unmarshalBinaryInterop(data []byte) error { return unmarshalBinaryWithSignatureAndData(info, L1InfoFuncInteropBytes4, data) } func unmarshalBinaryWithSignatureAndData(info *L1BlockInfo, signature []byte, data []byte) error { - if len(data) != L1InfoEcotoneLen { + if len(data) != L1InfoIsthmusLen { return fmt.Errorf("data is unexpected length: %d", len(data)) } r := bytes.NewReader(data) @@ -246,19 +357,19 @@ func unmarshalBinaryWithSignatureAndData(info *L1BlockInfo, signature []byte, da return err } if err := binary.Read(r, binary.BigEndian, &info.BaseFeeScalar); err != nil { - return ErrInvalidFormat + return ErrInvalidIsthmusFormat } if err := binary.Read(r, binary.BigEndian, &info.BlobBaseFeeScalar); err != nil { - return ErrInvalidFormat + return ErrInvalidIsthmusFormat } if err := binary.Read(r, binary.BigEndian, &info.SequenceNumber); err != nil { - return ErrInvalidFormat + return ErrInvalidIsthmusFormat } if err := binary.Read(r, binary.BigEndian, &info.Time); err != nil { - return ErrInvalidFormat + return ErrInvalidIsthmusFormat } if err := binary.Read(r, binary.BigEndian, &info.Number); err != nil { - return ErrInvalidFormat + return ErrInvalidIsthmusFormat } if info.BaseFee, err = solabi.ReadUint256(r); err != nil { return err @@ -273,12 +384,22 @@ func unmarshalBinaryWithSignatureAndData(info *L1BlockInfo, signature []byte, da if info.BatcherAddr, err = solabi.ReadAddress(r); err != nil { return err } + if err := binary.Read(r, binary.BigEndian, &info.OperatorFeeScalar); err != nil { + return ErrInvalidIsthmusFormat + } + if err := binary.Read(r, binary.BigEndian, &info.OperatorFeeConstant); err != nil { + return ErrInvalidIsthmusFormat + } if !solabi.EmptyReader(r) { return errors.New("too many bytes") } return nil } +func (info *L1BlockInfo) unmarshalBinaryIsthmus(data []byte) error { + return unmarshalBinaryWithSignatureAndData(info, L1InfoFuncIsthmusBytes4, data) +} + // isEcotoneButNotFirstBlock returns whether the specified block is subject to the Ecotone upgrade, // but is not the activation block itself. func isEcotoneButNotFirstBlock(rollupCfg *rollup.Config, l2Timestamp uint64) bool { @@ -295,6 +416,12 @@ func isInteropButNotFirstBlock(rollupCfg *rollup.Config, l2Timestamp uint64) boo return rollupCfg.IsInterop(l2Timestamp) && !rollupCfg.IsInteropActivationBlock(l2Timestamp) } +// isIsthmusButNotFirstBlock returns whether the specified block is subject to the Isthmus upgrade, +// but is not the activation block itself. +func isIsthmusButNotFirstBlock(rollupCfg *rollup.Config, l2Timestamp uint64) bool { + return rollupCfg.IsIsthmus(l2Timestamp) && !rollupCfg.IsIsthmusActivationBlock(l2Timestamp) +} + // L1BlockInfoFromBytes is the inverse of L1InfoDeposit, to see where the L2 chain is derived from func L1BlockInfoFromBytes(rollupCfg *rollup.Config, l2BlockTime uint64, data []byte) (*L1BlockInfo, error) { var info L1BlockInfo @@ -302,6 +429,9 @@ func L1BlockInfoFromBytes(rollupCfg *rollup.Config, l2BlockTime uint64, data []b if isInteropButNotFirstBlock(rollupCfg, l2BlockTime) { return &info, info.unmarshalBinaryInterop(data) } + if isIsthmusButNotFirstBlock(rollupCfg, l2BlockTime) { + return &info, info.unmarshalBinaryIsthmus(data) + } if isEcotoneButNotFirstBlock(rollupCfg, l2BlockTime) { return &info, info.unmarshalBinaryEcotone(data) } @@ -321,6 +451,7 @@ func L1InfoDeposit(rollupCfg *rollup.Config, sysCfg eth.SystemConfig, seqNumber } var data []byte if isEcotoneButNotFirstBlock(rollupCfg, l2Timestamp) { + isIsthmusActivated := isIsthmusButNotFirstBlock(rollupCfg, l2Timestamp) l1BlockInfo.BlobBaseFee = block.BlobBaseFee() if l1BlockInfo.BlobBaseFee == nil { // The L2 spec states to use the MIN_BLOB_GASPRICE from EIP-4844 if not yet active on L1. @@ -332,6 +463,13 @@ func L1InfoDeposit(rollupCfg *rollup.Config, sysCfg eth.SystemConfig, seqNumber } l1BlockInfo.BlobBaseFeeScalar = scalars.BlobBaseFeeScalar l1BlockInfo.BaseFeeScalar = scalars.BaseFeeScalar + + if isIsthmusActivated { + operatorFee := sysCfg.OperatorFee() + l1BlockInfo.OperatorFeeScalar = operatorFee.Scalar + l1BlockInfo.OperatorFeeConstant = operatorFee.Constant + } + if isInteropButNotFirstBlock(rollupCfg, l2Timestamp) { out, err := l1BlockInfo.marshalBinaryInterop() if err != nil { @@ -339,11 +477,19 @@ func L1InfoDeposit(rollupCfg *rollup.Config, sysCfg eth.SystemConfig, seqNumber } data = out } else { - out, err := l1BlockInfo.marshalBinaryEcotone() - if err != nil { - return nil, fmt.Errorf("failed to marshal Ecotone l1 block info: %w", err) + if isIsthmusActivated { + out, err := l1BlockInfo.marshalBinaryIsthmus() + if err != nil { + return nil, fmt.Errorf("failed to marshal Isthmus l1 block info: %w", err) + } + data = out + } else { + out, err := l1BlockInfo.marshalBinaryEcotone() + if err != nil { + return nil, fmt.Errorf("failed to marshal Ecotone l1 block info: %w", err) + } + data = out } - data = out } } else { l1BlockInfo.L1FeeOverhead = sysCfg.Overhead diff --git a/op-node/rollup/derive/l1_block_info_test.go b/op-node/rollup/derive/l1_block_info_test.go index 3f7dd0647e6d8..03e1b4ec65280 100644 --- a/op-node/rollup/derive/l1_block_info_test.go +++ b/op-node/rollup/derive/l1_block_info_test.go @@ -154,6 +154,45 @@ func TestParseL1InfoDepositTxData(t *testing.T) { require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) require.Equal(t, L1InfoEcotoneLen, len(depTx.Data)) }) + t.Run("isthmus", func(t *testing.T) { + rng := rand.New(rand.NewSource(1234)) + info := testutils.MakeBlockInfo(nil)(rng) + rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} + rollupCfg.ActivateAtGenesis(rollup.Isthmus) + // run 1 block after isthmus transition + timestamp := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime + depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, timestamp) + require.NoError(t, err) + require.False(t, depTx.IsSystemTransaction) + require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) + require.Equal(t, L1InfoIsthmusLen, len(depTx.Data)) + }) + t.Run("activation-block isthmus", func(t *testing.T) { + rng := rand.New(rand.NewSource(1234)) + info := testutils.MakeBlockInfo(nil)(rng) + rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} + rollupCfg.ActivateAtGenesis(rollup.Granite) + isthmusTime := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime // activate isthmus just after genesis + rollupCfg.InteropTime = &isthmusTime + depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, isthmusTime) + require.NoError(t, err) + require.False(t, depTx.IsSystemTransaction) + require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) + // Isthmus activates, but ecotone L1 info is still used at this upgrade block + require.Equal(t, L1InfoEcotoneLen, len(depTx.Data)) + require.Equal(t, L1InfoFuncEcotoneBytes4, depTx.Data[:4]) + }) + t.Run("genesis-block isthmus", func(t *testing.T) { + rng := rand.New(rand.NewSource(1234)) + info := testutils.MakeBlockInfo(nil)(rng) + rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} + rollupCfg.ActivateAtGenesis(rollup.Isthmus) + depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, rollupCfg.Genesis.L2Time) + require.NoError(t, err) + require.False(t, depTx.IsSystemTransaction) + require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) + require.Equal(t, L1InfoIsthmusLen, len(depTx.Data)) + }) t.Run("interop", func(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) @@ -165,23 +204,23 @@ func TestParseL1InfoDepositTxData(t *testing.T) { require.NoError(t, err) require.False(t, depTx.IsSystemTransaction) require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) - require.Equal(t, L1InfoEcotoneLen, len(depTx.Data), "the length is same in interop") + require.Equal(t, L1InfoIsthmusLen, len(depTx.Data), "the length is same in interop") require.Equal(t, L1InfoFuncInteropBytes4, depTx.Data[:4], "upgrade is active, need interop signature") }) t.Run("activation-block interop", func(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Fjord) + rollupCfg.ActivateAtGenesis(rollup.Isthmus) interopTime := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime // activate interop just after genesis rollupCfg.InteropTime = &interopTime depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, interopTime) require.NoError(t, err) require.False(t, depTx.IsSystemTransaction) require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) - // Interop activates, but ecotone L1 info is still used at this upgrade block - require.Equal(t, L1InfoEcotoneLen, len(depTx.Data)) - require.Equal(t, L1InfoFuncEcotoneBytes4, depTx.Data[:4]) + // Interop activates, but isthmus L1 info is still used at this upgrade block + require.Equal(t, L1InfoIsthmusLen, len(depTx.Data)) + require.Equal(t, L1InfoFuncIsthmusBytes4, depTx.Data[:4]) }) t.Run("genesis-block interop", func(t *testing.T) { rng := rand.New(rand.NewSource(1234)) @@ -192,7 +231,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { require.NoError(t, err) require.False(t, depTx.IsSystemTransaction) require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) - require.Equal(t, L1InfoEcotoneLen, len(depTx.Data)) + require.Equal(t, L1InfoIsthmusLen, len(depTx.Data)) }) } diff --git a/op-node/rollup/derive/payload_util.go b/op-node/rollup/derive/payload_util.go index 6da1a952b5fe1..eb02d1afa4565 100644 --- a/op-node/rollup/derive/payload_util.go +++ b/op-node/rollup/derive/payload_util.go @@ -97,5 +97,12 @@ func PayloadToSystemConfig(rollupCfg *rollup.Config, payload *eth.ExecutionPaylo d, e := eip1559.DecodeHoloceneExtraData(payload.ExtraData) copy(r.EIP1559Params[:], eip1559.EncodeHolocene1559Params(d, e)) } + + if rollupCfg.IsIsthmus(uint64(payload.Timestamp)) { + r.OperatorFeeParams = eth.EncodeOperatorFeeParams(eth.OperatorFeeParams{ + Scalar: info.OperatorFeeScalar, + Constant: info.OperatorFeeConstant, + }) + } return r, nil } diff --git a/op-node/rollup/derive/system_config.go b/op-node/rollup/derive/system_config.go index 72c4e713c30e9..64e21ff15f33f 100644 --- a/op-node/rollup/derive/system_config.go +++ b/op-node/rollup/derive/system_config.go @@ -22,6 +22,7 @@ var ( SystemConfigUpdateGasLimit = common.Hash{31: 2} SystemConfigUpdateUnsafeBlockSigner = common.Hash{31: 3} SystemConfigUpdateEIP1559Params = common.Hash{31: 4} + SystemConfigUpdateOperatorFeeParams = common.Hash{31: 5} ) var ( @@ -157,6 +158,22 @@ func ProcessSystemConfigUpdateLogEvent(destSysCfg *eth.SystemConfig, ev *types.L } copy(destSysCfg.EIP1559Params[:], params[24:32]) return nil + case SystemConfigUpdateOperatorFeeParams: + if pointer, err := solabi.ReadUint64(reader); err != nil || pointer != 32 { + return NewCriticalError(errors.New("invalid pointer field")) + } + if length, err := solabi.ReadUint64(reader); err != nil || length != 32 { + return NewCriticalError(errors.New("invalid length field")) + } + params, err := solabi.ReadEthBytes32(reader) + if err != nil { + return NewCriticalError(errors.New("could not read operator fee params")) + } + if !solabi.EmptyReader(reader) { + return NewCriticalError(errors.New("too many bytes")) + } + destSysCfg.OperatorFeeParams = params + return nil case SystemConfigUpdateUnsafeBlockSigner: // Ignored in derivation. This configurable applies to runtime configuration outside of the derivation. return nil diff --git a/op-node/rollup/derive/system_config_test.go b/op-node/rollup/derive/system_config_test.go index add1790938796..5906f26cbea77 100644 --- a/op-node/rollup/derive/system_config_test.go +++ b/op-node/rollup/derive/system_config_test.go @@ -32,7 +32,8 @@ var ( oneUint256 = abi.Arguments{ {Type: uint256T}, } - eip1559Params = []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8} + eip1559Params = []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8} + operatorFeeParams = []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xd, 0x8} ) // TestProcessSystemConfigUpdateLogEvent tests the parsing of an event and mutating the @@ -208,6 +209,28 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) { }, err: false, }, + { + name: "SystemConfigUpdateOperatorFeeParams", + log: &types.Log{ + Topics: []common.Hash{ + ConfigUpdateEventABIHash, + ConfigUpdateEventVersion0, + SystemConfigUpdateOperatorFeeParams, + }, + }, + hook: func(t *testing.T, log *types.Log) *types.Log { + numberData, err := oneUint256.Pack(new(big.Int).SetBytes(operatorFeeParams)) + require.NoError(t, err) + data, err := bytesArgs.Pack(numberData) + require.NoError(t, err) + log.Data = data + return log + }, + config: eth.SystemConfig{ + OperatorFeeParams: eth.Bytes32(operatorFeeParams), + }, + err: false, + }, } for _, test := range tests { diff --git a/op-service/eth/types.go b/op-service/eth/types.go index ae458b1e0e2a0..c64c93e651634 100644 --- a/op-service/eth/types.go +++ b/op-service/eth/types.go @@ -517,6 +517,8 @@ type SystemConfig struct { // value will be 0 if Holocene is not active, or if derivation has yet to // process any EIP_1559_PARAMS system config update events. EIP1559Params Bytes8 `json:"eip1559Params"` + // OperatorFeeParams identifies the operator fee parameters. + OperatorFeeParams Bytes32 `json:"operatorFeeParams"` // More fields can be added for future SystemConfig versions. // MarshalPreHolocene indicates whether or not this struct should be @@ -627,6 +629,32 @@ func CheckEcotoneL1SystemConfigScalar(scalar [32]byte) error { } } +type OperatorFeeParams struct { + Scalar uint32 + Constant uint64 +} + +func (sysCfg *SystemConfig) OperatorFee() OperatorFeeParams { + return DecodeOperatorFeeParams(sysCfg.OperatorFeeParams) +} + +// DecodeScalar decodes the operatorFeeScalar and operatorFeeConstant from a 32-byte scalar value. +// It uses the first byte to determine the scalar format. +func DecodeOperatorFeeParams(scalar [32]byte) OperatorFeeParams { + return OperatorFeeParams{ + Scalar: binary.BigEndian.Uint32(scalar[20:24]), + Constant: binary.BigEndian.Uint64(scalar[24:32]), + } +} + +// EncodeOperatorFeeParams encodes the OperatorFeeParams into a 32-byte value +func EncodeOperatorFeeParams(params OperatorFeeParams) (scalar [32]byte) { + + binary.BigEndian.PutUint32(scalar[20:24], params.Scalar) + binary.BigEndian.PutUint64(scalar[24:32], params.Constant) + return +} + type Bytes48 [48]byte func (b *Bytes48) UnmarshalJSON(text []byte) error { diff --git a/op-service/eth/types_test.go b/op-service/eth/types_test.go index 5c24330f0d41a..ea1d40d930fb8 100644 --- a/op-service/eth/types_test.go +++ b/op-service/eth/types_test.go @@ -67,6 +67,13 @@ func TestEcotoneScalars(t *testing.T) { } } +func TestOperatorFeeScalars(t *testing.T) { + sysConfig := SystemConfig{OperatorFeeParams: Bytes32{0: 0, 20: 4, 29: 3}} + params := sysConfig.OperatorFee() + require.Equal(t, uint32(0x4000000), params.Scalar) + require.Equal(t, uint64(0x30000), params.Constant) +} + func FuzzEncodeScalar(f *testing.F) { f.Fuzz(func(t *testing.T, blobBaseFeeScalar uint32, baseFeeScalar uint32) { encoded := EncodeScalar(EcotoneScalars{BlobBaseFeeScalar: blobBaseFeeScalar, BaseFeeScalar: baseFeeScalar}) @@ -77,18 +84,28 @@ func FuzzEncodeScalar(f *testing.F) { }) } +func FuzzEncodeOperatorFeeParams(f *testing.F) { + f.Fuzz(func(t *testing.T, scalar uint32, constant uint64) { + encoded := EncodeOperatorFeeParams(OperatorFeeParams{Scalar: scalar, Constant: constant}) + scalars := DecodeOperatorFeeParams(encoded) + require.Equal(t, scalar, scalars.Scalar) + require.Equal(t, constant, scalars.Constant) + }) +} + func TestSystemConfigMarshaling(t *testing.T) { sysConfig := SystemConfig{ - BatcherAddr: common.Address{'A'}, - Overhead: Bytes32{0x4, 0x5, 0x6}, - Scalar: Bytes32{0x7, 0x8, 0x9}, - GasLimit: 1234, + BatcherAddr: common.Address{'A'}, + Overhead: Bytes32{0x4, 0x5, 0x6}, + Scalar: Bytes32{0x7, 0x8, 0x9}, + OperatorFeeParams: Bytes32{0x1, 0x2, 0x3}, + GasLimit: 1234, // Leave EIP1559 params empty to prove that the // zero value is sent. } j, err := json.Marshal(sysConfig) require.NoError(t, err) - require.Equal(t, `{"batcherAddr":"0x4100000000000000000000000000000000000000","overhead":"0x0405060000000000000000000000000000000000000000000000000000000000","scalar":"0x0708090000000000000000000000000000000000000000000000000000000000","gasLimit":1234,"eip1559Params":"0x0000000000000000"}`, string(j)) + require.Equal(t, `{"batcherAddr":"0x4100000000000000000000000000000000000000","overhead":"0x0405060000000000000000000000000000000000000000000000000000000000","scalar":"0x0708090000000000000000000000000000000000000000000000000000000000","gasLimit":1234,"eip1559Params":"0x0000000000000000","operatorFeeParams":"0x0102030000000000000000000000000000000000000000000000000000000000"}`, string(j)) sysConfig.MarshalPreHolocene = true j, err = json.Marshal(sysConfig) require.NoError(t, err) diff --git a/op-service/predeploys/addresses.go b/op-service/predeploys/addresses.go index 750c391e104b9..143abd04a8611 100644 --- a/op-service/predeploys/addresses.go +++ b/op-service/predeploys/addresses.go @@ -23,6 +23,7 @@ const ( ProxyAdmin = "0x4200000000000000000000000000000000000018" BaseFeeVault = "0x4200000000000000000000000000000000000019" L1FeeVault = "0x420000000000000000000000000000000000001a" + OperatorFeeVault = "0x420000000000000000000000000000000000001b" SchemaRegistry = "0x4200000000000000000000000000000000000020" EAS = "0x4200000000000000000000000000000000000021" CrossL2Inbox = "0x4200000000000000000000000000000000000022" @@ -63,6 +64,7 @@ var ( ProxyAdminAddr = common.HexToAddress(ProxyAdmin) BaseFeeVaultAddr = common.HexToAddress(BaseFeeVault) L1FeeVaultAddr = common.HexToAddress(L1FeeVault) + OperatorFeeVaultAddr = common.HexToAddress(OperatorFeeVault) SchemaRegistryAddr = common.HexToAddress(SchemaRegistry) EASAddr = common.HexToAddress(EAS) CrossL2InboxAddr = common.HexToAddress(CrossL2Inbox) @@ -117,6 +119,7 @@ func init() { Predeploys["ProxyAdmin"] = &Predeploy{Address: ProxyAdminAddr} Predeploys["BaseFeeVault"] = &Predeploy{Address: BaseFeeVaultAddr} Predeploys["L1FeeVault"] = &Predeploy{Address: L1FeeVaultAddr} + Predeploys["OperatorFeeVault"] = &Predeploy{Address: OperatorFeeVaultAddr} Predeploys["SchemaRegistry"] = &Predeploy{Address: SchemaRegistryAddr} Predeploys["EAS"] = &Predeploy{Address: EASAddr} Predeploys["Create2Deployer"] = &Predeploy{ diff --git a/op-service/solabi/util.go b/op-service/solabi/util.go index 41c01106a323c..f5d48a657693f 100644 --- a/op-service/solabi/util.go +++ b/op-service/solabi/util.go @@ -16,6 +16,7 @@ import ( var ( addressEmptyPadding [12]byte = [12]byte{} uint64EmptyPadding [24]byte = [24]byte{} + uint8EmptyPadding [31]byte = [31]byte{} ) func ReadSignature(r io.Reader) ([]byte, error) { @@ -132,3 +133,13 @@ func WriteUint64(w io.Writer, n uint64) error { } return nil } + +func WriteUint8(w io.Writer, n uint8) error { + if _, err := w.Write(uint8EmptyPadding[:]); err != nil { + return err + } + if err := binary.Write(w, binary.BigEndian, n); err != nil { + return err + } + return nil +} diff --git a/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol b/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol index e687a17e048bb..e5677516fbf54 100644 --- a/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol +++ b/packages/contracts-bedrock/interfaces/L1/ISystemConfig.sol @@ -9,7 +9,8 @@ interface ISystemConfig { FEE_SCALARS, GAS_LIMIT, UNSAFE_BLOCK_SIGNER, - EIP_1559_PARAMS + EIP_1559_PARAMS, + OPERATOR_FEE_PARAMS } struct Addresses { @@ -61,6 +62,8 @@ interface ISystemConfig { function l1StandardBridge() external view returns (address addr_); function maximumGasLimit() external pure returns (uint64); function minimumGasLimit() external view returns (uint64); + function operatorFeeConstant() external view returns (uint64); + function operatorFeeScalar() external view returns (uint32); function optimismMintableERC20Factory() external view returns (address addr_); function optimismPortal() external view returns (address addr_); function overhead() external view returns (uint256); @@ -72,6 +75,7 @@ interface ISystemConfig { function setGasConfig(uint256 _overhead, uint256 _scalar) external; function setGasConfigEcotone(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external; function setGasLimit(uint64 _gasLimit) external; + function setOperatorFeeScalars(uint32 _operatorFeeScalar, uint64 _operatorFeeConstant) external; function setUnsafeBlockSigner(address _unsafeBlockSigner) external; function setEIP1559Params(uint32 _denominator, uint32 _elasticity) external; function startBlock() external view returns (uint256 startBlock_); diff --git a/packages/contracts-bedrock/interfaces/L1/ISystemConfigInterop.sol b/packages/contracts-bedrock/interfaces/L1/ISystemConfigInterop.sol index c9b63db2b1df0..19cac2b41543a 100644 --- a/packages/contracts-bedrock/interfaces/L1/ISystemConfigInterop.sol +++ b/packages/contracts-bedrock/interfaces/L1/ISystemConfigInterop.sol @@ -32,6 +32,8 @@ interface ISystemConfigInterop { function l1StandardBridge() external view returns (address addr_); function maximumGasLimit() external pure returns (uint64); function minimumGasLimit() external view returns (uint64); + function operatorFeeConstant() external view returns (uint64); + function operatorFeeScalar() external view returns (uint32); function optimismMintableERC20Factory() external view returns (address addr_); function optimismPortal() external view returns (address addr_); function overhead() external view returns (uint256); @@ -45,6 +47,7 @@ interface ISystemConfigInterop { function setGasLimit(uint64 _gasLimit) external; function setUnsafeBlockSigner(address _unsafeBlockSigner) external; function setEIP1559Params(uint32 _denominator, uint32 _elasticity) external; + function setOperatorFeeScalars(uint32 _operatorFeeScalar, uint64 _operatorFeeConstant) external; function startBlock() external view returns (uint256 startBlock_); function transferOwnership(address newOwner) external; // nosemgrep function unsafeBlockSigner() external view returns (address addr_); diff --git a/packages/contracts-bedrock/interfaces/L2/IGasPriceOracle.sol b/packages/contracts-bedrock/interfaces/L2/IGasPriceOracle.sol index 8063725cb86b7..8e1b4255a079c 100644 --- a/packages/contracts-bedrock/interfaces/L2/IGasPriceOracle.sol +++ b/packages/contracts-bedrock/interfaces/L2/IGasPriceOracle.sol @@ -12,13 +12,16 @@ interface IGasPriceOracle { function getL1Fee(bytes memory _data) external view returns (uint256); function getL1FeeUpperBound(uint256 _unsignedTxSize) external view returns (uint256); function getL1GasUsed(bytes memory _data) external view returns (uint256); + function getOperatorFee(uint256 _gasUsed) external view returns (uint256); function isEcotone() external view returns (bool); function isFjord() external view returns (bool); + function isIsthmus() external view returns (bool); function l1BaseFee() external view returns (uint256); function overhead() external view returns (uint256); function scalar() external view returns (uint256); function setEcotone() external; function setFjord() external; + function setIsthmus() external; function version() external view returns (string memory); function __constructor__() external; diff --git a/packages/contracts-bedrock/interfaces/L2/IL1Block.sol b/packages/contracts-bedrock/interfaces/L2/IL1Block.sol index ecac79801000a..30c42275adf9a 100644 --- a/packages/contracts-bedrock/interfaces/L2/IL1Block.sol +++ b/packages/contracts-bedrock/interfaces/L2/IL1Block.sol @@ -16,6 +16,8 @@ interface IL1Block { function l1FeeOverhead() external view returns (uint256); function l1FeeScalar() external view returns (uint256); function number() external view returns (uint64); + function operatorFeeScalar() external view returns (uint32); + function operatorFeeConstant() external view returns (uint64); function sequenceNumber() external view returns (uint64); function setL1BlockValues( uint64 _number, @@ -29,6 +31,7 @@ interface IL1Block { ) external; function setL1BlockValuesEcotone() external; + function setL1BlockValuesIsthmus() external; function timestamp() external view returns (uint64); function version() external pure returns (string memory); diff --git a/packages/contracts-bedrock/interfaces/L2/IL1BlockInterop.sol b/packages/contracts-bedrock/interfaces/L2/IL1BlockInterop.sol index dea7ad721e0b2..53cfc890ca0da 100644 --- a/packages/contracts-bedrock/interfaces/L2/IL1BlockInterop.sol +++ b/packages/contracts-bedrock/interfaces/L2/IL1BlockInterop.sol @@ -35,6 +35,8 @@ interface IL1BlockInterop { function l1FeeOverhead() external view returns (uint256); function l1FeeScalar() external view returns (uint256); function number() external view returns (uint64); + function operatorFeeScalar() external view returns (uint32); + function operatorFeeConstant() external view returns (uint64); function sequenceNumber() external view returns (uint64); function setConfig(ConfigType _type, bytes memory _value) external; function setL1BlockValues( @@ -50,6 +52,7 @@ interface IL1BlockInterop { external; function setL1BlockValuesEcotone() external; function setL1BlockValuesInterop() external; + function setL1BlockValuesIsthmus() external; function timestamp() external view returns (uint64); function version() external pure returns (string memory); diff --git a/packages/contracts-bedrock/interfaces/L2/IOperatorFeeVault.sol b/packages/contracts-bedrock/interfaces/L2/IOperatorFeeVault.sol new file mode 100644 index 0000000000000..63978e203bca2 --- /dev/null +++ b/packages/contracts-bedrock/interfaces/L2/IOperatorFeeVault.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Types } from "src/libraries/Types.sol"; + +interface IOperatorFeeVault { + event Withdrawal(uint256 value, address to, address from); + event Withdrawal(uint256 value, address to, address from, Types.WithdrawalNetwork withdrawalNetwork); + + receive() external payable; + + function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); + function RECIPIENT() external view returns (address); + function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); + function minWithdrawalAmount() external view returns (uint256 amount_); + function recipient() external view returns (address recipient_); + function totalProcessed() external view returns (uint256); + function withdraw() external; + function withdrawalNetwork() external view returns (Types.WithdrawalNetwork network_); + + function version() external view returns (string memory); + + function __constructor__() + external; +} diff --git a/packages/contracts-bedrock/scripts/Artifacts.s.sol b/packages/contracts-bedrock/scripts/Artifacts.s.sol index 1f42384bd1ad4..5858c8aa4c597 100644 --- a/packages/contracts-bedrock/scripts/Artifacts.s.sol +++ b/packages/contracts-bedrock/scripts/Artifacts.s.sol @@ -116,6 +116,8 @@ contract Artifacts { return payable(Predeploys.BASE_FEE_VAULT); } else if (digest == keccak256(bytes("L1FeeVault"))) { return payable(Predeploys.L1_FEE_VAULT); + } else if (digest == keccak256(bytes("OperatorFeeVault"))) { + return payable(Predeploys.OPERATOR_FEE_VAULT); } else if (digest == keccak256(bytes("GovernanceToken"))) { return payable(Predeploys.GOVERNANCE_TOKEN); } else if (digest == keccak256(bytes("SchemaRegistry"))) { diff --git a/packages/contracts-bedrock/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index 9e04181c0f882..7ab4e9d6efb13 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -21,6 +21,7 @@ import { Types } from "src/libraries/Types.sol"; import { ISequencerFeeVault } from "interfaces/L2/ISequencerFeeVault.sol"; import { IBaseFeeVault } from "interfaces/L2/IBaseFeeVault.sol"; import { IL1FeeVault } from "interfaces/L2/IL1FeeVault.sol"; +import { IOperatorFeeVault } from "interfaces/L2/IOperatorFeeVault.sol"; import { IOptimismMintableERC721Factory } from "interfaces/L2/IOptimismMintableERC721Factory.sol"; import { IGovernanceToken } from "interfaces/governance/IGovernanceToken.sol"; import { IOptimismMintableERC20Factory } from "interfaces/universal/IOptimismMintableERC20Factory.sol"; @@ -182,6 +183,9 @@ contract L2Genesis is Deployer { if (writeForkGenesisAllocs(_fork, Fork.HOLOCENE, _mode)) { return; } + + activateIsthmus(); + if (writeForkGenesisAllocs(_fork, Fork.ISTHMUS, _mode)) { return; } @@ -268,7 +272,8 @@ contract L2Genesis is Deployer { setProxyAdmin(); // 18 setBaseFeeVault(); // 19 setL1FeeVault(); // 1A - // 1B,1C,1D,1E,1F: not used. + setOperatorFeeVault(); // 1B + // 1C,1D,1E,1F: not used. setSchemaRegistry(); // 20 setEAS(); // 21 setGovernanceToken(); // 42: OP (not behind a proxy) @@ -484,6 +489,24 @@ contract L2Genesis is Deployer { vm.resetNonce(address(vault)); } + /// @notice This predeploy is following the safety invariant #2. + function setOperatorFeeVault() public { + IOperatorFeeVault vault = IOperatorFeeVault( + DeployUtils.create1({ + _name: "OperatorFeeVault", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IOperatorFeeVault.__constructor__, ())) + }) + ); + + address impl = Predeploys.predeployToCodeNamespace(Predeploys.OPERATOR_FEE_VAULT); + console.log("Setting %s implementation at: %s", "OperatorFeeVault", impl); + vm.etch(impl, address(vault).code); + + /// Reset so its not included state dump + vm.etch(address(vault), ""); + vm.resetNonce(address(vault)); + } + /// @notice This predeploy is following the safety invariant #2. function setGovernanceToken() public { if (!cfg.enableGovernance()) { @@ -609,6 +632,12 @@ contract L2Genesis is Deployer { IGasPriceOracle(Predeploys.GAS_PRICE_ORACLE).setFjord(); } + function activateIsthmus() public { + console.log("Activating isthmus in GasPriceOracle contract"); + vm.prank(IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).DEPOSITOR_ACCOUNT()); + IGasPriceOracle(Predeploys.GAS_PRICE_ORACLE).setIsthmus(); + } + /// @notice Sets the bytecode in state function _setImplementationCode(address _addr) internal returns (address) { string memory cname = Predeploys.getName(_addr); diff --git a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol index 6a55abc6eb752..d6d09d020d47e 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol @@ -59,6 +59,8 @@ contract DeployConfig is Script { uint256 public l2GenesisBlockGasLimit; uint32 public basefeeScalar; uint32 public blobbasefeeScalar; + uint32 public operatorFeeScalar; + uint64 public operatorFeeConstant; bool public enableGovernance; uint256 public eip1559Denominator; uint256 public eip1559Elasticity; @@ -137,6 +139,8 @@ contract DeployConfig is Script { l2GenesisBlockGasLimit = stdJson.readUint(_json, "$.l2GenesisBlockGasLimit"); basefeeScalar = uint32(_readOr(_json, "$.gasPriceOracleBaseFeeScalar", 1368)); blobbasefeeScalar = uint32(_readOr(_json, "$.gasPriceOracleBlobBaseFeeScalar", 810949)); + operatorFeeScalar = uint32(_readOr(_json, "$.gasPriceOracleOperatorFeeScalar", 0)); + operatorFeeConstant = uint64(_readOr(_json, "$.gasPriceOracleOperatorFeeConstant", 0)); enableGovernance = _readOr(_json, "$.enableGovernance", false); eip1559Denominator = stdJson.readUint(_json, "$.eip1559Denominator"); diff --git a/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol index 2112d614251ae..9541db0bbab5a 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol @@ -59,6 +59,9 @@ contract DeployOPChainInput is BaseDeployIO { Duration internal _disputeMaxClockDuration; bool internal _allowCustomDisputeParameters; + uint32 internal _operatorFeeScalar; + uint64 internal _operatorFeeConstant; + function set(bytes4 _sel, address _addr) public { require(_addr != address(0), "DeployOPChainInput: cannot set zero address"); if (_sel == this.opChainProxyAdminOwner.selector) _opChainProxyAdminOwner = _addr; @@ -91,6 +94,10 @@ contract DeployOPChainInput is BaseDeployIO { _disputeClockExtension = Duration.wrap(SafeCast.toUint64(_value)); } else if (_sel == this.disputeMaxClockDuration.selector) { _disputeMaxClockDuration = Duration.wrap(SafeCast.toUint64(_value)); + } else if (_sel == this.operatorFeeScalar.selector) { + _operatorFeeScalar = SafeCast.toUint32(_value); + } else if (_sel == this.operatorFeeConstant.selector) { + _operatorFeeConstant = SafeCast.toUint64(_value); } else { revert("DeployOPChainInput: unknown selector"); } @@ -214,6 +221,14 @@ contract DeployOPChainInput is BaseDeployIO { function allowCustomDisputeParameters() public view returns (bool) { return _allowCustomDisputeParameters; } + + function operatorFeeScalar() public view returns (uint32) { + return _operatorFeeScalar; + } + + function operatorFeeConstant() public view returns (uint64) { + return _operatorFeeConstant; + } } contract DeployOPChainOutput is BaseDeployIO { diff --git a/packages/contracts-bedrock/snapshots/abi/GasPriceOracle.json b/packages/contracts-bedrock/snapshots/abi/GasPriceOracle.json index cf35030235947..36efa6c5768f4 100644 --- a/packages/contracts-bedrock/snapshots/abi/GasPriceOracle.json +++ b/packages/contracts-bedrock/snapshots/abi/GasPriceOracle.json @@ -147,6 +147,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasUsed", + "type": "uint256" + } + ], + "name": "getOperatorFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "isEcotone", @@ -173,6 +192,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "isIsthmus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "l1BaseFee", @@ -226,6 +258,13 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "setIsthmus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "version", diff --git a/packages/contracts-bedrock/snapshots/abi/L1Block.json b/packages/contracts-bedrock/snapshots/abi/L1Block.json index 8ab5df00fcdd7..153d2676cf5bb 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1Block.json +++ b/packages/contracts-bedrock/snapshots/abi/L1Block.json @@ -186,6 +186,32 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "operatorFeeConstant", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "operatorFeeScalar", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "sequenceNumber", @@ -254,6 +280,13 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "setL1BlockValuesIsthmus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "timestamp", diff --git a/packages/contracts-bedrock/snapshots/abi/L1BlockInterop.json b/packages/contracts-bedrock/snapshots/abi/L1BlockInterop.json index 3e838b5d80767..b3b3d62cb48ae 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1BlockInterop.json +++ b/packages/contracts-bedrock/snapshots/abi/L1BlockInterop.json @@ -238,6 +238,32 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "operatorFeeConstant", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "operatorFeeScalar", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "sequenceNumber", @@ -331,6 +357,13 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "setL1BlockValuesIsthmus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "timestamp", diff --git a/packages/contracts-bedrock/snapshots/abi/OperatorFeeVault.json b/packages/contracts-bedrock/snapshots/abi/OperatorFeeVault.json new file mode 100644 index 0000000000000..657c3d278085b --- /dev/null +++ b/packages/contracts-bedrock/snapshots/abi/OperatorFeeVault.json @@ -0,0 +1,178 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + { + "inputs": [], + "name": "MIN_WITHDRAWAL_AMOUNT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RECIPIENT", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WITHDRAWAL_NETWORK", + "outputs": [ + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minWithdrawalAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "recipient", + "outputs": [ + { + "internalType": "address", + "name": "recipient_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalProcessed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawalNetwork", + "outputs": [ + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "network_", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + } + ], + "name": "Withdrawal", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "enum Types.WithdrawalNetwork", + "name": "withdrawalNetwork", + "type": "uint8" + } + ], + "name": "Withdrawal", + "type": "event" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/SystemConfig.json b/packages/contracts-bedrock/snapshots/abi/SystemConfig.json index 7105f16bf4485..5009ab31ca872 100644 --- a/packages/contracts-bedrock/snapshots/abi/SystemConfig.json +++ b/packages/contracts-bedrock/snapshots/abi/SystemConfig.json @@ -465,6 +465,32 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "operatorFeeConstant", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "operatorFeeScalar", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "optimismMintableERC20Factory", @@ -662,6 +688,24 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "_operatorFeeScalar", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "_operatorFeeConstant", + "type": "uint64" + } + ], + "name": "setOperatorFeeScalars", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/packages/contracts-bedrock/snapshots/abi/SystemConfigInterop.json b/packages/contracts-bedrock/snapshots/abi/SystemConfigInterop.json index f87d9e9e54678..8bcac1f13ccc9 100644 --- a/packages/contracts-bedrock/snapshots/abi/SystemConfigInterop.json +++ b/packages/contracts-bedrock/snapshots/abi/SystemConfigInterop.json @@ -608,6 +608,32 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "operatorFeeConstant", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "operatorFeeScalar", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "optimismMintableERC20Factory", @@ -818,6 +844,24 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "_operatorFeeScalar", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "_operatorFeeConstant", + "type": "uint64" + } + ], + "name": "setOperatorFeeScalars", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 42eacc880d131..77dcc8c2c3667 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -44,12 +44,12 @@ "sourceCodeHash": "0xfd56e63e76b1f203cceeb9bbb14396ae803cbbbf7e80ca0ee11fb586321812af" }, "src/L1/SystemConfig.sol": { - "initCodeHash": "0x98c1049952199f55ae63e34ec61a839d43bde52b0892c482ae4246d0c088e826", - "sourceCodeHash": "0x9016b1979c2f1def83a849389543708d857cf0430756815737dadda8e63047c5" + "initCodeHash": "0xd5b8b8eb47763556d9953019d1f81b1d790f15433aa9696b159a3fc45ecee148", + "sourceCodeHash": "0x6bfbc78b0fef2f65beff11a81f924728a7bd439a56986997621099551805aff9" }, "src/L1/SystemConfigInterop.sol": { - "initCodeHash": "0x36fd6c64d81c83fd97e039ab77fb6dfd3a76f12faba923bf04491bb124b590e8", - "sourceCodeHash": "0x609a10f2f85a2b1cc60a5accd795f65c84edc09b0e98124011bd9e7caeb905d9" + "initCodeHash": "0xbef4696b2dcb6d43c3b3c438338bfb2224a1ea5002ed0612ec36a7821d7e3da2", + "sourceCodeHash": "0x1653aaa4d2b44d34ca1f9f2b4971eeb7594c8c2d27771b1f68b8d38cb79f2368" }, "src/L2/BaseFeeVault.sol": { "initCodeHash": "0xc403d4c555d8e69a2699e01d192ae7327136701fa02da10a6d75a584b3c364c9", @@ -64,16 +64,16 @@ "sourceCodeHash": "0xe5c08ce62327113e4bbaf29f47e5f1ddfad6fbd63c07132eedfba5af5325f331" }, "src/L2/GasPriceOracle.sol": { - "initCodeHash": "0x83d50e3b34cd1b4de32f1cced28796b07aefc526cc17ceb1903ad55f4abc90b7", - "sourceCodeHash": "0x305c72d7be9149fce7095bd4641a1a19acada3126fbc43599f674cadbf6e7d6c" + "initCodeHash": "0x38ef70b2783dd45ad807afcf57972c7df4abaaeb5d16d17cdb451b9e931a9cbb", + "sourceCodeHash": "0x4351fe2ac1106c8c220b8cfe7839bc107c24d8084deb21259ac954f5a362725d" }, "src/L2/L1Block.sol": { - "initCodeHash": "0xc4c2f3ceaa2738a326f7c3e449c45bc642c0810f4c21332b261bb3a3b3f4397e", - "sourceCodeHash": "0x0d72e0709675fdef8b22255000f49d895ee57a7c682cfbc60a5e272b03d38115" + "initCodeHash": "0xa1f984b8ea199574261c19122b5a9c8c7dbd3633980b1e7aaf6b7af24af60478", + "sourceCodeHash": "0xd04d64355dcf55247ac937748518e7f9620ae3f9eabe80fae9a82c0115ed77bc" }, "src/L2/L1BlockInterop.sol": { - "initCodeHash": "0xb2782f1ca0fa0899aa5e879471d9e9044e032e7f931fedcff7803c9a43f8a735", - "sourceCodeHash": "0x01017177d32f567df0273acb1561043d97cf0a36308a95917e0f402682ae5209" + "initCodeHash": "0x55d09f00ad284fd7ca4b55c45fb901ed021b83118012be217aec53876ab34c12", + "sourceCodeHash": "0x7dd627c198a583fbe2c7d257f06001e1a2e563c6c7d79ea6ba9ca0d47cd1599b" }, "src/L2/L1FeeVault.sol": { "initCodeHash": "0x6745b7be3895a5e8d373df0066d931bae29c47672ac46c2f5829bd0052cc6d9e", @@ -103,6 +103,10 @@ "initCodeHash": "0xc56db8cb569efa0467fd53ab3fa218af3051e54f5517d7fafb7b5831b4350618", "sourceCodeHash": "0x72062343a044e9c56f4143dcfc71706286eb205902006c2afcf6a4cd90c3e9f8" }, + "src/L2/OperatorFeeVault.sol": { + "initCodeHash": "0x3d8c0d7736e8767f2f797da1c20c5fe30bd7f48a4cf75f376290481ad7c0f91f", + "sourceCodeHash": "0x2022fdb4e32769eb9446dab4aed4b8abb5261fd866f381cccfa7869df1a2adff" + }, "src/L2/OptimismMintableERC721.sol": { "initCodeHash": "0xcfa6ad9997a422aef5a19a490a0a535bc870ee34b1f5258c2949eb3680f71e8a", "sourceCodeHash": "0xb67b91f28c8666fee26c40375f835c61629e0f14054bfaf78bc3c61175bbf136" diff --git a/packages/contracts-bedrock/snapshots/storageLayout/GasPriceOracle.json b/packages/contracts-bedrock/snapshots/storageLayout/GasPriceOracle.json index f5149cb06ce82..8e4127173dc23 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/GasPriceOracle.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/GasPriceOracle.json @@ -12,5 +12,12 @@ "offset": 1, "slot": "0", "type": "bool" + }, + { + "bytes": "1", + "label": "isIsthmus", + "offset": 2, + "slot": "0", + "type": "bool" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L1Block.json b/packages/contracts-bedrock/snapshots/storageLayout/L1Block.json index 2928d2147b5c8..2c23f06367859 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L1Block.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1Block.json @@ -75,5 +75,19 @@ "offset": 0, "slot": "7", "type": "uint256" + }, + { + "bytes": "8", + "label": "operatorFeeConstant", + "offset": 0, + "slot": "8", + "type": "uint64" + }, + { + "bytes": "4", + "label": "operatorFeeScalar", + "offset": 8, + "slot": "8", + "type": "uint32" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L1BlockInterop.json b/packages/contracts-bedrock/snapshots/storageLayout/L1BlockInterop.json index 14ee2ff9609a0..d7f312e0bf7ad 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L1BlockInterop.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1BlockInterop.json @@ -76,11 +76,25 @@ "slot": "7", "type": "uint256" }, + { + "bytes": "8", + "label": "operatorFeeConstant", + "offset": 0, + "slot": "8", + "type": "uint64" + }, + { + "bytes": "4", + "label": "operatorFeeScalar", + "offset": 8, + "slot": "8", + "type": "uint32" + }, { "bytes": "64", "label": "dependencySet", "offset": 0, - "slot": "8", + "slot": "9", "type": "struct EnumerableSet.UintSet" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json b/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json new file mode 100644 index 0000000000000..93c5a7ec8a6b3 --- /dev/null +++ b/packages/contracts-bedrock/snapshots/storageLayout/OperatorFeeVault.json @@ -0,0 +1,16 @@ +[ + { + "bytes": "32", + "label": "totalProcessed", + "offset": 0, + "slot": "0", + "type": "uint256" + }, + { + "bytes": "1536", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "uint256[48]" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/SystemConfig.json b/packages/contracts-bedrock/snapshots/storageLayout/SystemConfig.json index a6184a1f10dd5..ea0d05feb90d5 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/SystemConfig.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/SystemConfig.json @@ -96,5 +96,19 @@ "offset": 4, "slot": "106", "type": "uint32" + }, + { + "bytes": "4", + "label": "operatorFeeScalar", + "offset": 8, + "slot": "106", + "type": "uint32" + }, + { + "bytes": "8", + "label": "operatorFeeConstant", + "offset": 12, + "slot": "106", + "type": "uint64" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/SystemConfigInterop.json b/packages/contracts-bedrock/snapshots/storageLayout/SystemConfigInterop.json index a6184a1f10dd5..ea0d05feb90d5 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/SystemConfigInterop.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/SystemConfigInterop.json @@ -96,5 +96,19 @@ "offset": 4, "slot": "106", "type": "uint32" + }, + { + "bytes": "4", + "label": "operatorFeeScalar", + "offset": 8, + "slot": "106", + "type": "uint32" + }, + { + "bytes": "8", + "label": "operatorFeeConstant", + "offset": 12, + "slot": "106", + "type": "uint64" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/src/L1/SystemConfig.sol b/packages/contracts-bedrock/src/L1/SystemConfig.sol index d5cc62db1a6d5..e767bc64a50ba 100644 --- a/packages/contracts-bedrock/src/L1/SystemConfig.sol +++ b/packages/contracts-bedrock/src/L1/SystemConfig.sol @@ -28,7 +28,8 @@ contract SystemConfig is OwnableUpgradeable, ISemver { FEE_SCALARS, GAS_LIMIT, UNSAFE_BLOCK_SIGNER, - EIP_1559_PARAMS + EIP_1559_PARAMS, + OPERATOR_FEE_PARAMS } /// @notice Struct representing the addresses of L1 system contracts. These should be the @@ -122,6 +123,12 @@ contract SystemConfig is OwnableUpgradeable, ISemver { /// @notice The EIP-1559 elasticity multiplier. uint32 public eip1559Elasticity; + /// @notice The operator fee scalar. + uint32 public operatorFeeScalar; + + /// @notice The operator fee constant. + uint64 public operatorFeeConstant; + /// @notice Emitted when configuration is updated. /// @param version SystemConfig version. /// @param updateType Type of update. @@ -129,9 +136,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver { event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data); /// @notice Semantic version. - /// @custom:semver 2.4.0 + /// @custom:semver 2.5.0 function version() public pure virtual returns (string memory) { - return "2.4.0"; + return "2.5.0"; } /// @notice Constructs the SystemConfig contract. @@ -375,6 +382,22 @@ contract SystemConfig is OwnableUpgradeable, ISemver { emit ConfigUpdate(VERSION, UpdateType.EIP_1559_PARAMS, data); } + /// @notice Updates the operator fee parameters. Can only be called by the owner. + /// @param _operatorFeeScalar operator fee scalar. + /// @param _operatorFeeConstant operator fee constant. + function setOperatorFeeScalars(uint32 _operatorFeeScalar, uint64 _operatorFeeConstant) external onlyOwner { + _setOperatorFeeScalars(_operatorFeeScalar, _operatorFeeConstant); + } + + /// @notice Internal function for updating the operator fee parameters. + function _setOperatorFeeScalars(uint32 _operatorFeeScalar, uint64 _operatorFeeConstant) internal { + operatorFeeScalar = _operatorFeeScalar; + operatorFeeConstant = _operatorFeeConstant; + + bytes memory data = abi.encode(uint256(_operatorFeeScalar) << 64 | _operatorFeeConstant); + emit ConfigUpdate(VERSION, UpdateType.OPERATOR_FEE_PARAMS, data); + } + /// @notice Sets the start block in a backwards compatible way. Proxies /// that were initialized before the startBlock existed in storage /// can have their start block set by a user provided override. diff --git a/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol b/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol index e18ed7400f39c..1d7bd8794517f 100644 --- a/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol +++ b/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol @@ -65,9 +65,9 @@ contract SystemConfigInterop is SystemConfig { Storage.setAddress(DEPENDENCY_MANAGER_SLOT, _dependencyManager); } - /// @custom:semver +interop + /// @custom:semver +interop.1 function version() public pure override returns (string memory) { - return string.concat(super.version(), "+interop"); + return string.concat(super.version(), "+interop.1"); } /// @notice Adds a chain to the interop dependency set. Can only be called by the dependency manager. diff --git a/packages/contracts-bedrock/src/L2/GasPriceOracle.sol b/packages/contracts-bedrock/src/L2/GasPriceOracle.sol index 11b6c897db857..5af0b0e9de0f3 100644 --- a/packages/contracts-bedrock/src/L2/GasPriceOracle.sol +++ b/packages/contracts-bedrock/src/L2/GasPriceOracle.sol @@ -5,6 +5,7 @@ pragma solidity 0.8.15; import { LibZip } from "@solady/utils/LibZip.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { Constants } from "src/libraries/Constants.sol"; +import { Arithmetic } from "src/libraries/Arithmetic.sol"; // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; @@ -29,8 +30,8 @@ contract GasPriceOracle is ISemver { uint256 public constant DECIMALS = 6; /// @notice Semantic version. - /// @custom:semver 1.3.1-beta.4 - string public constant version = "1.3.1-beta.4"; + /// @custom:semver 1.4.0 + string public constant version = "1.4.0"; /// @notice This is the intercept value for the linear regression used to estimate the final size of the /// compressed transaction. @@ -50,6 +51,9 @@ contract GasPriceOracle is ISemver { /// @notice Indicates whether the network has gone through the Fjord upgrade. bool public isFjord; + /// @notice Indicates whether the network has gone through the Isthmus upgrade. + bool public isIsthmus; + /// @notice Computes the L1 portion of the fee based on the size of the rlp encoded input /// transaction, the current L1 base fee, and the various dynamic parameters. /// @param _data Unsigned fully RLP-encoded transaction to get the L1 fee for. @@ -100,6 +104,17 @@ contract GasPriceOracle is ISemver { isFjord = true; } + /// @notice Set chain to be Isthmus chain (callable by depositor account) + function setIsthmus() external { + require( + msg.sender == Constants.DEPOSITOR_ACCOUNT, + "GasPriceOracle: only the depositor account can set isIsthmus flag" + ); + require(isFjord, "GasPriceOracle: Isthmus can only be activated after Fjord"); + require(isIsthmus == false, "GasPriceOracle: Isthmus already active"); + isIsthmus = true; + } + /// @notice Retrieves the current gas price (base fee). /// @return Current L2 gas price (base fee). function gasPrice() public view returns (uint256) { @@ -179,6 +194,17 @@ contract GasPriceOracle is ISemver { return l1GasUsed + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).l1FeeOverhead(); } + function getOperatorFee(uint256 _gasUsed) public view returns (uint256) { + if (!isIsthmus) { + return 0; + } + + return Arithmetic.saturatingAdd( + Arithmetic.saturatingMul(_gasUsed, IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).operatorFeeScalar()) / 1e6, + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).operatorFeeConstant() + ); + } + /// @notice Computation of the L1 portion of the fee for Bedrock. /// @param _data Unsigned fully RLP-encoded transaction to get the L1 fee for. /// @return L1 fee that should be paid for the tx diff --git a/packages/contracts-bedrock/src/L2/L1Block.sol b/packages/contracts-bedrock/src/L2/L1Block.sol index 81b942446ceaa..63d508c478c34 100644 --- a/packages/contracts-bedrock/src/L2/L1Block.sol +++ b/packages/contracts-bedrock/src/L2/L1Block.sol @@ -56,9 +56,15 @@ contract L1Block is ISemver { /// @notice The latest L1 blob base fee. uint256 public blobBaseFee; - /// @custom:semver 1.5.1-beta.6 + /// @notice The constant value applied to the operator fee. + uint64 public operatorFeeConstant; + + /// @notice The scalar value applied to the operator fee. + uint32 public operatorFeeScalar; + + /// @custom:semver 1.6.0 function version() public pure virtual returns (string memory) { - return "1.5.1-beta.6"; + return "1.6.0"; } /// @notice Returns the gas paying token, its decimals, name and symbol. @@ -167,4 +173,44 @@ contract L1Block is ISemver { sstore(batcherHash.slot, calldataload(132)) // bytes32 } } + + /// @notice Updates the L1 block values for an Isthmus upgraded chain. + /// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size. + /// Params are expected to be in the following order: + /// 1. _baseFeeScalar L1 base fee scalar + /// 2. _blobBaseFeeScalar L1 blob base fee scalar + /// 3. _sequenceNumber Number of L2 blocks since epoch start. + /// 4. _timestamp L1 timestamp. + /// 5. _number L1 blocknumber. + /// 6. _basefee L1 base fee. + /// 7. _blobBaseFee L1 blob base fee. + /// 8. _hash L1 blockhash. + /// 9. _batcherHash Versioned hash to authenticate batcher by. + /// 10. _operatorFeeScalar Operator fee scalar. + /// 11. _operatorFeeConstant Operator fee constant. + function setL1BlockValuesIsthmus() public { + _setL1BlockValuesIsthmus(); + } + + /// @notice Updates the L1 block values for an Isthmus upgraded chain. + /// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size. + /// Params are expected to be in the following order: + /// 1. _baseFeeScalar L1 base fee scalar + /// 2. _blobBaseFeeScalar L1 blob base fee scalar + /// 3. _sequenceNumber Number of L2 blocks since epoch start. + /// 4. _timestamp L1 timestamp. + /// 5. _number L1 blocknumber. + /// 6. _basefee L1 base fee. + /// 7. _blobBaseFee L1 blob base fee. + /// 8. _hash L1 blockhash. + /// 9. _batcherHash Versioned hash to authenticate batcher by. + /// 10. _operatorFeeScalar Operator fee scalar. + /// 11. _operatorFeeConstant Operator fee constant. + function _setL1BlockValuesIsthmus() internal { + _setL1BlockValuesEcotone(); + assembly { + // operatorFeeScalar (uint32), operatorFeeConstant (uint64) + sstore(operatorFeeConstant.slot, shr(160, calldataload(164))) + } + } } diff --git a/packages/contracts-bedrock/src/L2/L1BlockInterop.sol b/packages/contracts-bedrock/src/L2/L1BlockInterop.sol index 3cc03c1ef5349..19c3130601561 100644 --- a/packages/contracts-bedrock/src/L2/L1BlockInterop.sol +++ b/packages/contracts-bedrock/src/L2/L1BlockInterop.sol @@ -46,9 +46,9 @@ contract L1BlockInterop is L1Block { /// keccak256(abi.encode(uint256(keccak256("l1Block.identifier.isDeposit")) - 1)) & ~bytes32(uint256(0xff)) uint256 internal constant IS_DEPOSIT_SLOT = 0x921bd3a089295c6e5540e8fba8195448d253efd6f2e3e495b499b627dc36a300; - /// @custom:semver +interop-beta.4 + /// @custom:semver +interop.6 function version() public pure override returns (string memory) { - return string.concat(super.version(), "+interop-beta.4"); + return string.concat(super.version(), "+interop.6"); } /// @notice Returns whether the call was triggered from a a deposit or not. diff --git a/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol new file mode 100644 index 0000000000000..b7341824d6f80 --- /dev/null +++ b/packages/contracts-bedrock/src/L2/OperatorFeeVault.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +// Contracts +import { FeeVault } from "src/L2/FeeVault.sol"; + +// Libraries +import { Types } from "src/libraries/Types.sol"; +import { Predeploys } from "src/libraries/Predeploys.sol"; + +// Interfaces +import { ISemver } from "interfaces/universal/ISemver.sol"; + +/// @custom:proxied true +/// @custom:predeploy 0x420000000000000000000000000000000000001B +/// @title OperatorFeeVault +/// @notice The OperatorFeeVault accumulates the operator portion of the transaction fees. +contract OperatorFeeVault is FeeVault, ISemver { + /// @notice Semantic version. + /// @custom:semver 1.0.0 + string public constant version = "1.0.0"; + + /// @notice Constructs the OperatorFeeVault contract. + /// Funds are withdrawn to the base fee vault on the L2 network. + constructor() FeeVault(Predeploys.BASE_FEE_VAULT, 0, Types.WithdrawalNetwork.L2) { } +} diff --git a/packages/contracts-bedrock/src/libraries/Arithmetic.sol b/packages/contracts-bedrock/src/libraries/Arithmetic.sol index 140affaa718d5..d4f44c6103fc5 100644 --- a/packages/contracts-bedrock/src/libraries/Arithmetic.sol +++ b/packages/contracts-bedrock/src/libraries/Arithmetic.sol @@ -26,4 +26,30 @@ library Arithmetic { function cdexp(int256 _coefficient, int256 _denominator, int256 _exponent) internal pure returns (int256) { return (_coefficient * (FixedPointMathLib.powWad(1e18 - (1e18 / _denominator), _exponent * 1e18))) / 1e18; } + + /// @notice Saturating addition. + /// @param _x The first value. + /// @param _y The second value. + /// @return z_ The sum of the two values, or the maximum value if the sum overflows. + /// @dev Returns `min(2 ** 256 - 1, x + y)`. + /// @dev Taken from Solady + /// https://github.com/Vectorized/solady/blob/63416d60c78aba70a12ca1b3c11125d1061caa12/src/utils/FixedPointMathLib.sol#L673 + function saturatingAdd(uint256 _x, uint256 _y) internal pure returns (uint256 z_) { + assembly ("memory-safe") { + z_ := or(sub(0, lt(add(_x, _y), _x)), add(_x, _y)) + } + } + + /// @notice Saturating multiplication. + /// @param _x The first value. + /// @param _y The second value. + /// @return z_ The product of the two values, or the maximum value if the product overflows. + /// @dev Returns `min(2 ** 256 - 1, x * y). + /// @dev Taken from Solady + /// https://github.com/Vectorized/solady/blob/63416d60c78aba70a12ca1b3c11125d1061caa12/src/utils/FixedPointMathLib.sol#L681 + function saturatingMul(uint256 _x, uint256 _y) internal pure returns (uint256 z_) { + assembly ("memory-safe") { + z_ := or(sub(or(iszero(_x), eq(div(mul(_x, _y), _x), _y)), 1), mul(_x, _y)) + } + } } diff --git a/packages/contracts-bedrock/src/libraries/Encoding.sol b/packages/contracts-bedrock/src/libraries/Encoding.sol index 5aa4ee7d3d8a4..00c20ea459bb4 100644 --- a/packages/contracts-bedrock/src/libraries/Encoding.sol +++ b/packages/contracts-bedrock/src/libraries/Encoding.sol @@ -177,6 +177,52 @@ library Encoding { ); } + /// @notice Returns an appropriately encoded call to L1Block.setL1BlockValuesIsthmus + /// @param _baseFeeScalar L1 base fee Scalar + /// @param _blobBaseFeeScalar L1 blob base fee Scalar + /// @param _sequenceNumber Number of L2 blocks since epoch start. + /// @param _timestamp L1 timestamp. + /// @param _number L1 blocknumber. + /// @param _baseFee L1 base fee. + /// @param _blobBaseFee L1 blob base fee. + /// @param _hash L1 blockhash. + /// @param _batcherHash Versioned hash to authenticate batcher by. + /// @param _operatorFeeScalar Operator fee scalar. + /// @param _operatorFeeConstant Operator fee constant. + function encodeSetL1BlockValuesIsthmus( + uint32 _baseFeeScalar, + uint32 _blobBaseFeeScalar, + uint64 _sequenceNumber, + uint64 _timestamp, + uint64 _number, + uint256 _baseFee, + uint256 _blobBaseFee, + bytes32 _hash, + bytes32 _batcherHash, + uint32 _operatorFeeScalar, + uint64 _operatorFeeConstant + ) + internal + pure + returns (bytes memory) + { + bytes4 functionSignature = bytes4(keccak256("setL1BlockValuesIsthmus()")); + return abi.encodePacked( + functionSignature, + _baseFeeScalar, + _blobBaseFeeScalar, + _sequenceNumber, + _timestamp, + _number, + _baseFee, + _blobBaseFee, + _hash, + _batcherHash, + _operatorFeeScalar, + _operatorFeeConstant + ); + } + /// @notice Returns an appropriately encoded call to L1Block.setL1BlockValuesInterop /// @param _baseFeeScalar L1 base fee Scalar /// @param _blobBaseFeeScalar L1 blob base fee Scalar diff --git a/packages/contracts-bedrock/src/libraries/Predeploys.sol b/packages/contracts-bedrock/src/libraries/Predeploys.sol index c700d74e9f068..1c7496e1ec4a9 100644 --- a/packages/contracts-bedrock/src/libraries/Predeploys.sol +++ b/packages/contracts-bedrock/src/libraries/Predeploys.sol @@ -68,6 +68,9 @@ library Predeploys { /// @notice Address of the L1FeeVault predeploy. address internal constant L1_FEE_VAULT = 0x420000000000000000000000000000000000001A; + /// @notice Address of the OperatorFeeVault predeploy. + address internal constant OPERATOR_FEE_VAULT = 0x420000000000000000000000000000000000001b; + /// @notice Address of the SchemaRegistry predeploy. address internal constant SCHEMA_REGISTRY = 0x4200000000000000000000000000000000000020; @@ -128,6 +131,7 @@ library Predeploys { if (_addr == PROXY_ADMIN) return "ProxyAdmin"; if (_addr == BASE_FEE_VAULT) return "BaseFeeVault"; if (_addr == L1_FEE_VAULT) return "L1FeeVault"; + if (_addr == OPERATOR_FEE_VAULT) return "OperatorFeeVault"; if (_addr == SCHEMA_REGISTRY) return "SchemaRegistry"; if (_addr == EAS) return "EAS"; if (_addr == GOVERNANCE_TOKEN) return "GovernanceToken"; @@ -154,10 +158,10 @@ library Predeploys { || _addr == SEQUENCER_FEE_WALLET || _addr == OPTIMISM_MINTABLE_ERC20_FACTORY || _addr == L1_BLOCK_NUMBER || _addr == L2_ERC721_BRIDGE || _addr == L1_BLOCK_ATTRIBUTES || _addr == L2_TO_L1_MESSAGE_PASSER || _addr == OPTIMISM_MINTABLE_ERC721_FACTORY || _addr == PROXY_ADMIN || _addr == BASE_FEE_VAULT - || _addr == L1_FEE_VAULT || _addr == SCHEMA_REGISTRY || _addr == EAS || _addr == GOVERNANCE_TOKEN - || (_useInterop && _addr == CROSS_L2_INBOX) || (_useInterop && _addr == L2_TO_L2_CROSS_DOMAIN_MESSENGER) - || (_useInterop && _addr == SUPERCHAIN_WETH) || (_useInterop && _addr == ETH_LIQUIDITY) - || (_useInterop && _addr == SUPERCHAIN_TOKEN_BRIDGE); + || _addr == L1_FEE_VAULT || _addr == OPERATOR_FEE_VAULT || _addr == SCHEMA_REGISTRY || _addr == EAS + || _addr == GOVERNANCE_TOKEN || (_useInterop && _addr == CROSS_L2_INBOX) + || (_useInterop && _addr == L2_TO_L2_CROSS_DOMAIN_MESSENGER) || (_useInterop && _addr == SUPERCHAIN_WETH) + || (_useInterop && _addr == ETH_LIQUIDITY) || (_useInterop && _addr == SUPERCHAIN_TOKEN_BRIDGE); } function isPredeployNamespace(address _addr) internal pure returns (bool) { diff --git a/packages/contracts-bedrock/test/L2/GasPriceOracle.t.sol b/packages/contracts-bedrock/test/L2/GasPriceOracle.t.sol index f013325ef7e7e..8b92a7dbd5e14 100644 --- a/packages/contracts-bedrock/test/L2/GasPriceOracle.t.sol +++ b/packages/contracts-bedrock/test/L2/GasPriceOracle.t.sol @@ -27,6 +27,8 @@ contract GasPriceOracle_Test is CommonTest { uint256 constant l1FeeScalar = 10; uint32 constant blobBaseFeeScalar = 15; uint32 constant baseFeeScalar = 20; + uint32 constant operatorFeeScalar = 4_000_000; + uint64 constant operatorFeeConstant = 300; /// @dev Sets up the test suite. function setUp() public virtual override { @@ -351,4 +353,47 @@ contract GasPriceOracleFjordActive_Test is GasPriceOracle_Test { uint256 upperBound = gasPriceOracle.getL1FeeUpperBound(data.length); assertEq(upperBound, 111214); } + + /// @dev Tests that `operatorFee` is 0 is Isthmus is not activated. + function test_getOperatorFee_succeeds() external view { + assertEq(gasPriceOracle.isIsthmus(), false); + assertEq(gasPriceOracle.getOperatorFee(10), 0); + } +} + +contract GasPriceOracleIsthmus_Test is GasPriceOracle_Test { + /// @dev Sets up the test suite. + function setUp() public virtual override { + l2Fork = Fork.ISTHMUS; + super.setUp(); + + bytes memory calldataPacked = Encoding.encodeSetL1BlockValuesIsthmus( + baseFeeScalar, + blobBaseFeeScalar, + sequenceNumber, + timestamp, + number, + baseFee, + blobBaseFee, + hash, + batcherHash, + operatorFeeScalar, + operatorFeeConstant + ); + + vm.prank(depositor); + (bool success,) = address(l1Block).call(calldataPacked); + require(success, "GasPriceOracleIsthmus_Test: Function call failed"); + } + + /// @dev Tests that `operatorFee` is set correctly. + function test_getOperatorFee_succeeds() external view { + assertEq(gasPriceOracle.getOperatorFee(10), 10 * operatorFeeScalar / 1e6 + operatorFeeConstant); + } + + /// @dev Tests that `setIsthmus` is only callable by the depositor. + function test_setIsthmus_wrongCaller_reverts() external { + vm.expectRevert("GasPriceOracle: only the depositor account can set isIsthmus flag"); + gasPriceOracle.setIsthmus(); + } } diff --git a/packages/contracts-bedrock/test/L2/L1Block.t.sol b/packages/contracts-bedrock/test/L2/L1Block.t.sol index 4e9b0cb2f6f46..c300e09223a6f 100644 --- a/packages/contracts-bedrock/test/L2/L1Block.t.sol +++ b/packages/contracts-bedrock/test/L2/L1Block.t.sol @@ -180,3 +180,108 @@ contract L1BlockEcotone_Test is L1BlockTest { assertEq(data, expReturn); } } + +contract L1BlockIsthmus_Test is L1BlockTest { + /// @dev Tests that setL1BlockValuesIsthmus updates the values appropriately. + function testFuzz_setL1BlockValuesIsthmus_succeeds( + uint32 baseFeeScalar, + uint32 blobBaseFeeScalar, + uint64 sequenceNumber, + uint64 timestamp, + uint64 number, + uint256 baseFee, + uint256 blobBaseFee, + bytes32 hash, + bytes32 batcherHash, + uint32 operatorFeeScalar, + uint64 operatorFeeConstant + ) + external + { + bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesIsthmus( + baseFeeScalar, + blobBaseFeeScalar, + sequenceNumber, + timestamp, + number, + baseFee, + blobBaseFee, + hash, + batcherHash, + operatorFeeScalar, + operatorFeeConstant + ); + + vm.prank(depositor); + (bool success,) = address(l1Block).call(functionCallDataPacked); + assertTrue(success, "Function call failed"); + + assertEq(l1Block.baseFeeScalar(), baseFeeScalar); + assertEq(l1Block.blobBaseFeeScalar(), blobBaseFeeScalar); + assertEq(l1Block.sequenceNumber(), sequenceNumber); + assertEq(l1Block.timestamp(), timestamp); + assertEq(l1Block.number(), number); + assertEq(l1Block.basefee(), baseFee); + assertEq(l1Block.blobBaseFee(), blobBaseFee); + assertEq(l1Block.hash(), hash); + assertEq(l1Block.batcherHash(), batcherHash); + assertEq(l1Block.operatorFeeScalar(), operatorFeeScalar); + assertEq(l1Block.operatorFeeConstant(), operatorFeeConstant); + + // ensure we didn't accidentally pollute the 128 bits of the sequencenum+scalars slot that + // should be empty + bytes32 scalarsSlot = vm.load(address(l1Block), bytes32(uint256(3))); + bytes32 mask128 = hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000"; + + assertEq(0, scalarsSlot & mask128); + + // ensure we didn't accidentally pollute the 128 bits of the number & timestamp slot that + // should be empty + bytes32 numberTimestampSlot = vm.load(address(l1Block), bytes32(uint256(0))); + assertEq(0, numberTimestampSlot & mask128); + } + + /// @dev Tests that `setL1BlockValuesIsthmus` succeeds if sender address is the depositor + function test_setL1BlockValuesIsthmus_isDepositor_succeeds() external { + bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesIsthmus( + type(uint32).max, + type(uint32).max, + type(uint64).max, + type(uint64).max, + type(uint64).max, + type(uint256).max, + type(uint256).max, + bytes32(type(uint256).max), + bytes32(type(uint256).max), + type(uint32).max, + type(uint64).max + ); + + vm.prank(depositor); + (bool success,) = address(l1Block).call(functionCallDataPacked); + assertTrue(success, "function call failed"); + } + + /// @dev Tests that `setL1BlockValuesIsthmus` reverts if sender address is not the depositor + function test_setL1BlockValuesIsthmus_notDepositor_reverts() external { + bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesIsthmus( + type(uint32).max, + type(uint32).max, + type(uint64).max, + type(uint64).max, + type(uint64).max, + type(uint256).max, + type(uint256).max, + bytes32(type(uint256).max), + bytes32(type(uint256).max), + type(uint32).max, + type(uint64).max + ); + + (bool success, bytes memory data) = address(l1Block).call(functionCallDataPacked); + assertTrue(!success, "function call should have failed"); + // make sure return value is the expected function selector for "NotDepositor()" + bytes memory expReturn = hex"3cc50b45"; + assertEq(data, expReturn); + } +} diff --git a/packages/contracts-bedrock/test/L2/L2Genesis.t.sol b/packages/contracts-bedrock/test/L2/L2Genesis.t.sol index 68c67d7e3798e..f105a86632ab1 100644 --- a/packages/contracts-bedrock/test/L2/L2Genesis.t.sol +++ b/packages/contracts-bedrock/test/L2/L2Genesis.t.sol @@ -139,8 +139,8 @@ contract L2GenesisTest is Test { // 2 predeploys do not have proxies assertEq(getCodeCount(_path, "Proxy.sol:Proxy"), Predeploys.PREDEPLOY_COUNT - 2); - // 22 proxies have the implementation set if useInterop is true and 17 if useInterop is false - assertEq(getPredeployCountWithSlotSet(_path, Constants.PROXY_IMPLEMENTATION_ADDRESS), _useInterop ? 22 : 17); + // 23 proxies have the implementation set if useInterop is true and 18 if useInterop is false + assertEq(getPredeployCountWithSlotSet(_path, Constants.PROXY_IMPLEMENTATION_ADDRESS), _useInterop ? 23 : 18); // All proxies except 2 have the proxy 1967 admin slot set to the proxy admin assertEq( @@ -175,7 +175,7 @@ contract L2GenesisTest is Test { uint256 expected = 0; expected += 2048 - 2; // predeploy proxies - expected += 21; // predeploy implementations (excl. legacy erc20-style eth and legacy message sender) + expected += 22; // predeploy implementations (excl. legacy erc20-style eth and legacy message sender) expected += 256; // precompiles expected += 14; // preinstalls expected += 1; // 4788 deployer account diff --git a/packages/contracts-bedrock/test/L2/OperatorFeeVault.t.sol b/packages/contracts-bedrock/test/L2/OperatorFeeVault.t.sol new file mode 100644 index 0000000000000..ab90d627014a5 --- /dev/null +++ b/packages/contracts-bedrock/test/L2/OperatorFeeVault.t.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +// Testing utilities +import { CommonTest } from "test/setup/CommonTest.sol"; + +// Libraries +import { Types } from "src/libraries/Types.sol"; +import { Predeploys } from "src/libraries/Predeploys.sol"; + +// Test the implementations of the FeeVault +contract FeeVault_Test is CommonTest { + /// @dev Tests that the constructor sets the correct values. + function test_constructor_operatorFeeVault_succeeds() external view { + assertEq(operatorFeeVault.RECIPIENT(), Predeploys.BASE_FEE_VAULT); + assertEq(operatorFeeVault.recipient(), Predeploys.BASE_FEE_VAULT); + assertEq(operatorFeeVault.MIN_WITHDRAWAL_AMOUNT(), 0); + assertEq(operatorFeeVault.minWithdrawalAmount(), 0); + assertEq(uint8(operatorFeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L2)); + assertEq(uint8(operatorFeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); + } +} diff --git a/packages/contracts-bedrock/test/L2/Predeploys.t.sol b/packages/contracts-bedrock/test/L2/Predeploys.t.sol index a6a4e5b32b436..dbe97c7f616be 100644 --- a/packages/contracts-bedrock/test/L2/Predeploys.t.sol +++ b/packages/contracts-bedrock/test/L2/Predeploys.t.sol @@ -34,8 +34,8 @@ contract PredeploysBaseTest is CommonTest { /// @dev Returns true if the predeploy uses immutables. function _usesImmutables(address _addr) internal pure returns (bool) { return _addr == Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY || _addr == Predeploys.SEQUENCER_FEE_WALLET - || _addr == Predeploys.BASE_FEE_VAULT || _addr == Predeploys.L1_FEE_VAULT || _addr == Predeploys.EAS - || _addr == Predeploys.GOVERNANCE_TOKEN; + || _addr == Predeploys.BASE_FEE_VAULT || _addr == Predeploys.L1_FEE_VAULT + || _addr == Predeploys.OPERATOR_FEE_VAULT || _addr == Predeploys.EAS || _addr == Predeploys.GOVERNANCE_TOKEN; } function test_predeployToCodeNamespace_works() external pure { diff --git a/packages/contracts-bedrock/test/setup/Setup.sol b/packages/contracts-bedrock/test/setup/Setup.sol index f984c72360b7d..0b7c218845055 100644 --- a/packages/contracts-bedrock/test/setup/Setup.sol +++ b/packages/contracts-bedrock/test/setup/Setup.sol @@ -44,6 +44,7 @@ import { IOptimismSuperchainERC20Factory } from "interfaces/L2/IOptimismSupercha import { IBaseFeeVault } from "interfaces/L2/IBaseFeeVault.sol"; import { ISequencerFeeVault } from "interfaces/L2/ISequencerFeeVault.sol"; import { IL1FeeVault } from "interfaces/L2/IL1FeeVault.sol"; +import { IOperatorFeeVault } from "interfaces/L2/IOperatorFeeVault.sol"; import { IGasPriceOracle } from "interfaces/L2/IGasPriceOracle.sol"; import { IL1Block } from "interfaces/L2/IL1Block.sol"; import { ISuperchainWETH } from "interfaces/L2/ISuperchainWETH.sol"; @@ -120,6 +121,7 @@ contract Setup { IBaseFeeVault baseFeeVault = IBaseFeeVault(payable(Predeploys.BASE_FEE_VAULT)); ISequencerFeeVault sequencerFeeVault = ISequencerFeeVault(payable(Predeploys.SEQUENCER_FEE_WALLET)); IL1FeeVault l1FeeVault = IL1FeeVault(payable(Predeploys.L1_FEE_VAULT)); + IOperatorFeeVault operatorFeeVault = IOperatorFeeVault(payable(Predeploys.OPERATOR_FEE_VAULT)); IGasPriceOracle gasPriceOracle = IGasPriceOracle(Predeploys.GAS_PRICE_ORACLE); IL1Block l1Block = IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES); IGovernanceToken governanceToken = IGovernanceToken(Predeploys.GOVERNANCE_TOKEN); @@ -285,6 +287,7 @@ contract Setup { labelPredeploy(Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY); labelPredeploy(Predeploys.BASE_FEE_VAULT); labelPredeploy(Predeploys.L1_FEE_VAULT); + labelPredeploy(Predeploys.OPERATOR_FEE_VAULT); labelPredeploy(Predeploys.L1_BLOCK_ATTRIBUTES); labelPredeploy(Predeploys.GAS_PRICE_ORACLE); labelPredeploy(Predeploys.LEGACY_MESSAGE_PASSER); diff --git a/packages/contracts-bedrock/test/universal/Specs.t.sol b/packages/contracts-bedrock/test/universal/Specs.t.sol index 61e1c6a4a0582..83593bc15d24d 100644 --- a/packages/contracts-bedrock/test/universal/Specs.t.sol +++ b/packages/contracts-bedrock/test/universal/Specs.t.sol @@ -348,6 +348,8 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "SystemConfig", _sel: _getSel("gasLimit()") }); _addSpec({ _name: "SystemConfig", _sel: _getSel("eip1559Denominator()") }); _addSpec({ _name: "SystemConfig", _sel: _getSel("eip1559Elasticity()") }); + _addSpec({ _name: "SystemConfig", _sel: _getSel("operatorFeeScalar()") }); + _addSpec({ _name: "SystemConfig", _sel: _getSel("operatorFeeConstant()") }); _addSpec({ _name: "SystemConfig", _sel: ISystemConfig.initialize.selector }); _addSpec({ _name: "SystemConfig", _sel: ISystemConfig.minimumGasLimit.selector }); _addSpec({ _name: "SystemConfig", _sel: _getSel("overhead()") }); @@ -359,6 +361,11 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "SystemConfig", _sel: ISystemConfig.setGasConfig.selector, _auth: Role.SYSTEMCONFIGOWNER }); _addSpec({ _name: "SystemConfig", _sel: ISystemConfig.setGasLimit.selector, _auth: Role.SYSTEMCONFIGOWNER }); _addSpec({ _name: "SystemConfig", _sel: ISystemConfig.setEIP1559Params.selector, _auth: Role.SYSTEMCONFIGOWNER }); + _addSpec({ + _name: "SystemConfig", + _sel: ISystemConfig.setOperatorFeeScalars.selector, + _auth: Role.SYSTEMCONFIGOWNER + }); _addSpec({ _name: "SystemConfig", _sel: ISystemConfig.setUnsafeBlockSigner.selector, @@ -400,6 +407,8 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("gasLimit()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("eip1559Denominator()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("eip1559Elasticity()") }); + _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("operatorFeeScalar()") }); + _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("operatorFeeConstant()") }); _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfigInterop.initialize.selector }); _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfig.initialize.selector }); _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfigInterop.minimumGasLimit.selector }); @@ -428,6 +437,11 @@ contract Specification_Test is CommonTest { _sel: ISystemConfigInterop.setEIP1559Params.selector, _auth: Role.SYSTEMCONFIGOWNER }); + _addSpec({ + _name: "SystemConfigInterop", + _sel: ISystemConfigInterop.setOperatorFeeScalars.selector, + _auth: Role.SYSTEMCONFIGOWNER + }); _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfigInterop.setUnsafeBlockSigner.selector,