diff --git a/bindings/network/exit.go b/bindings/network/exit.go index 72b4a7730..d7890f161 100644 --- a/bindings/network/exit.go +++ b/bindings/network/exit.go @@ -47,6 +47,19 @@ func GetRequestedEth(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*big.Int, return *value, nil } +// Get the current EIP-7002 exit fee in wei +func GetExitFee(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*big.Int, error) { + rocketNetworkExit, err := getRocketNetworkExit(rp, opts) + if err != nil { + return nil, err + } + value := new(*big.Int) + if err := rocketNetworkExit.Call(opts, value, "getExitFee"); err != nil { + return nil, fmt.Errorf("error getting exit fee: %w", err) + } + return *value, nil +} + // Get the start of the cooperative exit phase for a Minipool func GetMinipoolCooperativeExitStart(rp *rocketpool.RocketPool, minipoolAddress common.Address, opts *bind.CallOpts) (time.Time, error) { rocketNetworkExit, err := getRocketNetworkExit(rp, opts) diff --git a/bindings/settings/protocol/exit.go b/bindings/settings/protocol/exit.go index 19b507797..2b9b98bdc 100644 --- a/bindings/settings/protocol/exit.go +++ b/bindings/settings/protocol/exit.go @@ -3,7 +3,6 @@ package protocol import ( "fmt" "math/big" - "sync" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -17,95 +16,90 @@ import ( // Config const ( - ExitSettingsContractName string = "rocketDAOProtocolSettingsExit" - CooperativeExitPhaseSettingPath string = "cooperative.exit.phase" - DidNotExitPenaltyBaseSettingPath string = "did.not.exit.penalty.base" - DidNotExitBaseSettingPath string = "did.not.exit.base" - DidNotExitBackoffSettingPath string = "did.not.exit.backoff" + // Exit settings are stored in the network settings contract. + CooperativeExitPhaseSettingPath string = "network.cooperative.exit.phase" + DidNotExitPenaltyBaseSettingPath string = "network.did.not.exit.penalty.base" + DidNotExitBaseSettingPath string = "network.did.not.exit.base" + DidNotExitBackoffSettingPath string = "network.did.not.exit.backoff" ) -// Minimum time a validator must remain exit-requested before triggered exit or penalty (hours) +// Minimum time a validator must remain exit-requested before triggered exit or penalty func GetCooperativeExitPhase(rp *rocketpool.RocketPool, opts *bind.CallOpts) (time.Duration, error) { - exitSettingsContract, err := getExitSettingsContract(rp, opts) + networkSettingsContract, err := getNetworkSettingsContract(rp, opts) if err != nil { return 0, err } value := new(*big.Int) - if err := exitSettingsContract.Call(opts, value, "getCooperativeExitPhase"); err != nil { + if err := networkSettingsContract.Call(opts, value, "getCooperativeExitPhase"); err != nil { return 0, fmt.Errorf("error getting cooperative exit phase: %w", err) } - return time.Duration((*value).Int64()) * time.Hour, nil + return time.Duration((*value).Int64()) * time.Second, nil } + +// Propose the cooperative exit phase in seconds func ProposeCooperativeExitPhase(rp *rocketpool.RocketPool, value *big.Int, blockNumber uint32, treeNodes []types.VotingTreeNode, opts *bind.TransactOpts) (uint64, common.Hash, error) { - return protocol.ProposeSetUint(rp, fmt.Sprintf("set %s", CooperativeExitPhaseSettingPath), ExitSettingsContractName, CooperativeExitPhaseSettingPath, value, blockNumber, treeNodes, opts) + return protocol.ProposeSetUint(rp, fmt.Sprintf("set %s", CooperativeExitPhaseSettingPath), NetworkSettingsContractName, CooperativeExitPhaseSettingPath, value, blockNumber, treeNodes, opts) } func EstimateProposeCooperativeExitPhaseGas(rp *rocketpool.RocketPool, value *big.Int, blockNumber uint32, treeNodes []types.VotingTreeNode, opts *bind.TransactOpts) (gaslimit.Limits, error) { - return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", CooperativeExitPhaseSettingPath), ExitSettingsContractName, CooperativeExitPhaseSettingPath, value, blockNumber, treeNodes, opts) + return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", CooperativeExitPhaseSettingPath), NetworkSettingsContractName, CooperativeExitPhaseSettingPath, value, blockNumber, treeNodes, opts) } // Base penalty applied to a minipool that fails to exit when requested func GetDidNotExitPenaltyBase(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*big.Int, error) { - exitSettingsContract, err := getExitSettingsContract(rp, opts) + networkSettingsContract, err := getNetworkSettingsContract(rp, opts) if err != nil { return nil, err } value := new(*big.Int) - if err := exitSettingsContract.Call(opts, value, "getDidNotExitPenaltyBase"); err != nil { + if err := networkSettingsContract.Call(opts, value, "getDidNotExitPenaltyBase"); err != nil { return nil, fmt.Errorf("error getting did not exit penalty base: %w", err) } return *value, nil } func ProposeDidNotExitPenaltyBase(rp *rocketpool.RocketPool, value *big.Int, blockNumber uint32, treeNodes []types.VotingTreeNode, opts *bind.TransactOpts) (uint64, common.Hash, error) { - return protocol.ProposeSetUint(rp, fmt.Sprintf("set %s", DidNotExitPenaltyBaseSettingPath), ExitSettingsContractName, DidNotExitPenaltyBaseSettingPath, value, blockNumber, treeNodes, opts) + return protocol.ProposeSetUint(rp, fmt.Sprintf("set %s", DidNotExitPenaltyBaseSettingPath), NetworkSettingsContractName, DidNotExitPenaltyBaseSettingPath, value, blockNumber, treeNodes, opts) } func EstimateProposeDidNotExitPenaltyBaseGas(rp *rocketpool.RocketPool, value *big.Int, blockNumber uint32, treeNodes []types.VotingTreeNode, opts *bind.TransactOpts) (gaslimit.Limits, error) { - return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", DidNotExitPenaltyBaseSettingPath), ExitSettingsContractName, DidNotExitPenaltyBaseSettingPath, value, blockNumber, treeNodes, opts) + return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", DidNotExitPenaltyBaseSettingPath), NetworkSettingsContractName, DidNotExitPenaltyBaseSettingPath, value, blockNumber, treeNodes, opts) } -// Initial window between consecutive did-not-exit penalties (days) +// Base delay after a failed cooperative exit before the protocol can try again func GetDidNotExitBase(rp *rocketpool.RocketPool, opts *bind.CallOpts) (time.Duration, error) { - exitSettingsContract, err := getExitSettingsContract(rp, opts) + networkSettingsContract, err := getNetworkSettingsContract(rp, opts) if err != nil { return 0, err } value := new(*big.Int) - if err := exitSettingsContract.Call(opts, value, "getDidNotExitBase"); err != nil { + if err := networkSettingsContract.Call(opts, value, "getDidNotExitBase"); err != nil { return 0, fmt.Errorf("error getting did not exit base: %w", err) } - return time.Duration((*value).Int64()) * 24 * time.Hour, nil + return time.Duration((*value).Int64()) * time.Second, nil } + +// Propose the base delay in seconds func ProposeDidNotExitBase(rp *rocketpool.RocketPool, value *big.Int, blockNumber uint32, treeNodes []types.VotingTreeNode, opts *bind.TransactOpts) (uint64, common.Hash, error) { - return protocol.ProposeSetUint(rp, fmt.Sprintf("set %s", DidNotExitBaseSettingPath), ExitSettingsContractName, DidNotExitBaseSettingPath, value, blockNumber, treeNodes, opts) + return protocol.ProposeSetUint(rp, fmt.Sprintf("set %s", DidNotExitBaseSettingPath), NetworkSettingsContractName, DidNotExitBaseSettingPath, value, blockNumber, treeNodes, opts) } func EstimateProposeDidNotExitBaseGas(rp *rocketpool.RocketPool, value *big.Int, blockNumber uint32, treeNodes []types.VotingTreeNode, opts *bind.TransactOpts) (gaslimit.Limits, error) { - return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", DidNotExitBaseSettingPath), ExitSettingsContractName, DidNotExitBaseSettingPath, value, blockNumber, treeNodes, opts) + return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", DidNotExitBaseSettingPath), NetworkSettingsContractName, DidNotExitBaseSettingPath, value, blockNumber, treeNodes, opts) } // Multiplier applied to the penalty window on each iteration (18-decimal fixed point): // the i-th window is did_not_exit_base * did_not_exit_backoff ** i func GetDidNotExitBackoff(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*big.Int, error) { - exitSettingsContract, err := getExitSettingsContract(rp, opts) + networkSettingsContract, err := getNetworkSettingsContract(rp, opts) if err != nil { return nil, err } value := new(*big.Int) - if err := exitSettingsContract.Call(opts, value, "getDidNotExitBackoff"); err != nil { + if err := networkSettingsContract.Call(opts, value, "getDidNotExitBackoff"); err != nil { return nil, fmt.Errorf("error getting did not exit backoff: %w", err) } return *value, nil } func ProposeDidNotExitBackoff(rp *rocketpool.RocketPool, value *big.Int, blockNumber uint32, treeNodes []types.VotingTreeNode, opts *bind.TransactOpts) (uint64, common.Hash, error) { - return protocol.ProposeSetUint(rp, fmt.Sprintf("set %s", DidNotExitBackoffSettingPath), ExitSettingsContractName, DidNotExitBackoffSettingPath, value, blockNumber, treeNodes, opts) + return protocol.ProposeSetUint(rp, fmt.Sprintf("set %s", DidNotExitBackoffSettingPath), NetworkSettingsContractName, DidNotExitBackoffSettingPath, value, blockNumber, treeNodes, opts) } func EstimateProposeDidNotExitBackoffGas(rp *rocketpool.RocketPool, value *big.Int, blockNumber uint32, treeNodes []types.VotingTreeNode, opts *bind.TransactOpts) (gaslimit.Limits, error) { - return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", DidNotExitBackoffSettingPath), ExitSettingsContractName, DidNotExitBackoffSettingPath, value, blockNumber, treeNodes, opts) -} - -// Get contracts -var exitSettingsContractLock sync.Mutex - -func getExitSettingsContract(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*rocketpool.Contract, error) { - exitSettingsContractLock.Lock() - defer exitSettingsContractLock.Unlock() - return rp.GetContract(ExitSettingsContractName, opts) + return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", DidNotExitBackoffSettingPath), NetworkSettingsContractName, DidNotExitBackoffSettingPath, value, blockNumber, treeNodes, opts) } diff --git a/bindings/settings/protocol/setting-types.go b/bindings/settings/protocol/setting-types.go index 136ab5986..dcf5f7a8a 100644 --- a/bindings/settings/protocol/setting-types.go +++ b/bindings/settings/protocol/setting-types.go @@ -62,6 +62,10 @@ var pdaoSettingKinds = map[string]map[string]settingKind{ MinipoolUserDistributeWindowLengthSettingPath: settingKindUint256, }, NetworkSettingsContractName: { + CooperativeExitPhaseSettingPath: settingKindUint256, + DidNotExitPenaltyBaseSettingPath: settingKindUint256, + DidNotExitBaseSettingPath: settingKindUint256, + DidNotExitBackoffSettingPath: settingKindUint256, NodeConsensusThresholdSettingPath: settingKindUint256, SubmitBalancesEnabledSettingPath: settingKindBool, SubmitBalancesFrequencySettingPath: settingKindUint256, @@ -138,12 +142,6 @@ var pdaoSettingKinds = map[string]map[string]settingKind{ PerformanceChallengePeriodSettingPath: settingKindUint256, PerformanceChallengeBondSettingPath: settingKindUint256, }, - ExitSettingsContractName: { - CooperativeExitPhaseSettingPath: settingKindUint256, - DidNotExitPenaltyBaseSettingPath: settingKindUint256, - DidNotExitBaseSettingPath: settingKindUint256, - DidNotExitBackoffSettingPath: settingKindUint256, - }, } // GetProposalSettingType returns the on-chain type used by proposalSettingMulti diff --git a/rocketpool-cli/cli/saturn2-check.go b/rocketpool-cli/cli/saturn2-check.go index aff18525d..3f5c2ed53 100644 --- a/rocketpool-cli/cli/saturn2-check.go +++ b/rocketpool-cli/cli/saturn2-check.go @@ -12,8 +12,15 @@ const Saturn2NotDeployedMessage = "This command is not available until Saturn 2 // IsSaturn2OnlySetting reports whether a protocol setting exists only after Saturn 2. func IsSaturn2OnlySetting(contract, setting string) bool { switch contract { - case protocol.PerformanceSettingsContractName, protocol.ExitSettingsContractName: + case protocol.PerformanceSettingsContractName: return true + case protocol.NetworkSettingsContractName: + switch setting { + case protocol.CooperativeExitPhaseSettingPath, protocol.DidNotExitPenaltyBaseSettingPath, + protocol.DidNotExitBaseSettingPath, protocol.DidNotExitBackoffSettingPath: + return true + } + return false case protocol.MegapoolSettingsContractName: return setting == protocol.MegapoolPrestakeChallengePeriodPath default: diff --git a/rocketpool-cli/pdao/commands.go b/rocketpool-cli/pdao/commands.go index 12656776e..47d486762 100644 --- a/rocketpool-cli/pdao/commands.go +++ b/rocketpool-cli/pdao/commands.go @@ -21,7 +21,6 @@ const ( floatMultiplierUsage string = "specify a multiplier (e.g., '1.5')" epochCountUsage string = "specify a number, in epochs (eg., '100')" hourCountUsage string = "specify a number, in hours (e.g., '72')" - dayCountUsage string = "specify a number, in days (e.g., '28')" durationUsage string = "specify a duration using hours, minutes, and seconds (e.g., '20m' or '72h0m0s')" addressListUsage string = "specify a list of one or more addresses separated by commas (e.g., '0x1a2b3c4d5e6f7890abcdef1234567890abcdef12,0xabcdefabcdefabcdefabcdefabcdefabcdefabcd')" ) @@ -3571,7 +3570,7 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { { Name: "cooperative-exit-phase", Aliases: []string{"cep"}, - Usage: fmt.Sprintf("Propose updating the %s setting; %s", protocol.CooperativeExitPhaseSettingPath, hourCountUsage), + Usage: fmt.Sprintf("Propose updating the %s setting; %s", protocol.CooperativeExitPhaseSettingPath, durationUsage), UsageText: "rocketpool pdao propose setting exit cooperative-exit-phase value", Flags: []cli.Flag{ &cli.BoolFlag{ @@ -3590,7 +3589,7 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { if err := cliutils.ValidateArgCount(c, 1); err != nil { return err } - value, err := cliutils.ValidatePositiveUint("value", c.Args().Get(0)) + value, err := cliutils.ValidateDuration("value", c.Args().Get(0)) if err != nil { return err } @@ -3641,7 +3640,7 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { { Name: "did-not-exit-base", Aliases: []string{"dneb"}, - Usage: fmt.Sprintf("Propose updating the %s setting; %s", protocol.DidNotExitBaseSettingPath, dayCountUsage), + Usage: fmt.Sprintf("Propose updating the %s setting; %s", protocol.DidNotExitBaseSettingPath, durationUsage), UsageText: "rocketpool pdao propose setting exit did-not-exit-base value", Flags: []cli.Flag{ &cli.BoolFlag{ @@ -3660,7 +3659,7 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { if err := cliutils.ValidateArgCount(c, 1); err != nil { return err } - value, err := cliutils.ValidatePositiveUint("value", c.Args().Get(0)) + value, err := cliutils.ValidateDuration("value", c.Args().Get(0)) if err != nil { return err } diff --git a/rocketpool-cli/pdao/propose-settings.go b/rocketpool-cli/pdao/propose-settings.go index 86874d9fe..e1216039c 100644 --- a/rocketpool-cli/pdao/propose-settings.go +++ b/rocketpool-cli/pdao/propose-settings.go @@ -400,24 +400,24 @@ func proposeSettingPerformanceChallengeBond(value *big.Int, yes bool, toJson str return proposeSetting(protocol.PerformanceSettingsContractName, protocol.PerformanceChallengeBondSettingPath, trueValue, yes, toJson) } -func proposeSettingCooperativeExitPhase(value uint64, yes bool, toJson string) error { - trueValue := fmt.Sprint(value) - return proposeSetting(protocol.ExitSettingsContractName, protocol.CooperativeExitPhaseSettingPath, trueValue, yes, toJson) +func proposeSettingCooperativeExitPhase(value time.Duration, yes bool, toJson string) error { + trueValue := fmt.Sprint(uint64(value.Seconds())) + return proposeSetting(protocol.NetworkSettingsContractName, protocol.CooperativeExitPhaseSettingPath, trueValue, yes, toJson) } func proposeSettingDidNotExitPenaltyBase(value *big.Int, yes bool, toJson string) error { trueValue := value.String() - return proposeSetting(protocol.ExitSettingsContractName, protocol.DidNotExitPenaltyBaseSettingPath, trueValue, yes, toJson) + return proposeSetting(protocol.NetworkSettingsContractName, protocol.DidNotExitPenaltyBaseSettingPath, trueValue, yes, toJson) } -func proposeSettingDidNotExitBase(value uint64, yes bool, toJson string) error { - trueValue := fmt.Sprint(value) - return proposeSetting(protocol.ExitSettingsContractName, protocol.DidNotExitBaseSettingPath, trueValue, yes, toJson) +func proposeSettingDidNotExitBase(value time.Duration, yes bool, toJson string) error { + trueValue := fmt.Sprint(uint64(value.Seconds())) + return proposeSetting(protocol.NetworkSettingsContractName, protocol.DidNotExitBaseSettingPath, trueValue, yes, toJson) } func proposeSettingDidNotExitBackoff(value *big.Int, yes bool, toJson string) error { trueValue := value.String() - return proposeSetting(protocol.ExitSettingsContractName, protocol.DidNotExitBackoffSettingPath, trueValue, yes, toJson) + return proposeSetting(protocol.NetworkSettingsContractName, protocol.DidNotExitBackoffSettingPath, trueValue, yes, toJson) } func proposeSettingNodeCommissionShare(value *big.Int, yes bool, toJson string) error { diff --git a/rocketpool/api/pdao/propose-settings.go b/rocketpool/api/pdao/propose-settings.go index ee1c31e13..9d01eeb30 100644 --- a/rocketpool/api/pdao/propose-settings.go +++ b/rocketpool/api/pdao/propose-settings.go @@ -354,6 +354,50 @@ func canProposeSetting(c *cli.Command, contractName string, settingName string, case protocol.NetworkSettingsContractName: switch settingName { + // CooperativeExitPhase + case protocol.CooperativeExitPhaseSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + response.GasLimits, err = protocol.EstimateProposeCooperativeExitPhaseGas(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error estimating gas for proposing CooperativeExitPhase: %w", err) + } + + // DidNotExitPenaltyBase + case protocol.DidNotExitPenaltyBaseSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + response.GasLimits, err = protocol.EstimateProposeDidNotExitPenaltyBaseGas(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error estimating gas for proposing DidNotExitPenaltyBase: %w", err) + } + + // DidNotExitBase + case protocol.DidNotExitBaseSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + response.GasLimits, err = protocol.EstimateProposeDidNotExitBaseGas(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error estimating gas for proposing DidNotExitBase: %w", err) + } + + // DidNotExitBackoff + case protocol.DidNotExitBackoffSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + response.GasLimits, err = protocol.EstimateProposeDidNotExitBackoffGas(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error estimating gas for proposing DidNotExitBackoff: %w", err) + } + // NodeConsensusThreshold case protocol.NodeConsensusThresholdSettingPath: newValue, err := cliutils.ValidateBigInt(valueName, value) @@ -1040,53 +1084,6 @@ func canProposeSetting(c *cli.Command, contractName string, settingName string, } } - case protocol.ExitSettingsContractName: - switch settingName { - // CooperativeExitPhase - case protocol.CooperativeExitPhaseSettingPath: - newValue, err := cliutils.ValidateBigInt(valueName, value) - if err != nil { - return nil, err - } - response.GasLimits, err = protocol.EstimateProposeCooperativeExitPhaseGas(rp, newValue, blockNumber, pollard, opts) - if err != nil { - return nil, fmt.Errorf("error estimating gas for proposing CooperativeExitPhase: %w", err) - } - - // DidNotExitPenaltyBase - case protocol.DidNotExitPenaltyBaseSettingPath: - newValue, err := cliutils.ValidateBigInt(valueName, value) - if err != nil { - return nil, err - } - response.GasLimits, err = protocol.EstimateProposeDidNotExitPenaltyBaseGas(rp, newValue, blockNumber, pollard, opts) - if err != nil { - return nil, fmt.Errorf("error estimating gas for proposing DidNotExitPenaltyBase: %w", err) - } - - // DidNotExitBase - case protocol.DidNotExitBaseSettingPath: - newValue, err := cliutils.ValidateBigInt(valueName, value) - if err != nil { - return nil, err - } - response.GasLimits, err = protocol.EstimateProposeDidNotExitBaseGas(rp, newValue, blockNumber, pollard, opts) - if err != nil { - return nil, fmt.Errorf("error estimating gas for proposing DidNotExitBase: %w", err) - } - - // DidNotExitBackoff - case protocol.DidNotExitBackoffSettingPath: - newValue, err := cliutils.ValidateBigInt(valueName, value) - if err != nil { - return nil, err - } - response.GasLimits, err = protocol.EstimateProposeDidNotExitBackoffGas(rp, newValue, blockNumber, pollard, opts) - if err != nil { - return nil, fmt.Errorf("error estimating gas for proposing DidNotExitBackoff: %w", err) - } - } - } // Make sure a setting was actually hit @@ -1367,6 +1364,50 @@ func proposeSetting(c *cli.Command, contractName string, settingName string, val case protocol.NetworkSettingsContractName: switch settingName { + // CooperativeExitPhase + case protocol.CooperativeExitPhaseSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + proposalID, hash, err = protocol.ProposeCooperativeExitPhase(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error proposing CooperativeExitPhase: %w", err) + } + + // DidNotExitPenaltyBase + case protocol.DidNotExitPenaltyBaseSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + proposalID, hash, err = protocol.ProposeDidNotExitPenaltyBase(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error proposing DidNotExitPenaltyBase: %w", err) + } + + // DidNotExitBase + case protocol.DidNotExitBaseSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + proposalID, hash, err = protocol.ProposeDidNotExitBase(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error proposing DidNotExitBase: %w", err) + } + + // DidNotExitBackoff + case protocol.DidNotExitBackoffSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + proposalID, hash, err = protocol.ProposeDidNotExitBackoff(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error proposing DidNotExitBackoff: %w", err) + } + // NodeConsensusThreshold case protocol.NodeConsensusThresholdSettingPath: newValue, err := cliutils.ValidateBigInt(valueName, value) @@ -2054,53 +2095,6 @@ func proposeSetting(c *cli.Command, contractName string, settingName string, val } } - case protocol.ExitSettingsContractName: - switch settingName { - // CooperativeExitPhase - case protocol.CooperativeExitPhaseSettingPath: - newValue, err := cliutils.ValidateBigInt(valueName, value) - if err != nil { - return nil, err - } - proposalID, hash, err = protocol.ProposeCooperativeExitPhase(rp, newValue, blockNumber, pollard, opts) - if err != nil { - return nil, fmt.Errorf("error proposing CooperativeExitPhase: %w", err) - } - - // DidNotExitPenaltyBase - case protocol.DidNotExitPenaltyBaseSettingPath: - newValue, err := cliutils.ValidateBigInt(valueName, value) - if err != nil { - return nil, err - } - proposalID, hash, err = protocol.ProposeDidNotExitPenaltyBase(rp, newValue, blockNumber, pollard, opts) - if err != nil { - return nil, fmt.Errorf("error proposing DidNotExitPenaltyBase: %w", err) - } - - // DidNotExitBase - case protocol.DidNotExitBaseSettingPath: - newValue, err := cliutils.ValidateBigInt(valueName, value) - if err != nil { - return nil, err - } - proposalID, hash, err = protocol.ProposeDidNotExitBase(rp, newValue, blockNumber, pollard, opts) - if err != nil { - return nil, fmt.Errorf("error proposing DidNotExitBase: %w", err) - } - - // DidNotExitBackoff - case protocol.DidNotExitBackoffSettingPath: - newValue, err := cliutils.ValidateBigInt(valueName, value) - if err != nil { - return nil, err - } - proposalID, hash, err = protocol.ProposeDidNotExitBackoff(rp, newValue, blockNumber, pollard, opts) - if err != nil { - return nil, fmt.Errorf("error proposing DidNotExitBackoff: %w", err) - } - } - } // Make sure a setting was actually hit diff --git a/rocketpool/node/check-megapool-exit-requests.go b/rocketpool/node/check-megapool-exit-requests.go index 682df2ef5..1482692dd 100644 --- a/rocketpool/node/check-megapool-exit-requests.go +++ b/rocketpool/node/check-megapool-exit-requests.go @@ -142,8 +142,9 @@ func (t *checkMegapoolExitRequests) run(state *state.NetworkStateIndex) error { return err } - // Search MegapoolExitRequested events over a window covering the cooperative exit phase - lookbackBlocks := uint64(cooperativeExitPhase / (time.Duration(state.BeaconConfig.SecondsPerSlot) * time.Second)) + // Search the cooperative phase plus the enforcement window so overdue requests can be retried. + lookbackDuration := cooperativeExitPhase + exitRequestEnforcementWindow + lookbackBlocks := uint64(lookbackDuration / (time.Duration(state.BeaconConfig.SecondsPerSlot) * time.Second)) if lookbackBlocks == 0 { lookbackBlocks = 1 } @@ -298,6 +299,13 @@ func (t *checkMegapoolExitRequests) forceExitMegapoolValidator(mp megapool.Megap return err } + // Fund the EIP-7002 exit fee for both gas estimation and submission + exitFee, err := network.GetExitFee(t.rp, nil) + if err != nil { + return err + } + opts.Value = exitFee + // Get the gas limit gasInfo, err := network.EstimateForceMegapoolExitGas(t.rp, request.MegapoolAddress, request.ValidatorId, opts) if err != nil { diff --git a/rocketpool/node/check-minipool-exit-requests.go b/rocketpool/node/check-minipool-exit-requests.go index a24534904..2bc0f0bad 100644 --- a/rocketpool/node/check-minipool-exit-requests.go +++ b/rocketpool/node/check-minipool-exit-requests.go @@ -152,8 +152,9 @@ func (t *checkMinipoolExitRequests) run(state *state.NetworkStateIndex) error { return err } - // Search MinipoolExitRequested events over a window covering the cooperative exit phase - lookbackBlocks := uint64(cooperativeExitPhase / (time.Duration(state.BeaconConfig.SecondsPerSlot) * time.Second)) + // Search the cooperative phase plus the enforcement window so overdue requests can be retried. + lookbackDuration := cooperativeExitPhase + exitRequestEnforcementWindow + lookbackBlocks := uint64(lookbackDuration / (time.Duration(state.BeaconConfig.SecondsPerSlot) * time.Second)) if lookbackBlocks == 0 { lookbackBlocks = 1 } @@ -323,6 +324,13 @@ func (t *checkMinipoolExitRequests) forceExitMinipool(mpd *rpstate.NativeMinipoo return err } + // Fund the EIP-7002 exit fee for both gas estimation and submission + exitFee, err := network.GetExitFee(t.rp, nil) + if err != nil { + return err + } + opts.Value = exitFee + // Get the gas limit gasInfo, err := network.EstimateForceMinipoolExitGas(t.rp, mpd.MinipoolAddress, opts) if err != nil { diff --git a/rocketpool/node/node.go b/rocketpool/node/node.go index 59197a8c3..cf5a31a36 100644 --- a/rocketpool/node/node.go +++ b/rocketpool/node/node.go @@ -39,6 +39,9 @@ var ( const ( MaxConcurrentEth1Requests = 200 + // Keep exit requests in the scan for seven days after the cooperative phase. + exitRequestEnforcementWindow = 7 * 24 * time.Hour + DownloadRewardsTreesColor = color.FgGreen MetricsColor = color.FgHiYellow ManageFeeRecipientColor = color.FgHiCyan