diff --git a/aptos-move/framework/aptos-framework/doc/aptos_governance.md b/aptos-move/framework/aptos-framework/doc/aptos_governance.md index a1af79916d8..72d8499f0ab 100644 --- a/aptos-move/framework/aptos-framework/doc/aptos_governance.md +++ b/aptos-move/framework/aptos-framework/doc/aptos_governance.md @@ -37,6 +37,8 @@ on a proposal multiple times as long as the total voting power of these votes do - [Function `initialize`](#0x1_aptos_governance_initialize) - [Function `update_governance_config`](#0x1_aptos_governance_update_governance_config) - [Function `initialize_partial_voting`](#0x1_aptos_governance_initialize_partial_voting) +- [Function `partial_voting_initialized`](#0x1_aptos_governance_partial_voting_initialized) +- [Function `initialize_partial_voting_if_needed`](#0x1_aptos_governance_initialize_partial_voting_if_needed) - [Function `get_voting_duration_secs`](#0x1_aptos_governance_get_voting_duration_secs) - [Function `get_min_voting_threshold`](#0x1_aptos_governance_get_min_voting_threshold) - [Function `get_required_proposer_stake`](#0x1_aptos_governance_get_required_proposer_stake) @@ -72,6 +74,8 @@ on a proposal multiple times as long as the total voting power of these votes do - [Function `initialize`](#@Specification_1_initialize) - [Function `update_governance_config`](#@Specification_1_update_governance_config) - [Function `initialize_partial_voting`](#@Specification_1_initialize_partial_voting) + - [Function `partial_voting_initialized`](#@Specification_1_partial_voting_initialized) + - [Function `initialize_partial_voting_if_needed`](#@Specification_1_initialize_partial_voting_if_needed) - [Function `get_voting_duration_secs`](#@Specification_1_get_voting_duration_secs) - [Function `get_min_voting_threshold`](#@Specification_1_get_min_voting_threshold) - [Function `get_required_proposer_stake`](#@Specification_1_get_required_proposer_stake) @@ -1099,6 +1103,65 @@ proposals with a signer for the aptos_framework (0x1) account. + + + + +## Function `partial_voting_initialized` + + + +
#[view]
+public fun partial_voting_initialized(): bool
+
+
+
+
+public fun partial_voting_initialized(): bool {
+ exists<VotingRecordsV2>(@aptos_framework)
+}
+
+
+
+
+public fun initialize_partial_voting_if_needed(aptos_framework: &signer)
+
+
+
+
+public fun initialize_partial_voting_if_needed(
+ aptos_framework: &signer,
+) {
+ system_addresses::assert_aptos_framework(aptos_framework);
+
+ if (!partial_voting_initialized()) {
+ move_to(aptos_framework, VotingRecordsV2 {
+ votes: smart_table::new(),
+ });
+ }
+}
+
+
+
+
#[view]
+public fun partial_voting_initialized(): bool
+
+
+
+
+
+pragma opaque;
+aborts_if false;
+ensures result == exists<VotingRecordsV2>(@aptos_framework);
+
+
+
+
+
+
+### Function `initialize_partial_voting_if_needed`
+
+
+public fun initialize_partial_voting_if_needed(aptos_framework: &signer)
+
+
+
+Signer address must be @aptos_framework.
+
+
+let addr = signer::address_of(aptos_framework);
+aborts_if addr != @aptos_framework;
+ensures exists<VotingRecordsV2>(@aptos_framework);
+
+
+
+
diff --git a/aptos-move/framework/aptos-framework/doc/delegation_pool.md b/aptos-move/framework/aptos-framework/doc/delegation_pool.md
index 1b91662621b..065149909a1 100644
--- a/aptos-move/framework/aptos-framework/doc/delegation_pool.md
+++ b/aptos-move/framework/aptos-framework/doc/delegation_pool.md
@@ -152,6 +152,7 @@ transferred to A
- [Function `owner_cap_exists`](#0x1_delegation_pool_owner_cap_exists)
- [Function `get_owned_pool_address`](#0x1_delegation_pool_get_owned_pool_address)
- [Function `delegation_pool_exists`](#0x1_delegation_pool_delegation_pool_exists)
+- [Function `governance_records_initialized`](#0x1_delegation_pool_governance_records_initialized)
- [Function `partial_governance_voting_enabled`](#0x1_delegation_pool_partial_governance_voting_enabled)
- [Function `observed_lockup_cycle`](#0x1_delegation_pool_observed_lockup_cycle)
- [Function `is_next_commission_percentage_effective`](#0x1_delegation_pool_is_next_commission_percentage_effective)
@@ -179,6 +180,7 @@ transferred to A
- [Function `initialize_delegation_pool`](#0x1_delegation_pool_initialize_delegation_pool)
- [Function `beneficiary_for_operator`](#0x1_delegation_pool_beneficiary_for_operator)
- [Function `enable_partial_governance_voting`](#0x1_delegation_pool_enable_partial_governance_voting)
+- [Function `enable_partial_governance_voting_if_needed`](#0x1_delegation_pool_enable_partial_governance_voting_if_needed)
- [Function `vote`](#0x1_delegation_pool_vote)
- [Function `create_proposal`](#0x1_delegation_pool_create_proposal)
- [Function `assert_owner_cap_exists`](#0x1_delegation_pool_assert_owner_cap_exists)
@@ -2120,6 +2122,32 @@ Return whether a delegation pool exists at supplied address addr.
+
+
+
+
+## Function `governance_records_initialized`
+
+Return whether a delegation pool has governance records initialized.
+
+
+#[view]
+public fun governance_records_initialized(pool_address: address): bool
+
+
+
+
+public fun governance_records_initialized(pool_address: address): bool {
+ exists<GovernanceRecords>(pool_address)
+}
+
+
+
+
public fun partial_governance_voting_enabled(pool_address: address): bool {
- exists<GovernanceRecords>(pool_address) && stake::get_delegated_voter(pool_address) == pool_address
+ governance_records_initialized(pool_address) && stake::get_delegated_voter(pool_address) == pool_address
}
@@ -3083,6 +3111,37 @@ The existing voter will be replaced. The function is permissionless.
+
+
+
+
+## Function `enable_partial_governance_voting_if_needed`
+
+Enable partial governance voting on a delegation pool if it has not already been initialized.
+This is intended for idempotent migration scripts over existing delegation pools.
+
+
+public entry fun enable_partial_governance_voting_if_needed(pool_address: address)
+
+
+
+
+public entry fun enable_partial_governance_voting_if_needed(
+ pool_address: address,
+) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ assert_delegation_pool_exists(pool_address);
+ if (!governance_records_initialized(pool_address)) {
+ enable_partial_governance_voting(pool_address);
+ }
+}
+
+
+
+
const EINVALID_BENEFICIARY_ADDRESS: u64 = 10;
+
+
+
+
Caller must be either the staker, operator, or beneficiary.
@@ -2283,6 +2293,12 @@ the beneficiary. An operator can set one beneficiary for staking contract pools,
assert!(features::operator_beneficiary_change_enabled(), std::error::invalid_state(
EOPERATOR_BENEFICIARY_CHANGE_NOT_SUPPORTED
));
+ // @vm_reserved can never have an account created for it, so it can't receive coin distributions.
+ // Allowing it as a beneficiary would permanently brick distribution for the staking contract.
+ assert!(
+ new_beneficiary != @vm_reserved,
+ error::invalid_argument(EINVALID_BENEFICIARY_ADDRESS),
+ );
// The beneficiay address of an operator is stored under the operator's address.
// So, the operator does not need to be validated with respect to a staking pool.
let operator_addr = signer::address_of(operator);
diff --git a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
index 2cff97836bb..7cf74286cc3 100644
--- a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
+++ b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
@@ -525,6 +525,12 @@ pub enum EntryFunctionCall {
pool_address: AccountAddress,
},
+ /// Enable partial governance voting on a delegation pool if it has not already been initialized.
+ /// This is intended for idempotent migration scripts over existing delegation pools.
+ DelegationPoolEnablePartialGovernanceVotingIfNeeded {
+ pool_address: AccountAddress,
+ },
+
/// Evict a delegator that is not allowlisted by unlocking their entire stake.
DelegationPoolEvictDelegator {
delegator_address: AccountAddress,
@@ -1657,6 +1663,9 @@ impl EntryFunctionCall {
DelegationPoolEnablePartialGovernanceVoting { pool_address } => {
delegation_pool_enable_partial_governance_voting(pool_address)
},
+ DelegationPoolEnablePartialGovernanceVotingIfNeeded { pool_address } => {
+ delegation_pool_enable_partial_governance_voting_if_needed(pool_address)
+ },
DelegationPoolEvictDelegator { delegator_address } => {
delegation_pool_evict_delegator(delegator_address)
},
@@ -3498,6 +3507,25 @@ pub fn delegation_pool_enable_partial_governance_voting(
))
}
+/// Enable partial governance voting on a delegation pool if it has not already been initialized.
+/// This is intended for idempotent migration scripts over existing delegation pools.
+pub fn delegation_pool_enable_partial_governance_voting_if_needed(
+ pool_address: AccountAddress,
+) -> TransactionPayload {
+ TransactionPayload::EntryFunction(EntryFunction::new(
+ ModuleId::new(
+ AccountAddress::new([
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1,
+ ]),
+ ident_str!("delegation_pool").to_owned(),
+ ),
+ ident_str!("enable_partial_governance_voting_if_needed").to_owned(),
+ vec![],
+ vec![bcs::to_bytes(&pool_address).unwrap()],
+ ))
+}
+
/// Evict a delegator that is not allowlisted by unlocking their entire stake.
pub fn delegation_pool_evict_delegator(delegator_address: AccountAddress) -> TransactionPayload {
TransactionPayload::EntryFunction(EntryFunction::new(
@@ -6722,6 +6750,20 @@ mod decoder {
}
}
+ pub fn delegation_pool_enable_partial_governance_voting_if_needed(
+ payload: &TransactionPayload,
+ ) -> Optionconst NATIVE_BRIDGE: u64 = 72;