diff --git a/graft/subnet-evm/commontype/BUILD.bazel b/graft/subnet-evm/commontype/BUILD.bazel index de45b3147181..7fc67e7c8ac6 100644 --- a/graft/subnet-evm/commontype/BUILD.bazel +++ b/graft/subnet-evm/commontype/BUILD.bazel @@ -10,6 +10,7 @@ go_library( name = "commontype", srcs = [ "fee_config.go", + "gas_price_config.go", "test_fee_config.go", ], importpath = "github.com/ava-labs/avalanchego/graft/subnet-evm/commontype", @@ -21,7 +22,15 @@ go_library( graft_go_test( name = "commontype_test", - srcs = ["fee_config_test.go"], + srcs = [ + "fee_config_test.go", + "gas_price_config_test.go", + ], + data = glob(["testdata/**"]), embed = [":commontype"], - deps = ["@com_github_stretchr_testify//require"], + deps = [ + "//utils", + "@com_github_ava_labs_libevm//common", + "@com_github_stretchr_testify//require", + ], ) diff --git a/graft/subnet-evm/commontype/gas_price_config.go b/graft/subnet-evm/commontype/gas_price_config.go new file mode 100644 index 000000000000..543a30005508 --- /dev/null +++ b/graft/subnet-evm/commontype/gas_price_config.go @@ -0,0 +1,112 @@ +// Copyright (C) 2019, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package commontype + +import ( + "encoding/binary" + "errors" + + "github.com/ava-labs/libevm/common" +) + +const MinTargetGas uint64 = 1_000_000 + +// DefaultGasPriceConfig returns a default gas price config for the dynamic +// gas limit mechanism. +// +// The default values are: +// - TargetGas: 1_000_000 +// - MinGasPrice: 1 +// - TimeToDouble: 60 +func DefaultGasPriceConfig() GasPriceConfig { + return GasPriceConfig{ + TargetGas: 1_000_000, + MinGasPrice: 1, + TimeToDouble: 60, + } +} + +var ( + ErrMinGasPriceTooLow = errors.New("minGasPrice must be greater than 0") + + errTargetGasMustBeZero = errors.New("targetGas must be 0 when validatorTargetGas is true") + errTargetGasBelowMin = errors.New("targetGas must be at least MinTargetGas") + errTimeToDoubleTooLow = errors.New("timeToDouble must be greater than 0") + errTimeToDoubleMustBeZero = errors.New("timeToDouble must be 0 when staticPricing is true") +) + +// GasPriceConfig specifies the parameters for the dynamic gas limit and +// gas price mechanism. +// See [GasPriceConfig.Verify] for validation constraints between fields. +type GasPriceConfig struct { + ValidatorTargetGas bool `json:"validatorTargetGas"` // when true, validators control targetGas via node preferences + TargetGas uint64 `json:"targetGas"` // target gas consumption per second + StaticPricing bool `json:"staticPricing"` // when true, gas price is always minGasPrice + MinGasPrice uint64 `json:"minGasPrice"` // minimum gas price in wei + TimeToDouble uint64 `json:"timeToDouble"` // seconds for gas price to double at max capacity +} + +// Verify returns an error if the config violates any field constraints. +func (a *GasPriceConfig) Verify() error { + switch { + case a.MinGasPrice == 0: + return ErrMinGasPriceTooLow + case a.ValidatorTargetGas && a.TargetGas != 0: + return errTargetGasMustBeZero + case !a.ValidatorTargetGas && a.TargetGas < MinTargetGas: + return errTargetGasBelowMin + case a.StaticPricing && a.TimeToDouble != 0: + return errTimeToDoubleMustBeZero + case !a.StaticPricing && a.TimeToDouble == 0: + return errTimeToDoubleTooLow + default: + return nil + } +} + +// Pack encodes the gas price config into a single common.Hash (32 bytes). +// +// Layout (26 bytes used, 6 bytes padding): +// +// h[0] ValidatorTargetGas (bool) +// h[1:9] TargetGas (uint64) +// h[9] StaticPricing (bool) +// h[10:18] MinGasPrice (uint64) +// h[18:26] TimeToDouble (uint64) +func (a *GasPriceConfig) Pack() common.Hash { + var h common.Hash + put := binary.BigEndian.PutUint64 + + if a.ValidatorTargetGas { + h[0] = 1 + } + put(h[1:], a.TargetGas) + if a.StaticPricing { + h[9] = 1 + } + put(h[10:], a.MinGasPrice) + put(h[18:], a.TimeToDouble) + return h +} + +// UnpackFrom decodes a packed common.Hash into the gas price config fields. +// See [GasPriceConfig.Pack] for the byte layout. +func (a *GasPriceConfig) UnpackFrom(h common.Hash) { + u64 := binary.BigEndian.Uint64 + + a.ValidatorTargetGas = h[0] != 0 + a.TargetGas = u64(h[1:]) + a.StaticPricing = h[9] != 0 + a.MinGasPrice = u64(h[10:]) + a.TimeToDouble = u64(h[18:]) +} + +// Equal returns true if both configs are nil or have identical field values. +func (a *GasPriceConfig) Equal(other *GasPriceConfig) bool { + if a == nil || other == nil { + return a == other + } + + return *a == *other +} diff --git a/graft/subnet-evm/commontype/gas_price_config_test.go b/graft/subnet-evm/commontype/gas_price_config_test.go new file mode 100644 index 000000000000..57c614a0980a --- /dev/null +++ b/graft/subnet-evm/commontype/gas_price_config_test.go @@ -0,0 +1,220 @@ +// Copyright (C) 2019, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package commontype + +import ( + "math" + "testing" + + "github.com/ava-labs/libevm/common" + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/utils" +) + +func TestGasPriceConfigVerify(t *testing.T) { + tests := []struct { + name string + config GasPriceConfig + want error + }{ + { + name: "valid config", + config: DefaultGasPriceConfig(), + }, + { + name: "valid with validatorTargetGas", + config: GasPriceConfig{ + ValidatorTargetGas: true, + MinGasPrice: 1, + TimeToDouble: 60, + }, + }, + { + name: "valid with staticPricing", + config: GasPriceConfig{ + TargetGas: MinTargetGas, + StaticPricing: true, + MinGasPrice: 1, + }, + }, + { + name: "valid with both validatorTargetGas and staticPricing", + config: GasPriceConfig{ + ValidatorTargetGas: true, + StaticPricing: true, + MinGasPrice: 1, + }, + }, + { + name: "minGasPrice zero", + config: GasPriceConfig{ + TargetGas: MinTargetGas, + TimeToDouble: 60, + }, + want: ErrMinGasPriceTooLow, + }, + { + name: "targetGas must be zero when validatorTargetGas is true", + config: GasPriceConfig{ + ValidatorTargetGas: true, + TargetGas: MinTargetGas, + MinGasPrice: 1, + TimeToDouble: 60, + }, + want: errTargetGasMustBeZero, + }, + { + name: "targetGas below minimum", + config: GasPriceConfig{ + TargetGas: MinTargetGas - 1, + MinGasPrice: 1, + TimeToDouble: 60, + }, + want: errTargetGasBelowMin, + }, + { + name: "targetGas at minimum boundary", + config: GasPriceConfig{ + TargetGas: MinTargetGas, + MinGasPrice: 1, + TimeToDouble: 1, + }, + }, + { + name: "timeToDouble must be zero when staticPricing is true", + config: GasPriceConfig{ + TargetGas: MinTargetGas, + StaticPricing: true, + MinGasPrice: 1, + TimeToDouble: 60, + }, + want: errTimeToDoubleMustBeZero, + }, + { + name: "timeToDouble must be positive when staticPricing is false", + config: GasPriceConfig{ + TargetGas: MinTargetGas, + MinGasPrice: 1, + }, + want: errTimeToDoubleTooLow, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.config.Verify() + require.ErrorIs(t, err, tt.want, "Verify") + }) + } +} + +// TestGasPriceConfigPackFormat asserts exact packed bytes for known configs. +// This catches backward-incompatible format changes that round-trip tests miss. +func TestGasPriceConfigPackFormat(t *testing.T) { + tests := []struct { + name string + config GasPriceConfig + want common.Hash + }{ + { + name: "default config", + config: DefaultGasPriceConfig(), + want: common.HexToHash("0x0000000000000f4240000000000000000001000000000000003c000000000000"), + }, + { + name: "all flags true and max uint64", + config: GasPriceConfig{ + ValidatorTargetGas: true, + TargetGas: math.MaxUint64, + StaticPricing: true, + MinGasPrice: math.MaxUint64, + TimeToDouble: math.MaxUint64, + }, + want: common.HexToHash("0x01ffffffffffffffff01ffffffffffffffffffffffffffffffff000000000000"), + }, + { + name: "validatorTargetGas mode", + config: GasPriceConfig{ + ValidatorTargetGas: true, + MinGasPrice: 1, + TimeToDouble: 60, + }, + want: common.HexToHash("0x010000000000000000000000000000000001000000000000003c000000000000"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.want, tt.config.Pack(), "Pack") + }) + } +} + +func FuzzGasPriceConfigPacking(f *testing.F) { + f.Add(false, false, uint64(0), uint64(0), uint64(0)) + f.Add(true, true, uint64(math.MaxUint64), uint64(math.MaxUint64), uint64(math.MaxUint64)) + f.Add(false, false, MinTargetGas, uint64(1), uint64(60)) + f.Add(true, false, uint64(0), uint64(1), uint64(60)) + f.Add(false, true, MinTargetGas, uint64(1), uint64(0)) + f.Add(true, true, uint64(0), uint64(1), uint64(0)) + + f.Fuzz(func(t *testing.T, validator, static bool, target, minGas, double uint64) { + in := &GasPriceConfig{validator, target, static, minGas, double} + got := new(GasPriceConfig) + got.UnpackFrom(in.Pack()) + require.Equalf(t, *in, *got, "%T.UnpackFrom(%[1]T.Pack()) round trip", in) + require.Truef(t, got.Equal(in), "%T.Equal([packed original])", got) + }) +} + +func TestGasPriceConfigEqual(t *testing.T) { + tests := []struct { + name string + a *GasPriceConfig + b *GasPriceConfig + want bool + }{ + { + name: "both equal", + a: utils.PointerTo(DefaultGasPriceConfig()), + b: utils.PointerTo(DefaultGasPriceConfig()), + want: true, + }, + { + name: "different targetGas", + a: utils.PointerTo(DefaultGasPriceConfig()), + b: func() *GasPriceConfig { + c := DefaultGasPriceConfig() + c.TargetGas++ + return &c + }(), + want: false, + }, + { + name: "other nil", + a: utils.PointerTo(DefaultGasPriceConfig()), + b: nil, + want: false, + }, + { + name: "receiver nil", + a: nil, + b: utils.PointerTo(DefaultGasPriceConfig()), + want: false, + }, + { + name: "both nil", + a: nil, + b: nil, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equalf(t, tt.want, tt.a.Equal(tt.b), "%T(%+v).Equal(%+v)", tt.a, tt.a, tt.b) + }) + } +} diff --git a/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/03eeae4f73409617 b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/03eeae4f73409617 new file mode 100644 index 000000000000..6128774ed75a --- /dev/null +++ b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/03eeae4f73409617 @@ -0,0 +1,6 @@ +go test fuzz v1 +bool(true) +bool(false) +uint64(6148914691236517205) +uint64(12297829382473034410) +uint64(6148914691236517205) diff --git a/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/6148d56c0c7926ba b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/6148d56c0c7926ba new file mode 100644 index 000000000000..e5d47eff8d30 --- /dev/null +++ b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/6148d56c0c7926ba @@ -0,0 +1,6 @@ +go test fuzz v1 +bool(true) +bool(true) +uint64(9223372036854775808) +uint64(9223372036854775807) +uint64(4294967296) diff --git a/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/913ddfe768f28110 b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/913ddfe768f28110 new file mode 100644 index 000000000000..91925b316fba --- /dev/null +++ b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/913ddfe768f28110 @@ -0,0 +1,6 @@ +go test fuzz v1 +bool(true) +bool(false) +uint64(1) +uint64(1) +uint64(1) diff --git a/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/b727bde1998d0574 b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/b727bde1998d0574 new file mode 100644 index 000000000000..77dee35c9c8a --- /dev/null +++ b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/b727bde1998d0574 @@ -0,0 +1,6 @@ +go test fuzz v1 +bool(false) +bool(false) +uint64(1000002) +uint64(1) +uint64(60) diff --git a/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/e8a09054e7baf023 b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/e8a09054e7baf023 new file mode 100644 index 000000000000..48b3f0933a9c --- /dev/null +++ b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/e8a09054e7baf023 @@ -0,0 +1,6 @@ +go test fuzz v1 +bool(false) +bool(false) +uint64(49) +uint64(0) +uint64(0) diff --git a/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/e8d0fcf613345acd b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/e8d0fcf613345acd new file mode 100644 index 000000000000..e94e2ecb60a1 --- /dev/null +++ b/graft/subnet-evm/commontype/testdata/fuzz/FuzzGasPriceConfigPacking/e8d0fcf613345acd @@ -0,0 +1,6 @@ +go test fuzz v1 +bool(false) +bool(true) +uint64(1000099) +uint64(1) +uint64(0) diff --git a/graft/subnet-evm/precompile/contracts/acp224feemanager/IACP224FeeManager.sol b/graft/subnet-evm/precompile/contracts/acp224feemanager/IACP224FeeManager.sol deleted file mode 100644 index 6398ab9213d0..000000000000 --- a/graft/subnet-evm/precompile/contracts/acp224feemanager/IACP224FeeManager.sol +++ /dev/null @@ -1,45 +0,0 @@ -//SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -import "precompile/allowlist/IAllowList.sol"; - -/// @title ACP-224 Fee Manager Interface -/// @notice Interface for managing dynamic gas limit and fee parameters -/// @dev Inherits from IAllowList for access control -interface IACP224FeeManager is IAllowList { - /// @notice Configuration parameters for the dynamic fee mechanism - /// @dev Fields are ordered so each mode flag precedes the parameter(s) it governs, - /// reducing the risk of mis-ordering arguments. - struct FeeConfig { - bool validatorTargetGas; // When true, validators control targetGas via node preferences - uint256 targetGas; // Target gas consumption per second (T) - bool staticPricing; // When true, gas price is always minGasPrice - uint256 minGasPrice; // Minimum gas price in wei (M) - uint256 timeToDouble; // Seconds for gas price to double at max capacity - } - - /// @notice Emitted when fee configuration is updated - /// @param sender Address that triggered the update - /// @param oldFeeConfig Previous configuration - /// @param newFeeConfig New configuration - event FeeConfigUpdated( - address indexed sender, - FeeConfig oldFeeConfig, - FeeConfig newFeeConfig - ); - - /// @notice Set the fee configuration - /// @param config New fee configuration parameters - function setFeeConfig(FeeConfig calldata config) external; - - /// @notice Get the current fee configuration - /// @return config Current fee configuration - function getFeeConfig() external view returns (FeeConfig memory config); - - /// @notice Get the block number when fee config was last changed - /// @return blockNumber Block number of last configuration change - function getFeeConfigLastChangedAt() - external - view - returns (uint256 blockNumber); -} diff --git a/graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings/gen_iacp224feemanager_binding.go b/graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings/gen_iacp224feemanager_binding.go deleted file mode 100644 index 293153de80e0..000000000000 --- a/graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings/gen_iacp224feemanager_binding.go +++ /dev/null @@ -1,697 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package bindings - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ava-labs/libevm" - "github.com/ava-labs/libevm/accounts/abi" - "github.com/ava-labs/avalanchego/graft/subnet-evm/accounts/abi/bind" - "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/core/types" - "github.com/ava-labs/libevm/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// IACP224FeeManagerFeeConfig is an auto generated low-level Go binding around an user-defined struct. -type IACP224FeeManagerFeeConfig struct { - ValidatorTargetGas bool - TargetGas *big.Int - StaticPricing bool - MinGasPrice *big.Int - TimeToDouble *big.Int -} - -// IACP224FeeManagerMetaData contains all meta data concerning the IACP224FeeManager contract. -var IACP224FeeManagerMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"validatorTargetGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"targetGas\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"staticPricing\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"minGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeToDouble\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structIACP224FeeManager.FeeConfig\",\"name\":\"oldFeeConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"validatorTargetGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"targetGas\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"staticPricing\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"minGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeToDouble\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structIACP224FeeManager.FeeConfig\",\"name\":\"newFeeConfig\",\"type\":\"tuple\"}],\"name\":\"FeeConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"role\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldRole\",\"type\":\"uint256\"}],\"name\":\"RoleSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getFeeConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"validatorTargetGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"targetGas\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"staticPricing\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"minGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeToDouble\",\"type\":\"uint256\"}],\"internalType\":\"structIACP224FeeManager.FeeConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeConfigLastChangedAt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"readAllowList\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"role\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setEnabled\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"validatorTargetGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"targetGas\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"staticPricing\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"minGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeToDouble\",\"type\":\"uint256\"}],\"internalType\":\"structIACP224FeeManager.FeeConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setFeeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setNone\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", -} - -// IACP224FeeManagerABI is the input ABI used to generate the binding from. -// Deprecated: Use IACP224FeeManagerMetaData.ABI instead. -var IACP224FeeManagerABI = IACP224FeeManagerMetaData.ABI - -// IACP224FeeManager is an auto generated Go binding around an Ethereum contract. -type IACP224FeeManager struct { - IACP224FeeManagerCaller // Read-only binding to the contract - IACP224FeeManagerTransactor // Write-only binding to the contract - IACP224FeeManagerFilterer // Log filterer for contract events -} - -// IACP224FeeManagerCaller is an auto generated read-only Go binding around an Ethereum contract. -type IACP224FeeManagerCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// IACP224FeeManagerTransactor is an auto generated write-only Go binding around an Ethereum contract. -type IACP224FeeManagerTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// IACP224FeeManagerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type IACP224FeeManagerFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// IACP224FeeManagerSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type IACP224FeeManagerSession struct { - Contract *IACP224FeeManager // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// IACP224FeeManagerCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type IACP224FeeManagerCallerSession struct { - Contract *IACP224FeeManagerCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// IACP224FeeManagerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type IACP224FeeManagerTransactorSession struct { - Contract *IACP224FeeManagerTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// IACP224FeeManagerRaw is an auto generated low-level Go binding around an Ethereum contract. -type IACP224FeeManagerRaw struct { - Contract *IACP224FeeManager // Generic contract binding to access the raw methods on -} - -// IACP224FeeManagerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type IACP224FeeManagerCallerRaw struct { - Contract *IACP224FeeManagerCaller // Generic read-only contract binding to access the raw methods on -} - -// IACP224FeeManagerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type IACP224FeeManagerTransactorRaw struct { - Contract *IACP224FeeManagerTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewIACP224FeeManager creates a new instance of IACP224FeeManager, bound to a specific deployed contract. -func NewIACP224FeeManager(address common.Address, backend bind.ContractBackend) (*IACP224FeeManager, error) { - contract, err := bindIACP224FeeManager(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &IACP224FeeManager{IACP224FeeManagerCaller: IACP224FeeManagerCaller{contract: contract}, IACP224FeeManagerTransactor: IACP224FeeManagerTransactor{contract: contract}, IACP224FeeManagerFilterer: IACP224FeeManagerFilterer{contract: contract}}, nil -} - -// NewIACP224FeeManagerCaller creates a new read-only instance of IACP224FeeManager, bound to a specific deployed contract. -func NewIACP224FeeManagerCaller(address common.Address, caller bind.ContractCaller) (*IACP224FeeManagerCaller, error) { - contract, err := bindIACP224FeeManager(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &IACP224FeeManagerCaller{contract: contract}, nil -} - -// NewIACP224FeeManagerTransactor creates a new write-only instance of IACP224FeeManager, bound to a specific deployed contract. -func NewIACP224FeeManagerTransactor(address common.Address, transactor bind.ContractTransactor) (*IACP224FeeManagerTransactor, error) { - contract, err := bindIACP224FeeManager(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &IACP224FeeManagerTransactor{contract: contract}, nil -} - -// NewIACP224FeeManagerFilterer creates a new log filterer instance of IACP224FeeManager, bound to a specific deployed contract. -func NewIACP224FeeManagerFilterer(address common.Address, filterer bind.ContractFilterer) (*IACP224FeeManagerFilterer, error) { - contract, err := bindIACP224FeeManager(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &IACP224FeeManagerFilterer{contract: contract}, nil -} - -// bindIACP224FeeManager binds a generic wrapper to an already deployed contract. -func bindIACP224FeeManager(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := IACP224FeeManagerMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_IACP224FeeManager *IACP224FeeManagerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _IACP224FeeManager.Contract.IACP224FeeManagerCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_IACP224FeeManager *IACP224FeeManagerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.IACP224FeeManagerTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_IACP224FeeManager *IACP224FeeManagerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.IACP224FeeManagerTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_IACP224FeeManager *IACP224FeeManagerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _IACP224FeeManager.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_IACP224FeeManager *IACP224FeeManagerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_IACP224FeeManager *IACP224FeeManagerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.contract.Transact(opts, method, params...) -} - -// GetFeeConfig is a free data retrieval call binding the contract method 0x5fbbc0d2. -// -// Solidity: function getFeeConfig() view returns((bool,uint256,bool,uint256,uint256) config) -func (_IACP224FeeManager *IACP224FeeManagerCaller) GetFeeConfig(opts *bind.CallOpts) (IACP224FeeManagerFeeConfig, error) { - var out []interface{} - err := _IACP224FeeManager.contract.Call(opts, &out, "getFeeConfig") - - if err != nil { - return *new(IACP224FeeManagerFeeConfig), err - } - - out0 := *abi.ConvertType(out[0], new(IACP224FeeManagerFeeConfig)).(*IACP224FeeManagerFeeConfig) - - return out0, err - -} - -// GetFeeConfig is a free data retrieval call binding the contract method 0x5fbbc0d2. -// -// Solidity: function getFeeConfig() view returns((bool,uint256,bool,uint256,uint256) config) -func (_IACP224FeeManager *IACP224FeeManagerSession) GetFeeConfig() (IACP224FeeManagerFeeConfig, error) { - return _IACP224FeeManager.Contract.GetFeeConfig(&_IACP224FeeManager.CallOpts) -} - -// GetFeeConfig is a free data retrieval call binding the contract method 0x5fbbc0d2. -// -// Solidity: function getFeeConfig() view returns((bool,uint256,bool,uint256,uint256) config) -func (_IACP224FeeManager *IACP224FeeManagerCallerSession) GetFeeConfig() (IACP224FeeManagerFeeConfig, error) { - return _IACP224FeeManager.Contract.GetFeeConfig(&_IACP224FeeManager.CallOpts) -} - -// GetFeeConfigLastChangedAt is a free data retrieval call binding the contract method 0x9e05549a. -// -// Solidity: function getFeeConfigLastChangedAt() view returns(uint256 blockNumber) -func (_IACP224FeeManager *IACP224FeeManagerCaller) GetFeeConfigLastChangedAt(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _IACP224FeeManager.contract.Call(opts, &out, "getFeeConfigLastChangedAt") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetFeeConfigLastChangedAt is a free data retrieval call binding the contract method 0x9e05549a. -// -// Solidity: function getFeeConfigLastChangedAt() view returns(uint256 blockNumber) -func (_IACP224FeeManager *IACP224FeeManagerSession) GetFeeConfigLastChangedAt() (*big.Int, error) { - return _IACP224FeeManager.Contract.GetFeeConfigLastChangedAt(&_IACP224FeeManager.CallOpts) -} - -// GetFeeConfigLastChangedAt is a free data retrieval call binding the contract method 0x9e05549a. -// -// Solidity: function getFeeConfigLastChangedAt() view returns(uint256 blockNumber) -func (_IACP224FeeManager *IACP224FeeManagerCallerSession) GetFeeConfigLastChangedAt() (*big.Int, error) { - return _IACP224FeeManager.Contract.GetFeeConfigLastChangedAt(&_IACP224FeeManager.CallOpts) -} - -// ReadAllowList is a free data retrieval call binding the contract method 0xeb54dae1. -// -// Solidity: function readAllowList(address addr) view returns(uint256 role) -func (_IACP224FeeManager *IACP224FeeManagerCaller) ReadAllowList(opts *bind.CallOpts, addr common.Address) (*big.Int, error) { - var out []interface{} - err := _IACP224FeeManager.contract.Call(opts, &out, "readAllowList", addr) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// ReadAllowList is a free data retrieval call binding the contract method 0xeb54dae1. -// -// Solidity: function readAllowList(address addr) view returns(uint256 role) -func (_IACP224FeeManager *IACP224FeeManagerSession) ReadAllowList(addr common.Address) (*big.Int, error) { - return _IACP224FeeManager.Contract.ReadAllowList(&_IACP224FeeManager.CallOpts, addr) -} - -// ReadAllowList is a free data retrieval call binding the contract method 0xeb54dae1. -// -// Solidity: function readAllowList(address addr) view returns(uint256 role) -func (_IACP224FeeManager *IACP224FeeManagerCallerSession) ReadAllowList(addr common.Address) (*big.Int, error) { - return _IACP224FeeManager.Contract.ReadAllowList(&_IACP224FeeManager.CallOpts, addr) -} - -// SetAdmin is a paid mutator transaction binding the contract method 0x704b6c02. -// -// Solidity: function setAdmin(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerTransactor) SetAdmin(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.contract.Transact(opts, "setAdmin", addr) -} - -// SetAdmin is a paid mutator transaction binding the contract method 0x704b6c02. -// -// Solidity: function setAdmin(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerSession) SetAdmin(addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.SetAdmin(&_IACP224FeeManager.TransactOpts, addr) -} - -// SetAdmin is a paid mutator transaction binding the contract method 0x704b6c02. -// -// Solidity: function setAdmin(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerTransactorSession) SetAdmin(addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.SetAdmin(&_IACP224FeeManager.TransactOpts, addr) -} - -// SetEnabled is a paid mutator transaction binding the contract method 0x0aaf7043. -// -// Solidity: function setEnabled(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerTransactor) SetEnabled(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.contract.Transact(opts, "setEnabled", addr) -} - -// SetEnabled is a paid mutator transaction binding the contract method 0x0aaf7043. -// -// Solidity: function setEnabled(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerSession) SetEnabled(addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.SetEnabled(&_IACP224FeeManager.TransactOpts, addr) -} - -// SetEnabled is a paid mutator transaction binding the contract method 0x0aaf7043. -// -// Solidity: function setEnabled(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerTransactorSession) SetEnabled(addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.SetEnabled(&_IACP224FeeManager.TransactOpts, addr) -} - -// SetFeeConfig is a paid mutator transaction binding the contract method 0x77954fb2. -// -// Solidity: function setFeeConfig((bool,uint256,bool,uint256,uint256) config) returns() -func (_IACP224FeeManager *IACP224FeeManagerTransactor) SetFeeConfig(opts *bind.TransactOpts, config IACP224FeeManagerFeeConfig) (*types.Transaction, error) { - return _IACP224FeeManager.contract.Transact(opts, "setFeeConfig", config) -} - -// SetFeeConfig is a paid mutator transaction binding the contract method 0x77954fb2. -// -// Solidity: function setFeeConfig((bool,uint256,bool,uint256,uint256) config) returns() -func (_IACP224FeeManager *IACP224FeeManagerSession) SetFeeConfig(config IACP224FeeManagerFeeConfig) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.SetFeeConfig(&_IACP224FeeManager.TransactOpts, config) -} - -// SetFeeConfig is a paid mutator transaction binding the contract method 0x77954fb2. -// -// Solidity: function setFeeConfig((bool,uint256,bool,uint256,uint256) config) returns() -func (_IACP224FeeManager *IACP224FeeManagerTransactorSession) SetFeeConfig(config IACP224FeeManagerFeeConfig) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.SetFeeConfig(&_IACP224FeeManager.TransactOpts, config) -} - -// SetManager is a paid mutator transaction binding the contract method 0xd0ebdbe7. -// -// Solidity: function setManager(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerTransactor) SetManager(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.contract.Transact(opts, "setManager", addr) -} - -// SetManager is a paid mutator transaction binding the contract method 0xd0ebdbe7. -// -// Solidity: function setManager(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerSession) SetManager(addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.SetManager(&_IACP224FeeManager.TransactOpts, addr) -} - -// SetManager is a paid mutator transaction binding the contract method 0xd0ebdbe7. -// -// Solidity: function setManager(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerTransactorSession) SetManager(addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.SetManager(&_IACP224FeeManager.TransactOpts, addr) -} - -// SetNone is a paid mutator transaction binding the contract method 0x8c6bfb3b. -// -// Solidity: function setNone(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerTransactor) SetNone(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.contract.Transact(opts, "setNone", addr) -} - -// SetNone is a paid mutator transaction binding the contract method 0x8c6bfb3b. -// -// Solidity: function setNone(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerSession) SetNone(addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.SetNone(&_IACP224FeeManager.TransactOpts, addr) -} - -// SetNone is a paid mutator transaction binding the contract method 0x8c6bfb3b. -// -// Solidity: function setNone(address addr) returns() -func (_IACP224FeeManager *IACP224FeeManagerTransactorSession) SetNone(addr common.Address) (*types.Transaction, error) { - return _IACP224FeeManager.Contract.SetNone(&_IACP224FeeManager.TransactOpts, addr) -} - -// IACP224FeeManagerFeeConfigUpdatedIterator is returned from FilterFeeConfigUpdated and is used to iterate over the raw logs and unpacked data for FeeConfigUpdated events raised by the IACP224FeeManager contract. -type IACP224FeeManagerFeeConfigUpdatedIterator struct { - Event *IACP224FeeManagerFeeConfigUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *IACP224FeeManagerFeeConfigUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(IACP224FeeManagerFeeConfigUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(IACP224FeeManagerFeeConfigUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *IACP224FeeManagerFeeConfigUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *IACP224FeeManagerFeeConfigUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// IACP224FeeManagerFeeConfigUpdated represents a FeeConfigUpdated event raised by the IACP224FeeManager contract. -type IACP224FeeManagerFeeConfigUpdated struct { - Sender common.Address - OldFeeConfig IACP224FeeManagerFeeConfig - NewFeeConfig IACP224FeeManagerFeeConfig - Raw types.Log // Blockchain specific contextual infos -} - -// FilterFeeConfigUpdated is a free log retrieval operation binding the contract event 0x9efcd525309619a819a671641a5e57f40370865dbcdaacec4c3c9901a3574269. -// -// Solidity: event FeeConfigUpdated(address indexed sender, (bool,uint256,bool,uint256,uint256) oldFeeConfig, (bool,uint256,bool,uint256,uint256) newFeeConfig) -func (_IACP224FeeManager *IACP224FeeManagerFilterer) FilterFeeConfigUpdated(opts *bind.FilterOpts, sender []common.Address) (*IACP224FeeManagerFeeConfigUpdatedIterator, error) { - - var senderRule []interface{} - for _, senderItem := range sender { - senderRule = append(senderRule, senderItem) - } - - logs, sub, err := _IACP224FeeManager.contract.FilterLogs(opts, "FeeConfigUpdated", senderRule) - if err != nil { - return nil, err - } - return &IACP224FeeManagerFeeConfigUpdatedIterator{contract: _IACP224FeeManager.contract, event: "FeeConfigUpdated", logs: logs, sub: sub}, nil -} - -// WatchFeeConfigUpdated is a free log subscription operation binding the contract event 0x9efcd525309619a819a671641a5e57f40370865dbcdaacec4c3c9901a3574269. -// -// Solidity: event FeeConfigUpdated(address indexed sender, (bool,uint256,bool,uint256,uint256) oldFeeConfig, (bool,uint256,bool,uint256,uint256) newFeeConfig) -func (_IACP224FeeManager *IACP224FeeManagerFilterer) WatchFeeConfigUpdated(opts *bind.WatchOpts, sink chan<- *IACP224FeeManagerFeeConfigUpdated, sender []common.Address) (event.Subscription, error) { - - var senderRule []interface{} - for _, senderItem := range sender { - senderRule = append(senderRule, senderItem) - } - - logs, sub, err := _IACP224FeeManager.contract.WatchLogs(opts, "FeeConfigUpdated", senderRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(IACP224FeeManagerFeeConfigUpdated) - if err := _IACP224FeeManager.contract.UnpackLog(event, "FeeConfigUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseFeeConfigUpdated is a log parse operation binding the contract event 0x9efcd525309619a819a671641a5e57f40370865dbcdaacec4c3c9901a3574269. -// -// Solidity: event FeeConfigUpdated(address indexed sender, (bool,uint256,bool,uint256,uint256) oldFeeConfig, (bool,uint256,bool,uint256,uint256) newFeeConfig) -func (_IACP224FeeManager *IACP224FeeManagerFilterer) ParseFeeConfigUpdated(log types.Log) (*IACP224FeeManagerFeeConfigUpdated, error) { - event := new(IACP224FeeManagerFeeConfigUpdated) - if err := _IACP224FeeManager.contract.UnpackLog(event, "FeeConfigUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// IACP224FeeManagerRoleSetIterator is returned from FilterRoleSet and is used to iterate over the raw logs and unpacked data for RoleSet events raised by the IACP224FeeManager contract. -type IACP224FeeManagerRoleSetIterator struct { - Event *IACP224FeeManagerRoleSet // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *IACP224FeeManagerRoleSetIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(IACP224FeeManagerRoleSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(IACP224FeeManagerRoleSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *IACP224FeeManagerRoleSetIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *IACP224FeeManagerRoleSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// IACP224FeeManagerRoleSet represents a RoleSet event raised by the IACP224FeeManager contract. -type IACP224FeeManagerRoleSet struct { - Role *big.Int - Account common.Address - Sender common.Address - OldRole *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRoleSet is a free log retrieval operation binding the contract event 0xcdb7ea01f00a414d78757bdb0f6391664ba3fedf987eed280927c1e7d695be3e. -// -// Solidity: event RoleSet(uint256 indexed role, address indexed account, address indexed sender, uint256 oldRole) -func (_IACP224FeeManager *IACP224FeeManagerFilterer) FilterRoleSet(opts *bind.FilterOpts, role []*big.Int, account []common.Address, sender []common.Address) (*IACP224FeeManagerRoleSetIterator, error) { - - var roleRule []interface{} - for _, roleItem := range role { - roleRule = append(roleRule, roleItem) - } - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - var senderRule []interface{} - for _, senderItem := range sender { - senderRule = append(senderRule, senderItem) - } - - logs, sub, err := _IACP224FeeManager.contract.FilterLogs(opts, "RoleSet", roleRule, accountRule, senderRule) - if err != nil { - return nil, err - } - return &IACP224FeeManagerRoleSetIterator{contract: _IACP224FeeManager.contract, event: "RoleSet", logs: logs, sub: sub}, nil -} - -// WatchRoleSet is a free log subscription operation binding the contract event 0xcdb7ea01f00a414d78757bdb0f6391664ba3fedf987eed280927c1e7d695be3e. -// -// Solidity: event RoleSet(uint256 indexed role, address indexed account, address indexed sender, uint256 oldRole) -func (_IACP224FeeManager *IACP224FeeManagerFilterer) WatchRoleSet(opts *bind.WatchOpts, sink chan<- *IACP224FeeManagerRoleSet, role []*big.Int, account []common.Address, sender []common.Address) (event.Subscription, error) { - - var roleRule []interface{} - for _, roleItem := range role { - roleRule = append(roleRule, roleItem) - } - var accountRule []interface{} - for _, accountItem := range account { - accountRule = append(accountRule, accountItem) - } - var senderRule []interface{} - for _, senderItem := range sender { - senderRule = append(senderRule, senderItem) - } - - logs, sub, err := _IACP224FeeManager.contract.WatchLogs(opts, "RoleSet", roleRule, accountRule, senderRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(IACP224FeeManagerRoleSet) - if err := _IACP224FeeManager.contract.UnpackLog(event, "RoleSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRoleSet is a log parse operation binding the contract event 0xcdb7ea01f00a414d78757bdb0f6391664ba3fedf987eed280927c1e7d695be3e. -// -// Solidity: event RoleSet(uint256 indexed role, address indexed account, address indexed sender, uint256 oldRole) -func (_IACP224FeeManager *IACP224FeeManagerFilterer) ParseRoleSet(log types.Log) (*IACP224FeeManagerRoleSet, error) { - event := new(IACP224FeeManagerRoleSet) - if err := _IACP224FeeManager.contract.UnpackLog(event, "RoleSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/graft/subnet-evm/precompile/contracts/gaspricemanager/BUILD.bazel b/graft/subnet-evm/precompile/contracts/gaspricemanager/BUILD.bazel new file mode 100644 index 000000000000..6b476640927b --- /dev/null +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/BUILD.bazel @@ -0,0 +1,54 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("//.bazel:defs.bzl", "graft_go_test") + +go_library( + name = "gaspricemanager", + srcs = [ + "config.go", + "contract.go", + "event.go", + "module.go", + ], + embedsrcs = ["IGasPriceManager.abi"], + importpath = "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contracts/gaspricemanager", + visibility = ["//visibility:public"], + deps = [ + "//graft/subnet-evm/commontype", + "//graft/subnet-evm/precompile/allowlist", + "//graft/subnet-evm/precompile/contract", + "//graft/subnet-evm/precompile/modules", + "//graft/subnet-evm/precompile/precompileconfig", + "@com_github_ava_labs_libevm//accounts/abi", + "@com_github_ava_labs_libevm//common", + "@com_github_ava_labs_libevm//core/types", + "@com_github_ava_labs_libevm//core/vm", + ], +) + +graft_go_test( + name = "gaspricemanager_test", + srcs = [ + "config_test.go", + "contract_test.go", + ], + embed = [":gaspricemanager"], + deps = [ + "//graft/subnet-evm/commontype", + "//graft/subnet-evm/core/extstate", + "//graft/subnet-evm/precompile/allowlist", + "//graft/subnet-evm/precompile/allowlist/allowlisttest", + "//graft/subnet-evm/precompile/contract", + "//graft/subnet-evm/precompile/precompileconfig", + "//graft/subnet-evm/precompile/precompiletest", + "//utils", + "@com_github_ava_labs_libevm//common", + "@com_github_ava_labs_libevm//core/vm", + "@com_github_stretchr_testify//require", + "@org_uber_go_mock//gomock", + ], +) + +package(default_visibility = [ + "//graft/subnet-evm:__subpackages__", + "//graft/subnet-evm:external_consumers", +]) diff --git a/graft/subnet-evm/precompile/contracts/acp224feemanager/IACP224FeeManager.abi b/graft/subnet-evm/precompile/contracts/gaspricemanager/IGasPriceManager.abi similarity index 78% rename from graft/subnet-evm/precompile/contracts/acp224feemanager/IACP224FeeManager.abi rename to graft/subnet-evm/precompile/contracts/gaspricemanager/IGasPriceManager.abi index 64f17bc868ac..8813033f5270 100644 --- a/graft/subnet-evm/precompile/contracts/acp224feemanager/IACP224FeeManager.abi +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/IGasPriceManager.abi @@ -16,9 +16,9 @@ "type": "bool" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "targetGas", - "type": "uint256" + "type": "uint64" }, { "internalType": "bool", @@ -26,19 +26,19 @@ "type": "bool" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "minGasPrice", - "type": "uint256" + "type": "uint64" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "timeToDouble", - "type": "uint256" + "type": "uint64" } ], "indexed": false, - "internalType": "struct IACP224FeeManager.FeeConfig", - "name": "oldFeeConfig", + "internalType": "struct IGasPriceManager.GasPriceConfig", + "name": "oldGasPriceConfig", "type": "tuple" }, { @@ -49,9 +49,9 @@ "type": "bool" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "targetGas", - "type": "uint256" + "type": "uint64" }, { "internalType": "bool", @@ -59,23 +59,23 @@ "type": "bool" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "minGasPrice", - "type": "uint256" + "type": "uint64" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "timeToDouble", - "type": "uint256" + "type": "uint64" } ], "indexed": false, - "internalType": "struct IACP224FeeManager.FeeConfig", - "name": "newFeeConfig", + "internalType": "struct IGasPriceManager.GasPriceConfig", + "name": "newGasPriceConfig", "type": "tuple" } ], - "name": "FeeConfigUpdated", + "name": "GasPriceConfigUpdated", "type": "event" }, { @@ -111,7 +111,7 @@ }, { "inputs": [], - "name": "getFeeConfig", + "name": "getGasPriceConfig", "outputs": [ { "components": [ @@ -121,9 +121,9 @@ "type": "bool" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "targetGas", - "type": "uint256" + "type": "uint64" }, { "internalType": "bool", @@ -131,17 +131,17 @@ "type": "bool" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "minGasPrice", - "type": "uint256" + "type": "uint64" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "timeToDouble", - "type": "uint256" + "type": "uint64" } ], - "internalType": "struct IACP224FeeManager.FeeConfig", + "internalType": "struct IGasPriceManager.GasPriceConfig", "name": "config", "type": "tuple" } @@ -151,7 +151,7 @@ }, { "inputs": [], - "name": "getFeeConfigLastChangedAt", + "name": "getGasPriceConfigLastChangedAt", "outputs": [ { "internalType": "uint256", @@ -217,9 +217,9 @@ "type": "bool" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "targetGas", - "type": "uint256" + "type": "uint64" }, { "internalType": "bool", @@ -227,22 +227,22 @@ "type": "bool" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "minGasPrice", - "type": "uint256" + "type": "uint64" }, { - "internalType": "uint256", + "internalType": "uint64", "name": "timeToDouble", - "type": "uint256" + "type": "uint64" } ], - "internalType": "struct IACP224FeeManager.FeeConfig", + "internalType": "struct IGasPriceManager.GasPriceConfig", "name": "config", "type": "tuple" } ], - "name": "setFeeConfig", + "name": "setGasPriceConfig", "outputs": [], "stateMutability": "nonpayable", "type": "function" diff --git a/graft/subnet-evm/precompile/contracts/gaspricemanager/IGasPriceManager.sol b/graft/subnet-evm/precompile/contracts/gaspricemanager/IGasPriceManager.sol new file mode 100644 index 000000000000..203cefdc8089 --- /dev/null +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/IGasPriceManager.sol @@ -0,0 +1,45 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "precompile/allowlist/IAllowList.sol"; + +/// @title Gas Price Manager Interface +/// @notice Interface for managing dynamic gas limit and gas price parameters +/// @dev Inherits from IAllowList for access control +interface IGasPriceManager is IAllowList { + /// @notice Configuration parameters for the dynamic gas price mechanism + /// @dev Fields are ordered so each mode flag precedes the parameter(s) it governs, + /// reducing the risk of mis-ordering arguments. + struct GasPriceConfig { + bool validatorTargetGas; // When true, validators control targetGas via node preferences + uint64 targetGas; // Target gas consumption per second (T) + bool staticPricing; // When true, gas price is always minGasPrice + uint64 minGasPrice; // Minimum gas price in wei (M) + uint64 timeToDouble; // Seconds for gas price to double at max capacity + } + + /// @notice Emitted when the gas price configuration is updated + /// @param sender Address that triggered the update + /// @param oldGasPriceConfig Previous configuration + /// @param newGasPriceConfig New configuration + event GasPriceConfigUpdated( + address indexed sender, + GasPriceConfig oldGasPriceConfig, + GasPriceConfig newGasPriceConfig + ); + + /// @notice Set the gas price configuration + /// @param config New gas price configuration parameters + function setGasPriceConfig(GasPriceConfig calldata config) external; + + /// @notice Get the current gas price configuration + /// @return config Current gas price configuration + function getGasPriceConfig() external view returns (GasPriceConfig memory config); + + /// @notice Get the block number when the gas price config was last changed + /// @return blockNumber Block number of last configuration change + function getGasPriceConfigLastChangedAt() + external + view + returns (uint256 blockNumber); +} diff --git a/graft/subnet-evm/precompile/contracts/gaspricemanager/config.go b/graft/subnet-evm/precompile/contracts/gaspricemanager/config.go new file mode 100644 index 000000000000..cb6a3e5f9761 --- /dev/null +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/config.go @@ -0,0 +1,80 @@ +// Copyright (C) 2019, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package gaspricemanager + +import ( + "github.com/ava-labs/libevm/common" + + "github.com/ava-labs/avalanchego/graft/subnet-evm/commontype" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/allowlist" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/precompileconfig" +) + +var _ precompileconfig.Config = (*Config)(nil) + +// Config is the configuration for the gas price manager precompile. +// It specifies: +// - when the precompile is activated ([precompileconfig.Upgrade]) +// - who may call it ([allowlist.AllowListConfig]) +// - an optional initial gas price config ([commontype.GasPriceConfig]) to write to contract storage on activation. +type Config struct { + allowlist.AllowListConfig + precompileconfig.Upgrade + InitialGasPriceConfig *commontype.GasPriceConfig `json:"initialGasPriceConfig,omitempty"` // activated immediately on precompile enable if provided +} + +// NewConfig returns a config that enables GasPriceManager at `blockTimestamp`. +func NewConfig(blockTimestamp *uint64, admins []common.Address, enabled []common.Address, managers []common.Address, initialConfig *commontype.GasPriceConfig) *Config { + return &Config{ + AllowListConfig: allowlist.AllowListConfig{ + AdminAddresses: admins, + EnabledAddresses: enabled, + ManagerAddresses: managers, + }, + Upgrade: precompileconfig.Upgrade{BlockTimestamp: blockTimestamp}, + InitialGasPriceConfig: initialConfig, + } +} + +// NewDisableConfig returns a config that disables GasPriceManager at `blockTimestamp`. +func NewDisableConfig(blockTimestamp *uint64) *Config { + return &Config{ + Upgrade: precompileconfig.Upgrade{ + BlockTimestamp: blockTimestamp, + Disable: true, + }, + } +} + +// Key must match ConfigKey used in the precompile module. +func (*Config) Key() string { return ConfigKey } + +// Equal returns true if [cfg] is a *Config identical to [c]. +func (c *Config) Equal(cfg precompileconfig.Config) bool { + if c == nil { + return cfg == nil + } + other, ok := (cfg).(*Config) + if !ok || other == nil { + return false + } + eq := c.Upgrade.Equal(&other.Upgrade) && c.AllowListConfig.Equal(&other.AllowListConfig) + if !eq { + return false + } + + return c.InitialGasPriceConfig.Equal(other.InitialGasPriceConfig) +} + +// Verify validates the allow list config and, if set, the initial gas price config. +func (c *Config) Verify(chainConfig precompileconfig.ChainConfig) error { + if err := c.AllowListConfig.Verify(chainConfig, c.Upgrade); err != nil { + return err + } + if c.InitialGasPriceConfig == nil { + return nil + } + + return c.InitialGasPriceConfig.Verify() +} diff --git a/graft/subnet-evm/precompile/contracts/gaspricemanager/config_test.go b/graft/subnet-evm/precompile/contracts/gaspricemanager/config_test.go new file mode 100644 index 000000000000..2aaa9ab34e24 --- /dev/null +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/config_test.go @@ -0,0 +1,94 @@ +// Copyright (C) 2019, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package gaspricemanager_test + +import ( + "testing" + + "github.com/ava-labs/libevm/common" + "go.uber.org/mock/gomock" + + "github.com/ava-labs/avalanchego/graft/subnet-evm/commontype" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/allowlist/allowlisttest" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contracts/gaspricemanager" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/precompileconfig" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/precompiletest" + "github.com/ava-labs/avalanchego/utils" +) + +func TestVerify(t *testing.T) { + admins := []common.Address{allowlisttest.TestAdminAddr} + + // Field-level validation is covered in commontype.TestGasPriceConfigVerify. + // Here we only test that Config.Verify delegates to InitialGasPriceConfig.Verify. + tests := map[string]precompiletest.ConfigVerifyTest{ + "nil initialGasPriceConfig": { + Config: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, nil, nil, nil), + }, + "valid initialGasPriceConfig": { + Config: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, nil, nil, utils.PointerTo(commontype.DefaultGasPriceConfig())), + }, + "invalid initialGasPriceConfig": { + Config: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, nil, nil, &commontype.GasPriceConfig{ + TargetGas: commontype.MinTargetGas, + TimeToDouble: 60, + }), + ExpectedError: commontype.ErrMinGasPriceTooLow, + }, + } + allowlisttest.VerifyPrecompileWithAllowListTests(t, gaspricemanager.Module, tests) +} + +func TestEqual(t *testing.T) { + admins := []common.Address{allowlisttest.TestAdminAddr} + enableds := []common.Address{allowlisttest.TestEnabledAddr} + tests := map[string]precompiletest.ConfigEqualTest{ + "non-nil config and nil other": { + Config: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, enableds, nil, nil), + Other: nil, + Expected: false, + }, + "typed nil config and typed nil other": { + Config: (*gaspricemanager.Config)(nil), + Other: (*gaspricemanager.Config)(nil), + Expected: false, + }, + "typed nil config and nil other": { + Config: (*gaspricemanager.Config)(nil), + Other: nil, + Expected: true, + }, + "different type": { + Config: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, enableds, nil, nil), + Other: precompileconfig.NewMockConfig(gomock.NewController(t)), + Expected: false, + }, + "different timestamp": { + Config: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, nil, nil, nil), + Other: gaspricemanager.NewConfig(utils.PointerTo[uint64](4), admins, nil, nil, nil), + Expected: false, + }, + "non-nil initial config and nil initial config": { + Config: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, nil, nil, utils.PointerTo(commontype.DefaultGasPriceConfig())), + Other: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, nil, nil, nil), + Expected: false, + }, + "different initial config": { + Config: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, nil, nil, utils.PointerTo(commontype.DefaultGasPriceConfig())), + Other: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, nil, nil, + func() *commontype.GasPriceConfig { + c := commontype.DefaultGasPriceConfig() + c.TargetGas = 20_000_000 + return &c + }()), + Expected: false, + }, + "same config": { + Config: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, nil, nil, utils.PointerTo(commontype.DefaultGasPriceConfig())), + Other: gaspricemanager.NewConfig(utils.PointerTo[uint64](3), admins, nil, nil, utils.PointerTo(commontype.DefaultGasPriceConfig())), + Expected: true, + }, + } + allowlisttest.EqualPrecompileWithAllowListTests(t, gaspricemanager.Module, tests) +} diff --git a/graft/subnet-evm/precompile/contracts/gaspricemanager/contract.go b/graft/subnet-evm/precompile/contracts/gaspricemanager/contract.go new file mode 100644 index 000000000000..6de9828c77d7 --- /dev/null +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/contract.go @@ -0,0 +1,295 @@ +// Copyright (C) 2019, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package gaspricemanager + +import ( + "errors" + "fmt" + "math/big" + + "github.com/ava-labs/libevm/accounts/abi" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/core/vm" + + _ "embed" + + "github.com/ava-labs/avalanchego/graft/subnet-evm/commontype" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/allowlist" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contract" +) + +//go:embed IGasPriceManager.abi +var GasPriceManagerRawABI string + +var GasPriceManagerABI = contract.ParseABI(GasPriceManagerRawABI) + +const ( + numGasPriceConfigField = 5 // validatorTargetGas, targetGas, staticPricing, minGasPrice, timeToDouble + + getGasPriceConfigGasCost uint64 = contract.ReadGasCostPerSlot + getGasPriceConfigLastChangedAtGasCost uint64 = contract.ReadGasCostPerSlot + // GasPriceConfigUpdated has 2 topics (event sig + indexed sender) and non-indexed + // data containing old + new GasPriceConfig. Each config has numGasPriceConfigField + // static fields, each ABI-encoded as a 32-byte word, so the total data size + // is numGasPriceConfigField * 32 bytes * 2 configs. + gasPriceConfigUpdatedEventGasCost uint64 = contract.LogGas + contract.LogTopicGas*2 + contract.LogDataGas*numGasPriceConfigField*common.HashLength*2 + setGasPriceConfigGasCost uint64 = allowlist.ReadAllowListGasCost + + contract.WriteGasCostPerSlot*2 + // gas price config slot + lastChangedAt slot + getGasPriceConfigGasCost + // reading old config for event + gasPriceConfigUpdatedEventGasCost +) + +var ( + errCannotSetGasPriceConfig = errors.New("non-enabled cannot call setGasPriceConfig") + errInvalidABIConfig = errors.New("failed to convert ABI config") + errNilBlockNumber = errors.New("block number cannot be nil") +) + +var gasPriceManagerPrecompile = createGasPriceManagerPrecompile() + +func createGasPriceManagerPrecompile() contract.StatefulPrecompiledContract { + abiFunctionMap := map[string]contract.RunStatefulPrecompileFunc{ + "getGasPriceConfig": getGasPriceConfig, + "getGasPriceConfigLastChangedAt": getGasPriceConfigLastChangedAt, + "setGasPriceConfig": setGasPriceConfig, + } + functions := make([]*contract.StatefulPrecompileFunction, 0, len(abiFunctionMap)+len(allowlist.AllowListABI.Methods)) + functions = append(functions, allowlist.CreateAllowListFunctions(ContractAddress)...) + + for name, function := range abiFunctionMap { + method, ok := GasPriceManagerABI.Methods[name] + if !ok { + panic(fmt.Errorf("given method (%s) does not exist in the ABI", name)) + } + functions = append(functions, contract.NewStatefulPrecompileFunction(method.ID, function)) + } + statefulContract, err := contract.NewStatefulPrecompileContract(nil, functions) // nil = no fallback + if err != nil { + panic(err) + } + return statefulContract +} + +// getGasPriceConfig + +//nolint:revive // unused params are part of RunStatefulPrecompileFunc signature +func getGasPriceConfig( + accessibleState contract.AccessibleState, + caller common.Address, + self common.Address, // EVM-semantic self; see libevm.AddressContext + input []byte, // ignored + suppliedGas uint64, + readOnly bool, // ignored - method only reads +) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = contract.DeductGas(suppliedGas, getGasPriceConfigGasCost); err != nil { + return nil, 0, err + } + + gasPriceConfig := GetStoredGasPriceConfig(accessibleState.GetStateDB(), self) + + output, err := PackGetGasPriceConfigOutput(gasPriceConfig) + if err != nil { + return nil, remainingGas, err + } + + return output, remainingGas, nil +} + +// PackGetGasPriceConfig packs the getGasPriceConfig calldata including the 4-byte selector. +func PackGetGasPriceConfig() ([]byte, error) { + return GasPriceManagerABI.Pack("getGasPriceConfig") +} + +// PackGetGasPriceConfigOutput ABI-encodes [config] as getGasPriceConfig return data. +func PackGetGasPriceConfigOutput(config commontype.GasPriceConfig) ([]byte, error) { + return GasPriceManagerABI.PackOutput("getGasPriceConfig", config) +} + +// UnpackGetGasPriceConfigOutput decodes ABI-encoded getGasPriceConfig return data. +func UnpackGetGasPriceConfigOutput(output []byte) (commontype.GasPriceConfig, error) { + var config commontype.GasPriceConfig + err := GasPriceManagerABI.UnpackIntoInterface(&config, "getGasPriceConfig", output) + return config, err +} + +// getGasPriceConfigLastChangedAt + +//nolint:revive // unused params are part of RunStatefulPrecompileFunc signature +func getGasPriceConfigLastChangedAt( + accessibleState contract.AccessibleState, + caller common.Address, + self common.Address, // EVM-semantic self; see libevm.AddressContext + input []byte, // ignored + suppliedGas uint64, + readOnly bool, // ignored - method only reads +) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = contract.DeductGas(suppliedGas, getGasPriceConfigLastChangedAtGasCost); err != nil { + return nil, 0, err + } + + lastChangedAt := GetGasPriceConfigLastChangedAt(accessibleState.GetStateDB(), self) + packedOutput, err := PackGetGasPriceConfigLastChangedAtOutput(lastChangedAt) + if err != nil { + return nil, remainingGas, err + } + + return packedOutput, remainingGas, nil +} + +// PackGetGasPriceConfigLastChangedAt packs the calldata including the 4-byte selector. +func PackGetGasPriceConfigLastChangedAt() ([]byte, error) { + return GasPriceManagerABI.Pack("getGasPriceConfigLastChangedAt") +} + +// PackGetGasPriceConfigLastChangedAtOutput ABI-encodes [blockNumber] as return data. +func PackGetGasPriceConfigLastChangedAtOutput(blockNumber *big.Int) ([]byte, error) { + return GasPriceManagerABI.PackOutput("getGasPriceConfigLastChangedAt", blockNumber) +} + +// UnpackGetGasPriceConfigLastChangedAtOutput decodes ABI-encoded return data. +func UnpackGetGasPriceConfigLastChangedAtOutput(output []byte) (*big.Int, error) { + res, err := GasPriceManagerABI.Unpack("getGasPriceConfigLastChangedAt", output) + if err != nil { + return nil, err + } + unpacked := *abi.ConvertType(res[0], new(*big.Int)).(**big.Int) + return unpacked, nil +} + +// setGasPriceConfig + +func setGasPriceConfig( + accessibleState contract.AccessibleState, + caller common.Address, + self common.Address, // EVM-semantic self; see libevm.AddressContext + input []byte, + suppliedGas uint64, + readOnly bool, +) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = contract.DeductGas(suppliedGas, setGasPriceConfigGasCost); err != nil { + return nil, 0, err + } + + if readOnly { + return nil, remainingGas, vm.ErrWriteProtection + } + + stateDB := accessibleState.GetStateDB() + callerStatus := GetGasPriceManagerAllowListStatus(stateDB, self, caller) + if !callerStatus.IsEnabled() { + return nil, remainingGas, fmt.Errorf("%w: %s", errCannotSetGasPriceConfig, caller) + } + + gasPriceConfig, err := UnpackSetGasPriceConfigInput(input) + if err != nil { + return nil, remainingGas, err + } + + blockNumber := accessibleState.GetBlockContext().Number() + if blockNumber == nil { + return nil, remainingGas, errNilBlockNumber + } + + oldConfig := GetStoredGasPriceConfig(stateDB, self) + + if err := StoreGasPriceConfig(stateDB, self, gasPriceConfig, blockNumber); err != nil { + return nil, remainingGas, err + } + topics, data, err := PackGasPriceConfigUpdatedEvent( + caller, + oldConfig, + gasPriceConfig, + ) + if err != nil { + return nil, remainingGas, err + } + + stateDB.AddLog(&types.Log{ + Address: self, + Topics: topics, + Data: data, + BlockNumber: blockNumber.Uint64(), + }) + + return []byte{}, remainingGas, nil +} + +// PackSetGasPriceConfig packs [config] into ABI-encoded calldata including the 4-byte selector. +func PackSetGasPriceConfig(config commontype.GasPriceConfig) ([]byte, error) { + return GasPriceManagerABI.Pack("setGasPriceConfig", config) +} + +// UnpackSetGasPriceConfigInput assumes [input] does not include the 4-byte selector. +func UnpackSetGasPriceConfigInput(input []byte) (commontype.GasPriceConfig, error) { + // UnpackInputIntoInterface doesn't work for single-tuple arguments: copyAtomic + // tries to assign the whole tuple to the first struct field (a bool), causing a + // type mismatch. Use method.Inputs.Unpack + abi.ConvertType instead. + method, ok := GasPriceManagerABI.Methods["setGasPriceConfig"] + if !ok { + return commontype.GasPriceConfig{}, errors.New("method setGasPriceConfig not found") + } + res, err := method.Inputs.Unpack(input) + if err != nil { + return commontype.GasPriceConfig{}, err + } + config, ok := abi.ConvertType(res[0], new(commontype.GasPriceConfig)).(*commontype.GasPriceConfig) + if !ok { + return commontype.GasPriceConfig{}, errInvalidABIConfig + } + return *config, nil +} + +// storageSlot returns a storage key with the "gasprm" namespace prefix +// left-aligned in the hash. This avoids collisions with AllowList role +// storage, which right-aligns 20-byte addresses via BytesToHash and +// therefore always has 12 leading zero bytes. +func storageSlot(key ...byte) common.Hash { + s := common.Hash{'g', 'a', 's', 'p', 'r', 'm'} + copy(s[6:], key) + return s +} + +var ( + gasPriceConfigStorageKey = storageSlot('g', 'p') + gasPriceConfigLastChangedAtKey = storageSlot('l', 'c', 'a') +) + +// GetGasPriceManagerAllowListStatus returns the role of `address` for the allowlist. +func GetGasPriceManagerAllowListStatus(stateDB contract.StateReader, contractAddr common.Address, address common.Address) allowlist.Role { + return allowlist.GetAllowListStatus(stateDB, contractAddr, address) +} + +// SetGasPriceManagerAllowListStatus assumes [role] has already been verified as valid. +// Roles are stored keyed by address hash, so precompile storage keys must not collide +// with address-derived keys. +func SetGasPriceManagerAllowListStatus(stateDB contract.StateDB, contractAddr common.Address, address common.Address, role allowlist.Role) { + allowlist.SetAllowListRole(stateDB, contractAddr, address, role) +} + +// GetStoredGasPriceConfig returns the gas price config from contract storage. +// Configure always stores a value during activation, so the caller +// MUST NOT call this before the precompile has been configured. +func GetStoredGasPriceConfig(stateDB contract.StateReader, contractAddr common.Address) commontype.GasPriceConfig { + var cfg commontype.GasPriceConfig + cfg.UnpackFrom(stateDB.GetState(contractAddr, gasPriceConfigStorageKey)) + return cfg +} + +// GetGasPriceConfigLastChangedAt returns the block number of the last gas price config update. +func GetGasPriceConfigLastChangedAt(stateDB contract.StateReader, contractAddr common.Address) *big.Int { + val := stateDB.GetState(contractAddr, gasPriceConfigLastChangedAtKey) + return val.Big() +} + +// StoreGasPriceConfig validates and persists gasPriceConfig and blockNumber to contract storage. +func StoreGasPriceConfig(stateDB contract.StateDB, contractAddr common.Address, gasPriceConfig commontype.GasPriceConfig, blockNumber *big.Int) error { + if err := gasPriceConfig.Verify(); err != nil { + return fmt.Errorf("cannot verify gas price config: %w", err) + } + + stateDB.SetState(contractAddr, gasPriceConfigStorageKey, gasPriceConfig.Pack()) + stateDB.SetState(contractAddr, gasPriceConfigLastChangedAtKey, common.BigToHash(blockNumber)) + return nil +} diff --git a/graft/subnet-evm/precompile/contracts/gaspricemanager/contract_test.go b/graft/subnet-evm/precompile/contracts/gaspricemanager/contract_test.go new file mode 100644 index 000000000000..8d8f79e3a209 --- /dev/null +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/contract_test.go @@ -0,0 +1,380 @@ +// Copyright (C) 2019, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package gaspricemanager + +import ( + "math/big" + "testing" + + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/graft/subnet-evm/commontype" + "github.com/ava-labs/avalanchego/graft/subnet-evm/core/extstate" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/allowlist" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/allowlist/allowlisttest" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contract" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/precompiletest" +) + +var ( + testGasPriceConfig = commontype.GasPriceConfig{ + TargetGas: 10_000_000, + MinGasPrice: 1, + TimeToDouble: 60, + } + + // testBoolGasPriceConfig exercises boolean field round-trip through storage + // (ValidatorTargetGas=true, StaticPricing=true). + testBoolGasPriceConfig = commontype.GasPriceConfig{ + ValidatorTargetGas: true, + StaticPricing: true, + MinGasPrice: 1, + } + + testBlockNumber = big.NewInt(7) + + // defaultConfig sets up roles via Configure, which also stores + // DefaultGasPriceConfig to contract storage. + defaultConfig = &Config{ + AllowListConfig: allowlist.AllowListConfig{ + AdminAddresses: []common.Address{allowlisttest.TestAdminAddr}, + ManagerAddresses: []common.Address{allowlisttest.TestManagerAddr}, + EnabledAddresses: []common.Address{allowlisttest.TestEnabledAddr}, + }, + } +) + +func mustPackGetGasPriceConfigInput(t testing.TB) []byte { + t.Helper() + input, err := PackGetGasPriceConfig() + require.NoError(t, err, "PackGetGasPriceConfig()") + return input +} + +func mustPackGetGasPriceConfigLastChangedAtInput(t testing.TB) []byte { + t.Helper() + input, err := PackGetGasPriceConfigLastChangedAt() + require.NoError(t, err, "PackGetGasPriceConfigLastChangedAt()") + return input +} + +func mustPackSetGasPriceConfigInput(t testing.TB, config commontype.GasPriceConfig) []byte { + t.Helper() + input, err := PackSetGasPriceConfig(config) + require.NoError(t, err, "PackSetGasPriceConfig()") + return input +} + +func mustStoreTestGasPriceConfig(t testing.TB, state *extstate.StateDB) { + t.Helper() + require.NoError(t, StoreGasPriceConfig(state, ContractAddress, testGasPriceConfig, testBlockNumber), "StoreGasPriceConfig()") +} + +func mustPackGetGasPriceConfigOutput(t testing.TB, config commontype.GasPriceConfig) []byte { + t.Helper() + res, err := PackGetGasPriceConfigOutput(config) + require.NoError(t, err, "PackGetGasPriceConfigOutput()") + return res +} + +func mustPackGetGasPriceConfigLastChangedAtOutput(t testing.TB, blockNumber *big.Int) []byte { + t.Helper() + res, err := PackGetGasPriceConfigLastChangedAtOutput(blockNumber) + require.NoError(t, err, "PackGetGasPriceConfigLastChangedAtOutput()") + return res +} + +func TestGasPriceManagerRun(t *testing.T) { + tests := []precompiletest.PrecompileTest{ + // getGasPriceConfig — all roles can read + { + Name: "getGasPriceConfig_from_NoRole", + Caller: allowlisttest.TestNoRoleAddr, + Config: defaultConfig, + InputFn: mustPackGetGasPriceConfigInput, + SuppliedGas: getGasPriceConfigGasCost, + ExpectedRes: mustPackGetGasPriceConfigOutput(t, commontype.DefaultGasPriceConfig()), + }, + { + Name: "getGasPriceConfig_from_Enabled", + Caller: allowlisttest.TestEnabledAddr, + Config: defaultConfig, + InputFn: mustPackGetGasPriceConfigInput, + SuppliedGas: getGasPriceConfigGasCost, + ExpectedRes: mustPackGetGasPriceConfigOutput(t, commontype.DefaultGasPriceConfig()), + }, + { + Name: "getGasPriceConfig_from_Manager", + Caller: allowlisttest.TestManagerAddr, + Config: defaultConfig, + InputFn: mustPackGetGasPriceConfigInput, + SuppliedGas: getGasPriceConfigGasCost, + ExpectedRes: mustPackGetGasPriceConfigOutput(t, commontype.DefaultGasPriceConfig()), + }, + { + Name: "getGasPriceConfig_from_Admin", + Caller: allowlisttest.TestAdminAddr, + Config: defaultConfig, + InputFn: mustPackGetGasPriceConfigInput, + SuppliedGas: getGasPriceConfigGasCost, + ExpectedRes: mustPackGetGasPriceConfigOutput(t, commontype.DefaultGasPriceConfig()), + }, + { + Name: "getGasPriceConfig_returns_initialGasPriceConfig_from_configure", + Caller: allowlisttest.TestNoRoleAddr, + InputFn: mustPackGetGasPriceConfigInput, + Config: &Config{ + InitialGasPriceConfig: &testGasPriceConfig, + }, + SuppliedGas: getGasPriceConfigGasCost, + ExpectedRes: mustPackGetGasPriceConfigOutput(t, testGasPriceConfig), + }, + { + Name: "getGasPriceConfig_after_store_returns_new_config", + Caller: allowlisttest.TestEnabledAddr, + BeforeHook: mustStoreTestGasPriceConfig, + InputFn: mustPackGetGasPriceConfigInput, + SuppliedGas: getGasPriceConfigGasCost, + ExpectedRes: mustPackGetGasPriceConfigOutput(t, testGasPriceConfig), + }, + { + Name: "getGasPriceConfig_boolean_fields_round_trip", + Caller: allowlisttest.TestEnabledAddr, + BeforeHook: func(t testing.TB, state *extstate.StateDB) { + t.Helper() + require.NoError(t, StoreGasPriceConfig(state, ContractAddress, testBoolGasPriceConfig, testBlockNumber), "StoreGasPriceConfig()") + }, + InputFn: mustPackGetGasPriceConfigInput, + SuppliedGas: getGasPriceConfigGasCost, + ExpectedRes: mustPackGetGasPriceConfigOutput(t, testBoolGasPriceConfig), + }, + { + Name: "getGasPriceConfig_insufficient_gas", + Caller: allowlisttest.TestNoRoleAddr, + InputFn: mustPackGetGasPriceConfigInput, + SuppliedGas: getGasPriceConfigGasCost - 1, + ExpectedErr: vm.ErrOutOfGas, + }, + + // getGasPriceConfigLastChangedAt — all roles can read + { + Name: "getGasPriceConfigLastChangedAt_from_NoRole", + Caller: allowlisttest.TestNoRoleAddr, + BeforeHook: mustStoreTestGasPriceConfig, + InputFn: mustPackGetGasPriceConfigLastChangedAtInput, + SuppliedGas: getGasPriceConfigLastChangedAtGasCost, + ExpectedRes: mustPackGetGasPriceConfigLastChangedAtOutput(t, testBlockNumber), + }, + { + Name: "getGasPriceConfigLastChangedAt_from_Enabled", + Caller: allowlisttest.TestEnabledAddr, + BeforeHook: mustStoreTestGasPriceConfig, + InputFn: mustPackGetGasPriceConfigLastChangedAtInput, + SuppliedGas: getGasPriceConfigLastChangedAtGasCost, + ExpectedRes: mustPackGetGasPriceConfigLastChangedAtOutput(t, testBlockNumber), + }, + { + Name: "getGasPriceConfigLastChangedAt_from_Manager", + Caller: allowlisttest.TestManagerAddr, + BeforeHook: mustStoreTestGasPriceConfig, + InputFn: mustPackGetGasPriceConfigLastChangedAtInput, + SuppliedGas: getGasPriceConfigLastChangedAtGasCost, + ExpectedRes: mustPackGetGasPriceConfigLastChangedAtOutput(t, testBlockNumber), + }, + { + Name: "getGasPriceConfigLastChangedAt_from_Admin", + Caller: allowlisttest.TestAdminAddr, + BeforeHook: mustStoreTestGasPriceConfig, + InputFn: mustPackGetGasPriceConfigLastChangedAtInput, + SuppliedGas: getGasPriceConfigLastChangedAtGasCost, + ExpectedRes: mustPackGetGasPriceConfigLastChangedAtOutput(t, testBlockNumber), + }, + { + Name: "getGasPriceConfigLastChangedAt_insufficient_gas", + Caller: allowlisttest.TestNoRoleAddr, + InputFn: mustPackGetGasPriceConfigLastChangedAtInput, + SuppliedGas: getGasPriceConfigLastChangedAtGasCost - 1, + ExpectedErr: vm.ErrOutOfGas, + }, + + // setGasPriceConfig — NoRole rejected, Enabled/Manager/Admin succeed + { + Name: "setGasPriceConfig_from_NoRole_rejected", + Caller: allowlisttest.TestNoRoleAddr, + Config: defaultConfig, + InputFn: func(t testing.TB) []byte { + return mustPackSetGasPriceConfigInput(t, testGasPriceConfig) + }, + SuppliedGas: setGasPriceConfigGasCost, + ExpectedErr: errCannotSetGasPriceConfig, + }, + { + Name: "setGasPriceConfig_from_Enabled", + Caller: allowlisttest.TestEnabledAddr, + Config: defaultConfig, + InputFn: func(t testing.TB) []byte { + return mustPackSetGasPriceConfigInput(t, testGasPriceConfig) + }, + SuppliedGas: setGasPriceConfigGasCost, + ExpectedRes: []byte{}, + AfterHook: func(t testing.TB, state *extstate.StateDB) { + got := GetStoredGasPriceConfig(state, ContractAddress) + require.Equal(t, testGasPriceConfig, got, "GetStoredGasPriceConfig()") + }, + }, + { + Name: "setGasPriceConfig_from_Manager", + Caller: allowlisttest.TestManagerAddr, + Config: defaultConfig, + InputFn: func(t testing.TB) []byte { + return mustPackSetGasPriceConfigInput(t, testGasPriceConfig) + }, + SuppliedGas: setGasPriceConfigGasCost, + ExpectedRes: []byte{}, + AfterHook: func(t testing.TB, state *extstate.StateDB) { + got := GetStoredGasPriceConfig(state, ContractAddress) + require.Equal(t, testGasPriceConfig, got, "GetStoredGasPriceConfig()") + }, + }, + { + Name: "setGasPriceConfig_from_Admin", + Caller: allowlisttest.TestAdminAddr, + Config: defaultConfig, + InputFn: func(t testing.TB) []byte { + return mustPackSetGasPriceConfigInput(t, testGasPriceConfig) + }, + SuppliedGas: setGasPriceConfigGasCost, + ExpectedRes: []byte{}, + AfterHook: func(t testing.TB, state *extstate.StateDB) { + got := GetStoredGasPriceConfig(state, ContractAddress) + require.Equal(t, testGasPriceConfig, got, "GetStoredGasPriceConfig()") + }, + }, + { + Name: "setGasPriceConfig_readOnly_rejected", + Caller: allowlisttest.TestEnabledAddr, + Config: defaultConfig, + InputFn: func(t testing.TB) []byte { + return mustPackSetGasPriceConfigInput(t, testGasPriceConfig) + }, + SuppliedGas: setGasPriceConfigGasCost, + ReadOnly: true, + ExpectedErr: vm.ErrWriteProtection, + }, + { + Name: "setGasPriceConfig_insufficient_gas", + Caller: allowlisttest.TestEnabledAddr, + InputFn: func(t testing.TB) []byte { + return mustPackSetGasPriceConfigInput(t, testGasPriceConfig) + }, + SuppliedGas: setGasPriceConfigGasCost - 1, + ExpectedErr: vm.ErrOutOfGas, + }, + { + Name: "setGasPriceConfig_nil_block_number", + Caller: allowlisttest.TestEnabledAddr, + BeforeHook: func(t testing.TB, state *extstate.StateDB) { + t.Helper() + allowlisttest.SetDefaultRoles(Module.Address)(t, state) + require.NoError(t, StoreGasPriceConfig(state, ContractAddress, commontype.DefaultGasPriceConfig(), big.NewInt(0)), "StoreGasPriceConfig()") + }, + InputFn: func(t testing.TB) []byte { + return mustPackSetGasPriceConfigInput(t, testGasPriceConfig) + }, + SetupBlockContext: func(mbc *contract.MockBlockContext) { + mbc.EXPECT().Number().Return((*big.Int)(nil)).AnyTimes() + mbc.EXPECT().Timestamp().Return(uint64(0)).AnyTimes() + }, + SuppliedGas: setGasPriceConfigGasCost, + ExpectedErr: errNilBlockNumber, + }, + { + Name: "setGasPriceConfig_invalid_config", + Caller: allowlisttest.TestEnabledAddr, + Config: defaultConfig, + InputFn: func(t testing.TB) []byte { + return mustPackSetGasPriceConfigInput(t, commontype.GasPriceConfig{ + TargetGas: commontype.MinTargetGas, + TimeToDouble: 60, + }) + }, + SuppliedGas: setGasPriceConfigGasCost, + ExpectedErr: commontype.ErrMinGasPriceTooLow, + }, + { + Name: "setGasPriceConfig_emits_event", + Caller: allowlisttest.TestEnabledAddr, + Config: defaultConfig, + InputFn: func(t testing.TB) []byte { + return mustPackSetGasPriceConfigInput(t, testGasPriceConfig) + }, + SetupBlockContext: func(mbc *contract.MockBlockContext) { + mbc.EXPECT().Number().Return(testBlockNumber).AnyTimes() + mbc.EXPECT().Timestamp().Return(uint64(0)).AnyTimes() + }, + SuppliedGas: setGasPriceConfigGasCost, + ExpectedRes: []byte{}, + AfterHook: func(t testing.TB, state *extstate.StateDB) { + gasPriceConfig := GetStoredGasPriceConfig(state, ContractAddress) + require.Equal(t, testGasPriceConfig, gasPriceConfig, "GetStoredGasPriceConfig()") + + lastChangedAt := GetGasPriceConfigLastChangedAt(state, ContractAddress) + require.Equal(t, testBlockNumber, lastChangedAt, "GetGasPriceConfigLastChangedAt()") + + logs := state.Logs() + require.Len(t, logs, 1, "logs emitted") + log := logs[0] + require.Equal(t, ContractAddress, log.Address, "log address") + + require.Len(t, log.Topics, 2, "topics (event sig + indexed sender)") + wantTopics, _, err := PackGasPriceConfigUpdatedEvent( + allowlisttest.TestEnabledAddr, + commontype.DefaultGasPriceConfig(), + testGasPriceConfig, + ) + require.NoError(t, err, "PackGasPriceConfigUpdatedEvent()") + require.Equal(t, wantTopics, log.Topics, "event topics") + + unpacked, err := UnpackGasPriceConfigUpdatedEventData(log.Data) + require.NoError(t, err, "UnpackGasPriceConfigUpdatedEventData()") + require.Equal(t, commontype.DefaultGasPriceConfig(), unpacked.OldGasPriceConfig, "old gas price config in event") + require.Equal(t, testGasPriceConfig, unpacked.NewGasPriceConfig, "new gas price config in event") + }, + }, + } + + allowlisttest.RunPrecompileWithAllowListTests(t, Module, tests) +} + +func TestUnpackSetGasPriceConfigInput_malformed(t *testing.T) { + tests := []struct { + name string + input []byte + wantErr string + }{ + { + name: "nil", + wantErr: "abi: attempting to unmarshal an empty string while arguments are expected", + }, + { + name: "empty", + input: []byte{}, + wantErr: "abi: attempting to unmarshal an empty string while arguments are expected", + }, + { + name: "random", + input: []byte("random"), + wantErr: "abi: cannot marshal in to go type: length insufficient", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := UnpackSetGasPriceConfigInput(tt.input) + //nolint:forbidigo // ABI decode errors are unexported; ErrorIs is not possible + require.ErrorContains(t, err, tt.wantErr, "UnpackSetGasPriceConfigInput(%x)", tt.input) + }) + } +} diff --git a/graft/subnet-evm/precompile/contracts/gaspricemanager/event.go b/graft/subnet-evm/precompile/contracts/gaspricemanager/event.go new file mode 100644 index 000000000000..43bed1fb9a11 --- /dev/null +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/event.go @@ -0,0 +1,28 @@ +// Copyright (C) 2019, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package gaspricemanager + +import ( + "github.com/ava-labs/libevm/common" + + "github.com/ava-labs/avalanchego/graft/subnet-evm/commontype" +) + +// GasPriceConfigUpdatedEventData holds the non-indexed data from a GasPriceConfigUpdated event. +type GasPriceConfigUpdatedEventData struct { + OldGasPriceConfig commontype.GasPriceConfig + NewGasPriceConfig commontype.GasPriceConfig +} + +// PackGasPriceConfigUpdatedEvent returns topic hashes and ABI-encoded non-indexed data. +func PackGasPriceConfigUpdatedEvent(sender common.Address, oldConfig commontype.GasPriceConfig, newConfig commontype.GasPriceConfig) ([]common.Hash, []byte, error) { + return GasPriceManagerABI.PackEvent("GasPriceConfigUpdated", sender, oldConfig, newConfig) +} + +// UnpackGasPriceConfigUpdatedEventData decodes the non-indexed portion of a GasPriceConfigUpdated log. +func UnpackGasPriceConfigUpdatedEventData(dataBytes []byte) (GasPriceConfigUpdatedEventData, error) { + var data GasPriceConfigUpdatedEventData + err := GasPriceManagerABI.UnpackIntoInterface(&data, "GasPriceConfigUpdated", dataBytes) + return data, err +} diff --git a/graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings/BUILD.bazel b/graft/subnet-evm/precompile/contracts/gaspricemanager/gaspricemanagertest/bindings/BUILD.bazel similarity index 84% rename from graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings/BUILD.bazel rename to graft/subnet-evm/precompile/contracts/gaspricemanager/gaspricemanagertest/bindings/BUILD.bazel index 66253a1a832a..a0bab17215e5 100644 --- a/graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings/BUILD.bazel +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/gaspricemanagertest/bindings/BUILD.bazel @@ -9,9 +9,9 @@ go_library( name = "bindings", srcs = [ "compile.go", - "gen_iacp224feemanager_binding.go", + "gen_igaspricemanager_binding.go", ], - importpath = "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings", + importpath = "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contracts/gaspricemanager/gaspricemanagertest/bindings", deps = [ "//graft/subnet-evm/accounts/abi/bind", "@com_github_ava_labs_libevm//:libevm", diff --git a/graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings/compile.go b/graft/subnet-evm/precompile/contracts/gaspricemanager/gaspricemanagertest/bindings/compile.go similarity index 71% rename from graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings/compile.go rename to graft/subnet-evm/precompile/contracts/gaspricemanager/gaspricemanagertest/bindings/compile.go index f34b126dac65..376841490097 100644 --- a/graft/subnet-evm/precompile/contracts/acp224feemanager/acp224feemanagertest/bindings/compile.go +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/gaspricemanagertest/bindings/compile.go @@ -4,9 +4,9 @@ package bindings // Step 1: Compile interface to generate ABI at top level -//go:generate solc -o ../.. --overwrite --abi --base-path ../../../../.. --pretty-json --evm-version cancun ../../IACP224FeeManager.sol +//go:generate solc -o ../.. --overwrite --abi --base-path ../../../../.. --pretty-json --evm-version cancun ../../IGasPriceManager.sol // Step 2: Generate Go bindings from the compiled artifacts -//go:generate go run github.com/ava-labs/libevm/cmd/abigen --pkg bindings --type IACP224FeeManager --abi ../../IACP224FeeManager.abi --out gen_iacp224feemanager_binding.go +//go:generate go run github.com/ava-labs/libevm/cmd/abigen --pkg bindings --type IGasPriceManager --abi ../../IGasPriceManager.abi --out gen_igaspricemanager_binding.go // Step 3: Replace import paths in generated binding to use subnet-evm instead of libevm // This is necessary because the libevm bindings package is not compatible with the subnet-evm simulated backend, which is used for testing. -//go:generate sh -c "sed -i.bak -e 's|github.com/ava-labs/libevm/accounts/abi/bind|github.com/ava-labs/avalanchego/graft/subnet-evm/accounts/abi/bind|g' gen_iacp224feemanager_binding.go && rm -f gen_iacp224feemanager_binding.go.bak" +//go:generate sh -c "sed -i.bak -e 's|github.com/ava-labs/libevm/accounts/abi/bind|github.com/ava-labs/avalanchego/graft/subnet-evm/accounts/abi/bind|g' gen_igaspricemanager_binding.go && rm -f gen_igaspricemanager_binding.go.bak" diff --git a/graft/subnet-evm/precompile/contracts/gaspricemanager/gaspricemanagertest/bindings/gen_igaspricemanager_binding.go b/graft/subnet-evm/precompile/contracts/gaspricemanager/gaspricemanagertest/bindings/gen_igaspricemanager_binding.go new file mode 100644 index 000000000000..0bfe1010211a --- /dev/null +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/gaspricemanagertest/bindings/gen_igaspricemanager_binding.go @@ -0,0 +1,697 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ava-labs/libevm" + "github.com/ava-labs/libevm/accounts/abi" + "github.com/ava-labs/avalanchego/graft/subnet-evm/accounts/abi/bind" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IGasPriceManagerGasPriceConfig is an auto generated low-level Go binding around an user-defined struct. +type IGasPriceManagerGasPriceConfig struct { + ValidatorTargetGas bool + TargetGas uint64 + StaticPricing bool + MinGasPrice uint64 + TimeToDouble uint64 +} + +// IGasPriceManagerMetaData contains all meta data concerning the IGasPriceManager contract. +var IGasPriceManagerMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"validatorTargetGas\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"targetGas\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"staticPricing\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"minGasPrice\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"timeToDouble\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structIGasPriceManager.GasPriceConfig\",\"name\":\"oldGasPriceConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"validatorTargetGas\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"targetGas\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"staticPricing\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"minGasPrice\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"timeToDouble\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structIGasPriceManager.GasPriceConfig\",\"name\":\"newGasPriceConfig\",\"type\":\"tuple\"}],\"name\":\"GasPriceConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"role\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldRole\",\"type\":\"uint256\"}],\"name\":\"RoleSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getGasPriceConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"validatorTargetGas\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"targetGas\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"staticPricing\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"minGasPrice\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"timeToDouble\",\"type\":\"uint64\"}],\"internalType\":\"structIGasPriceManager.GasPriceConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasPriceConfigLastChangedAt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"readAllowList\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"role\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setEnabled\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"validatorTargetGas\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"targetGas\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"staticPricing\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"minGasPrice\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"timeToDouble\",\"type\":\"uint64\"}],\"internalType\":\"structIGasPriceManager.GasPriceConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setGasPriceConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setNone\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// IGasPriceManagerABI is the input ABI used to generate the binding from. +// Deprecated: Use IGasPriceManagerMetaData.ABI instead. +var IGasPriceManagerABI = IGasPriceManagerMetaData.ABI + +// IGasPriceManager is an auto generated Go binding around an Ethereum contract. +type IGasPriceManager struct { + IGasPriceManagerCaller // Read-only binding to the contract + IGasPriceManagerTransactor // Write-only binding to the contract + IGasPriceManagerFilterer // Log filterer for contract events +} + +// IGasPriceManagerCaller is an auto generated read-only Go binding around an Ethereum contract. +type IGasPriceManagerCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IGasPriceManagerTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IGasPriceManagerTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IGasPriceManagerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IGasPriceManagerFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IGasPriceManagerSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IGasPriceManagerSession struct { + Contract *IGasPriceManager // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IGasPriceManagerCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IGasPriceManagerCallerSession struct { + Contract *IGasPriceManagerCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IGasPriceManagerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IGasPriceManagerTransactorSession struct { + Contract *IGasPriceManagerTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IGasPriceManagerRaw is an auto generated low-level Go binding around an Ethereum contract. +type IGasPriceManagerRaw struct { + Contract *IGasPriceManager // Generic contract binding to access the raw methods on +} + +// IGasPriceManagerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IGasPriceManagerCallerRaw struct { + Contract *IGasPriceManagerCaller // Generic read-only contract binding to access the raw methods on +} + +// IGasPriceManagerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IGasPriceManagerTransactorRaw struct { + Contract *IGasPriceManagerTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIGasPriceManager creates a new instance of IGasPriceManager, bound to a specific deployed contract. +func NewIGasPriceManager(address common.Address, backend bind.ContractBackend) (*IGasPriceManager, error) { + contract, err := bindIGasPriceManager(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IGasPriceManager{IGasPriceManagerCaller: IGasPriceManagerCaller{contract: contract}, IGasPriceManagerTransactor: IGasPriceManagerTransactor{contract: contract}, IGasPriceManagerFilterer: IGasPriceManagerFilterer{contract: contract}}, nil +} + +// NewIGasPriceManagerCaller creates a new read-only instance of IGasPriceManager, bound to a specific deployed contract. +func NewIGasPriceManagerCaller(address common.Address, caller bind.ContractCaller) (*IGasPriceManagerCaller, error) { + contract, err := bindIGasPriceManager(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IGasPriceManagerCaller{contract: contract}, nil +} + +// NewIGasPriceManagerTransactor creates a new write-only instance of IGasPriceManager, bound to a specific deployed contract. +func NewIGasPriceManagerTransactor(address common.Address, transactor bind.ContractTransactor) (*IGasPriceManagerTransactor, error) { + contract, err := bindIGasPriceManager(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IGasPriceManagerTransactor{contract: contract}, nil +} + +// NewIGasPriceManagerFilterer creates a new log filterer instance of IGasPriceManager, bound to a specific deployed contract. +func NewIGasPriceManagerFilterer(address common.Address, filterer bind.ContractFilterer) (*IGasPriceManagerFilterer, error) { + contract, err := bindIGasPriceManager(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IGasPriceManagerFilterer{contract: contract}, nil +} + +// bindIGasPriceManager binds a generic wrapper to an already deployed contract. +func bindIGasPriceManager(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IGasPriceManagerMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IGasPriceManager *IGasPriceManagerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IGasPriceManager.Contract.IGasPriceManagerCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IGasPriceManager *IGasPriceManagerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IGasPriceManager.Contract.IGasPriceManagerTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IGasPriceManager *IGasPriceManagerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IGasPriceManager.Contract.IGasPriceManagerTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IGasPriceManager *IGasPriceManagerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IGasPriceManager.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IGasPriceManager *IGasPriceManagerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IGasPriceManager.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IGasPriceManager *IGasPriceManagerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IGasPriceManager.Contract.contract.Transact(opts, method, params...) +} + +// GetGasPriceConfig is a free data retrieval call binding the contract method 0x445821e3. +// +// Solidity: function getGasPriceConfig() view returns((bool,uint64,bool,uint64,uint64) config) +func (_IGasPriceManager *IGasPriceManagerCaller) GetGasPriceConfig(opts *bind.CallOpts) (IGasPriceManagerGasPriceConfig, error) { + var out []interface{} + err := _IGasPriceManager.contract.Call(opts, &out, "getGasPriceConfig") + + if err != nil { + return *new(IGasPriceManagerGasPriceConfig), err + } + + out0 := *abi.ConvertType(out[0], new(IGasPriceManagerGasPriceConfig)).(*IGasPriceManagerGasPriceConfig) + + return out0, err + +} + +// GetGasPriceConfig is a free data retrieval call binding the contract method 0x445821e3. +// +// Solidity: function getGasPriceConfig() view returns((bool,uint64,bool,uint64,uint64) config) +func (_IGasPriceManager *IGasPriceManagerSession) GetGasPriceConfig() (IGasPriceManagerGasPriceConfig, error) { + return _IGasPriceManager.Contract.GetGasPriceConfig(&_IGasPriceManager.CallOpts) +} + +// GetGasPriceConfig is a free data retrieval call binding the contract method 0x445821e3. +// +// Solidity: function getGasPriceConfig() view returns((bool,uint64,bool,uint64,uint64) config) +func (_IGasPriceManager *IGasPriceManagerCallerSession) GetGasPriceConfig() (IGasPriceManagerGasPriceConfig, error) { + return _IGasPriceManager.Contract.GetGasPriceConfig(&_IGasPriceManager.CallOpts) +} + +// GetGasPriceConfigLastChangedAt is a free data retrieval call binding the contract method 0xeb8df396. +// +// Solidity: function getGasPriceConfigLastChangedAt() view returns(uint256 blockNumber) +func (_IGasPriceManager *IGasPriceManagerCaller) GetGasPriceConfigLastChangedAt(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IGasPriceManager.contract.Call(opts, &out, "getGasPriceConfigLastChangedAt") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetGasPriceConfigLastChangedAt is a free data retrieval call binding the contract method 0xeb8df396. +// +// Solidity: function getGasPriceConfigLastChangedAt() view returns(uint256 blockNumber) +func (_IGasPriceManager *IGasPriceManagerSession) GetGasPriceConfigLastChangedAt() (*big.Int, error) { + return _IGasPriceManager.Contract.GetGasPriceConfigLastChangedAt(&_IGasPriceManager.CallOpts) +} + +// GetGasPriceConfigLastChangedAt is a free data retrieval call binding the contract method 0xeb8df396. +// +// Solidity: function getGasPriceConfigLastChangedAt() view returns(uint256 blockNumber) +func (_IGasPriceManager *IGasPriceManagerCallerSession) GetGasPriceConfigLastChangedAt() (*big.Int, error) { + return _IGasPriceManager.Contract.GetGasPriceConfigLastChangedAt(&_IGasPriceManager.CallOpts) +} + +// ReadAllowList is a free data retrieval call binding the contract method 0xeb54dae1. +// +// Solidity: function readAllowList(address addr) view returns(uint256 role) +func (_IGasPriceManager *IGasPriceManagerCaller) ReadAllowList(opts *bind.CallOpts, addr common.Address) (*big.Int, error) { + var out []interface{} + err := _IGasPriceManager.contract.Call(opts, &out, "readAllowList", addr) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ReadAllowList is a free data retrieval call binding the contract method 0xeb54dae1. +// +// Solidity: function readAllowList(address addr) view returns(uint256 role) +func (_IGasPriceManager *IGasPriceManagerSession) ReadAllowList(addr common.Address) (*big.Int, error) { + return _IGasPriceManager.Contract.ReadAllowList(&_IGasPriceManager.CallOpts, addr) +} + +// ReadAllowList is a free data retrieval call binding the contract method 0xeb54dae1. +// +// Solidity: function readAllowList(address addr) view returns(uint256 role) +func (_IGasPriceManager *IGasPriceManagerCallerSession) ReadAllowList(addr common.Address) (*big.Int, error) { + return _IGasPriceManager.Contract.ReadAllowList(&_IGasPriceManager.CallOpts, addr) +} + +// SetAdmin is a paid mutator transaction binding the contract method 0x704b6c02. +// +// Solidity: function setAdmin(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerTransactor) SetAdmin(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.contract.Transact(opts, "setAdmin", addr) +} + +// SetAdmin is a paid mutator transaction binding the contract method 0x704b6c02. +// +// Solidity: function setAdmin(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerSession) SetAdmin(addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.Contract.SetAdmin(&_IGasPriceManager.TransactOpts, addr) +} + +// SetAdmin is a paid mutator transaction binding the contract method 0x704b6c02. +// +// Solidity: function setAdmin(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerTransactorSession) SetAdmin(addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.Contract.SetAdmin(&_IGasPriceManager.TransactOpts, addr) +} + +// SetEnabled is a paid mutator transaction binding the contract method 0x0aaf7043. +// +// Solidity: function setEnabled(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerTransactor) SetEnabled(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.contract.Transact(opts, "setEnabled", addr) +} + +// SetEnabled is a paid mutator transaction binding the contract method 0x0aaf7043. +// +// Solidity: function setEnabled(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerSession) SetEnabled(addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.Contract.SetEnabled(&_IGasPriceManager.TransactOpts, addr) +} + +// SetEnabled is a paid mutator transaction binding the contract method 0x0aaf7043. +// +// Solidity: function setEnabled(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerTransactorSession) SetEnabled(addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.Contract.SetEnabled(&_IGasPriceManager.TransactOpts, addr) +} + +// SetGasPriceConfig is a paid mutator transaction binding the contract method 0x65c97a28. +// +// Solidity: function setGasPriceConfig((bool,uint64,bool,uint64,uint64) config) returns() +func (_IGasPriceManager *IGasPriceManagerTransactor) SetGasPriceConfig(opts *bind.TransactOpts, config IGasPriceManagerGasPriceConfig) (*types.Transaction, error) { + return _IGasPriceManager.contract.Transact(opts, "setGasPriceConfig", config) +} + +// SetGasPriceConfig is a paid mutator transaction binding the contract method 0x65c97a28. +// +// Solidity: function setGasPriceConfig((bool,uint64,bool,uint64,uint64) config) returns() +func (_IGasPriceManager *IGasPriceManagerSession) SetGasPriceConfig(config IGasPriceManagerGasPriceConfig) (*types.Transaction, error) { + return _IGasPriceManager.Contract.SetGasPriceConfig(&_IGasPriceManager.TransactOpts, config) +} + +// SetGasPriceConfig is a paid mutator transaction binding the contract method 0x65c97a28. +// +// Solidity: function setGasPriceConfig((bool,uint64,bool,uint64,uint64) config) returns() +func (_IGasPriceManager *IGasPriceManagerTransactorSession) SetGasPriceConfig(config IGasPriceManagerGasPriceConfig) (*types.Transaction, error) { + return _IGasPriceManager.Contract.SetGasPriceConfig(&_IGasPriceManager.TransactOpts, config) +} + +// SetManager is a paid mutator transaction binding the contract method 0xd0ebdbe7. +// +// Solidity: function setManager(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerTransactor) SetManager(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.contract.Transact(opts, "setManager", addr) +} + +// SetManager is a paid mutator transaction binding the contract method 0xd0ebdbe7. +// +// Solidity: function setManager(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerSession) SetManager(addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.Contract.SetManager(&_IGasPriceManager.TransactOpts, addr) +} + +// SetManager is a paid mutator transaction binding the contract method 0xd0ebdbe7. +// +// Solidity: function setManager(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerTransactorSession) SetManager(addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.Contract.SetManager(&_IGasPriceManager.TransactOpts, addr) +} + +// SetNone is a paid mutator transaction binding the contract method 0x8c6bfb3b. +// +// Solidity: function setNone(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerTransactor) SetNone(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.contract.Transact(opts, "setNone", addr) +} + +// SetNone is a paid mutator transaction binding the contract method 0x8c6bfb3b. +// +// Solidity: function setNone(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerSession) SetNone(addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.Contract.SetNone(&_IGasPriceManager.TransactOpts, addr) +} + +// SetNone is a paid mutator transaction binding the contract method 0x8c6bfb3b. +// +// Solidity: function setNone(address addr) returns() +func (_IGasPriceManager *IGasPriceManagerTransactorSession) SetNone(addr common.Address) (*types.Transaction, error) { + return _IGasPriceManager.Contract.SetNone(&_IGasPriceManager.TransactOpts, addr) +} + +// IGasPriceManagerGasPriceConfigUpdatedIterator is returned from FilterGasPriceConfigUpdated and is used to iterate over the raw logs and unpacked data for GasPriceConfigUpdated events raised by the IGasPriceManager contract. +type IGasPriceManagerGasPriceConfigUpdatedIterator struct { + Event *IGasPriceManagerGasPriceConfigUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IGasPriceManagerGasPriceConfigUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IGasPriceManagerGasPriceConfigUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IGasPriceManagerGasPriceConfigUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IGasPriceManagerGasPriceConfigUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IGasPriceManagerGasPriceConfigUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IGasPriceManagerGasPriceConfigUpdated represents a GasPriceConfigUpdated event raised by the IGasPriceManager contract. +type IGasPriceManagerGasPriceConfigUpdated struct { + Sender common.Address + OldGasPriceConfig IGasPriceManagerGasPriceConfig + NewGasPriceConfig IGasPriceManagerGasPriceConfig + Raw types.Log // Blockchain specific contextual infos +} + +// FilterGasPriceConfigUpdated is a free log retrieval operation binding the contract event 0x9456356f1b11d07d47f9bd3d568279a926ea8caceec0e6078e426eaea579be66. +// +// Solidity: event GasPriceConfigUpdated(address indexed sender, (bool,uint64,bool,uint64,uint64) oldGasPriceConfig, (bool,uint64,bool,uint64,uint64) newGasPriceConfig) +func (_IGasPriceManager *IGasPriceManagerFilterer) FilterGasPriceConfigUpdated(opts *bind.FilterOpts, sender []common.Address) (*IGasPriceManagerGasPriceConfigUpdatedIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IGasPriceManager.contract.FilterLogs(opts, "GasPriceConfigUpdated", senderRule) + if err != nil { + return nil, err + } + return &IGasPriceManagerGasPriceConfigUpdatedIterator{contract: _IGasPriceManager.contract, event: "GasPriceConfigUpdated", logs: logs, sub: sub}, nil +} + +// WatchGasPriceConfigUpdated is a free log subscription operation binding the contract event 0x9456356f1b11d07d47f9bd3d568279a926ea8caceec0e6078e426eaea579be66. +// +// Solidity: event GasPriceConfigUpdated(address indexed sender, (bool,uint64,bool,uint64,uint64) oldGasPriceConfig, (bool,uint64,bool,uint64,uint64) newGasPriceConfig) +func (_IGasPriceManager *IGasPriceManagerFilterer) WatchGasPriceConfigUpdated(opts *bind.WatchOpts, sink chan<- *IGasPriceManagerGasPriceConfigUpdated, sender []common.Address) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IGasPriceManager.contract.WatchLogs(opts, "GasPriceConfigUpdated", senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IGasPriceManagerGasPriceConfigUpdated) + if err := _IGasPriceManager.contract.UnpackLog(event, "GasPriceConfigUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseGasPriceConfigUpdated is a log parse operation binding the contract event 0x9456356f1b11d07d47f9bd3d568279a926ea8caceec0e6078e426eaea579be66. +// +// Solidity: event GasPriceConfigUpdated(address indexed sender, (bool,uint64,bool,uint64,uint64) oldGasPriceConfig, (bool,uint64,bool,uint64,uint64) newGasPriceConfig) +func (_IGasPriceManager *IGasPriceManagerFilterer) ParseGasPriceConfigUpdated(log types.Log) (*IGasPriceManagerGasPriceConfigUpdated, error) { + event := new(IGasPriceManagerGasPriceConfigUpdated) + if err := _IGasPriceManager.contract.UnpackLog(event, "GasPriceConfigUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IGasPriceManagerRoleSetIterator is returned from FilterRoleSet and is used to iterate over the raw logs and unpacked data for RoleSet events raised by the IGasPriceManager contract. +type IGasPriceManagerRoleSetIterator struct { + Event *IGasPriceManagerRoleSet // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IGasPriceManagerRoleSetIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IGasPriceManagerRoleSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IGasPriceManagerRoleSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IGasPriceManagerRoleSetIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IGasPriceManagerRoleSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IGasPriceManagerRoleSet represents a RoleSet event raised by the IGasPriceManager contract. +type IGasPriceManagerRoleSet struct { + Role *big.Int + Account common.Address + Sender common.Address + OldRole *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleSet is a free log retrieval operation binding the contract event 0xcdb7ea01f00a414d78757bdb0f6391664ba3fedf987eed280927c1e7d695be3e. +// +// Solidity: event RoleSet(uint256 indexed role, address indexed account, address indexed sender, uint256 oldRole) +func (_IGasPriceManager *IGasPriceManagerFilterer) FilterRoleSet(opts *bind.FilterOpts, role []*big.Int, account []common.Address, sender []common.Address) (*IGasPriceManagerRoleSetIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IGasPriceManager.contract.FilterLogs(opts, "RoleSet", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &IGasPriceManagerRoleSetIterator{contract: _IGasPriceManager.contract, event: "RoleSet", logs: logs, sub: sub}, nil +} + +// WatchRoleSet is a free log subscription operation binding the contract event 0xcdb7ea01f00a414d78757bdb0f6391664ba3fedf987eed280927c1e7d695be3e. +// +// Solidity: event RoleSet(uint256 indexed role, address indexed account, address indexed sender, uint256 oldRole) +func (_IGasPriceManager *IGasPriceManagerFilterer) WatchRoleSet(opts *bind.WatchOpts, sink chan<- *IGasPriceManagerRoleSet, role []*big.Int, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IGasPriceManager.contract.WatchLogs(opts, "RoleSet", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IGasPriceManagerRoleSet) + if err := _IGasPriceManager.contract.UnpackLog(event, "RoleSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleSet is a log parse operation binding the contract event 0xcdb7ea01f00a414d78757bdb0f6391664ba3fedf987eed280927c1e7d695be3e. +// +// Solidity: event RoleSet(uint256 indexed role, address indexed account, address indexed sender, uint256 oldRole) +func (_IGasPriceManager *IGasPriceManagerFilterer) ParseRoleSet(log types.Log) (*IGasPriceManagerRoleSet, error) { + event := new(IGasPriceManagerRoleSet) + if err := _IGasPriceManager.contract.UnpackLog(event, "RoleSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/graft/subnet-evm/precompile/contracts/gaspricemanager/module.go b/graft/subnet-evm/precompile/contracts/gaspricemanager/module.go new file mode 100644 index 000000000000..e48dad75728c --- /dev/null +++ b/graft/subnet-evm/precompile/contracts/gaspricemanager/module.go @@ -0,0 +1,62 @@ +// Copyright (C) 2019, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package gaspricemanager + +import ( + "fmt" + + "github.com/ava-labs/libevm/common" + + "github.com/ava-labs/avalanchego/graft/subnet-evm/commontype" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contract" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/modules" + "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/precompileconfig" +) + +var _ contract.Configurator = (*configurator)(nil) + +// ConfigKey must be unique across all precompiles. +const ConfigKey = "gasPriceManagerConfig" + +var ContractAddress = common.HexToAddress("0x0200000000000000000000000000000000000006") + +var Module = modules.Module{ + ConfigKey: ConfigKey, + Address: ContractAddress, + Contract: gasPriceManagerPrecompile, + Configurator: &configurator{}, +} + +type configurator struct{} + +func init() { + if err := modules.RegisterModule(Module); err != nil { + panic(err) + } +} + +// MakeConfig returns a zero-valued config for JSON unmarshaling when +// loading this precompile's config from chain config or upgrades. +func (*configurator) MakeConfig() precompileconfig.Config { + return new(Config) +} + +// Configure performs one-time initialization when the precompile activates. +// It seeds contract storage with the initial gas price config and allowlist state. +// This function MUST only be called once as re-running it would reset that +// initialized state. +func (*configurator) Configure(chainConfig precompileconfig.ChainConfig, cfg precompileconfig.Config, state contract.StateDB, blockContext contract.ConfigurationBlockContext) error { + config, ok := cfg.(*Config) + if !ok { + return fmt.Errorf("expected config type %T, got %T: %v", &Config{}, cfg, cfg) + } + initialGasPriceConfig := commontype.DefaultGasPriceConfig() + if config.InitialGasPriceConfig != nil { + initialGasPriceConfig = *config.InitialGasPriceConfig + } + if err := StoreGasPriceConfig(state, ContractAddress, initialGasPriceConfig, blockContext.Number()); err != nil { + return fmt.Errorf("cannot configure initial gas price config: %w", err) + } + return config.AllowListConfig.Configure(chainConfig, ContractAddress, state, blockContext) +} diff --git a/graft/subnet-evm/precompile/registry/registry.go b/graft/subnet-evm/precompile/registry/registry.go index 29638b6d8eee..fe6da76a9d74 100644 --- a/graft/subnet-evm/precompile/registry/registry.go +++ b/graft/subnet-evm/precompile/registry/registry.go @@ -7,6 +7,8 @@ package registry // Force imports of each precompile to ensure each precompile's init function runs and registers itself // with the registry. import ( + // TODO(JonathanOppenheimer): Uncomment when gaspricemanager init() registration is enabled. + // _ "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contracts/gaspricemanager" _ "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contracts/deployerallowlist" _ "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contracts/feemanager" _ "github.com/ava-labs/avalanchego/graft/subnet-evm/precompile/contracts/nativeminter" @@ -33,5 +35,6 @@ import ( // FeeManagerAddress = common.HexToAddress("0x0200000000000000000000000000000000000003") // RewardManagerAddress = common.HexToAddress("0x0200000000000000000000000000000000000004") // WarpAddress = common.HexToAddress("0x0200000000000000000000000000000000000005") +// GasPriceManagerAddress = common.HexToAddress("0x0200000000000000000000000000000000000006") // ADD YOUR PRECOMPILE HERE // {YourPrecompile}Address = common.HexToAddress("0x03000000000000000000000000000000000000??")