diff --git a/bindings/dao/upgrades/details.go b/bindings/dao/upgrades/details.go index 740b7b73e..4bd820b0f 100644 --- a/bindings/dao/upgrades/details.go +++ b/bindings/dao/upgrades/details.go @@ -5,6 +5,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "golang.org/x/sync/errgroup" "github.com/rocket-pool/smartnode/bindings/rocketpool" @@ -25,6 +26,23 @@ type UpgradeProposalDetails struct { UpgradeAbi string `json:"upgradeAbi"` } +// On-chain upgrade types are stored as keccak256 of the type string +var upgradeProposalTypeNames = map[common.Hash]string{ + crypto.Keccak256Hash([]byte("upgradeContract")): "UpgradeContract", + crypto.Keccak256Hash([]byte("addContract")): "AddContract", + crypto.Keccak256Hash([]byte("addABI")): "AddABI", + crypto.Keccak256Hash([]byte("upgradeABI")): "UpgradeABI", +} + +// TypeName returns the interpreted upgrade type, or the type hash if unknown +func (p UpgradeProposalDetails) TypeName() string { + hash := common.Hash(p.Type) + if name, ok := upgradeProposalTypeNames[hash]; ok { + return name + } + return hash.Hex() +} + // Get all upgrade proposal details func GetUpgradeProposals(rp *rocketpool.RocketPool, opts *bind.CallOpts) ([]UpgradeProposalDetails, error) { diff --git a/bindings/settings/protocol/network.go b/bindings/settings/protocol/network.go index 801d9eb5e..a9fb38f32 100644 --- a/bindings/settings/protocol/network.go +++ b/bindings/settings/protocol/network.go @@ -39,6 +39,7 @@ const ( NetworkPDAOSharePath string = "network.pdao.share" NetworkMaxNodeShareSecurityCouncilAdderPath string = "network.max.node.commission.share.council.adder" NetworkMaxRethBalanceDeltaPath string = "network.max.reth.balance.delta" + NetworkRethDepositDelaySettingPath string = "network.reth.deposit.delay" ) // The threshold of trusted nodes that must reach consensus on oracle data to commit it @@ -519,6 +520,25 @@ func EstimateMaxRethDeltaGas(rp *rocketpool.RocketPool, value *big.Int, blockNum return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", NetworkMaxRethBalanceDeltaPath), NetworkSettingsContractName, NetworkMaxRethBalanceDeltaPath, value, blockNumber, treeNodes, opts) } +// The number of blocks that must pass after a deposit before a user's rETH can be transferred +func GetRethDepositDelay(rp *rocketpool.RocketPool, opts *bind.CallOpts) (uint64, error) { + networkSettingsContract, err := getNetworkSettingsContract(rp, opts) + if err != nil { + return 0, err + } + value := new(*big.Int) + if err := networkSettingsContract.Call(opts, value, "getRethDepositDelay"); err != nil { + return 0, fmt.Errorf("error getting reth deposit delay: %w", err) + } + return (*value).Uint64(), nil +} +func ProposeRethDepositDelay(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", NetworkRethDepositDelaySettingPath), NetworkSettingsContractName, NetworkRethDepositDelaySettingPath, value, blockNumber, treeNodes, opts) +} +func EstimateProposeRethDepositDelayGas(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", NetworkRethDepositDelaySettingPath), NetworkSettingsContractName, NetworkRethDepositDelaySettingPath, value, blockNumber, treeNodes, opts) +} + // Get contracts var networkSettingsContractLock sync.Mutex diff --git a/bindings/settings/protocol/node.go b/bindings/settings/protocol/node.go index a7b327544..eac702b69 100644 --- a/bindings/settings/protocol/node.go +++ b/bindings/settings/protocol/node.go @@ -25,6 +25,8 @@ const ( MinimumLegacyRplStakePath string = "node.minimum.legacy.staked.rpl" ReducedBondSettingPath string = "reduced.bond" NodeUnstakingPeriodSettingPath string = "node.unstaking.period" + NodeWithdrawalCooldownSettingPath string = "node.withdrawal.cooldown" + MaximumStakeForVotingPowerSettingPath string = "node.voting.power.stake.maximum" ) // Node registrations currently enabled @@ -186,6 +188,44 @@ func EstimateProposeNodeUnstakingPeriod(rp *rocketpool.RocketPool, value *big.In return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", NodeUnstakingPeriodSettingPath), NodeSettingsContractName, NodeUnstakingPeriodSettingPath, value, blockNumber, treeNodes, opts) } +// The period of time a node must wait after staking RPL before it can be withdrawn again +func GetWithdrawalCooldown(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*big.Int, error) { + nodeSettingsContract, err := getNodeSettingsContract(rp, opts) + if err != nil { + return nil, err + } + value := new(*big.Int) + if err := nodeSettingsContract.Call(opts, value, "getWithdrawalCooldown"); err != nil { + return nil, fmt.Errorf("error getting the withdrawal cooldown: %w", err) + } + return *value, nil +} +func ProposeWithdrawalCooldown(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", NodeWithdrawalCooldownSettingPath), NodeSettingsContractName, NodeWithdrawalCooldownSettingPath, value, blockNumber, treeNodes, opts) +} +func EstimateProposeWithdrawalCooldownGas(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", NodeWithdrawalCooldownSettingPath), NodeSettingsContractName, NodeWithdrawalCooldownSettingPath, value, blockNumber, treeNodes, opts) +} + +// Maximum staked RPL that applies to voting power per minipool, as a fraction of assigned user ETH value (100%-500%) +func GetMaximumStakeForVotingPower(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*big.Int, error) { + nodeSettingsContract, err := getNodeSettingsContract(rp, opts) + if err != nil { + return nil, err + } + value := new(*big.Int) + if err := nodeSettingsContract.Call(opts, value, "getMaximumStakeForVotingPower"); err != nil { + return nil, fmt.Errorf("error getting maximum stake for voting power: %w", err) + } + return *value, nil +} +func ProposeMaximumStakeForVotingPower(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", MaximumStakeForVotingPowerSettingPath), NodeSettingsContractName, MaximumStakeForVotingPowerSettingPath, value, blockNumber, treeNodes, opts) +} +func EstimateProposeMaximumStakeForVotingPowerGas(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", MaximumStakeForVotingPowerSettingPath), NodeSettingsContractName, MaximumStakeForVotingPowerSettingPath, value, blockNumber, treeNodes, opts) +} + // Get contracts var nodeSettingsContractLock sync.Mutex diff --git a/bindings/settings/protocol/security.go b/bindings/settings/protocol/security.go index df6ca1020..c4b70b639 100644 --- a/bindings/settings/protocol/security.go +++ b/bindings/settings/protocol/security.go @@ -23,6 +23,8 @@ const ( SecurityProposalVoteTimeSettingPath string = "proposal.vote.time" SecurityProposalExecuteTimeSettingPath string = "proposal.execute.time" SecurityProposalActionTimeSettingPath string = "proposal.action.time" + SecurityUpgradeVetoQuorumSettingPath string = "upgradeveto.quorum" + SecurityUpgradeDelaySettingPath string = "upgrade.delay" ) // Security council member quorum threshold that must be met for proposals to pass @@ -120,6 +122,44 @@ func EstimateProposeSecurityProposalActionTimeGas(rp *rocketpool.RocketPool, val return protocol.EstimateProposeSetUintGas(rp, fmt.Sprintf("set %s", SecurityProposalActionTimeSettingPath), SecuritySettingsContractName, SecurityProposalActionTimeSettingPath, value, blockNumber, treeNodes, opts) } +// Security council quorum threshold that must be met to veto a protocol upgrade +func GetSecurityUpgradeVetoQuorum(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*big.Int, error) { + securitySettingsContract, err := getSecuritySettingsContract(rp, opts) + if err != nil { + return nil, err + } + value := new(*big.Int) + if err := securitySettingsContract.Call(opts, value, "getUpgradeVetoQuorum"); err != nil { + return nil, fmt.Errorf("error getting security upgrade veto quorum: %w", err) + } + return *value, nil +} +func ProposeSecurityUpgradeVetoQuorum(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", SecurityUpgradeVetoQuorumSettingPath), SecuritySettingsContractName, SecurityUpgradeVetoQuorumSettingPath, value, blockNumber, treeNodes, opts) +} +func EstimateProposeSecurityUpgradeVetoQuorumGas(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", SecurityUpgradeVetoQuorumSettingPath), SecuritySettingsContractName, SecurityUpgradeVetoQuorumSettingPath, value, blockNumber, treeNodes, opts) +} + +// How long after a protocol upgrade proposal passes that the security council has to veto it +func GetSecurityUpgradeDelay(rp *rocketpool.RocketPool, opts *bind.CallOpts) (time.Duration, error) { + securitySettingsContract, err := getSecuritySettingsContract(rp, opts) + if err != nil { + return 0, err + } + value := new(*big.Int) + if err := securitySettingsContract.Call(opts, value, "getUpgradeDelay"); err != nil { + return 0, fmt.Errorf("error getting security upgrade delay: %w", err) + } + return time.Second * time.Duration((*value).Uint64()), nil +} +func ProposeSecurityUpgradeDelay(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", SecurityUpgradeDelaySettingPath), SecuritySettingsContractName, SecurityUpgradeDelaySettingPath, value, blockNumber, treeNodes, opts) +} +func EstimateProposeSecurityUpgradeDelayGas(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", SecurityUpgradeDelaySettingPath), SecuritySettingsContractName, SecurityUpgradeDelaySettingPath, value, blockNumber, treeNodes, opts) +} + // Get contracts var securitySettingsContractLock sync.Mutex diff --git a/bindings/settings/protocol/setting-types.go b/bindings/settings/protocol/setting-types.go index f90efa86f..cd086fe48 100644 --- a/bindings/settings/protocol/setting-types.go +++ b/bindings/settings/protocol/setting-types.go @@ -82,6 +82,7 @@ var pdaoSettingKinds = map[string]map[string]settingKind{ NetworkPDAOSharePath: settingKindUint256, NetworkMaxNodeShareSecurityCouncilAdderPath: settingKindUint256, NetworkMaxRethBalanceDeltaPath: settingKindUint256, + NetworkRethDepositDelaySettingPath: settingKindUint256, }, NodeSettingsContractName: { NodeRegistrationEnabledSettingPath: settingKindBool, @@ -91,6 +92,8 @@ var pdaoSettingKinds = map[string]map[string]settingKind{ MinimumLegacyRplStakePath: settingKindUint256, ReducedBondSettingPath: settingKindUint256, NodeUnstakingPeriodSettingPath: settingKindUint256, + NodeWithdrawalCooldownSettingPath: settingKindUint256, + MaximumStakeForVotingPowerSettingPath: settingKindUint256, }, ProposalsSettingsContractName: { VotePhase1TimeSettingPath: settingKindUint256, @@ -113,6 +116,8 @@ var pdaoSettingKinds = map[string]map[string]settingKind{ SecurityProposalVoteTimeSettingPath: settingKindUint256, SecurityProposalExecuteTimeSettingPath: settingKindUint256, SecurityProposalActionTimeSettingPath: settingKindUint256, + SecurityUpgradeVetoQuorumSettingPath: settingKindUint256, + SecurityUpgradeDelaySettingPath: settingKindUint256, }, MegapoolSettingsContractName: { MegapoolTimeBeforeDissolveSettingsPath: settingKindUint256, diff --git a/rocketpool-cli/odao/execute-upgrade.go b/rocketpool-cli/odao/execute-upgrade.go index 70608b3fa..4df4e935a 100644 --- a/rocketpool-cli/odao/execute-upgrade.go +++ b/rocketpool-cli/odao/execute-upgrade.go @@ -5,8 +5,6 @@ import ( "strconv" "time" - "github.com/ethereum/go-ethereum/common" - "github.com/rocket-pool/smartnode/bindings/dao/upgrades" "github.com/rocket-pool/smartnode/bindings/transactions/gaslimit" "github.com/rocket-pool/smartnode/bindings/types" @@ -34,17 +32,12 @@ func getUpgradeProposals() error { fmt.Printf("Found %d upgrade proposals.\n\n", len(upgradeProposals.Proposals)) - typeMap := make(map[string]string) - typeMap["0x529a09aed0ded46c4cc64a5f9a6cb6dbde240a9e9c966041749f311248110e11"] = "UpgradeContract" - typeMap["0x19f10da52b60efe9f5ee07f5d429a865c0bda23ae1482284927780c41b724cef"] = "AddContract" - typeMap["0x1ca99adef8e0f1a6fa2cbc2b46aedc54c66479f38df59bff3575de40893db660"] = "AddABI" - typeMap["0xbe19c295254203061a6ecbbdd7353a2134a6bae25c11f27532123ce4a4be1600"] = "UpgradeABI" // Print upgrade proposals for _, proposal := range upgradeProposals.Proposals { fmt.Printf("Upgrade proposal %d: %s\n", proposal.ID, proposal.Name) fmt.Printf(" State: %s\n", types.UpgradeProposalStates[types.UpgradeProposalState(proposal.State)]) fmt.Printf(" End time: %s\n", time.Unix(proposal.EndTime.Int64(), 0).Format(time.RFC3339)) - fmt.Printf(" Type: %s\n", typeMap[common.BytesToHash([]byte(proposal.Type[:])).String()]) + fmt.Printf(" Type: %s\n", proposal.TypeName()) fmt.Printf(" Upgrade address: %s\n", proposal.UpgradeAddress) fmt.Printf(" Upgrade ABI: %s\n", proposal.UpgradeAbi) @@ -92,6 +85,7 @@ func executeUpgrade(proposal string, yes bool) error { fmt.Printf(" ID %d: %s\n", proposal.ID, proposal.Name) fmt.Printf(" State: %s\n", types.UpgradeProposalStates[types.UpgradeProposalState(proposal.State)]) fmt.Printf(" End time: %s\n", time.Unix(proposal.EndTime.Int64(), 0).Format(time.RFC3339)) + fmt.Printf(" Type: %s\n", proposal.TypeName()) fmt.Printf(" Upgrade address: %s\n", proposal.UpgradeAddress) fmt.Printf(" Upgrade ABI: %s\n\n", proposal.UpgradeAbi) } @@ -134,7 +128,7 @@ func executeUpgrade(proposal string, yes bool) error { options := make([]string, len(executableProposals)+1) options[0] = "All available proposals" for pi, proposal := range executableProposals { - options[pi+1] = fmt.Sprintf("proposal %d (name: '%s', type: '%s', upgrade address: '%s', upgrade ABI: '%s')", proposal.ID, proposal.Name, proposal.Type, proposal.UpgradeAddress, proposal.UpgradeAbi) + options[pi+1] = fmt.Sprintf("proposal %d (name: '%s', type: '%s', upgrade address: '%s', upgrade ABI: '%s')", proposal.ID, proposal.Name, proposal.TypeName(), proposal.UpgradeAddress, proposal.UpgradeAbi) } selected, _ := prompt.Select("Please select a proposal to execute:", options) @@ -173,7 +167,7 @@ func executeUpgrade(proposal string, yes bool) error { // Execute proposals for _, proposal := range selectedProposals { g.Assign(rp) - response, err := rp.ExecuteTNDAOProposal(proposal.ID) + response, err := rp.ExecuteUpgradeProposal(proposal.ID) if err != nil { fmt.Printf("Could not execute proposal %d: %s.\n", proposal.ID, err) continue diff --git a/rocketpool-cli/pdao/commands.go b/rocketpool-cli/pdao/commands.go index edbe0e057..7a2676ff3 100644 --- a/rocketpool-cli/pdao/commands.go +++ b/rocketpool-cli/pdao/commands.go @@ -2035,6 +2035,39 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { }, }, + + { + Name: "reth-deposit-delay", + Aliases: []string{"rdd"}, + Usage: fmt.Sprintf("Propose updating the %s setting; %s", protocol.NetworkRethDepositDelaySettingPath, blockCountUsage), + UsageText: "rocketpool pdao propose setting network reth-deposit-delay value", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "yes", + Aliases: []string{"y"}, + Usage: "Automatically confirm all interactive questions", + }, + &cli.StringFlag{ + Name: "to-json", + Usage: "Write this setting to a JSON file instead of submitting a proposal (creates the file or appends to it)", + }, + }, + Action: func(ctx context.Context, c *cli.Command) error { + + // Validate args + if err := cliutils.ValidateArgCount(c, 1); err != nil { + return err + } + value, err := cliutils.ValidatePositiveUint("value", c.Args().Get(0)) + if err != nil { + return err + } + + // Run + return proposeRethDepositDelay(value, c.Bool("yes"), c.String("to-json")) + + }, + }, }, }, @@ -2282,6 +2315,76 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { }, }, + + { + Name: "withdrawal-cooldown", + Aliases: []string{"wc"}, + Usage: fmt.Sprintf("Propose updating the %s setting; %s", protocol.NodeWithdrawalCooldownSettingPath, durationUsage), + UsageText: "rocketpool pdao propose setting node withdrawal-cooldown value", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "yes", + Aliases: []string{"y"}, + Usage: "Automatically confirm all interactive questions", + }, + &cli.StringFlag{ + Name: "to-json", + Usage: "Write this setting to a JSON file instead of submitting a proposal (creates the file or appends to it)", + }, + }, + Action: func(ctx context.Context, c *cli.Command) error { + + // Validate args + if err := cliutils.ValidateArgCount(c, 1); err != nil { + return err + } + value, err := cliutils.ValidateDuration("value", c.Args().Get(0)) + if err != nil { + return err + } + + // Run + return proposeSettingNodeWithdrawalCooldown(value, c.Bool("yes"), c.String("to-json")) + + }, + }, + + { + Name: "max-stake-for-voting-power", + Aliases: []string{"msvp"}, + Usage: fmt.Sprintf("Propose updating the %s setting; %s", protocol.MaximumStakeForVotingPowerSettingPath, unboundedPercentUsage), + UsageText: "rocketpool pdao propose setting node max-stake-for-voting-power value", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "raw", + Usage: "Add this flag if your setting is an 18-decimal-fixed-point-integer (wei) value instead of a float", + }, + &cli.BoolFlag{ + Name: "yes", + Aliases: []string{"y"}, + Usage: "Automatically confirm all interactive questions", + }, + &cli.StringFlag{ + Name: "to-json", + Usage: "Write this setting to a JSON file instead of submitting a proposal (creates the file or appends to it)", + }, + }, + Action: func(ctx context.Context, c *cli.Command) error { + + // Validate args + if err := cliutils.ValidateArgCount(c, 1); err != nil { + return err + } + value, err := cliutils.ValidateFloat(c.Bool("raw"), "value", c.Args().Get(0), false, c.Bool("yes")) + if err != nil { + return err + } + + // Run + return proposeSettingNodeMaximumStakeForVotingPower(value, c.Bool("yes"), c.String("to-json")) + + }, + }, }, }, @@ -2854,6 +2957,76 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { }, }, + + { + Name: "upgrade-veto-quorum", + Aliases: []string{"uvq"}, + Usage: fmt.Sprintf("Propose updating the %s setting; %s", protocol.SecurityUpgradeVetoQuorumSettingPath, percentUsage), + UsageText: "rocketpool pdao propose setting security upgrade-veto-quorum value", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "raw", + Usage: "Add this flag if your setting is an 18-decimal-fixed-point-integer (wei) value instead of a float", + }, + &cli.BoolFlag{ + Name: "yes", + Aliases: []string{"y"}, + Usage: "Automatically confirm all interactive questions", + }, + &cli.StringFlag{ + Name: "to-json", + Usage: "Write this setting to a JSON file instead of submitting a proposal (creates the file or appends to it)", + }, + }, + Action: func(ctx context.Context, c *cli.Command) error { + + // Validate args + if err := cliutils.ValidateArgCount(c, 1); err != nil { + return err + } + value, err := cliutils.ValidateFloat(c.Bool("raw"), "value", c.Args().Get(0), true, c.Bool("yes")) + if err != nil { + return err + } + + // Run + return proposeSettingSecurityUpgradeVetoQuorum(value, c.Bool("yes"), c.String("to-json")) + + }, + }, + + { + Name: "upgrade-delay", + Aliases: []string{"ud"}, + Usage: fmt.Sprintf("Propose updating the %s setting; %s", protocol.SecurityUpgradeDelaySettingPath, durationUsage), + UsageText: "rocketpool pdao propose setting security upgrade-delay value", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "yes", + Aliases: []string{"y"}, + Usage: "Automatically confirm all interactive questions", + }, + &cli.StringFlag{ + Name: "to-json", + Usage: "Write this setting to a JSON file instead of submitting a proposal (creates the file or appends to it)", + }, + }, + Action: func(ctx context.Context, c *cli.Command) error { + + // Validate args + if err := cliutils.ValidateArgCount(c, 1); err != nil { + return err + } + value, err := cliutils.ValidateDuration("value", c.Args().Get(0)) + if err != nil { + return err + } + + // Run + return proposeSettingSecurityUpgradeDelay(value, c.Bool("yes"), c.String("to-json")) + + }, + }, }, }, diff --git a/rocketpool-cli/pdao/get-settings.go b/rocketpool-cli/pdao/get-settings.go index 633b832a7..7fd553b66 100644 --- a/rocketpool-cli/pdao/get-settings.go +++ b/rocketpool-cli/pdao/get-settings.go @@ -86,6 +86,7 @@ func getSettings() error { fmt.Printf("\tMax Commission Share Security Council Adder: %.2f%%\n", math.WeiToEth(response.Network.MaxNodeShareSecurityCouncilAdder)*100) fmt.Printf("\tMax rETH balance delta: %.2f%%\n", math.WeiToEth(response.Network.MaxRethBalanceDelta)*100) fmt.Printf("\tAllow listed controllers: %v\n", response.Network.AllowListedControllers) + fmt.Printf("\trETH Deposit Delay: %d Blocks\n", response.Network.RethDepositDelay) fmt.Println() // Node @@ -96,6 +97,8 @@ func getSettings() error { fmt.Printf("\tVacant Minipools Enabled: %t\n", response.Node.AreVacantMinipoolsEnabled) fmt.Printf("\tReduced Bond: %.6f ETH\n", response.Node.ReducedBond) fmt.Printf("\tNode Unstaking Period: %s\n", response.Node.NodeUnstakingPeriod) + fmt.Printf("\tWithdrawal Cooldown: %s\n", response.Node.WithdrawalCooldown) + fmt.Printf("\tMax Stake For Voting Power: %.2f%%\n", math.WeiToEth(response.Node.MaximumStakeForVotingPower)*100) fmt.Printf("\tMin Legacy RPL Stake: %s\n", response.Node.MinimumLegacyRplStake) fmt.Println() @@ -125,6 +128,8 @@ func getSettings() error { fmt.Printf("\tProposal Vote Time: %s\n", response.Security.ProposalVoteTime) fmt.Printf("\tProposal Execute Time: %s\n", response.Security.ProposalExecuteTime) fmt.Printf("\tProposal Action Time: %s\n", response.Security.ProposalActionTime) + fmt.Printf("\tUpgrade Veto Quorum: %.2f%%\n", math.WeiToEth(response.Security.UpgradeVetoQuorum)*100) + fmt.Printf("\tUpgrade Delay: %s\n", response.Security.UpgradeDelay) fmt.Println() // Megapool diff --git a/rocketpool-cli/pdao/propose-settings.go b/rocketpool-cli/pdao/propose-settings.go index 7b3fef5e8..b739f83a8 100644 --- a/rocketpool-cli/pdao/propose-settings.go +++ b/rocketpool-cli/pdao/propose-settings.go @@ -225,6 +225,16 @@ func proposeSettingNodeUnstakingPeriod(value time.Duration, yes bool, toJson str return proposeSetting(protocol.NodeSettingsContractName, protocol.NodeUnstakingPeriodSettingPath, trueValue, yes, toJson) } +func proposeSettingNodeWithdrawalCooldown(value time.Duration, yes bool, toJson string) error { + trueValue := fmt.Sprint(uint64(value.Seconds())) + return proposeSetting(protocol.NodeSettingsContractName, protocol.NodeWithdrawalCooldownSettingPath, trueValue, yes, toJson) +} + +func proposeSettingNodeMaximumStakeForVotingPower(value *big.Int, yes bool, toJson string) error { + trueValue := value.String() + return proposeSetting(protocol.NodeSettingsContractName, protocol.MaximumStakeForVotingPowerSettingPath, trueValue, yes, toJson) +} + func proposeSettingProposalsVotePhase1Time(value time.Duration, yes bool, toJson string) error { trueValue := fmt.Sprint(uint64(value.Seconds())) return proposeSetting(protocol.ProposalsSettingsContractName, protocol.VotePhase1TimeSettingPath, trueValue, yes, toJson) @@ -305,6 +315,16 @@ func proposeSettingSecurityProposalActionTime(value time.Duration, yes bool, toJ return proposeSetting(protocol.SecuritySettingsContractName, protocol.SecurityProposalActionTimeSettingPath, trueValue, yes, toJson) } +func proposeSettingSecurityUpgradeVetoQuorum(value *big.Int, yes bool, toJson string) error { + trueValue := value.String() + return proposeSetting(protocol.SecuritySettingsContractName, protocol.SecurityUpgradeVetoQuorumSettingPath, trueValue, yes, toJson) +} + +func proposeSettingSecurityUpgradeDelay(value time.Duration, yes bool, toJson string) error { + trueValue := fmt.Sprint(uint64(value.Seconds())) + return proposeSetting(protocol.SecuritySettingsContractName, protocol.SecurityUpgradeDelaySettingPath, trueValue, yes, toJson) +} + func proposeSettingMegapoolTimeBeforeDissolve(value time.Duration, yes bool, toJson string) error { trueValue := fmt.Sprint(uint64(value.Seconds())) return proposeSetting(protocol.MegapoolSettingsContractName, protocol.MegapoolTimeBeforeDissolveSettingsPath, trueValue, yes, toJson) @@ -375,6 +395,11 @@ func proposeMaxRethBalanceDelta(value *big.Int, yes bool, toJson string) error { return proposeSetting(protocol.NetworkSettingsContractName, protocol.NetworkMaxRethBalanceDeltaPath, trueValue, yes, toJson) } +func proposeRethDepositDelay(value uint64, yes bool, toJson string) error { + trueValue := fmt.Sprint(value) + return proposeSetting(protocol.NetworkSettingsContractName, protocol.NetworkRethDepositDelaySettingPath, trueValue, yes, toJson) +} + // Master general proposal function func proposeSetting(contract string, setting string, value string, yes bool, toJson string) error { if toJson != "" { diff --git a/rocketpool/api/pdao/get-settings.go b/rocketpool/api/pdao/get-settings.go index d06ca6d31..defad1082 100644 --- a/rocketpool/api/pdao/get-settings.go +++ b/rocketpool/api/pdao/get-settings.go @@ -110,6 +110,21 @@ func getSettings(c *cli.Command) (*api.GetPDAOSettingsResponse, error) { return err }) + wg.Go(func() error { + var err error + withdrawalCooldown, err := protocol.GetWithdrawalCooldown(rp, nil) + if err == nil { + response.Node.WithdrawalCooldown = time.Duration(withdrawalCooldown.Int64()) * time.Second + } + return err + }) + + wg.Go(func() error { + var err error + response.Node.MaximumStakeForVotingPower, err = protocol.GetMaximumStakeForVotingPower(rp, nil) + return err + }) + wg.Go(func() error { var err error response.Node.MinimumLegacyRplStake, err = protocol.GetMinimumLegacyRPLStakeRaw(rp, nil) @@ -393,6 +408,12 @@ func getSettings(c *cli.Command) (*api.GetPDAOSettingsResponse, error) { return err }) + wg.Go(func() error { + var err error + response.Network.RethDepositDelay, err = protocol.GetRethDepositDelay(rp, nil) + return err + }) + // === Node === wg.Go(func() error { @@ -521,6 +542,18 @@ func getSettings(c *cli.Command) (*api.GetPDAOSettingsResponse, error) { return err }) + wg.Go(func() error { + var err error + response.Security.UpgradeVetoQuorum, err = protocol.GetSecurityUpgradeVetoQuorum(rp, nil) + return err + }) + + wg.Go(func() error { + var err error + response.Security.UpgradeDelay, err = protocol.GetSecurityUpgradeDelay(rp, nil) + return err + }) + // Wait for data if err := wg.Wait(); err != nil { return nil, err diff --git a/rocketpool/api/pdao/propose-settings.go b/rocketpool/api/pdao/propose-settings.go index 3c7a935ff..05c5e8a3f 100644 --- a/rocketpool/api/pdao/propose-settings.go +++ b/rocketpool/api/pdao/propose-settings.go @@ -557,6 +557,17 @@ func canProposeSetting(c *cli.Command, contractName string, settingName string, return nil, fmt.Errorf("error estimating gas for proposing MaxRethBalanceDelta: %w", err) } + // RethDepositDelay + case protocol.NetworkRethDepositDelaySettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + response.GasLimits, err = protocol.EstimateProposeRethDepositDelayGas(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error estimating gas for proposing RethDepositDelay: %w", err) + } + } case protocol.NodeSettingsContractName: @@ -636,6 +647,28 @@ func canProposeSetting(c *cli.Command, contractName string, settingName string, return nil, fmt.Errorf("error estimating gas for proposing NodeUnstakingPeriod: %w", err) } + // WithdrawalCooldown + case protocol.NodeWithdrawalCooldownSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + response.GasLimits, err = protocol.EstimateProposeWithdrawalCooldownGas(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error estimating gas for proposing WithdrawalCooldown: %w", err) + } + + // MaximumStakeForVotingPower + case protocol.MaximumStakeForVotingPowerSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + response.GasLimits, err = protocol.EstimateProposeMaximumStakeForVotingPowerGas(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error estimating gas for proposing MaximumStakeForVotingPower: %w", err) + } + } case protocol.ProposalsSettingsContractName: @@ -819,6 +852,28 @@ func canProposeSetting(c *cli.Command, contractName string, settingName string, if err != nil { return nil, fmt.Errorf("error estimating gas for proposing SecurityProposalActionTime: %w", err) } + + // SecurityUpgradeVetoQuorum + case protocol.SecurityUpgradeVetoQuorumSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + response.GasLimits, err = protocol.EstimateProposeSecurityUpgradeVetoQuorumGas(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error estimating gas for proposing SecurityUpgradeVetoQuorum: %w", err) + } + + // SecurityUpgradeDelay + case protocol.SecurityUpgradeDelaySettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + response.GasLimits, err = protocol.EstimateProposeSecurityUpgradeDelayGas(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error estimating gas for proposing SecurityUpgradeDelay: %w", err) + } } case protocol.MegapoolSettingsContractName: @@ -1387,6 +1442,17 @@ func proposeSetting(c *cli.Command, contractName string, settingName string, val return nil, fmt.Errorf("error proposing MaxRethBalanceDelta: %w", err) } + // RethDepositDelay + case protocol.NetworkRethDepositDelaySettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + proposalID, hash, err = protocol.ProposeRethDepositDelay(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error proposing RethDepositDelay: %w", err) + } + } case protocol.NodeSettingsContractName: @@ -1465,6 +1531,28 @@ func proposeSetting(c *cli.Command, contractName string, settingName string, val return nil, fmt.Errorf("error proposing NodeUnstakingPeriod: %w", err) } + // WithdrawalCooldown + case protocol.NodeWithdrawalCooldownSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + proposalID, hash, err = protocol.ProposeWithdrawalCooldown(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error proposing WithdrawalCooldown: %w", err) + } + + // MaximumStakeForVotingPower + case protocol.MaximumStakeForVotingPowerSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + proposalID, hash, err = protocol.ProposeMaximumStakeForVotingPower(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error proposing MaximumStakeForVotingPower: %w", err) + } + } case protocol.ProposalsSettingsContractName: @@ -1650,6 +1738,28 @@ func proposeSetting(c *cli.Command, contractName string, settingName string, val if err != nil { return nil, fmt.Errorf("error proposing SecurityProposalActionTime: %w", err) } + + // SecurityUpgradeVetoQuorum + case protocol.SecurityUpgradeVetoQuorumSettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + proposalID, hash, err = protocol.ProposeSecurityUpgradeVetoQuorum(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error proposing SecurityUpgradeVetoQuorum: %w", err) + } + + // SecurityUpgradeDelay + case protocol.SecurityUpgradeDelaySettingPath: + newValue, err := cliutils.ValidateBigInt(valueName, value) + if err != nil { + return nil, err + } + proposalID, hash, err = protocol.ProposeSecurityUpgradeDelay(rp, newValue, blockNumber, pollard, opts) + if err != nil { + return nil, fmt.Errorf("error proposing SecurityUpgradeDelay: %w", err) + } } case protocol.MegapoolSettingsContractName: diff --git a/shared/types/api/pdao.go b/shared/types/api/pdao.go index b5c910d47..98f010f6a 100644 --- a/shared/types/api/pdao.go +++ b/shared/types/api/pdao.go @@ -136,6 +136,7 @@ type GetPDAOSettingsResponse struct { MaxNodeShareSecurityCouncilAdder *big.Int `json:"maxNodeCommissionShareCouncilAdder"` MaxRethBalanceDelta *big.Int `json:"maxRethBalanceDelta"` AllowListedControllers []common.Address `json:"allowListedControllers"` + RethDepositDelay uint64 `json:"rethDepositDelay"` } `json:"network"` Node struct { @@ -146,6 +147,8 @@ type GetPDAOSettingsResponse struct { MinimumLegacyRplStake *big.Int `json:"minimumLegacyRplStake"` ReducedBond float64 `json:"reducedBond"` NodeUnstakingPeriod time.Duration `json:"nodeUnstakingPeriod"` + WithdrawalCooldown time.Duration `json:"withdrawalCooldown"` + MaximumStakeForVotingPower *big.Int `json:"maximumStakeForVotingPower"` } `json:"node"` Proposals struct { @@ -171,6 +174,8 @@ type GetPDAOSettingsResponse struct { ProposalVoteTime time.Duration `json:"proposalVoteTime"` ProposalExecuteTime time.Duration `json:"proposalExecuteTime"` ProposalActionTime time.Duration `json:"proposalActionTime"` + UpgradeVetoQuorum *big.Int `json:"upgradeVetoQuorum"` + UpgradeDelay time.Duration `json:"upgradeDelay"` } `json:"security"` Megapool struct { diff --git a/shared/version.txt b/shared/version.txt index 3500250a4..63c737354 100644 --- a/shared/version.txt +++ b/shared/version.txt @@ -1 +1 @@ -1.21.0 +1.21.1-dev