diff --git a/aptos-move/framework/aptos-framework/doc/aptos_governance.md b/aptos-move/framework/aptos-framework/doc/aptos_governance.md index 4daf73a12bded..4598f8c382bbb 100644 --- a/aptos-move/framework/aptos-framework/doc/aptos_governance.md +++ b/aptos-move/framework/aptos-framework/doc/aptos_governance.md @@ -109,6 +109,7 @@ on a proposal multiple times as long as the total voting power of these votes do use 0x1::governance_proposal; use 0x1::math64; use 0x1::option; +use 0x1::permissioned_signer; use 0x1::randomness_config; use 0x1::reconfiguration_with_dkg; use 0x1::signer; @@ -1261,6 +1262,7 @@ Return proposal_id when a proposal is successfully created. metadata_hash: vector<u8>, is_multi_step_proposal: bool, ): u64 acquires GovernanceConfig, GovernanceEvents { + permissioned_signer::assert_master_signer(proposer); let proposer_address = signer::address_of(proposer); assert!( stake::get_delegated_voter(stake_pool) == proposer_address, @@ -1492,6 +1494,7 @@ cannot vote on the proposal even after partial governance voting is enabled. voting_power: u64, should_pass: bool, ) acquires ApprovedExecutionHashes, VotingRecords, VotingRecordsV2, GovernanceEvents { + permissioned_signer::assert_master_signer(voter); let voter_address = signer::address_of(voter); assert!(stake::get_delegated_voter(stake_pool) == voter_address, error::invalid_argument(ENOT_DELEGATED_VOTER)); diff --git a/aptos-move/framework/aptos-framework/doc/code.md b/aptos-move/framework/aptos-framework/doc/code.md index ce18af9e16fbc..cf52525ae13a5 100644 --- a/aptos-move/framework/aptos-framework/doc/code.md +++ b/aptos-move/framework/aptos-framework/doc/code.md @@ -50,6 +50,7 @@ This module supports functionality related to code management. use 0x1::features; use 0x1::object; use 0x1::option; +use 0x1::permissioned_signer; use 0x1::signer; use 0x1::string; use 0x1::system_addresses; @@ -598,6 +599,7 @@ package.
public fun publish_package(owner: &signer, pack: PackageMetadata, code: vector<vector<u8>>) acquires PackageRegistry {
+ permissioned_signer::assert_master_signer(owner);
// Disallow incompatible upgrade mode. Governance can decide later if this should be reconsidered.
assert!(
pack.upgrade_policy.policy > upgrade_policy_arbitrary().policy,
@@ -679,6 +681,7 @@ package.
public fun freeze_code_object(publisher: &signer, code_object: Object<PackageRegistry>) acquires PackageRegistry {
+ permissioned_signer::assert_master_signer(publisher);
let code_object_addr = object::object_address(&code_object);
assert!(exists<PackageRegistry>(code_object_addr), error::not_found(ECODE_OBJECT_DOES_NOT_EXIST));
assert!(
diff --git a/aptos-move/framework/aptos-framework/doc/delegation_pool.md b/aptos-move/framework/aptos-framework/doc/delegation_pool.md
index 9ce29ab22430e..cd1cc6c6a16c5 100644
--- a/aptos-move/framework/aptos-framework/doc/delegation_pool.md
+++ b/aptos-move/framework/aptos-framework/doc/delegation_pool.md
@@ -124,6 +124,7 @@ transferred to A
- [Resource `BeneficiaryForOperator`](#0x1_delegation_pool_BeneficiaryForOperator)
- [Resource `NextCommissionPercentage`](#0x1_delegation_pool_NextCommissionPercentage)
- [Resource `DelegationPoolAllowlisting`](#0x1_delegation_pool_DelegationPoolAllowlisting)
+- [Struct `DelegationPermission`](#0x1_delegation_pool_DelegationPermission)
- [Struct `AddStake`](#0x1_delegation_pool_AddStake)
- [Struct `AddStakeEvent`](#0x1_delegation_pool_AddStakeEvent)
- [Struct `ReactivateStake`](#0x1_delegation_pool_ReactivateStake)
@@ -171,6 +172,8 @@ transferred to A
- [Function `allowlisting_enabled`](#0x1_delegation_pool_allowlisting_enabled)
- [Function `delegator_allowlisted`](#0x1_delegation_pool_delegator_allowlisted)
- [Function `get_delegators_allowlist`](#0x1_delegation_pool_get_delegators_allowlist)
+- [Function `check_signer_permission`](#0x1_delegation_pool_check_signer_permission)
+- [Function `grant_permission`](#0x1_delegation_pool_grant_permission)
- [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)
@@ -245,6 +248,7 @@ transferred to A
use 0x1::error;
use 0x1::event;
use 0x1::features;
+use 0x1::permissioned_signer;
use 0x1::pool_u64_unbound;
use 0x1::signer;
use 0x1::smart_table;
@@ -678,6 +682,33 @@ evicted later by the pool owner.
+
+
+
+
+## Struct `DelegationPermission`
+
+
+
+struct DelegationPermission has copy, drop, store
+
+
+
+
+
+Fields
+
+
+
+-
+
dummy_field: bool
+
+-
+
+
+
+
+
@@ -1828,6 +1859,16 @@ There is not enough active
stake on the stake pool to unlock<
+
+
+Signer does not have permission to perform delegation logic.
+
+
+const ENO_DELEGATION_PERMISSION: u64 = 28;
+
+
+
+
Changing beneficiaries for operators is not supported.
@@ -2756,6 +2797,58 @@ Return allowlist or revert if allowlisting is not enabled for the provided deleg
+
+
+
+
+## Function `check_signer_permission`
+
+Permissions
+
+
+fun check_signer_permission(s: &signer)
+
+
+
+
+
+Implementation
+
+
+inline fun check_signer_permission(s: &signer) {
+ assert!(
+ permissioned_signer::check_permission_exists(s, DelegationPermission {}),
+ error::permission_denied(ENO_DELEGATION_PERMISSION),
+ );
+}
+
+
+
+
+
+
+
+
+## Function `grant_permission`
+
+
+
+public fun grant_permission(master: &signer, permissioned_signer: &signer)
+
+
+
+
+
+Implementation
+
+
+public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+ permissioned_signer::authorize(master, permissioned_signer, 1, DelegationPermission {})
+}
+
+
+
+
@@ -2782,6 +2875,7 @@ Ownership over setting the operator/voter is granted to owner
who h
operator_commission_percentage: u64,
delegation_pool_creation_seed: vector<u8>,
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(owner);
assert!(features::delegation_pools_enabled(), error::invalid_state(EDELEGATION_POOLS_DISABLED));
let owner_address = signer::address_of(owner);
assert!(!owner_cap_exists(owner_address), error::already_exists(EOWNER_CAP_ALREADY_EXISTS));
@@ -2942,6 +3036,7 @@ Vote on a proposal with a voter's voting power. To successfully vote, the follow
voting_power: u64,
should_pass: bool
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(voter);
assert_partial_governance_voting_enabled(pool_address);
// synchronize delegation and stake pools before any user operation.
synchronize_delegation_pool(pool_address);
@@ -3021,6 +3116,7 @@ voting power in THIS delegation pool must be not less than the minimum required
metadata_hash: vector<u8>,
is_multi_step_proposal: bool,
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(voter);
assert_partial_governance_voting_enabled(pool_address);
// synchronize delegation and stake pools before any user operation
@@ -3793,6 +3889,7 @@ Allows an owner to change the operator of the underlying stake pool.
owner: &signer,
new_operator: address
) acquires DelegationPoolOwnership, DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(owner);
let pool_address = get_owned_pool_address(signer::address_of(owner));
// synchronize delegation and stake pools before any user operation
// ensure the old operator is paid its uncommitted commission rewards
@@ -3828,6 +3925,7 @@ one for each pool.
operator: &signer,
new_beneficiary: address
) acquires BeneficiaryForOperator {
+ check_signer_permission(operator);
assert!(features::operator_beneficiary_change_enabled(), std::error::invalid_state(
EOPERATOR_BENEFICIARY_CHANGE_NOT_SUPPORTED
));
@@ -3873,6 +3971,7 @@ Allows an owner to update the commission percentage for the operator of the unde
owner: &signer,
new_commission_percentage: u64
) acquires DelegationPoolOwnership, DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(owner);
assert!(features::commission_change_delegation_pool_enabled(), error::invalid_state(
ECOMMISSION_RATE_CHANGE_NOT_SUPPORTED
));
@@ -3938,6 +4037,7 @@ Allows an owner to change the delegated voter of the underlying stake pool.
owner: &signer,
new_voter: address
) acquires DelegationPoolOwnership, DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(owner);
// No one can change delegated_voter once the partial governance voting feature is enabled.
assert!(
!features::delegation_pool_partial_governance_voting_enabled(),
@@ -3976,6 +4076,7 @@ this change won't take effects until the next lockup period.
pool_address: address,
new_voter: address
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(delegator);
assert_partial_governance_voting_enabled(pool_address);
// synchronize delegation and stake pools before any user operation
@@ -4053,6 +4154,7 @@ Enable delegators allowlisting as the pool owner.
public entry fun enable_delegators_allowlisting(
owner: &signer,
) acquires DelegationPoolOwnership, DelegationPool {
+ check_signer_permission(owner);
assert!(
features::delegation_pool_allowlisting_enabled(),
error::invalid_state(EDELEGATORS_ALLOWLISTING_NOT_SUPPORTED)
@@ -4091,6 +4193,7 @@ Disable delegators allowlisting as the pool owner. The existing allowlist will b
public entry fun disable_delegators_allowlisting(
owner: &signer,
) acquires DelegationPoolOwnership, DelegationPoolAllowlisting {
+ check_signer_permission(owner);
let pool_address = get_owned_pool_address(signer::address_of(owner));
assert_allowlisting_enabled(pool_address);
@@ -4126,6 +4229,7 @@ Allowlist a delegator as the pool owner.
owner: &signer,
delegator_address: address,
) acquires DelegationPoolOwnership, DelegationPoolAllowlisting {
+ check_signer_permission(owner);
let pool_address = get_owned_pool_address(signer::address_of(owner));
assert_allowlisting_enabled(pool_address);
@@ -4161,6 +4265,7 @@ Remove a delegator from the allowlist as the pool owner, but do not unlock their
owner: &signer,
delegator_address: address,
) acquires DelegationPoolOwnership, DelegationPoolAllowlisting {
+ check_signer_permission(owner);
let pool_address = get_owned_pool_address(signer::address_of(owner));
assert_allowlisting_enabled(pool_address);
@@ -4196,6 +4301,7 @@ Evict a delegator that is not allowlisted by unlocking their entire stake.
owner: &signer,
delegator_address: address,
) acquires DelegationPoolOwnership, DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage, DelegationPoolAllowlisting {
+ check_signer_permission(owner);
let pool_address = get_owned_pool_address(signer::address_of(owner));
assert_allowlisting_enabled(pool_address);
assert!(
@@ -4240,6 +4346,7 @@ Add amount
of coins to the delegation pool pool_address
address,
amount: u64
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage, DelegationPoolAllowlisting {
+ check_signer_permission(delegator);
// short-circuit if amount to add is 0 so no event is emitted
if (amount == 0) { return };
@@ -4317,6 +4424,7 @@ at most how much active stake there is on the stake pool.
pool_address: address,
amount: u64
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(delegator);
// short-circuit if amount to unlock is 0 so no event is emitted
if (amount == 0) { return };
@@ -4418,6 +4526,7 @@ Move amount
of coins from pending_inactive to active.
pool_address: address,
amount: u64
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage, DelegationPoolAllowlisting {
+ check_signer_permission(delegator);
// short-circuit if amount to reactivate is 0 so no event is emitted
if (amount == 0) { return };
@@ -4488,6 +4597,7 @@ Withdraw amount
of owned inactive stake from the delegation pool at
pool_address: address,
amount: u64
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(delegator);
assert!(amount > 0, error::invalid_argument(EWITHDRAW_ZERO_STAKE));
// synchronize delegation and stake pools before any user operation
synchronize_delegation_pool(pool_address);
diff --git a/aptos-move/framework/aptos-framework/doc/managed_coin.md b/aptos-move/framework/aptos-framework/doc/managed_coin.md
index 50c2383fd111d..5f1821115f381 100644
--- a/aptos-move/framework/aptos-framework/doc/managed_coin.md
+++ b/aptos-move/framework/aptos-framework/doc/managed_coin.md
@@ -429,7 +429,8 @@ The Capabilities should not be under the signer before creating;
The Capabilities should be under the signer after creating;
-include coin::InitializeInternalSchema<CoinType>;
+aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+include coin::InitializeInternalSchema<CoinType>;
aborts_if !string::spec_internal_check_utf8(name);
aborts_if !string::spec_internal_check_utf8(symbol);
aborts_if exists<Capabilities<CoinType>>(signer::address_of(account));
diff --git a/aptos-move/framework/aptos-framework/doc/resource_account.md b/aptos-move/framework/aptos-framework/doc/resource_account.md
index 318d15a785de7..b292e11870952 100644
--- a/aptos-move/framework/aptos-framework/doc/resource_account.md
+++ b/aptos-move/framework/aptos-framework/doc/resource_account.md
@@ -486,6 +486,8 @@ the SignerCapability.
let source_addr = signer::address_of(origin);
let resource_addr = account::spec_create_resource_address(source_addr, seed);
+let resource = create_signer::spec_create_signer(resource_addr);
+aborts_if permissioned_signer::spec_is_permissioned_signer(resource);
include RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIfWithoutAccountLimit;
@@ -547,7 +549,8 @@ the SignerCapability.
-let resource_addr = signer::address_of(resource);
+aborts_if permissioned_signer::spec_is_permissioned_signer(resource);
+let resource_addr = signer::address_of(resource);
// This enforces high-level requirement 1:
include RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIf;
// This enforces high-level requirement 2:
@@ -618,7 +621,8 @@ the SignerCapability.
-// This enforces high-level requirement 6:
+aborts_if permissioned_signer::spec_is_permissioned_signer(resource);
+// This enforces high-level requirement 6:
aborts_if !exists<Container>(source_addr);
let resource_addr = signer::address_of(resource);
let container = global<Container>(source_addr);
diff --git a/aptos-move/framework/aptos-framework/doc/stake.md b/aptos-move/framework/aptos-framework/doc/stake.md
index 017d83723ad91..f8fd44e48c764 100644
--- a/aptos-move/framework/aptos-framework/doc/stake.md
+++ b/aptos-move/framework/aptos-framework/doc/stake.md
@@ -33,6 +33,7 @@ or if their stake drops below the min required, they would get removed at the en
- [Struct `IndividualValidatorPerformance`](#0x1_stake_IndividualValidatorPerformance)
- [Resource `ValidatorPerformance`](#0x1_stake_ValidatorPerformance)
- [Struct `RegisterValidatorCandidateEvent`](#0x1_stake_RegisterValidatorCandidateEvent)
+- [Struct `StakePermission`](#0x1_stake_StakePermission)
- [Struct `RegisterValidatorCandidate`](#0x1_stake_RegisterValidatorCandidate)
- [Struct `SetOperatorEvent`](#0x1_stake_SetOperatorEvent)
- [Struct `SetOperator`](#0x1_stake_SetOperator)
@@ -65,6 +66,8 @@ or if their stake drops below the min required, they would get removed at the en
- [Constants](#@Constants_0)
- [Function `initialize_validator_fees`](#0x1_stake_initialize_validator_fees)
- [Function `add_transaction_fee`](#0x1_stake_add_transaction_fee)
+- [Function `check_signer_permission`](#0x1_stake_check_signer_permission)
+- [Function `grant_permission`](#0x1_stake_grant_permission)
- [Function `get_lockup_secs`](#0x1_stake_get_lockup_secs)
- [Function `get_remaining_lockup_secs`](#0x1_stake_get_remaining_lockup_secs)
- [Function `get_stake`](#0x1_stake_get_stake)
@@ -179,6 +182,7 @@ or if their stake drops below the min required, they would get removed at the en
use 0x1::fixed_point64;
use 0x1::math64;
use 0x1::option;
+use 0x1::permissioned_signer;
use 0x1::reconfiguration_state;
use 0x1::signer;
use 0x1::staking_config;
@@ -628,6 +632,33 @@ This allows the Stake module to mint rewards to stakers.
+
+
+
+
+## Struct `StakePermission`
+
+
+
+struct StakePermission has copy, drop, store
+
+
+
+
+
+Fields
+
+
+
+-
+
dummy_field: bool
+
+-
+
+
+
+
+
@@ -1734,6 +1765,16 @@ Validators cannot join or leave post genesis on this test network.
+
+
+Signer does not have permission to perform stake logic.
+
+
+const ENO_STAKE_PERMISSION: u64 = 28;
+
+
+
+
An account cannot own more than one owner capability.
@@ -1942,6 +1983,59 @@ Stores the transaction fee collected to the specified validator address.
+
+
+
+
+## Function `check_signer_permission`
+
+Permissions
+
+
+fun check_signer_permission(s: &signer)
+
+
+
+
+
+Implementation
+
+
+inline fun check_signer_permission(s: &signer) {
+ assert!(
+ permissioned_signer::check_permission_exists(s, StakePermission {}),
+ error::permission_denied(ENO_STAKE_PERMISSION),
+ );
+}
+
+
+
+
+
+
+
+
+## Function `grant_permission`
+
+Grant permission to mutate staking on behalf of the master signer.
+
+
+public fun grant_permission(master: &signer, permissioned_signer: &signer)
+
+
+
+
+
+Implementation
+
+
+public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+ permissioned_signer::authorize(master, permissioned_signer, 1, StakePermission {})
+}
+
+
+
+
@@ -2451,6 +2545,7 @@ to set later.
operator: address,
voter: address,
) acquires AllowedValidators, OwnerCapability, StakePool, ValidatorSet {
+ check_signer_permission(owner);
initialize_owner(owner);
move_to(owner, ValidatorConfig {
consensus_pubkey: vector::empty(),
@@ -2500,6 +2595,7 @@ Initialize the validator account and give ownership to the signing account.
network_addresses: vector<u8>,
fullnode_addresses: vector<u8>,
) acquires AllowedValidators {
+ check_signer_permission(account);
// Checks the public key has a valid proof-of-possession to prevent rogue-key attacks.
let pubkey_from_pop = &bls12381::public_key_from_bytes_with_pop(
consensus_pubkey,
@@ -2537,6 +2633,7 @@ Initialize the validator account and give ownership to the signing account.
fun initialize_owner(owner: &signer) acquires AllowedValidators {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert!(is_allowed(owner_address), error::not_found(EINELIGIBLE_VALIDATOR));
assert!(!stake_pool_exists(owner_address), error::already_exists(EALREADY_REGISTERED));
@@ -2591,6 +2688,7 @@ Extract and return owner capability from the signing account.
public fun extract_owner_cap(owner: &signer): OwnerCapability acquires OwnerCapability {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
move_from<OwnerCapability>(owner_address)
@@ -2619,6 +2717,7 @@ staking pool.
public fun deposit_owner_cap(owner: &signer, owner_cap: OwnerCapability) {
+ check_signer_permission(owner);
assert!(!exists<OwnerCapability>(signer::address_of(owner)), error::not_found(EOWNER_CAP_ALREADY_EXISTS));
move_to(owner, owner_cap);
}
@@ -2670,6 +2769,7 @@ Allows an owner to change the operator of the stake pool.
public entry fun set_operator(owner: &signer, new_operator: address) acquires OwnerCapability, StakePool {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
let ownership_cap = borrow_global<OwnerCapability>(owner_address);
@@ -2746,6 +2846,7 @@ Allows an owner to change the delegated voter of the stake pool.
public entry fun set_delegated_voter(owner: &signer, new_voter: address) acquires OwnerCapability, StakePool {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
let ownership_cap = borrow_global<OwnerCapability>(owner_address);
@@ -2802,6 +2903,7 @@ Add amount
of coins from the public entry fun add_stake(owner: &signer, amount: u64) acquires OwnerCapability, StakePool, ValidatorSet {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
let ownership_cap = borrow_global<OwnerCapability>(owner_address);
@@ -2902,6 +3004,7 @@ Move amount
of coins from pending_inactive to active.
public entry fun reactivate_stake(owner: &signer, amount: u64) acquires OwnerCapability, StakePool {
+ check_signer_permission(owner);
assert_reconfig_not_in_progress();
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
@@ -2989,6 +3092,7 @@ Rotate the consensus key of the validator, it'll take effect in next epoch.
new_consensus_pubkey: vector<u8>,
proof_of_possession: vector<u8>,
) acquires StakePool, ValidatorConfig {
+ check_signer_permission(operator);
assert_reconfig_not_in_progress();
assert_stake_pool_exists(pool_address);
@@ -3052,6 +3156,7 @@ Update the network and full node addresses of the validator. This only takes eff
new_network_addresses: vector<u8>,
new_fullnode_addresses: vector<u8>,
) acquires StakePool, ValidatorConfig {
+ check_signer_permission(operator);
assert_reconfig_not_in_progress();
assert_stake_pool_exists(pool_address);
let stake_pool = borrow_global_mut<StakePool>(pool_address);
@@ -3109,6 +3214,7 @@ Similar to increase_lockup_with_cap but will use ownership capability from the s
public entry fun increase_lockup(owner: &signer) acquires OwnerCapability, StakePool {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
let ownership_cap = borrow_global<OwnerCapability>(owner_address);
@@ -3192,6 +3298,7 @@ This can only called by the operator of the validator/staking pool.
operator: &signer,
pool_address: address
) acquires StakePool, ValidatorConfig, ValidatorSet {
+ check_signer_permission(operator);
assert!(
staking_config::get_allow_validator_set_change(&staking_config::get()),
error::invalid_argument(ENO_POST_GENESIS_VALIDATOR_SET_CHANGE_ALLOWED),
@@ -3294,6 +3401,7 @@ Similar to unlock_with_cap but will use ownership capability from the signing ac
public entry fun unlock(owner: &signer, amount: u64) acquires OwnerCapability, StakePool {
+ check_signer_permission(owner);
assert_reconfig_not_in_progress();
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
@@ -3381,6 +3489,7 @@ Withdraw from account
's inacti
owner: &signer,
withdraw_amount: u64
) acquires OwnerCapability, StakePool, ValidatorSet {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
let ownership_cap = borrow_global<OwnerCapability>(owner_address);
@@ -3479,6 +3588,7 @@ Can only be called by the operator of the validator/staking pool.
operator: &signer,
pool_address: address
) acquires StakePool, ValidatorSet {
+ check_signer_permission(operator);
assert_reconfig_not_in_progress();
let config = staking_config::get();
assert!(
@@ -4640,6 +4750,59 @@ Returns validator's next epoch voting power, including pending_active, active, a
+
+
+
+
+fun spec_get_reward_rate_1(config: StakingConfig): num {
+ if (features::spec_periodical_reward_rate_decrease_enabled()) {
+ let epoch_rewards_rate = global<staking_config::StakingRewardsConfig>(@aptos_framework).rewards_rate;
+ if (epoch_rewards_rate.value == 0) {
+ 0
+ } else {
+ let denominator_0 = aptos_std::fixed_point64::spec_divide_u128(staking_config::MAX_REWARDS_RATE, epoch_rewards_rate);
+ let denominator = if (denominator_0 > MAX_U64) {
+ MAX_U64
+ } else {
+ denominator_0
+ };
+ let nominator = aptos_std::fixed_point64::spec_multiply_u128(denominator, epoch_rewards_rate);
+ nominator
+ }
+ } else {
+ config.rewards_rate
+ }
+}
+
+
+
+
+
+
+
+
+fun spec_get_reward_rate_2(config: StakingConfig): num {
+ if (features::spec_periodical_reward_rate_decrease_enabled()) {
+ let epoch_rewards_rate = global<staking_config::StakingRewardsConfig>(@aptos_framework).rewards_rate;
+ if (epoch_rewards_rate.value == 0) {
+ 1
+ } else {
+ let denominator_0 = aptos_std::fixed_point64::spec_divide_u128(staking_config::MAX_REWARDS_RATE, epoch_rewards_rate);
+ let denominator = if (denominator_0 > MAX_U64) {
+ MAX_U64
+ } else {
+ denominator_0
+ };
+ denominator
+ }
+ } else {
+ config.rewards_rate_denominator
+ }
+}
+
+
+
+
### Resource `ValidatorSet`
@@ -5000,7 +5163,8 @@ Returns validator's next epoch voting power, including pending_active, active, a
-let owner_address = signer::address_of(owner);
+aborts_if permissioned_signer::spec_is_permissioned_signer(owner);
+let owner_address = signer::address_of(owner);
aborts_if exists<OwnerCapability>(owner_address);
ensures exists<OwnerCapability>(owner_address);
ensures global<OwnerCapability>(owner_address) == owner_cap;
@@ -5126,7 +5290,8 @@ Returns validator's next epoch voting power, including pending_active, active, a
-let pre_stake_pool = global<StakePool>(pool_address);
+aborts_if permissioned_signer::spec_is_permissioned_signer(operator);
+let pre_stake_pool = global<StakePool>(pool_address);
let post validator_info = global<ValidatorConfig>(pool_address);
aborts_if reconfiguration_state::spec_is_in_progress();
aborts_if !exists<StakePool>(pool_address);
@@ -5155,7 +5320,8 @@ Returns validator's next epoch voting power, including pending_active, active, a
-let pre_stake_pool = global<StakePool>(pool_address);
+aborts_if permissioned_signer::spec_is_permissioned_signer(operator);
+let pre_stake_pool = global<StakePool>(pool_address);
let post validator_info = global<ValidatorConfig>(pool_address);
modifies global<ValidatorConfig>(pool_address);
include StakedValueNochange;
@@ -5711,59 +5877,6 @@ Returns validator's next epoch voting power, including pending_active, active, a
-
-
-
-
-fun spec_get_reward_rate_1(config: StakingConfig): num {
- if (features::spec_periodical_reward_rate_decrease_enabled()) {
- let epoch_rewards_rate = global<staking_config::StakingRewardsConfig>(@aptos_framework).rewards_rate;
- if (epoch_rewards_rate.value == 0) {
- 0
- } else {
- let denominator_0 = aptos_std::fixed_point64::spec_divide_u128(staking_config::MAX_REWARDS_RATE, epoch_rewards_rate);
- let denominator = if (denominator_0 > MAX_U64) {
- MAX_U64
- } else {
- denominator_0
- };
- let nominator = aptos_std::fixed_point64::spec_multiply_u128(denominator, epoch_rewards_rate);
- nominator
- }
- } else {
- config.rewards_rate
- }
-}
-
-
-
-
-
-
-
-
-fun spec_get_reward_rate_2(config: StakingConfig): num {
- if (features::spec_periodical_reward_rate_decrease_enabled()) {
- let epoch_rewards_rate = global<staking_config::StakingRewardsConfig>(@aptos_framework).rewards_rate;
- if (epoch_rewards_rate.value == 0) {
- 1
- } else {
- let denominator_0 = aptos_std::fixed_point64::spec_divide_u128(staking_config::MAX_REWARDS_RATE, epoch_rewards_rate);
- let denominator = if (denominator_0 > MAX_U64) {
- MAX_U64
- } else {
- denominator_0
- };
- denominator
- }
- } else {
- config.rewards_rate_denominator
- }
-}
-
-
-
-
### Function `update_stake_pool`
diff --git a/aptos-move/framework/aptos-framework/doc/staking_proxy.md b/aptos-move/framework/aptos-framework/doc/staking_proxy.md
index c05adb7f26803..e8a756c4039fc 100644
--- a/aptos-move/framework/aptos-framework/doc/staking_proxy.md
+++ b/aptos-move/framework/aptos-framework/doc/staking_proxy.md
@@ -5,6 +5,10 @@
+- [Struct `StakeProxyPermission`](#0x1_staking_proxy_StakeProxyPermission)
+- [Constants](#@Constants_0)
+- [Function `check_signer_permission`](#0x1_staking_proxy_check_signer_permission)
+- [Function `grant_permission`](#0x1_staking_proxy_grant_permission)
- [Function `set_operator`](#0x1_staking_proxy_set_operator)
- [Function `set_voter`](#0x1_staking_proxy_set_voter)
- [Function `set_vesting_contract_operator`](#0x1_staking_proxy_set_vesting_contract_operator)
@@ -13,20 +17,22 @@
- [Function `set_vesting_contract_voter`](#0x1_staking_proxy_set_vesting_contract_voter)
- [Function `set_staking_contract_voter`](#0x1_staking_proxy_set_staking_contract_voter)
- [Function `set_stake_pool_voter`](#0x1_staking_proxy_set_stake_pool_voter)
-- [Specification](#@Specification_0)
+- [Specification](#@Specification_1)
- [High-level Requirements](#high-level-req)
- [Module-level Specification](#module-level-spec)
- - [Function `set_operator`](#@Specification_0_set_operator)
- - [Function `set_voter`](#@Specification_0_set_voter)
- - [Function `set_vesting_contract_operator`](#@Specification_0_set_vesting_contract_operator)
- - [Function `set_staking_contract_operator`](#@Specification_0_set_staking_contract_operator)
- - [Function `set_stake_pool_operator`](#@Specification_0_set_stake_pool_operator)
- - [Function `set_vesting_contract_voter`](#@Specification_0_set_vesting_contract_voter)
- - [Function `set_staking_contract_voter`](#@Specification_0_set_staking_contract_voter)
- - [Function `set_stake_pool_voter`](#@Specification_0_set_stake_pool_voter)
-
-
-use 0x1::signer;
+ - [Function `set_operator`](#@Specification_1_set_operator)
+ - [Function `set_voter`](#@Specification_1_set_voter)
+ - [Function `set_vesting_contract_operator`](#@Specification_1_set_vesting_contract_operator)
+ - [Function `set_staking_contract_operator`](#@Specification_1_set_staking_contract_operator)
+ - [Function `set_stake_pool_operator`](#@Specification_1_set_stake_pool_operator)
+ - [Function `set_vesting_contract_voter`](#@Specification_1_set_vesting_contract_voter)
+ - [Function `set_staking_contract_voter`](#@Specification_1_set_staking_contract_voter)
+ - [Function `set_stake_pool_voter`](#@Specification_1_set_stake_pool_voter)
+
+
+use 0x1::error;
+use 0x1::permissioned_signer;
+use 0x1::signer;
use 0x1::stake;
use 0x1::staking_contract;
use 0x1::vesting;
@@ -34,6 +40,101 @@
+
+
+## Struct `StakeProxyPermission`
+
+
+
+struct StakeProxyPermission has copy, drop, store
+
+
+
+
+
+Fields
+
+
+
+-
+
dummy_field: bool
+
+-
+
+
+
+
+
+
+
+
+
+## Constants
+
+
+
+
+Signer does not have permission to perform stake proxy logic.
+
+
+const ENO_STAKE_PERMISSION: u64 = 28;
+
+
+
+
+
+
+## Function `check_signer_permission`
+
+Permissions
+
+
+fun check_signer_permission(s: &signer)
+
+
+
+
+
+Implementation
+
+
+inline fun check_signer_permission(s: &signer) {
+ assert!(
+ permissioned_signer::check_permission_exists(s, StakeProxyPermission {}),
+ error::permission_denied(ENO_STAKE_PERMISSION),
+ );
+}
+
+
+
+
+
+
+
+
+## Function `grant_permission`
+
+Grant permission to mutate staking on behalf of the master signer.
+
+
+public fun grant_permission(master: &signer, permissioned_signer: &signer)
+
+
+
+
+
+Implementation
+
+
+public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+ permissioned_signer::authorize(master, permissioned_signer, 1, StakeProxyPermission {})
+}
+
+
+
+
+
+
## Function `set_operator`
@@ -102,6 +203,7 @@
public entry fun set_vesting_contract_operator(owner: &signer, old_operator: address, new_operator: address) {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
let vesting_contracts = &vesting::vesting_contracts(owner_address);
vector::for_each_ref(vesting_contracts, |vesting_contract| {
@@ -134,6 +236,7 @@
public entry fun set_staking_contract_operator(owner: &signer, old_operator: address, new_operator: address) {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
if (staking_contract::staking_contract_exists(owner_address, old_operator)) {
let current_commission_percentage = staking_contract::commission_percentage(owner_address, old_operator);
@@ -162,6 +265,7 @@
public entry fun set_stake_pool_operator(owner: &signer, new_operator: address) {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
if (stake::stake_pool_exists(owner_address)) {
stake::set_operator(owner, new_operator);
@@ -189,6 +293,7 @@
public entry fun set_vesting_contract_voter(owner: &signer, operator: address, new_voter: address) {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
let vesting_contracts = &vesting::vesting_contracts(owner_address);
vector::for_each_ref(vesting_contracts, |vesting_contract| {
@@ -220,6 +325,7 @@
public entry fun set_staking_contract_voter(owner: &signer, operator: address, new_voter: address) {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
if (staking_contract::staking_contract_exists(owner_address, operator)) {
staking_contract::update_voter(owner, operator, new_voter);
@@ -247,6 +353,7 @@
public entry fun set_stake_pool_voter(owner: &signer, new_voter: address) {
+ check_signer_permission(owner);
if (stake::stake_pool_exists(signer::address_of(owner))) {
stake::set_delegated_voter(owner, new_voter);
};
@@ -257,7 +364,7 @@
-
+
## Specification
@@ -329,7 +436,7 @@
-
+
### Function `set_operator`
@@ -349,7 +456,7 @@ Aborts if conditions of SetStakePoolOperator are not met
-
+
### Function `set_voter`
@@ -368,7 +475,7 @@ Aborts if conditions of SetStackingContractVoter and SetStackPoolVoterAbortsIf a
-
+
### Function `set_vesting_contract_operator`
@@ -384,7 +491,7 @@ Aborts if conditions of SetStackingContractVoter and SetStackPoolVoterAbortsIf a
-
+
### Function `set_staking_contract_operator`
@@ -438,7 +545,7 @@ Aborts if conditions of SetStackingContractVoter and SetStackPoolVoterAbortsIf a
-
+
### Function `set_stake_pool_operator`
@@ -463,6 +570,7 @@ One of them are not exists
schema SetStakePoolOperator {
owner: &signer;
new_operator: address;
+ aborts_if permissioned_signer::spec_is_permissioned_signer(owner);
let owner_address = signer::address_of(owner);
let ownership_cap = borrow_global<stake::OwnerCapability>(owner_address);
let pool_address = ownership_cap.pool_address;
@@ -473,7 +581,7 @@ One of them are not exists
-
+
### Function `set_vesting_contract_voter`
@@ -489,7 +597,7 @@ One of them are not exists
-
+
### Function `set_staking_contract_voter`
@@ -531,7 +639,7 @@ Then abort if the resource is not exist
-
+
### Function `set_stake_pool_voter`
@@ -554,6 +662,7 @@ Then abort if the resource is not exist
schema SetStakePoolVoterAbortsIf {
owner: &signer;
new_voter: address;
+ aborts_if permissioned_signer::spec_is_permissioned_signer(owner);
let owner_address = signer::address_of(owner);
let ownership_cap = global<stake::OwnerCapability>(owner_address);
let pool_address = ownership_cap.pool_address;
diff --git a/aptos-move/framework/aptos-framework/doc/vesting.md b/aptos-move/framework/aptos-framework/doc/vesting.md
index 6f2d17e23f75f..b3ecfc2cd6158 100644
--- a/aptos-move/framework/aptos-framework/doc/vesting.md
+++ b/aptos-move/framework/aptos-framework/doc/vesting.md
@@ -169,6 +169,7 @@ withdrawable, admin can call admin_withdraw to withdraw all funds to the vesting
use 0x1::features;
use 0x1::fixed_point32;
use 0x1::math64;
+use 0x1::permissioned_signer;
use 0x1::pool_u64;
use 0x1::signer;
use 0x1::simple_map;
@@ -3229,6 +3230,7 @@ This address should be deterministic for the same admin and vesting contract cre
fun verify_admin(admin: &signer, vesting_contract: &VestingContract) {
+ permissioned_signer::assert_master_signer(admin);
assert!(signer::address_of(admin) == vesting_contract.admin, error::unauthenticated(ENOT_ADMIN));
}
@@ -4318,7 +4320,8 @@ This address should be deterministic for the same admin and vesting contract cre
-// This enforces high-level requirement 9:
+aborts_if permissioned_signer::spec_is_permissioned_signer(admin);
+// This enforces high-level requirement 9:
aborts_if signer::address_of(admin) != vesting_contract.admin;
@@ -4499,6 +4502,7 @@ This address should be deterministic for the same admin and vesting contract cre
schema VerifyAdminAbortsIf {
contract_address: address;
admin: signer;
+ aborts_if permissioned_signer::spec_is_permissioned_signer(admin);
aborts_if !exists<VestingContract>(contract_address);
let vesting_contract = global<VestingContract>(contract_address);
aborts_if signer::address_of(admin) != vesting_contract.admin;
diff --git a/aptos-move/framework/aptos-framework/doc/voting.md b/aptos-move/framework/aptos-framework/doc/voting.md
index 946e707b6e2b2..f861c6f925df5 100644
--- a/aptos-move/framework/aptos-framework/doc/voting.md
+++ b/aptos-move/framework/aptos-framework/doc/voting.md
@@ -98,6 +98,7 @@ the resolution process.
use 0x1::features;
use 0x1::from_bcs;
use 0x1::option;
+use 0x1::permissioned_signer;
use 0x1::signer;
use 0x1::simple_map;
use 0x1::string;
@@ -796,6 +797,7 @@ Key used to track the resolvable time in the proposal's metadata.
public fun register<ProposalType: store>(account: &signer) {
+ permissioned_signer::assert_master_signer(account);
let addr = signer::address_of(account);
assert!(!exists<VotingForum<ProposalType>>(addr), error::already_exists(EVOTING_FORUM_ALREADY_REGISTERED));
@@ -1923,7 +1925,8 @@ Return true if the voting period of the given proposal has already ended.
-let addr = signer::address_of(account);
+aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+let addr = signer::address_of(account);
aborts_if exists<VotingForum<ProposalType>>(addr);
aborts_if !exists<account::Account>(addr);
let register_account = global<account::Account>(addr);
diff --git a/aptos-move/framework/aptos-framework/sources/aptos_governance.move b/aptos-move/framework/aptos-framework/sources/aptos_governance.move
index 19c8d45c92753..dc75f8c2a1c3c 100644
--- a/aptos-move/framework/aptos-framework/sources/aptos_governance.move
+++ b/aptos-move/framework/aptos-framework/sources/aptos_governance.move
@@ -31,6 +31,7 @@ module aptos_framework::aptos_governance {
use aptos_framework::system_addresses;
use aptos_framework::aptos_coin::{Self, AptosCoin};
use aptos_framework::consensus_config;
+ use aptos_framework::permissioned_signer;
use aptos_framework::randomness_config;
use aptos_framework::reconfiguration_with_dkg;
use aptos_framework::timestamp;
@@ -375,6 +376,7 @@ module aptos_framework::aptos_governance {
metadata_hash: vector,
is_multi_step_proposal: bool,
): u64 acquires GovernanceConfig, GovernanceEvents {
+ permissioned_signer::assert_master_signer(proposer);
let proposer_address = signer::address_of(proposer);
assert!(
stake::get_delegated_voter(stake_pool) == proposer_address,
@@ -506,6 +508,7 @@ module aptos_framework::aptos_governance {
voting_power: u64,
should_pass: bool,
) acquires ApprovedExecutionHashes, VotingRecords, VotingRecordsV2, GovernanceEvents {
+ permissioned_signer::assert_master_signer(voter);
let voter_address = signer::address_of(voter);
assert!(stake::get_delegated_voter(stake_pool) == voter_address, error::invalid_argument(ENOT_DELEGATED_VOTER));
diff --git a/aptos-move/framework/aptos-framework/sources/code.move b/aptos-move/framework/aptos-framework/sources/code.move
index ef884c9695d1c..3e4d2d7866d71 100644
--- a/aptos-move/framework/aptos-framework/sources/code.move
+++ b/aptos-move/framework/aptos-framework/sources/code.move
@@ -13,6 +13,7 @@ module aptos_framework::code {
use std::string;
use aptos_framework::event;
use aptos_framework::object::{Self, Object};
+ use aptos_framework::permissioned_signer;
// ----------------------------------------------------------------------
// Code Publishing
@@ -145,6 +146,7 @@ module aptos_framework::code {
/// Publishes a package at the given signer's address. The caller must provide package metadata describing the
/// package.
public fun publish_package(owner: &signer, pack: PackageMetadata, code: vector>) acquires PackageRegistry {
+ permissioned_signer::assert_master_signer(owner);
// Disallow incompatible upgrade mode. Governance can decide later if this should be reconsidered.
assert!(
pack.upgrade_policy.policy > upgrade_policy_arbitrary().policy,
@@ -206,6 +208,7 @@ module aptos_framework::code {
}
public fun freeze_code_object(publisher: &signer, code_object: Object) acquires PackageRegistry {
+ permissioned_signer::assert_master_signer(publisher);
let code_object_addr = object::object_address(&code_object);
assert!(exists(code_object_addr), error::not_found(ECODE_OBJECT_DOES_NOT_EXIST));
assert!(
diff --git a/aptos-move/framework/aptos-framework/sources/coin.spec.move b/aptos-move/framework/aptos-framework/sources/coin.spec.move
index 2564bc0daa8c6..aa4da455af04d 100644
--- a/aptos-move/framework/aptos-framework/sources/coin.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/coin.spec.move
@@ -395,6 +395,7 @@ spec aptos_framework::coin {
/// The creator of `CoinType` must be `@aptos_framework`.
/// `SupplyConfig` allow upgrade.
spec upgrade_supply(account: &signer) {
+ aborts_if permissioned_signer::spec_is_permissioned_signer(account);
let account_addr = signer::address_of(account);
let coin_address = type_info::type_of().account_address;
aborts_if coin_address != account_addr;
@@ -423,6 +424,7 @@ spec aptos_framework::coin {
}
spec initialize {
+ aborts_if permissioned_signer::spec_is_permissioned_signer(account);
let account_addr = signer::address_of(account);
/// [high-level-req-1.2]
aborts_if type_info::type_of().account_address != account_addr;
@@ -441,6 +443,7 @@ spec aptos_framework::coin {
monitor_supply: bool,
): (BurnCapability, FreezeCapability, MintCapability) {
use aptos_framework::aggregator_factory;
+ aborts_if permissioned_signer::spec_is_permissioned_signer(account);
let addr = signer::address_of(account);
aborts_if addr != @aptos_framework;
aborts_if monitor_supply && !exists(@aptos_framework);
@@ -473,6 +476,7 @@ spec aptos_framework::coin {
monitor_supply: bool,
parallelizable: bool,
): (BurnCapability, FreezeCapability, MintCapability) {
+ aborts_if permissioned_signer::spec_is_permissioned_signer(account);
include InitializeInternalSchema {
name: name.bytes,
symbol: symbol.bytes
diff --git a/aptos-move/framework/aptos-framework/sources/create_signer.spec.move b/aptos-move/framework/aptos-framework/sources/create_signer.spec.move
index 1bb4c0ffa9fd6..dab59d30da2db 100644
--- a/aptos-move/framework/aptos-framework/sources/create_signer.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/create_signer.spec.move
@@ -41,5 +41,8 @@ spec aptos_framework::create_signer {
pragma opaque;
aborts_if [abstract] false;
ensures [abstract] signer::address_of(result) == addr;
+ ensures [abstract] result == spec_create_signer(addr);
}
+
+ spec fun spec_create_signer(addr: address): signer;
}
diff --git a/aptos-move/framework/aptos-framework/sources/delegation_pool.move b/aptos-move/framework/aptos-framework/sources/delegation_pool.move
index be1643ca6b197..869669cf0e739 100644
--- a/aptos-move/framework/aptos-framework/sources/delegation_pool.move
+++ b/aptos-move/framework/aptos-framework/sources/delegation_pool.move
@@ -124,6 +124,7 @@ module aptos_framework::delegation_pool {
use aptos_framework::aptos_governance;
use aptos_framework::coin;
use aptos_framework::event::{Self, EventHandle, emit};
+ use aptos_framework::permissioned_signer;
use aptos_framework::stake;
use aptos_framework::stake::get_operator;
use aptos_framework::staking_config;
@@ -215,6 +216,9 @@ module aptos_framework::delegation_pool {
/// Cannot unlock the accumulated active stake of NULL_SHAREHOLDER(0x0).
const ECANNOT_UNLOCK_NULL_SHAREHOLDER: u64 = 27;
+ /// Signer does not have permission to perform delegation logic.
+ const ENO_DELEGATION_PERMISSION: u64 = 28;
+
const MAX_U64: u64 = 18446744073709551615;
/// Maximum operator percentage fee(of double digit precision): 22.85% is represented as 2285
@@ -346,6 +350,8 @@ module aptos_framework::delegation_pool {
allowlist: SmartTable,
}
+ struct DelegationPermission has copy, drop, store {}
+
#[event]
struct AddStake has drop, store {
pool_address: address,
@@ -832,6 +838,18 @@ module aptos_framework::delegation_pool {
allowlist
}
+ /// Permissions
+ inline fun check_signer_permission(s: &signer) {
+ assert!(
+ permissioned_signer::check_permission_exists(s, DelegationPermission {}),
+ error::permission_denied(ENO_DELEGATION_PERMISSION),
+ );
+ }
+
+ public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+ permissioned_signer::authorize(master, permissioned_signer, 1, DelegationPermission {})
+ }
+
/// Initialize a delegation pool of custom fixed `operator_commission_percentage`.
/// A resource account is created from `owner` signer and its supplied `delegation_pool_creation_seed`
/// to host the delegation pool resource and own the underlying stake pool.
@@ -841,6 +859,7 @@ module aptos_framework::delegation_pool {
operator_commission_percentage: u64,
delegation_pool_creation_seed: vector,
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(owner);
assert!(features::delegation_pools_enabled(), error::invalid_state(EDELEGATION_POOLS_DISABLED));
let owner_address = signer::address_of(owner);
assert!(!owner_cap_exists(owner_address), error::already_exists(EOWNER_CAP_ALREADY_EXISTS));
@@ -941,6 +960,7 @@ module aptos_framework::delegation_pool {
voting_power: u64,
should_pass: bool
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(voter);
assert_partial_governance_voting_enabled(pool_address);
// synchronize delegation and stake pools before any user operation.
synchronize_delegation_pool(pool_address);
@@ -1000,6 +1020,7 @@ module aptos_framework::delegation_pool {
metadata_hash: vector,
is_multi_step_proposal: bool,
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(voter);
assert_partial_governance_voting_enabled(pool_address);
// synchronize delegation and stake pools before any user operation
@@ -1292,6 +1313,7 @@ module aptos_framework::delegation_pool {
owner: &signer,
new_operator: address
) acquires DelegationPoolOwnership, DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(owner);
let pool_address = get_owned_pool_address(signer::address_of(owner));
// synchronize delegation and stake pools before any user operation
// ensure the old operator is paid its uncommitted commission rewards
@@ -1307,6 +1329,7 @@ module aptos_framework::delegation_pool {
operator: &signer,
new_beneficiary: address
) acquires BeneficiaryForOperator {
+ check_signer_permission(operator);
assert!(features::operator_beneficiary_change_enabled(), std::error::invalid_state(
EOPERATOR_BENEFICIARY_CHANGE_NOT_SUPPORTED
));
@@ -1332,6 +1355,7 @@ module aptos_framework::delegation_pool {
owner: &signer,
new_commission_percentage: u64
) acquires DelegationPoolOwnership, DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(owner);
assert!(features::commission_change_delegation_pool_enabled(), error::invalid_state(
ECOMMISSION_RATE_CHANGE_NOT_SUPPORTED
));
@@ -1377,6 +1401,7 @@ module aptos_framework::delegation_pool {
owner: &signer,
new_voter: address
) acquires DelegationPoolOwnership, DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(owner);
// No one can change delegated_voter once the partial governance voting feature is enabled.
assert!(
!features::delegation_pool_partial_governance_voting_enabled(),
@@ -1395,6 +1420,7 @@ module aptos_framework::delegation_pool {
pool_address: address,
new_voter: address
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(delegator);
assert_partial_governance_voting_enabled(pool_address);
// synchronize delegation and stake pools before any user operation
@@ -1452,6 +1478,7 @@ module aptos_framework::delegation_pool {
public entry fun enable_delegators_allowlisting(
owner: &signer,
) acquires DelegationPoolOwnership, DelegationPool {
+ check_signer_permission(owner);
assert!(
features::delegation_pool_allowlisting_enabled(),
error::invalid_state(EDELEGATORS_ALLOWLISTING_NOT_SUPPORTED)
@@ -1470,6 +1497,7 @@ module aptos_framework::delegation_pool {
public entry fun disable_delegators_allowlisting(
owner: &signer,
) acquires DelegationPoolOwnership, DelegationPoolAllowlisting {
+ check_signer_permission(owner);
let pool_address = get_owned_pool_address(signer::address_of(owner));
assert_allowlisting_enabled(pool_address);
@@ -1485,6 +1513,7 @@ module aptos_framework::delegation_pool {
owner: &signer,
delegator_address: address,
) acquires DelegationPoolOwnership, DelegationPoolAllowlisting {
+ check_signer_permission(owner);
let pool_address = get_owned_pool_address(signer::address_of(owner));
assert_allowlisting_enabled(pool_address);
@@ -1500,6 +1529,7 @@ module aptos_framework::delegation_pool {
owner: &signer,
delegator_address: address,
) acquires DelegationPoolOwnership, DelegationPoolAllowlisting {
+ check_signer_permission(owner);
let pool_address = get_owned_pool_address(signer::address_of(owner));
assert_allowlisting_enabled(pool_address);
@@ -1515,6 +1545,7 @@ module aptos_framework::delegation_pool {
owner: &signer,
delegator_address: address,
) acquires DelegationPoolOwnership, DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage, DelegationPoolAllowlisting {
+ check_signer_permission(owner);
let pool_address = get_owned_pool_address(signer::address_of(owner));
assert_allowlisting_enabled(pool_address);
assert!(
@@ -1539,6 +1570,7 @@ module aptos_framework::delegation_pool {
pool_address: address,
amount: u64
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage, DelegationPoolAllowlisting {
+ check_signer_permission(delegator);
// short-circuit if amount to add is 0 so no event is emitted
if (amount == 0) { return };
@@ -1596,6 +1628,7 @@ module aptos_framework::delegation_pool {
pool_address: address,
amount: u64
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(delegator);
// short-circuit if amount to unlock is 0 so no event is emitted
if (amount == 0) { return };
@@ -1657,6 +1690,7 @@ module aptos_framework::delegation_pool {
pool_address: address,
amount: u64
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage, DelegationPoolAllowlisting {
+ check_signer_permission(delegator);
// short-circuit if amount to reactivate is 0 so no event is emitted
if (amount == 0) { return };
@@ -1707,6 +1741,7 @@ module aptos_framework::delegation_pool {
pool_address: address,
amount: u64
) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+ check_signer_permission(delegator);
assert!(amount > 0, error::invalid_argument(EWITHDRAW_ZERO_STAKE));
// synchronize delegation and stake pools before any user operation
synchronize_delegation_pool(pool_address);
diff --git a/aptos-move/framework/aptos-framework/sources/managed_coin.spec.move b/aptos-move/framework/aptos-framework/sources/managed_coin.spec.move
index 344c9744f7c97..8569fa284d4a9 100644
--- a/aptos-move/framework/aptos-framework/sources/managed_coin.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/managed_coin.spec.move
@@ -97,6 +97,8 @@ spec aptos_framework::managed_coin {
decimals: u8,
monitor_supply: bool,
) {
+ use aptos_framework::permissioned_signer;
+ aborts_if permissioned_signer::spec_is_permissioned_signer(account);
include coin::InitializeInternalSchema;
aborts_if !string::spec_internal_check_utf8(name);
aborts_if !string::spec_internal_check_utf8(symbol);
diff --git a/aptos-move/framework/aptos-framework/sources/resource_account.spec.move b/aptos-move/framework/aptos-framework/sources/resource_account.spec.move
index 847e77853bdc4..902a15fec660d 100644
--- a/aptos-move/framework/aptos-framework/sources/resource_account.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/resource_account.spec.move
@@ -68,8 +68,12 @@ spec aptos_framework::resource_account {
seed: vector,
optional_auth_key: vector,
) {
+ use aptos_framework::permissioned_signer;
+ use aptos_framework::create_signer;
let source_addr = signer::address_of(origin);
let resource_addr = account::spec_create_resource_address(source_addr, seed);
+ let resource = create_signer::spec_create_signer(resource_addr);
+ aborts_if permissioned_signer::spec_is_permissioned_signer(resource);
include RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIfWithoutAccountLimit;
}
@@ -116,6 +120,8 @@ spec aptos_framework::resource_account {
resource_signer_cap: account::SignerCapability,
optional_auth_key: vector,
) {
+ use aptos_framework::permissioned_signer;
+ aborts_if permissioned_signer::spec_is_permissioned_signer(resource);
let resource_addr = signer::address_of(resource);
/// [high-level-req-1]
include RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIf;
@@ -172,6 +178,8 @@ spec aptos_framework::resource_account {
resource: &signer,
source_addr: address,
) : account::SignerCapability {
+ use aptos_framework::permissioned_signer;
+ aborts_if permissioned_signer::spec_is_permissioned_signer(resource);
/// [high-level-req-6]
aborts_if !exists(source_addr);
let resource_addr = signer::address_of(resource);
diff --git a/aptos-move/framework/aptos-framework/sources/stake.move b/aptos-move/framework/aptos-framework/sources/stake.move
index 0b65fa5f4eb7d..3070b2eaeaebb 100644
--- a/aptos-move/framework/aptos-framework/sources/stake.move
+++ b/aptos-move/framework/aptos-framework/sources/stake.move
@@ -34,6 +34,7 @@ module aptos_framework::stake {
use aptos_framework::system_addresses;
use aptos_framework::staking_config::{Self, StakingConfig, StakingRewardsConfig};
use aptos_framework::chain_status;
+ use aptos_framework::permissioned_signer;
friend aptos_framework::block;
friend aptos_framework::genesis;
@@ -81,6 +82,8 @@ module aptos_framework::stake {
const EFEES_TABLE_ALREADY_EXISTS: u64 = 19;
/// Validator set change temporarily disabled because of in-progress reconfiguration.
const ERECONFIGURATION_IN_PROGRESS: u64 = 20;
+ /// Signer does not have permission to perform stake logic.
+ const ENO_STAKE_PERMISSION: u64 = 28;
/// Validator status enum. We can switch to proper enum later once Move supports it.
const VALIDATOR_STATUS_PENDING_ACTIVE: u64 = 1;
@@ -204,6 +207,8 @@ module aptos_framework::stake {
pool_address: address,
}
+ struct StakePermission has copy, drop, store {}
+
#[event]
struct RegisterValidatorCandidate has drop, store {
pool_address: address,
@@ -366,6 +371,19 @@ module aptos_framework::stake {
}
}
+ /// Permissions
+ inline fun check_signer_permission(s: &signer) {
+ assert!(
+ permissioned_signer::check_permission_exists(s, StakePermission {}),
+ error::permission_denied(ENO_STAKE_PERMISSION),
+ );
+ }
+
+ /// Grant permission to mutate staking on behalf of the master signer.
+ public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+ permissioned_signer::authorize(master, permissioned_signer, 1, StakePermission {})
+ }
+
#[view]
/// Return the lockup expiration of the stake pool at `pool_address`.
/// This will throw an error if there's no stake pool at `pool_address`.
@@ -558,6 +576,7 @@ module aptos_framework::stake {
operator: address,
voter: address,
) acquires AllowedValidators, OwnerCapability, StakePool, ValidatorSet {
+ check_signer_permission(owner);
initialize_owner(owner);
move_to(owner, ValidatorConfig {
consensus_pubkey: vector::empty(),
@@ -587,6 +606,7 @@ module aptos_framework::stake {
network_addresses: vector,
fullnode_addresses: vector,
) acquires AllowedValidators {
+ check_signer_permission(account);
// Checks the public key has a valid proof-of-possession to prevent rogue-key attacks.
let pubkey_from_pop = &bls12381::public_key_from_bytes_with_pop(
consensus_pubkey,
@@ -604,6 +624,7 @@ module aptos_framework::stake {
}
fun initialize_owner(owner: &signer) acquires AllowedValidators {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert!(is_allowed(owner_address), error::not_found(EINELIGIBLE_VALIDATOR));
assert!(!stake_pool_exists(owner_address), error::already_exists(EALREADY_REGISTERED));
@@ -638,6 +659,7 @@ module aptos_framework::stake {
/// Extract and return owner capability from the signing account.
public fun extract_owner_cap(owner: &signer): OwnerCapability acquires OwnerCapability {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
move_from(owner_address)
@@ -646,6 +668,7 @@ module aptos_framework::stake {
/// Deposit `owner_cap` into `account`. This requires `account` to not already have ownership of another
/// staking pool.
public fun deposit_owner_cap(owner: &signer, owner_cap: OwnerCapability) {
+ check_signer_permission(owner);
assert!(!exists(signer::address_of(owner)), error::not_found(EOWNER_CAP_ALREADY_EXISTS));
move_to(owner, owner_cap);
}
@@ -657,6 +680,7 @@ module aptos_framework::stake {
/// Allows an owner to change the operator of the stake pool.
public entry fun set_operator(owner: &signer, new_operator: address) acquires OwnerCapability, StakePool {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
let ownership_cap = borrow_global(owner_address);
@@ -693,6 +717,7 @@ module aptos_framework::stake {
/// Allows an owner to change the delegated voter of the stake pool.
public entry fun set_delegated_voter(owner: &signer, new_voter: address) acquires OwnerCapability, StakePool {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
let ownership_cap = borrow_global(owner_address);
@@ -709,6 +734,7 @@ module aptos_framework::stake {
/// Add `amount` of coins from the `account` owning the StakePool.
public entry fun add_stake(owner: &signer, amount: u64) acquires OwnerCapability, StakePool, ValidatorSet {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
let ownership_cap = borrow_global(owner_address);
@@ -769,6 +795,7 @@ module aptos_framework::stake {
/// Move `amount` of coins from pending_inactive to active.
public entry fun reactivate_stake(owner: &signer, amount: u64) acquires OwnerCapability, StakePool {
+ check_signer_permission(owner);
assert_reconfig_not_in_progress();
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
@@ -816,6 +843,7 @@ module aptos_framework::stake {
new_consensus_pubkey: vector,
proof_of_possession: vector,
) acquires StakePool, ValidatorConfig {
+ check_signer_permission(operator);
assert_reconfig_not_in_progress();
assert_stake_pool_exists(pool_address);
@@ -859,6 +887,7 @@ module aptos_framework::stake {
new_network_addresses: vector,
new_fullnode_addresses: vector,
) acquires StakePool, ValidatorConfig {
+ check_signer_permission(operator);
assert_reconfig_not_in_progress();
assert_stake_pool_exists(pool_address);
let stake_pool = borrow_global_mut(pool_address);
@@ -896,6 +925,7 @@ module aptos_framework::stake {
/// Similar to increase_lockup_with_cap but will use ownership capability from the signing account.
public entry fun increase_lockup(owner: &signer) acquires OwnerCapability, StakePool {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
let ownership_cap = borrow_global(owner_address);
@@ -939,6 +969,7 @@ module aptos_framework::stake {
operator: &signer,
pool_address: address
) acquires StakePool, ValidatorConfig, ValidatorSet {
+ check_signer_permission(operator);
assert!(
staking_config::get_allow_validator_set_change(&staking_config::get()),
error::invalid_argument(ENO_POST_GENESIS_VALIDATOR_SET_CHANGE_ALLOWED),
@@ -1001,6 +1032,7 @@ module aptos_framework::stake {
/// Similar to unlock_with_cap but will use ownership capability from the signing account.
public entry fun unlock(owner: &signer, amount: u64) acquires OwnerCapability, StakePool {
+ check_signer_permission(owner);
assert_reconfig_not_in_progress();
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
@@ -1048,6 +1080,7 @@ module aptos_framework::stake {
owner: &signer,
withdraw_amount: u64
) acquires OwnerCapability, StakePool, ValidatorSet {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
assert_owner_cap_exists(owner_address);
let ownership_cap = borrow_global(owner_address);
@@ -1106,6 +1139,7 @@ module aptos_framework::stake {
operator: &signer,
pool_address: address
) acquires StakePool, ValidatorSet {
+ check_signer_permission(operator);
assert_reconfig_not_in_progress();
let config = staking_config::get();
assert!(
diff --git a/aptos-move/framework/aptos-framework/sources/stake.spec.move b/aptos-move/framework/aptos-framework/sources/stake.spec.move
index 44101fbcb134c..3ed44f710fa41 100644
--- a/aptos-move/framework/aptos-framework/sources/stake.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/stake.spec.move
@@ -310,6 +310,7 @@ spec aptos_framework::stake {
}
spec deposit_owner_cap(owner: &signer, owner_cap: OwnerCapability) {
+ aborts_if permissioned_signer::spec_is_permissioned_signer(owner);
let owner_address = signer::address_of(owner);
aborts_if exists(owner_address);
ensures exists(owner_address);
@@ -358,6 +359,7 @@ spec aptos_framework::stake {
new_network_addresses: vector,
new_fullnode_addresses: vector,
) {
+ aborts_if permissioned_signer::spec_is_permissioned_signer(operator);
let pre_stake_pool = global(pool_address);
let post validator_info = global(pool_address);
modifies global(pool_address);
@@ -404,6 +406,7 @@ spec aptos_framework::stake {
new_consensus_pubkey: vector,
proof_of_possession: vector,
) {
+ aborts_if permissioned_signer::spec_is_permissioned_signer(operator);
let pre_stake_pool = global(pool_address);
let post validator_info = global(pool_address);
aborts_if reconfiguration_state::spec_is_in_progress();
diff --git a/aptos-move/framework/aptos-framework/sources/staking_proxy.move b/aptos-move/framework/aptos-framework/sources/staking_proxy.move
index 26d1aa33372ce..598b51cae7a3c 100644
--- a/aptos-move/framework/aptos-framework/sources/staking_proxy.move
+++ b/aptos-move/framework/aptos-framework/sources/staking_proxy.move
@@ -1,11 +1,31 @@
module aptos_framework::staking_proxy {
+ use std::error;
use std::signer;
use std::vector;
+ use aptos_framework::permissioned_signer;
use aptos_framework::stake;
use aptos_framework::staking_contract;
use aptos_framework::vesting;
+ struct StakeProxyPermission has copy, drop, store {}
+
+ /// Signer does not have permission to perform stake proxy logic.
+ const ENO_STAKE_PERMISSION: u64 = 28;
+
+ /// Permissions
+ inline fun check_signer_permission(s: &signer) {
+ assert!(
+ permissioned_signer::check_permission_exists(s, StakeProxyPermission {}),
+ error::permission_denied(ENO_STAKE_PERMISSION),
+ );
+ }
+
+ /// Grant permission to mutate staking on behalf of the master signer.
+ public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+ permissioned_signer::authorize(master, permissioned_signer, 1, StakeProxyPermission {})
+ }
+
public entry fun set_operator(owner: &signer, old_operator: address, new_operator: address) {
set_vesting_contract_operator(owner, old_operator, new_operator);
set_staking_contract_operator(owner, old_operator, new_operator);
@@ -19,6 +39,7 @@ module aptos_framework::staking_proxy {
}
public entry fun set_vesting_contract_operator(owner: &signer, old_operator: address, new_operator: address) {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
let vesting_contracts = &vesting::vesting_contracts(owner_address);
vector::for_each_ref(vesting_contracts, |vesting_contract| {
@@ -31,6 +52,7 @@ module aptos_framework::staking_proxy {
}
public entry fun set_staking_contract_operator(owner: &signer, old_operator: address, new_operator: address) {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
if (staking_contract::staking_contract_exists(owner_address, old_operator)) {
let current_commission_percentage = staking_contract::commission_percentage(owner_address, old_operator);
@@ -39,6 +61,7 @@ module aptos_framework::staking_proxy {
}
public entry fun set_stake_pool_operator(owner: &signer, new_operator: address) {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
if (stake::stake_pool_exists(owner_address)) {
stake::set_operator(owner, new_operator);
@@ -46,6 +69,7 @@ module aptos_framework::staking_proxy {
}
public entry fun set_vesting_contract_voter(owner: &signer, operator: address, new_voter: address) {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
let vesting_contracts = &vesting::vesting_contracts(owner_address);
vector::for_each_ref(vesting_contracts, |vesting_contract| {
@@ -57,6 +81,7 @@ module aptos_framework::staking_proxy {
}
public entry fun set_staking_contract_voter(owner: &signer, operator: address, new_voter: address) {
+ check_signer_permission(owner);
let owner_address = signer::address_of(owner);
if (staking_contract::staking_contract_exists(owner_address, operator)) {
staking_contract::update_voter(owner, operator, new_voter);
@@ -64,6 +89,7 @@ module aptos_framework::staking_proxy {
}
public entry fun set_stake_pool_voter(owner: &signer, new_voter: address) {
+ check_signer_permission(owner);
if (stake::stake_pool_exists(signer::address_of(owner))) {
stake::set_delegated_voter(owner, new_voter);
};
diff --git a/aptos-move/framework/aptos-framework/sources/staking_proxy.spec.move b/aptos-move/framework/aptos-framework/sources/staking_proxy.spec.move
index a1da120f0eed4..d5b6ba29ad82e 100644
--- a/aptos-move/framework/aptos-framework/sources/staking_proxy.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/staking_proxy.spec.move
@@ -125,9 +125,12 @@ spec aptos_framework::staking_proxy {
}
spec schema SetStakePoolOperator {
+ use aptos_framework::permissioned_signer;
+
owner: &signer;
new_operator: address;
+ aborts_if permissioned_signer::spec_is_permissioned_signer(owner);
let owner_address = signer::address_of(owner);
let ownership_cap = borrow_global(owner_address);
let pool_address = ownership_cap.pool_address;
@@ -169,9 +172,12 @@ spec aptos_framework::staking_proxy {
}
spec schema SetStakePoolVoterAbortsIf {
+ use aptos_framework::permissioned_signer;
+
owner: &signer;
new_voter: address;
+ aborts_if permissioned_signer::spec_is_permissioned_signer(owner);
let owner_address = signer::address_of(owner);
let ownership_cap = global(owner_address);
let pool_address = ownership_cap.pool_address;
diff --git a/aptos-move/framework/aptos-framework/sources/vesting.move b/aptos-move/framework/aptos-framework/sources/vesting.move
index 9ede3acfa3d03..1a25757b81903 100644
--- a/aptos-move/framework/aptos-framework/sources/vesting.move
+++ b/aptos-move/framework/aptos-framework/sources/vesting.move
@@ -53,6 +53,7 @@ module aptos_framework::vesting {
use aptos_framework::staking_contract;
use aptos_framework::system_addresses;
use aptos_framework::timestamp;
+ use aptos_framework::permissioned_signer;
friend aptos_framework::genesis;
@@ -1142,6 +1143,7 @@ module aptos_framework::vesting {
}
fun verify_admin(admin: &signer, vesting_contract: &VestingContract) {
+ permissioned_signer::assert_master_signer(admin);
assert!(signer::address_of(admin) == vesting_contract.admin, error::unauthenticated(ENOT_ADMIN));
}
diff --git a/aptos-move/framework/aptos-framework/sources/vesting.spec.move b/aptos-move/framework/aptos-framework/sources/vesting.spec.move
index 3bcbcbb11c0de..1aa491d30089f 100644
--- a/aptos-move/framework/aptos-framework/sources/vesting.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/vesting.spec.move
@@ -530,6 +530,7 @@ spec aptos_framework::vesting {
}
spec verify_admin(admin: &signer, vesting_contract: &VestingContract) {
+ aborts_if permissioned_signer::spec_is_permissioned_signer(admin);
/// [high-level-req-9]
aborts_if signer::address_of(admin) != vesting_contract.admin;
}
@@ -630,6 +631,8 @@ spec aptos_framework::vesting {
spec schema VerifyAdminAbortsIf {
contract_address: address;
admin: signer;
+
+ aborts_if permissioned_signer::spec_is_permissioned_signer(admin);
aborts_if !exists(contract_address);
let vesting_contract = global(contract_address);
aborts_if signer::address_of(admin) != vesting_contract.admin;
diff --git a/aptos-move/framework/aptos-framework/sources/voting.move b/aptos-move/framework/aptos-framework/sources/voting.move
index a10e795b7369f..4dd70ad10e580 100644
--- a/aptos-move/framework/aptos-framework/sources/voting.move
+++ b/aptos-move/framework/aptos-framework/sources/voting.move
@@ -34,6 +34,7 @@ module aptos_framework::voting {
use aptos_framework::account;
use aptos_framework::event::{Self, EventHandle};
+ use aptos_framework::permissioned_signer;
use aptos_framework::timestamp;
use aptos_framework::transaction_context;
use aptos_std::from_bcs;
@@ -189,6 +190,7 @@ module aptos_framework::voting {
}
public fun register(account: &signer) {
+ permissioned_signer::assert_master_signer(account);
let addr = signer::address_of(account);
assert!(!exists>(addr), error::already_exists(EVOTING_FORUM_ALREADY_REGISTERED));
diff --git a/aptos-move/framework/aptos-framework/sources/voting.spec.move b/aptos-move/framework/aptos-framework/sources/voting.spec.move
index a1c05091e54b6..29681b5fa54bb 100644
--- a/aptos-move/framework/aptos-framework/sources/voting.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/voting.spec.move
@@ -44,6 +44,7 @@ spec aptos_framework::voting {
}
spec register(account: &signer) {
+ aborts_if permissioned_signer::spec_is_permissioned_signer(account);
let addr = signer::address_of(account);
// Will abort if there's already a `VotingForum` under addr