diff --git a/aptos-move/framework/aptos-framework/doc/aptos_governance.md b/aptos-move/framework/aptos-framework/doc/aptos_governance.md index c90cc82da7e23..6a11ad8d9f088 100644 --- a/aptos-move/framework/aptos-framework/doc/aptos_governance.md +++ b/aptos-move/framework/aptos-framework/doc/aptos_governance.md @@ -29,7 +29,10 @@ on a proposal multiple times as long as the total voting power of these votes do - [Struct `CreateProposal`](#0x1_aptos_governance_CreateProposal) - [Struct `Vote`](#0x1_aptos_governance_Vote) - [Struct `UpdateConfig`](#0x1_aptos_governance_UpdateConfig) +- [Struct `GovernancePermission`](#0x1_aptos_governance_GovernancePermission) - [Constants](#@Constants_0) +- [Function `check_signer_permission`](#0x1_aptos_governance_check_signer_permission) +- [Function `grant_permission`](#0x1_aptos_governance_grant_permission) - [Function `store_signer_cap`](#0x1_aptos_governance_store_signer_cap) - [Function `initialize`](#0x1_aptos_governance_initialize) - [Function `update_governance_config`](#0x1_aptos_governance_update_governance_config) @@ -61,7 +64,6 @@ on a proposal multiple times as long as the total voting power of these votes do - [Function `get_signer`](#0x1_aptos_governance_get_signer) - [Function `create_proposal_metadata`](#0x1_aptos_governance_create_proposal_metadata) - [Function `assert_voting_initialization`](#0x1_aptos_governance_assert_voting_initialization) -- [Function `initialize_for_verification`](#0x1_aptos_governance_initialize_for_verification) - [Specification](#@Specification_1) - [High-level Requirements](#high-level-req) - [Module-level Specification](#module-level-spec) @@ -96,7 +98,6 @@ on a proposal multiple times as long as the total voting power of these votes do - [Function `get_signer`](#@Specification_1_get_signer) - [Function `create_proposal_metadata`](#@Specification_1_create_proposal_metadata) - [Function `assert_voting_initialization`](#@Specification_1_assert_voting_initialization) - - [Function `initialize_for_verification`](#@Specification_1_initialize_for_verification)
use 0x1::account;
@@ -109,6 +110,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;
@@ -642,6 +644,33 @@ Event emitted when the governance configs are updated.
 
 
 
+
+
+
+
+## Struct `GovernancePermission`
+
+
+
+
struct GovernancePermission has copy, drop, store
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ +
@@ -738,6 +767,16 @@ The proposal in the argument is not a partial voting proposal. + + +Current permissioned signer cannot perform governance operations. + + +
const ENO_GOVERNANCE_PERMISSION: u64 = 15;
+
+ + + The specified stake pool must be part of the validator set @@ -817,6 +856,59 @@ Proposal metadata attribute keys. + + +## 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, GovernancePermission {}),
+        error::permission_denied(ENO_GOVERNANCE_PERMISSION),
+    );
+}
+
+ + + +
+ + + +## Function `grant_permission` + +Grant permission to perform governance operations 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_unlimited(master, permissioned_signer, GovernancePermission {})
+}
+
+ + + +
+ ## Function `store_signer_cap` @@ -1262,6 +1354,7 @@ Return proposal_id when a proposal is successfully created. metadata_hash: vector<u8>, is_multi_step_proposal: bool, ): u64 acquires GovernanceConfig, GovernanceEvents { + check_signer_permission(proposer); let proposer_address = signer::address_of(proposer); assert!( stake::get_delegated_voter(stake_pool) == proposer_address, @@ -1494,6 +1587,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)); @@ -1888,7 +1982,7 @@ Only called in testnet where the core resources account exists and has been gran
public fun get_signer_testnet_only(
     core_resources: &signer, signer_address: address): signer acquires GovernanceResponsbility {
     system_addresses::assert_core_resource(core_resources);
-    // Core resources account only has mint capability in tests/testnets.
+    // Core resources account only has mint capability in tests/testnets.
     assert!(aptos_coin::has_mint_capability(core_resources), error::unauthenticated(EUNAUTHORIZED));
     get_signer(signer_address)
 }
@@ -2017,36 +2111,6 @@ Return a signer for making changes to 0x1 as part of on-chain governance proposa
 
 
 
-
-
-
-
-## Function `initialize_for_verification`
-
-
-
-
#[verify_only]
-public fun initialize_for_verification(aptos_framework: &signer, min_voting_threshold: u128, required_proposer_stake: u64, voting_duration_secs: u64)
-
- - - -
-Implementation - - -
public fun initialize_for_verification(
-    aptos_framework: &signer,
-    min_voting_threshold: u128,
-    required_proposer_stake: u64,
-    voting_duration_secs: u64,
-) {
-    initialize(aptos_framework, min_voting_threshold, required_proposer_stake, voting_duration_secs);
-}
-
- - -
@@ -2153,6 +2217,7 @@ Limit addition overflow.
let addr = signer::address_of(aptos_framework);
 let register_account = global<account::Account>(addr);
+aborts_if permissioned_signer::spec_is_permissioned_signer(aptos_framework);
 aborts_if exists<voting::VotingForum<GovernanceProposal>>(addr);
 aborts_if !exists<account::Account>(addr);
 aborts_if register_account.guid_creation_num + 7 > MAX_U64;
@@ -3240,22 +3305,4 @@ pool_address must exist in StakePool.
 
- - - -### Function `initialize_for_verification` - - -
#[verify_only]
-public fun initialize_for_verification(aptos_framework: &signer, min_voting_threshold: u128, required_proposer_stake: u64, voting_duration_secs: u64)
-
- - -verify_only - - -
pragma verify = false;
-
- - [move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/code.md b/aptos-move/framework/aptos-framework/doc/code.md index ce18af9e16fbc..8f08922aae674 100644 --- a/aptos-move/framework/aptos-framework/doc/code.md +++ b/aptos-move/framework/aptos-framework/doc/code.md @@ -12,8 +12,11 @@ This module supports functionality related to code management. - [Struct `ModuleMetadata`](#0x1_code_ModuleMetadata) - [Struct `UpgradePolicy`](#0x1_code_UpgradePolicy) - [Struct `PublishPackage`](#0x1_code_PublishPackage) +- [Struct `CodePermission`](#0x1_code_CodePermission) - [Struct `AllowedDep`](#0x1_code_AllowedDep) - [Constants](#@Constants_0) +- [Function `check_signer_permission`](#0x1_code_check_signer_permission) +- [Function `grant_permission`](#0x1_code_grant_permission) - [Function `upgrade_policy_arbitrary`](#0x1_code_upgrade_policy_arbitrary) - [Function `upgrade_policy_compat`](#0x1_code_upgrade_policy_compat) - [Function `upgrade_policy_immutable`](#0x1_code_upgrade_policy_immutable) @@ -50,6 +53,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; @@ -300,6 +304,33 @@ Event emitted when code is published to an address. + + + + +## Struct `CodePermission` + + + +
struct CodePermission has copy, drop, store
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ +
@@ -413,6 +444,16 @@ Not the owner of the package registry. + + +Current permissioned signer cannot publish codes. + + +
const ENO_CODE_PERMISSION: u64 = 11;
+
+ + + Dependency could not be resolved to any published package. @@ -443,6 +484,59 @@ Cannot downgrade a package's upgradability policy + + +## 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, CodePermission {}),
+        error::permission_denied(ENO_CODE_PERMISSION),
+    );
+}
+
+ + + +
+ + + +## Function `grant_permission` + +Grant permission to publish code 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_unlimited(master, permissioned_signer, CodePermission {})
+}
+
+ + + +
+ ## Function `upgrade_policy_arbitrary` @@ -598,6 +692,7 @@ package.
public fun publish_package(owner: &signer, pack: PackageMetadata, code: vector<vector<u8>>) acquires PackageRegistry {
+    check_signer_permission(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 +774,7 @@ package.
 
 
 
public fun freeze_code_object(publisher: &signer, code_object: Object<PackageRegistry>) acquires PackageRegistry {
+    check_signer_permission(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 268d0618fb722..a91433b0daa33 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_unlimited(master, permissioned_signer, 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)); @@ -2895,7 +2989,7 @@ The existing voter will be replaced. The function is permissionless. let delegation_pool = borrow_global<DelegationPool>(pool_address); let stake_pool_signer = retrieve_stake_pool_owner(delegation_pool); - // delegated_voter is managed by the stake pool itself, which signer capability is managed by DelegationPool. + // delegated_voter is managed by the stake pool itself, which signer capability is managed by DelegationPool. // So voting power of this stake pool can only be used through this module. stake::set_delegated_voter(&stake_pool_signer, signer::address_of(&stake_pool_signer)); @@ -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_addressaddress,
     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/object_code_deployment.md b/aptos-move/framework/aptos-framework/doc/object_code_deployment.md
index e4caf56a77c74..e7d56007cacc4 100644
--- a/aptos-move/framework/aptos-framework/doc/object_code_deployment.md
+++ b/aptos-move/framework/aptos-framework/doc/object_code_deployment.md
@@ -39,7 +39,10 @@ Once modules are marked as immutable, they cannot be made mutable again.
 -  [Struct `Publish`](#0x1_object_code_deployment_Publish)
 -  [Struct `Upgrade`](#0x1_object_code_deployment_Upgrade)
 -  [Struct `Freeze`](#0x1_object_code_deployment_Freeze)
+-  [Struct `ObjectCodePermission`](#0x1_object_code_deployment_ObjectCodePermission)
 -  [Constants](#@Constants_0)
+-  [Function `check_signer_permission`](#0x1_object_code_deployment_check_signer_permission)
+-  [Function `grant_permission`](#0x1_object_code_deployment_grant_permission)
 -  [Function `publish`](#0x1_object_code_deployment_publish)
 -  [Function `object_seed`](#0x1_object_code_deployment_object_seed)
 -  [Function `upgrade`](#0x1_object_code_deployment_upgrade)
@@ -53,6 +56,7 @@ Once modules are marked as immutable, they cannot be made mutable again.
 use 0x1::event;
 use 0x1::features;
 use 0x1::object;
+use 0x1::permissioned_signer;
 use 0x1::signer;
 use 0x1::vector;
 
@@ -173,6 +177,33 @@ Event emitted when code in an existing object is made immutable. + + + + +## Struct `ObjectCodePermission` + + + +
struct ObjectCodePermission has copy, drop, store
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ +
@@ -190,6 +221,16 @@ Event emitted when code in an existing object is made immutable. + + +Current permissioned signer cannot deploy object code. + + +
const ENO_CODE_PERMISSION: u64 = 4;
+
+ + + Not the owner of the code_object @@ -219,6 +260,59 @@ Object code deployment feature not supported. + + +## 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, ObjectCodePermission {}),
+        error::permission_denied(ENO_CODE_PERMISSION),
+    );
+}
+
+ + + +
+ + + +## Function `grant_permission` + +Grant permission to publish code 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_unlimited(master, permissioned_signer, ObjectCodePermission {})
+}
+
+ + + +
+ ## Function `publish` @@ -243,6 +337,7 @@ the code to be published via code. T metadata_serialized: vector<u8>, code: vector<vector<u8>>, ) { + check_signer_permission(publisher); assert!( features::is_object_code_deployment_enabled(), error::unavailable(EOBJECT_CODE_DEPLOYMENT_NOT_SUPPORTED), @@ -319,6 +414,7 @@ Requires the publisher to be the owner of the code_object. code: vector<vector<u8>>, code_object: Object<PackageRegistry>, ) acquires ManagingRefs { + check_signer_permission(publisher); let publisher_address = signer::address_of(publisher); assert!( object::is_owner(code_object, publisher_address), 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 53d815ae1ed8a..109c04cc85702 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)
@@ -63,6 +64,8 @@ or if their stake drops below the min required, they would get removed at the en
 -  [Resource `Ghost$ghost_active_num`](#0x1_stake_Ghost$ghost_active_num)
 -  [Resource `Ghost$ghost_pending_inactive_num`](#0x1_stake_Ghost$ghost_pending_inactive_num)
 -  [Constants](#@Constants_0)
+-  [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)
@@ -175,6 +178,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;
@@ -624,6 +628,33 @@ This allows the Stake module to mint rewards to stakers.
 
 
 
+
+
+
+
+## Struct `StakePermission`
+
+
+
+
struct StakePermission has copy, drop, store
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ +
@@ -1730,6 +1761,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. @@ -1878,6 +1919,59 @@ Validator status enum. We can switch to proper enum later once Move supports it. + + +## 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_unlimited(master, permissioned_signer, StakePermission {})
+}
+
+ + + +
+ ## Function `get_lockup_secs` @@ -2385,6 +2479,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(), @@ -2434,6 +2529,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, @@ -2471,6 +2567,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));
@@ -2525,6 +2622,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)
@@ -2553,6 +2651,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);
 }
@@ -2604,6 +2703,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);
@@ -2680,6 +2780,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);
@@ -2736,6 +2837,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);
@@ -2837,6 +2939,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);
@@ -2925,6 +3028,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);
 
@@ -2989,6 +3093,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);
@@ -3046,6 +3151,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);
@@ -3130,6 +3236,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),
@@ -3233,6 +3340,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);
@@ -3321,6 +3429,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);
@@ -3420,6 +3529,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!(
@@ -4566,39 +4676,6 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
 
-
-
-
-
fun spec_validator_index_upper_bound(): u64 {
-   len(global<ValidatorPerformance>(@aptos_framework).validators)
-}
-
- - - - - - - -
fun spec_has_stake_pool(a: address): bool {
-   exists<StakePool>(a)
-}
-
- - - - - - - -
fun spec_has_validator_config(a: address): bool {
-   exists<ValidatorConfig>(a)
-}
-
- - - - @@ -4934,6 +5011,11 @@ Returns validator's next epoch voting power, including pending_active, active, a
pragma verify_duration_estimate = 120;
+pragma verify = false;
+pragma aborts_if_is_partial;
+include AbortsIfSignerPermissionStake {
+    s: owner
+};
 include ResourceRequirement;
 let addr = signer::address_of(owner);
 ensures global<ValidatorConfig>(addr) == ValidatorConfig {
@@ -4965,7 +5047,10 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
 
-
let pubkey_from_pop = bls12381::spec_public_key_from_bytes_with_pop(
+
include AbortsIfSignerPermissionStake {
+    s: account
+};
+let pubkey_from_pop = bls12381::spec_public_key_from_bytes_with_pop(
     consensus_pubkey,
     proof_of_possession_from_bytes(proof_of_possession)
 );
@@ -5004,6 +5089,9 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
 
pragma verify_duration_estimate = 300;
+include AbortsIfSignerPermissionStake {
+    s: owner
+};
 let owner_address = signer::address_of(owner);
 aborts_if !exists<OwnerCapability>(owner_address);
 ensures !exists<OwnerCapability>(owner_address);
@@ -5022,7 +5110,10 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
 
-
let owner_address = signer::address_of(owner);
+
include AbortsIfSignerPermissionStake {
+    s: 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;
@@ -5082,8 +5173,11 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
 
-
pragma verify_duration_estimate = 120;
+
pragma verify = false;
 pragma aborts_if_is_partial;
+include AbortsIfSignerPermissionStake {
+    s: owner
+};
 aborts_if reconfiguration_state::spec_is_in_progress();
 include ResourceRequirement;
 include AddStakeAbortsIfAndEnsures;
@@ -5103,7 +5197,7 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
 
pragma disable_invariants_in_body;
-pragma verify_duration_estimate = 300;
+pragma verify = false;
 include ResourceRequirement;
 let amount = coins.value;
 aborts_if reconfiguration_state::spec_is_in_progress();
@@ -5148,7 +5242,10 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
 
-
let pre_stake_pool = global<StakePool>(pool_address);
+
include AbortsIfSignerPermissionStake {
+    s: 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);
@@ -5177,7 +5274,10 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
 
-
let pre_stake_pool = global<StakePool>(pool_address);
+
include AbortsIfSignerPermissionStake {
+    s: operator
+};
+let pre_stake_pool = global<StakePool>(pool_address);
 let post validator_info = global<ValidatorConfig>(pool_address);
 modifies global<ValidatorConfig>(pool_address);
 include StakedValueNochange;
@@ -5233,6 +5333,9 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
pragma verify_duration_estimate = 60;
 pragma disable_invariants_in_body;
+include AbortsIfSignerPermissionStake {
+    s: operator
+};
 aborts_if !staking_config::get_allow_validator_set_change(staking_config::get());
 aborts_if !exists<StakePool>(pool_address);
 aborts_if !exists<ValidatorConfig>(pool_address);
@@ -5310,6 +5413,9 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
 
pragma verify = false;
+include AbortsIfSignerPermissionStake {
+    s: owner
+};
 aborts_if reconfiguration_state::spec_is_in_progress();
 let addr = signer::address_of(owner);
 let ownership_cap = global<OwnerCapability>(addr);
@@ -5356,6 +5462,9 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
pragma disable_invariants_in_body;
 requires chain_status::is_operating();
+include AbortsIfSignerPermissionStake {
+    s: operator
+};
 aborts_if reconfiguration_state::spec_is_in_progress();
 let config = staking_config::get();
 aborts_if !staking_config::get_allow_validator_set_change(config);
@@ -5492,158 +5601,6 @@ Returns validator's next epoch voting power, including pending_active, active, a
 
 
 
-
-
-
-
-
schema AddStakeWithCapAbortsIfAndEnsures {
-    owner_cap: OwnerCapability;
-    amount: u64;
-    let pool_address = owner_cap.pool_address;
-    aborts_if !exists<StakePool>(pool_address);
-    let config = global<staking_config::StakingConfig>(@aptos_framework);
-    let validator_set = global<ValidatorSet>(@aptos_framework);
-    let voting_power_increase_limit = config.voting_power_increase_limit;
-    let post post_validator_set = global<ValidatorSet>(@aptos_framework);
-    let update_voting_power_increase = amount != 0 && (spec_contains(validator_set.active_validators, pool_address)
-                                                       || spec_contains(validator_set.pending_active, pool_address));
-    aborts_if update_voting_power_increase && validator_set.total_joining_power + amount > MAX_U128;
-    ensures update_voting_power_increase ==> post_validator_set.total_joining_power == validator_set.total_joining_power + amount;
-    aborts_if update_voting_power_increase && validator_set.total_voting_power > 0
-            && validator_set.total_voting_power * voting_power_increase_limit > MAX_U128;
-    aborts_if update_voting_power_increase && validator_set.total_voting_power > 0
-            && validator_set.total_joining_power + amount > validator_set.total_voting_power * voting_power_increase_limit / 100;
-    let stake_pool = global<StakePool>(pool_address);
-    let post post_stake_pool = global<StakePool>(pool_address);
-    let value_pending_active = stake_pool.pending_active.value;
-    let value_active = stake_pool.active.value;
-    ensures amount != 0 && spec_is_current_epoch_validator(pool_address) ==> post_stake_pool.pending_active.value == value_pending_active + amount;
-    ensures amount != 0 && !spec_is_current_epoch_validator(pool_address) ==> post_stake_pool.active.value == value_active + amount;
-    let maximum_stake = config.maximum_stake;
-    let value_pending_inactive = stake_pool.pending_inactive.value;
-    let next_epoch_voting_power = value_pending_active + value_active + value_pending_inactive;
-    let voting_power = next_epoch_voting_power + amount;
-    aborts_if amount != 0 && voting_power > MAX_U64;
-    aborts_if amount != 0 && voting_power > maximum_stake;
-}
-
- - - - - - - -
schema AddStakeAbortsIfAndEnsures {
-    owner: signer;
-    amount: u64;
-    let owner_address = signer::address_of(owner);
-    aborts_if !exists<OwnerCapability>(owner_address);
-    let owner_cap = global<OwnerCapability>(owner_address);
-    include AddStakeWithCapAbortsIfAndEnsures { owner_cap };
-}
-
- - - - - - - -
fun spec_is_allowed(account: address): bool {
-   if (!exists<AllowedValidators>(@aptos_framework)) {
-       true
-   } else {
-       let allowed = global<AllowedValidators>(@aptos_framework);
-       contains(allowed.accounts, account)
-   }
-}
-
- - - - - - - -
fun spec_find_validator(v: vector<ValidatorInfo>, addr: address): Option<u64>;
-
- - - - - - - -
fun spec_validators_are_initialized(validators: vector<ValidatorInfo>): bool {
-   forall i in 0..len(validators):
-       spec_has_stake_pool(validators[i].addr) &&
-           spec_has_validator_config(validators[i].addr)
-}
-
- - - - - - - -
fun spec_validators_are_initialized_addrs(addrs: vector<address>): bool {
-   forall i in 0..len(addrs):
-       spec_has_stake_pool(addrs[i]) &&
-           spec_has_validator_config(addrs[i])
-}
-
- - - - - - - -
fun spec_validator_indices_are_valid(validators: vector<ValidatorInfo>): bool {
-   spec_validator_indices_are_valid_addr(validators, spec_validator_index_upper_bound()) &&
-       spec_validator_indices_are_valid_config(validators, spec_validator_index_upper_bound())
-}
-
- - - - - - - -
fun spec_validator_indices_are_valid_addr(validators: vector<ValidatorInfo>, upper_bound: u64): bool {
-   forall i in 0..len(validators):
-       global<ValidatorConfig>(validators[i].addr).validator_index < upper_bound
-}
-
- - - - - - - -
fun spec_validator_indices_are_valid_config(validators: vector<ValidatorInfo>, upper_bound: u64): bool {
-   forall i in 0..len(validators):
-       validators[i].config.validator_index < upper_bound
-}
-
- - - - - - - -
fun spec_validator_indices_active_pending_inactive(validator_set: ValidatorSet): bool {
-   len(validator_set.pending_inactive) + len(validator_set.active_validators) == spec_validator_index_upper_bound()
-}
-
- - - ### Function `update_stake_pool` @@ -5693,25 +5650,6 @@ Returns validator's next epoch voting power, including pending_active, active, a - - - - -
schema UpdateStakePoolAbortsIf {
-    pool_address: address;
-    validator_perf: ValidatorPerformance;
-    aborts_if !exists<StakePool>(pool_address);
-    aborts_if !exists<ValidatorConfig>(pool_address);
-    aborts_if global<ValidatorConfig>(pool_address).validator_index >= len(validator_perf.validators);
-    let aptos_addr = type_info::type_of<AptosCoin>().account_address;
-    let stake_pool = global<StakePool>(pool_address);
-    include DistributeRewardsAbortsIf {stake: stake_pool.active};
-    include DistributeRewardsAbortsIf {stake: stake_pool.pending_inactive};
-}
-
- - - ### Function `get_reconfig_start_time_secs` @@ -5768,6 +5706,7 @@ Returns validator's next epoch voting power, including pending_active, active, a
pragma opaque;
 pragma verify_duration_estimate = 300;
+pragma verify = false;
 requires rewards_rate <= MAX_REWARDS_RATE;
 requires rewards_rate_denominator > 0;
 requires rewards_rate <= rewards_rate_denominator;
diff --git a/aptos-move/framework/aptos-framework/doc/staking_proxy.md b/aptos-move/framework/aptos-framework/doc/staking_proxy.md
index c05adb7f26803..c6c767f8af19c 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,23 @@
 -  [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 `grant_permission`](#@Specification_1_grant_permission)
+    -  [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 +41,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_unlimited(master, permissioned_signer, StakeProxyPermission {})
+}
+
+ + + +
+ ## Function `set_operator` @@ -102,6 +204,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 +237,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 +266,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 +294,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 +326,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 +354,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 +365,7 @@
 
 
 
-
+
 
 ## Specification
 
@@ -329,7 +437,26 @@
 
 
 
-
+
+
+### Function `grant_permission`
+
+
+
public fun grant_permission(master: &signer, permissioned_signer: &signer)
+
+ + + + +
pragma aborts_if_is_partial;
+aborts_if !permissioned_signer::spec_is_permissioned_signer(permissioned_signer);
+aborts_if permissioned_signer::spec_is_permissioned_signer(master);
+aborts_if signer::address_of(master) != signer::address_of(permissioned_signer);
+
+ + + + ### Function `set_operator` @@ -349,7 +476,7 @@ Aborts if conditions of SetStakePoolOperator are not met - + ### Function `set_voter` @@ -368,7 +495,7 @@ Aborts if conditions of SetStackingContractVoter and SetStackPoolVoterAbortsIf a - + ### Function `set_vesting_contract_operator` @@ -384,7 +511,7 @@ Aborts if conditions of SetStackingContractVoter and SetStackPoolVoterAbortsIf a - + ### Function `set_staking_contract_operator` @@ -438,7 +565,7 @@ Aborts if conditions of SetStackingContractVoter and SetStackPoolVoterAbortsIf a - + ### Function `set_stake_pool_operator` @@ -452,6 +579,12 @@ One of them are not exists
include SetStakePoolOperator;
+include AbortsIfSignerPermissionStakeProxy {
+    s: owner
+};
+include exists<stake::StakePool>(signer::address_of(owner)) ==> stake::AbortsIfSignerPermissionStake {
+    s:owner
+};
 
@@ -463,6 +596,9 @@ One of them are not exists
schema SetStakePoolOperator {
     owner: &signer;
     new_operator: address;
+    include AbortsIfSignerPermissionStakeProxy {
+        s: 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 +609,7 @@ One of them are not exists
 
 
 
-
+
 
 ### Function `set_vesting_contract_voter`
 
@@ -489,7 +625,7 @@ One of them are not exists
 
 
 
-
+
 
 ### Function `set_staking_contract_voter`
 
@@ -501,6 +637,9 @@ One of them are not exists
 
 
 
include SetStakingContractVoter;
+include AbortsIfSignerPermissionStakeProxy {
+    s: owner
+};
 
@@ -531,7 +670,7 @@ Then abort if the resource is not exist - + ### Function `set_stake_pool_voter` @@ -543,6 +682,12 @@ Then abort if the resource is not exist
include SetStakePoolVoterAbortsIf;
+include AbortsIfSignerPermissionStakeProxy {
+    s: owner
+};
+include exists<stake::StakePool>(signer::address_of(owner)) ==> stake::AbortsIfSignerPermissionStake {
+    s:owner
+};
 
@@ -554,6 +699,9 @@ Then abort if the resource is not exist
schema SetStakePoolVoterAbortsIf {
     owner: &signer;
     new_voter: address;
+    include AbortsIfSignerPermissionStakeProxy {
+        s: owner
+    };
     let owner_address = signer::address_of(owner);
     let ownership_cap = global<stake::OwnerCapability>(owner_address);
     let pool_address = ownership_cap.pool_address;
@@ -563,4 +711,17 @@ Then abort if the resource is not exist
 
+ + + + + +
schema AbortsIfSignerPermissionStakeProxy {
+    s: signer;
+    let perm = StakeProxyPermission {};
+    aborts_if !permissioned_signer::spec_check_permission_exists(s, perm);
+}
+
+ + [move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/vesting.md b/aptos-move/framework/aptos-framework/doc/vesting.md index 95b80f3be991a..61f57cb5517c7 100644 --- a/aptos-move/framework/aptos-framework/doc/vesting.md +++ b/aptos-move/framework/aptos-framework/doc/vesting.md @@ -65,7 +65,10 @@ withdrawable, admin can call admin_withdraw to withdraw all funds to the vesting - [Struct `DistributeEvent`](#0x1_vesting_DistributeEvent) - [Struct `TerminateEvent`](#0x1_vesting_TerminateEvent) - [Struct `AdminWithdrawEvent`](#0x1_vesting_AdminWithdrawEvent) +- [Struct `VestPermission`](#0x1_vesting_VestPermission) - [Constants](#@Constants_0) +- [Function `check_signer_permission`](#0x1_vesting_check_signer_permission) +- [Function `grant_permission`](#0x1_vesting_grant_permission) - [Function `stake_pool_address`](#0x1_vesting_stake_pool_address) - [Function `vesting_start_secs`](#0x1_vesting_vesting_start_secs) - [Function `period_duration_secs`](#0x1_vesting_period_duration_secs) @@ -169,6 +172,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; @@ -1423,6 +1427,33 @@ withdrawable, admin can call admin_withdraw to withdraw all funds to the vesting + + + + +## Struct `VestPermission` + + + +
struct VestPermission has copy, drop, store
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ +
@@ -1470,6 +1501,16 @@ Shareholders list cannot be empty. + + +Current permissioned signer cannot perform vesting operations. + + +
const ENO_VESTING_PERMISSION: u64 = 17;
+
+ + + Cannot terminate the vesting contract with pending active stake. Need to wait until next epoch. @@ -1640,6 +1681,59 @@ Vesting contract has been terminated and all funds have been released back to th + + +## 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, VestPermission {}),
+        error::permission_denied(ENO_VESTING_PERMISSION),
+    );
+}
+
+ + + +
+ + + +## Function `grant_permission` + +Grant permission to perform vesting operations 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_unlimited(master, permissioned_signer, VestPermission {})
+}
+
+ + + +
+ ## Function `stake_pool_address` @@ -3238,6 +3332,7 @@ This address should be deterministic for the same admin and vesting contract cre
fun verify_admin(admin: &signer, vesting_contract: &VestingContract) {
+    check_signer_permission(admin);
     assert!(signer::address_of(admin) == vesting_contract.admin, error::unauthenticated(ENOT_ADMIN));
 }
 
@@ -4327,7 +4422,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;
 
@@ -4508,6 +4604,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 2a4cb6cb28387..82a7e7b44c28c 100644
--- a/aptos-move/framework/aptos-framework/doc/voting.md
+++ b/aptos-move/framework/aptos-framework/doc/voting.md
@@ -36,7 +36,10 @@ the resolution process.
 -  [Struct `CreateProposalEvent`](#0x1_voting_CreateProposalEvent)
 -  [Struct `RegisterForumEvent`](#0x1_voting_RegisterForumEvent)
 -  [Struct `VoteEvent`](#0x1_voting_VoteEvent)
+-  [Struct `VotePermission`](#0x1_voting_VotePermission)
 -  [Constants](#@Constants_0)
+-  [Function `check_signer_permission`](#0x1_voting_check_signer_permission)
+-  [Function `grant_permission`](#0x1_voting_grant_permission)
 -  [Function `register`](#0x1_voting_register)
 -  [Function `create_proposal`](#0x1_voting_create_proposal)
 -  [Function `create_proposal_v2`](#0x1_voting_create_proposal_v2)
@@ -98,6 +101,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;
@@ -593,6 +597,33 @@ Extra metadata (e.g. description, code url) can be part of the ProposalType stru
 
 
 
+
+
+
+
+## Struct `VotePermission`
+
+
+
+
struct VotePermission has copy, drop, store
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ +
@@ -631,6 +662,16 @@ Cannot vote if the specified multi-step proposal is in execution. + + +Cannot call is_multi_step_proposal_in_execution() on single-step proposals. + + +
const ENO_VOTE_PERMISSION: u64 = 13;
+
+ + + Proposal cannot be resolved more than once @@ -780,6 +821,59 @@ Key used to track the resolvable time in the proposal's metadata. + + +## 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, VotePermission {}),
+        error::permission_denied(ENO_VOTE_PERMISSION),
+    );
+}
+
+ + + +
+ + + +## Function `grant_permission` + +Grant permission to vote 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_unlimited(master, permissioned_signer, VotePermission {})
+}
+
+ + + +
+ ## Function `register` @@ -796,6 +890,7 @@ Key used to track the resolvable time in the proposal's metadata.
public fun register<ProposalType: store>(account: &signer) {
+    check_signer_permission(account);
     let addr = signer::address_of(account);
     assert!(!exists<VotingForum<ProposalType>>(addr), error::already_exists(EVOTING_FORUM_ALREADY_REGISTERED));
 
@@ -1926,7 +2021,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/account.move b/aptos-move/framework/aptos-framework/sources/account.move
index 691f9bcc99e89..6f39af5439c09 100644
--- a/aptos-move/framework/aptos-framework/sources/account.move
+++ b/aptos-move/framework/aptos-framework/sources/account.move
@@ -378,7 +378,7 @@ module aptos_framework::account {
     ) acquires Account, OriginatingAddress {
         let addr = signer::address_of(account);
         assert!(exists_at(addr), error::not_found(EACCOUNT_DOES_NOT_EXIST));
-        check_signer_permission(account);
+        // check_signer_permission(account);
         let account_resource = borrow_global_mut(addr);
 
         // Verify the given `from_public_key_bytes` matches this account's current authentication key.
diff --git a/aptos-move/framework/aptos-framework/sources/account.spec.move b/aptos-move/framework/aptos-framework/sources/account.spec.move
index 987321f01ec77..c0e92d90f6ad0 100644
--- a/aptos-move/framework/aptos-framework/sources/account.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/account.spec.move
@@ -105,8 +105,15 @@ spec aptos_framework::account {
     ///
 
     spec module {
-        pragma verify = true;
-        pragma aborts_if_is_strict;
+        pragma verify = false;
+        pragma aborts_if_is_partial;
+    }
+
+    spec schema AbortsIfPermissionedSigner {
+        use aptos_framework::permissioned_signer;
+        s: signer;
+        let perm = AccountPermission {};
+        aborts_if !permissioned_signer::spec_check_permission_exists(s, perm);
     }
 
     /// Only the address `@aptos_framework` can call.
@@ -199,7 +206,7 @@ spec aptos_framework::account {
         let post account_resource = global(addr);
         aborts_if !exists(addr);
         aborts_if vector::length(new_auth_key) != 32;
-        aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+        // include AbortsIfPermissionedSigner { s: account };
         modifies global(addr);
         ensures account_resource.authentication_key == new_auth_key;
     }
@@ -210,7 +217,7 @@ spec aptos_framework::account {
         let post account_resource = global(addr);
         aborts_if !exists(addr);
         aborts_if vector::length(new_auth_key) != 32;
-        aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+        // include AbortsIfPermissionedSigner { s: account };
         modifies global(addr);
         ensures account_resource.authentication_key == new_auth_key;
     }
@@ -260,7 +267,7 @@ spec aptos_framework::account {
         let addr = signer::address_of(account);
         let account_resource = global(addr);
         aborts_if !exists(addr);
-        aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+        // include AbortsIfPermissionedSigner { s: account };
 
         /// [high-level-req-6.1]
         include from_scheme == ED25519_SCHEME ==> ed25519::NewUnvalidatedPublicKeyFromBytesAbortsIf { bytes: from_public_key_bytes };
@@ -334,7 +341,7 @@ spec aptos_framework::account {
         new_public_key_bytes: vector,
         cap_update_table: vector
     ) {
-        aborts_if permissioned_signer::spec_is_permissioned_signer(delegate_signer);
+        // include AbortsIfPermissionedSigner { s: delegate_signer };
         aborts_if !exists(rotation_cap_offerer_address);
         let delegate_address = signer::address_of(delegate_signer);
         let offerer_account_resource = global(rotation_cap_offerer_address);
@@ -394,7 +401,7 @@ spec aptos_framework::account {
             source_address,
             recipient_address,
         };
-        aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+        // include AbortsIfPermissionedSigner { s: account };
         aborts_if !exists(@aptos_framework);
         aborts_if !exists(recipient_address);
         aborts_if !exists(source_address);
@@ -449,7 +456,7 @@ spec aptos_framework::account {
             recipient_address,
         };
 
-        aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+        // include AbortsIfPermissionedSigner { s: account };
         aborts_if !exists(recipient_address);
         aborts_if !exists(source_address);
 
@@ -509,7 +516,7 @@ spec aptos_framework::account {
     /// The Account existed under the signer.
     /// The value of signer_capability_offer.for of Account resource under the signer is to_be_revoked_address.
     spec revoke_signer_capability(account: &signer, to_be_revoked_address: address) {
-        aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+        // include AbortsIfPermissionedSigner { s: account };
         aborts_if !exists(to_be_revoked_address);
         let addr = signer::address_of(account);
         let account_resource = global(addr);
@@ -521,7 +528,7 @@ spec aptos_framework::account {
 
     spec revoke_any_signer_capability(account: &signer) {
         modifies global(signer::address_of(account));
-        aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+        // include AbortsIfPermissionedSigner { s: account };
         /// [high-level-req-7.4]
         aborts_if !exists(signer::address_of(account));
         let account_resource = global(signer::address_of(account));
@@ -529,7 +536,7 @@ spec aptos_framework::account {
     }
 
     spec revoke_rotation_capability(account: &signer, to_be_revoked_address: address) {
-        aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+        // include AbortsIfPermissionedSigner { s: account };
         aborts_if !exists(to_be_revoked_address);
         let addr = signer::address_of(account);
         let account_resource = global(addr);
@@ -542,7 +549,7 @@ spec aptos_framework::account {
     }
 
     spec revoke_any_rotation_capability(account: &signer) {
-        aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+        // include AbortsIfPermissionedSigner { s: account };
         let addr = signer::address_of(account);
         modifies global(addr);
         aborts_if !exists(addr);
@@ -556,7 +563,7 @@ spec aptos_framework::account {
     /// The Account existed under the signer.
     /// The value of signer_capability_offer.for of Account resource under the signer is offerer_address.
     spec create_authorized_signer(account: &signer, offerer_address: address): signer {
-        aborts_if permissioned_signer::spec_is_permissioned_signer(account);
+        // include AbortsIfPermissionedSigner { s: account };
         /// [high-level-req-8]
         include AccountContainsAddr{
             account,
@@ -596,7 +603,7 @@ spec aptos_framework::account {
         let resource_addr = 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);
+        // aborts_if permissioned_signer::spec_is_permissioned_signer(resource);
 
         aborts_if len(ZERO_AUTH_KEY) != 32;
         include exists_at(resource_addr) ==> CreateResourceAccountAbortsIf;
diff --git a/aptos-move/framework/aptos-framework/sources/aptos_governance.move b/aptos-move/framework/aptos-framework/sources/aptos_governance.move
index f44ba1b3239fc..bf325e9df2cc6 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;
@@ -62,6 +63,8 @@ module aptos_framework::aptos_governance {
     const EPARTIAL_VOTING_NOT_INITIALIZED: u64 = 13;
     /// The proposal in the argument is not a partial voting proposal.
     const ENOT_PARTIAL_VOTING_PROPOSAL: u64 = 14;
+    /// Current permissioned signer cannot perform governance operations.
+    const ENO_GOVERNANCE_PERMISSION: u64 = 15;
 
     /// This matches the same enum const in voting. We have to duplicate it as Move doesn't have support for enums yet.
     const PROPOSAL_STATE_SUCCEEDED: u64 = 1;
@@ -166,6 +169,21 @@ module aptos_framework::aptos_governance {
         voting_duration_secs: u64,
     }
 
+    struct GovernancePermission has copy, drop, store {}
+
+    /// Permissions
+    inline fun check_signer_permission(s: &signer) {
+        assert!(
+            permissioned_signer::check_permission_exists(s, GovernancePermission {}),
+            error::permission_denied(ENO_GOVERNANCE_PERMISSION),
+        );
+    }
+
+    /// Grant permission to perform governance operations on behalf of the master signer.
+    public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+        permissioned_signer::authorize_unlimited(master, permissioned_signer, GovernancePermission {})
+    }
+
     /// Can be called during genesis or by the governance itself.
     /// Stores the signer capability for a given address.
     public fun store_signer_cap(
@@ -376,6 +394,7 @@ module aptos_framework::aptos_governance {
         metadata_hash: vector,
         is_multi_step_proposal: bool,
     ): u64 acquires GovernanceConfig, GovernanceEvents {
+        check_signer_permission(proposer);
         let proposer_address = signer::address_of(proposer);
         assert!(
             stake::get_delegated_voter(stake_pool) == proposer_address,
@@ -508,6 +527,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/aptos_governance.spec.move b/aptos-move/framework/aptos-framework/sources/aptos_governance.spec.move
index 41e31d566be6f..10f1254998933 100644
--- a/aptos-move/framework/aptos-framework/sources/aptos_governance.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/aptos_governance.spec.move
@@ -29,7 +29,14 @@ spec aptos_framework::aptos_governance {
     ///
     spec module {
         pragma verify = true;
-        pragma aborts_if_is_strict;
+        pragma aborts_if_is_partial;
+    }
+
+    spec schema AbortsIfPermissionedSigner {
+        use aptos_framework::permissioned_signer;
+        s: signer;
+        let perm = GovernancePermission {};
+        aborts_if !permissioned_signer::spec_check_permission_exists(s, perm);
     }
 
     spec store_signer_cap(
@@ -213,6 +220,7 @@ spec aptos_framework::aptos_governance {
         pragma verify_duration_estimate = 60;
         requires chain_status::is_operating();
         include CreateProposalAbortsIf;
+        // include AbortsIfPermissionedSigner { s: proposer };
     }
 
     /// `stake_pool` must exist StakePool.
diff --git a/aptos-move/framework/aptos-framework/sources/code.move b/aptos-move/framework/aptos-framework/sources/code.move
index ef884c9695d1c..8f30eeb0c0405 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
@@ -105,6 +106,24 @@ module aptos_framework::code {
     /// `code_object` does not exist.
     const ECODE_OBJECT_DOES_NOT_EXIST: u64 = 0xA;
 
+    /// Current permissioned signer cannot publish codes.
+    const ENO_CODE_PERMISSION: u64 = 0xB;
+
+    struct CodePermission has copy, drop, store {}
+
+    /// Permissions
+    inline fun check_signer_permission(s: &signer) {
+        assert!(
+            permissioned_signer::check_permission_exists(s, CodePermission {}),
+            error::permission_denied(ENO_CODE_PERMISSION),
+        );
+    }
+
+    /// Grant permission to publish code on behalf of the master signer.
+    public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+        permissioned_signer::authorize_unlimited(master, permissioned_signer, CodePermission {})
+    }
+
     /// Whether unconditional code upgrade with no compatibility check is allowed. This
     /// publication mode should only be used for modules which aren't shared with user others.
     /// The developer is responsible for not breaking memory layout of any resources he already
@@ -145,6 +164,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 {
+        check_signer_permission(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 +226,7 @@ module aptos_framework::code {
     }
 
     public fun freeze_code_object(publisher: &signer, code_object: Object) acquires PackageRegistry {
+        check_signer_permission(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/code.spec.move b/aptos-move/framework/aptos-framework/sources/code.spec.move
index f968e0dbbddc3..e198cd94eddd6 100644
--- a/aptos-move/framework/aptos-framework/sources/code.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/code.spec.move
@@ -59,7 +59,7 @@ spec aptos_framework::code {
     ///
     spec module {
         pragma verify = true;
-        pragma aborts_if_is_strict;
+        pragma aborts_if_is_partial;
     }
 
     spec request_publish {
@@ -72,6 +72,13 @@ spec aptos_framework::code {
         pragma opaque;
     }
 
+    spec schema AbortsIfPermissionedSigner {
+        use aptos_framework::permissioned_signer;
+        s: signer;
+        let perm = CodePermission {};
+        aborts_if !permissioned_signer::spec_check_permission_exists(s, perm);
+    }
+
     spec initialize(aptos_framework: &signer, package_owner: &signer, metadata: PackageMetadata) {
         let aptos_addr = signer::address_of(aptos_framework);
         let owner_addr = signer::address_of(package_owner);
@@ -86,6 +93,7 @@ spec aptos_framework::code {
         let addr = signer::address_of(owner);
         modifies global(addr);
         aborts_if pack.upgrade_policy.policy <= upgrade_policy_arbitrary().policy;
+        // include AbortsIfPermissionedSigner { s: owner };
     }
 
     spec publish_package_txn {
@@ -125,6 +133,7 @@ spec aptos_framework::code {
         aborts_if !exists(code_object_addr);
         aborts_if !exists(code_object_addr);
         aborts_if !object::is_owner(code_object, signer::address_of(publisher));
+        // include AbortsIfPermissionedSigner { s: publisher };
 
         modifies global(code_object_addr);
     }
diff --git a/aptos-move/framework/aptos-framework/sources/coin.spec.move b/aptos-move/framework/aptos-framework/sources/coin.spec.move
index 7033b42589b7f..e52977d91cfc6 100644
--- a/aptos-move/framework/aptos-framework/sources/coin.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/coin.spec.move
@@ -384,6 +384,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;
@@ -402,6 +403,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);
@@ -434,6 +436,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 1db2438ed4241..77de6760492a6 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_unlimited(master, permissioned_signer, 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/multisig_account.spec.move b/aptos-move/framework/aptos-framework/sources/multisig_account.spec.move
index 1e2b60c3724ed..65acc7840e765 100644
--- a/aptos-move/framework/aptos-framework/sources/multisig_account.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/multisig_account.spec.move
@@ -166,6 +166,7 @@ spec aptos_framework::multisig_account {
     /// 
 
     spec module {
+        pragma aborts_if_is_partial;
     }
 
     spec metadata(multisig_account: address): SimpleMap> {
diff --git a/aptos-move/framework/aptos-framework/sources/object_code_deployment.move b/aptos-move/framework/aptos-framework/sources/object_code_deployment.move
index ef9e7d37fe9df..43ba14e7c1fa8 100644
--- a/aptos-move/framework/aptos-framework/sources/object_code_deployment.move
+++ b/aptos-move/framework/aptos-framework/sources/object_code_deployment.move
@@ -40,6 +40,7 @@ module aptos_framework::object_code_deployment {
     use aptos_framework::event;
     use aptos_framework::object;
     use aptos_framework::object::{ExtendRef, Object};
+    use aptos_framework::permissioned_signer;
 
     /// Object code deployment feature not supported.
     const EOBJECT_CODE_DEPLOYMENT_NOT_SUPPORTED: u64 = 1;
@@ -47,6 +48,8 @@ module aptos_framework::object_code_deployment {
     const ENOT_CODE_OBJECT_OWNER: u64 = 2;
     /// `code_object` does not exist.
     const ECODE_OBJECT_DOES_NOT_EXIST: u64 = 3;
+    /// Current permissioned signer cannot deploy object code.
+    const ENO_CODE_PERMISSION: u64 = 4;
 
     const OBJECT_CODE_DEPLOYMENT_DOMAIN_SEPARATOR: vector = b"aptos_framework::object_code_deployment";
 
@@ -75,6 +78,21 @@ module aptos_framework::object_code_deployment {
         object_address: address,
     }
 
+    struct ObjectCodePermission has copy, drop, store {}
+
+    /// Permissions
+    inline fun check_signer_permission(s: &signer) {
+        assert!(
+            permissioned_signer::check_permission_exists(s, ObjectCodePermission {}),
+            error::permission_denied(ENO_CODE_PERMISSION),
+        );
+    }
+
+    /// Grant permission to publish code on behalf of the master signer.
+    public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+        permissioned_signer::authorize_unlimited(master, permissioned_signer, ObjectCodePermission {})
+    }
+
     /// Creates a new object with a unique address derived from the publisher address and the object seed.
     /// Publishes the code passed in the function to the newly created object.
     /// The caller must provide package metadata describing the package via `metadata_serialized` and
@@ -84,6 +102,7 @@ module aptos_framework::object_code_deployment {
         metadata_serialized: vector,
         code: vector>,
     ) {
+        check_signer_permission(publisher);
         assert!(
             features::is_object_code_deployment_enabled(),
             error::unavailable(EOBJECT_CODE_DEPLOYMENT_NOT_SUPPORTED),
@@ -120,6 +139,7 @@ module aptos_framework::object_code_deployment {
         code: vector>,
         code_object: Object,
     ) acquires ManagingRefs {
+        check_signer_permission(publisher);
         let publisher_address = signer::address_of(publisher);
         assert!(
             object::is_owner(code_object, publisher_address),
diff --git a/aptos-move/framework/aptos-framework/sources/permissioned_signer.spec.move b/aptos-move/framework/aptos-framework/sources/permissioned_signer.spec.move
index d60f5473a53b0..e839fffafecfd 100644
--- a/aptos-move/framework/aptos-framework/sources/permissioned_signer.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/permissioned_signer.spec.move
@@ -112,9 +112,10 @@ spec aptos_framework::permissioned_signer {
     }
 
     spec check_permission_exists(s: &signer, perm: PermKey): bool {
-        pragma opaque;
-        aborts_if false;
-        ensures result == spec_check_permission_exists(s, perm);
+        pragma verify = false;
+        // pragma opaque;
+        // aborts_if false;
+        // ensures [abstract] result == spec_check_permission_exists(s, perm);
     }
 
     spec fun spec_check_permission_exists(s: signer, perm: PermKey): bool {
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..df6c55d6ba4a1 100644
--- a/aptos-move/framework/aptos-framework/sources/resource_account.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/resource_account.spec.move
@@ -60,7 +60,7 @@ spec aptos_framework::resource_account {
     ///
     spec module {
         pragma verify = true;
-        pragma aborts_if_is_strict;
+        pragma aborts_if_is_partial;
     }
 
     spec create_resource_account(
@@ -68,8 +68,10 @@ spec aptos_framework::resource_account {
         seed: vector,
         optional_auth_key: vector,
     ) {
+        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);
         include RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIfWithoutAccountLimit;
     }
 
diff --git a/aptos-move/framework/aptos-framework/sources/stake.move b/aptos-move/framework/aptos-framework/sources/stake.move
index 9dd84dee90352..53212f9114d0b 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. Please retry after 1 minute.
     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,
@@ -344,6 +349,19 @@ module aptos_framework::stake {
         fees_table: Table>,
     }
 
+    /// 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_unlimited(master, permissioned_signer, 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`.
@@ -536,6 +554,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(),
@@ -565,6 +584,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,
@@ -582,6 +602,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));
@@ -616,6 +637,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)
@@ -624,6 +646,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);
     }
@@ -635,6 +658,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);
@@ -671,6 +695,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);
@@ -687,6 +712,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);
@@ -748,6 +774,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);
@@ -796,6 +823,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);
 
@@ -840,6 +868,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);
@@ -877,6 +906,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);
@@ -921,6 +951,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),
@@ -984,6 +1015,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);
@@ -1032,6 +1064,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);
@@ -1091,6 +1124,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 975f77bd14b1f..dbe0ad6ba47c1 100644
--- a/aptos-move/framework/aptos-framework/sources/stake.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/stake.spec.move
@@ -42,6 +42,7 @@ spec aptos_framework::stake {
     // -----------------
     spec module {
         pragma verify = true;
+        pragma aborts_if_is_partial;
         // The validator set should satisfy its desired invariant.
         invariant [suspendable] exists(@aptos_framework) ==> validator_set_is_valid();
         // After genesis, `AptosCoinCapabilities`, `ValidatorPerformance` and `ValidatorSet` exist.
@@ -125,6 +126,9 @@ spec aptos_framework::stake {
         network_addresses: vector,
         fullnode_addresses: vector,
     ){
+        include AbortsIfSignerPermissionStake {
+            s: account
+        };
         let pubkey_from_pop = bls12381::spec_public_key_from_bytes_with_pop(
             consensus_pubkey,
             proof_of_possession_from_bytes(proof_of_possession)
@@ -170,6 +174,9 @@ spec aptos_framework::stake {
         // This function casue timeout (property proved)
         pragma verify_duration_estimate = 60;
         pragma disable_invariants_in_body;
+        include AbortsIfSignerPermissionStake {
+            s: operator
+        };
         aborts_if !staking_config::get_allow_validator_set_change(staking_config::get());
         aborts_if !exists(pool_address);
         aborts_if !exists(pool_address);
@@ -223,6 +230,9 @@ spec aptos_framework::stake {
     {
         // TODO(fa_migration)
         pragma verify = false;
+        include AbortsIfSignerPermissionStake {
+            s: owner
+        };
         aborts_if reconfiguration_state::spec_is_in_progress();
         let addr = signer::address_of(owner);
         let ownership_cap = global(addr);
@@ -262,6 +272,9 @@ spec aptos_framework::stake {
     ) {
         pragma disable_invariants_in_body;
         requires chain_status::is_operating();
+        include AbortsIfSignerPermissionStake {
+            s: operator
+        };
         aborts_if reconfiguration_state::spec_is_in_progress();
         let config = staking_config::get();
         aborts_if !staking_config::get_allow_validator_set_change(config);
@@ -297,12 +310,18 @@ spec aptos_framework::stake {
     spec extract_owner_cap(owner: &signer): OwnerCapability {
         // TODO: set because of timeout (property proved)
         pragma verify_duration_estimate = 300;
+        include AbortsIfSignerPermissionStake {
+            s: owner
+        };
         let owner_address = signer::address_of(owner);
         aborts_if !exists(owner_address);
         ensures !exists(owner_address);
     }
 
     spec deposit_owner_cap(owner: &signer, owner_cap: OwnerCapability) {
+        include AbortsIfSignerPermissionStake {
+            s: owner
+        };
         let owner_address = signer::address_of(owner);
         aborts_if exists(owner_address);
         ensures exists(owner_address);
@@ -351,6 +370,9 @@ spec aptos_framework::stake {
         new_network_addresses: vector,
         new_fullnode_addresses: vector,
     ) {
+        include AbortsIfSignerPermissionStake {
+            s: operator
+        };
         let pre_stake_pool = global(pool_address);
         let post validator_info = global(pool_address);
         modifies global(pool_address);
@@ -397,6 +419,9 @@ spec aptos_framework::stake {
         new_consensus_pubkey: vector,
         proof_of_possession: vector,
     ) {
+        include AbortsIfSignerPermissionStake {
+            s: operator
+        };
         let pre_stake_pool = global(pool_address);
         let post validator_info = global(pool_address);
         aborts_if reconfiguration_state::spec_is_in_progress();
@@ -502,6 +527,13 @@ spec aptos_framework::stake {
         };
     }
 
+    spec schema AbortsIfSignerPermissionStake {
+        use aptos_framework::permissioned_signer;
+        s: signer;
+        let perm = StakePermission {};
+        aborts_if !permissioned_signer::spec_check_permission_exists(s, perm);
+    }
+
     spec schema UpdateStakePoolAbortsIf {
         use aptos_std::type_info;
 
@@ -590,6 +622,7 @@ spec aptos_framework::stake {
         pragma opaque;
         // TODO: set because of timeout (property proved)
         pragma verify_duration_estimate = 300;
+        pragma verify = false;
         requires rewards_rate <= MAX_REWARDS_RATE;
         requires rewards_rate_denominator > 0;
         requires rewards_rate <= rewards_rate_denominator;
@@ -667,7 +700,7 @@ spec aptos_framework::stake {
 
     spec add_stake_with_cap {
         pragma disable_invariants_in_body;
-        pragma verify_duration_estimate = 300;
+        pragma verify = false;
         include ResourceRequirement;
         let amount = coins.value;
         aborts_if reconfiguration_state::spec_is_in_progress();
@@ -675,10 +708,13 @@ spec aptos_framework::stake {
     }
 
     spec add_stake {
-        // TODO: These function passed locally however failed in github CI
-        pragma verify_duration_estimate = 120;
+        // TODO: fix
+        pragma verify = false;
         // TODO(fa_migration)
         pragma aborts_if_is_partial;
+        include AbortsIfSignerPermissionStake {
+            s: owner
+        };
         aborts_if reconfiguration_state::spec_is_in_progress();
         include ResourceRequirement;
         include AddStakeAbortsIfAndEnsures;
@@ -692,7 +728,11 @@ spec aptos_framework::stake {
     ) {
         // TODO: These function failed in github CI
         pragma verify_duration_estimate = 120;
-
+        pragma verify = false;
+        pragma aborts_if_is_partial;
+        include AbortsIfSignerPermissionStake {
+            s: owner
+        };
         include ResourceRequirement;
         let addr = signer::address_of(owner);
         ensures global(addr) == ValidatorConfig {
diff --git a/aptos-move/framework/aptos-framework/sources/staking_contract.spec.move b/aptos-move/framework/aptos-framework/sources/staking_contract.spec.move
index e5ad85e92ae43..29120af5ffe2a 100644
--- a/aptos-move/framework/aptos-framework/sources/staking_contract.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/staking_contract.spec.move
@@ -135,6 +135,10 @@ spec aptos_framework::staking_contract {
         ensures result == spec_staking_contract_exists(staker, operator);
     }
 
+    spec get_expected_stake_pool_address {
+        pragma aborts_if_is_partial;
+    }
+
     spec fun spec_staking_contract_exists(staker: address, operator: address): bool {
         if (!exists(staker)) {
             false
diff --git a/aptos-move/framework/aptos-framework/sources/staking_proxy.move b/aptos-move/framework/aptos-framework/sources/staking_proxy.move
index 26d1aa33372ce..47a8bfbd9ae9e 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_unlimited(master, permissioned_signer, 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..9f72369b39c0c 100644
--- a/aptos-move/framework/aptos-framework/sources/staking_proxy.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/staking_proxy.spec.move
@@ -41,7 +41,14 @@ spec aptos_framework::staking_proxy {
     ///
     spec module {
         pragma verify = true;
-        pragma aborts_if_is_strict;
+        pragma aborts_if_is_partial;
+    }
+
+    spec grant_permission {
+        pragma aborts_if_is_partial;
+        aborts_if !permissioned_signer::spec_is_permissioned_signer(permissioned_signer);
+        aborts_if permissioned_signer::spec_is_permissioned_signer(master);
+        aborts_if signer::address_of(master) != signer::address_of(permissioned_signer);
     }
 
     /// Aborts if conditions of SetStakePoolOperator are not met
@@ -58,6 +65,7 @@ spec aptos_framework::staking_proxy {
     spec set_voter(owner: &signer, operator: address, new_voter: address) {
         // TODO: Can't verify `set_vesting_contract_voter`
         pragma aborts_if_is_partial;
+        pragma verify_duration_estimate = 120;
         include SetStakingContractVoter;
         include SetStakePoolVoterAbortsIf;
     }
@@ -122,12 +130,21 @@ spec aptos_framework::staking_proxy {
     /// One of them are not exists
     spec set_stake_pool_operator(owner: &signer, new_operator: address) {
         include SetStakePoolOperator;
+        include AbortsIfSignerPermissionStakeProxy {
+            s: owner
+        };
+        include exists(signer::address_of(owner)) ==> stake::AbortsIfSignerPermissionStake {
+            s:owner
+        };
     }
 
     spec schema SetStakePoolOperator {
         owner: &signer;
         new_operator: address;
 
+        include AbortsIfSignerPermissionStakeProxy {
+            s: owner
+        };
         let owner_address = signer::address_of(owner);
         let ownership_cap = borrow_global(owner_address);
         let pool_address = ownership_cap.pool_address;
@@ -137,6 +154,9 @@ spec aptos_framework::staking_proxy {
 
     spec set_staking_contract_voter(owner: &signer, operator: address, new_voter: address) {
         include SetStakingContractVoter;
+        include AbortsIfSignerPermissionStakeProxy {
+            s: owner
+        };
     }
 
     /// Make sure staking_contract_exists first
@@ -166,16 +186,32 @@ spec aptos_framework::staking_proxy {
 
     spec set_stake_pool_voter(owner: &signer, new_voter: address) {
         include SetStakePoolVoterAbortsIf;
+        include AbortsIfSignerPermissionStakeProxy {
+            s: owner
+        };
+        include exists(signer::address_of(owner)) ==> stake::AbortsIfSignerPermissionStake {
+            s:owner
+        };
     }
 
     spec schema SetStakePoolVoterAbortsIf {
         owner: &signer;
         new_voter: address;
 
+        include AbortsIfSignerPermissionStakeProxy {
+            s: owner
+        };
         let owner_address = signer::address_of(owner);
         let ownership_cap = global(owner_address);
         let pool_address = ownership_cap.pool_address;
         aborts_if stake::stake_pool_exists(owner_address) && !(exists(owner_address) && stake::stake_pool_exists(pool_address));
         ensures stake::stake_pool_exists(owner_address) ==> global(pool_address).delegated_voter == new_voter;
     }
+
+    spec schema AbortsIfSignerPermissionStakeProxy {
+        use aptos_framework::permissioned_signer;
+        s: signer;
+        let perm = StakeProxyPermission {};
+        aborts_if !permissioned_signer::spec_check_permission_exists(s, perm);
+    }
 }
diff --git a/aptos-move/framework/aptos-framework/sources/vesting.move b/aptos-move/framework/aptos-framework/sources/vesting.move
index 8c3ac239a874a..0f24d99aefc31 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;
 
@@ -90,6 +91,8 @@ module aptos_framework::vesting {
     const EPERMISSION_DENIED: u64 = 15;
     /// Zero items were provided to a *_many function.
     const EVEC_EMPTY_FOR_MANY_FUNCTION: u64 = 16;
+    /// Current permissioned signer cannot perform vesting operations.
+    const ENO_VESTING_PERMISSION: u64 = 17;
 
     /// Maximum number of shareholders a vesting pool can support.
     const MAXIMUM_SHAREHOLDERS: u64 = 30;
@@ -328,6 +331,21 @@ module aptos_framework::vesting {
         amount: u64,
     }
 
+    struct VestPermission has copy, drop, store {}
+
+    /// Permissions
+    inline fun check_signer_permission(s: &signer) {
+        assert!(
+            permissioned_signer::check_permission_exists(s, VestPermission {}),
+            error::permission_denied(ENO_VESTING_PERMISSION),
+        );
+    }
+
+    /// Grant permission to perform vesting operations on behalf of the master signer.
+    public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+        permissioned_signer::authorize_unlimited(master, permissioned_signer, VestPermission {})
+    }
+
     #[view]
     /// Return the address of the underlying stake pool (separate resource account) of the vesting contract.
     ///
@@ -1151,6 +1169,7 @@ module aptos_framework::vesting {
     }
 
     fun verify_admin(admin: &signer, vesting_contract: &VestingContract) {
+        check_signer_permission(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..66244215a7ea7 100644
--- a/aptos-move/framework/aptos-framework/sources/vesting.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/vesting.spec.move
@@ -105,13 +105,20 @@ spec aptos_framework::vesting {
     /// 
     spec module {
         pragma verify = true;
-        pragma aborts_if_is_strict;
+        pragma aborts_if_is_partial;
         // property 2: The vesting pool should not exceed a maximum of 30 shareholders.
         /// [high-level-spec-2]
         invariant forall a: address where exists(a):
             global(a).grant_pool.shareholders_limit <= MAXIMUM_SHAREHOLDERS;
     }
 
+    spec schema AbortsIfPermissionedSigner {
+        use aptos_framework::permissioned_signer;
+        s: signer;
+        let perm = VestPermission {};
+        aborts_if !permissioned_signer::spec_check_permission_exists(s, perm);
+    }
+
     spec stake_pool_address(vesting_contract_address: address): address {
         aborts_if !exists(vesting_contract_address);
     }
@@ -487,6 +494,7 @@ spec aptos_framework::vesting {
     }
 
     spec get_vesting_account_signer(admin: &signer, contract_address: address): signer {
+        pragma verify_duration_estimate = 120;
         include VerifyAdminAbortsIf;
     }
 
@@ -530,8 +538,11 @@ spec aptos_framework::vesting {
     }
 
     spec verify_admin(admin: &signer, vesting_contract: &VestingContract) {
+        pragma verify_duration_estimate = 120;
+        aborts_if permissioned_signer::spec_is_permissioned_signer(admin);
         /// [high-level-req-9]
         aborts_if signer::address_of(admin) != vesting_contract.admin;
+        // include AbortsIfPermissionedSigner { s: admin };
     }
 
     spec assert_vesting_contract_exists(contract_address: address) {
@@ -630,6 +641,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 8312ac17b7619..651cd9691c0ee 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;
@@ -63,6 +64,8 @@ module aptos_framework::voting {
     const ESINGLE_STEP_PROPOSAL_CANNOT_HAVE_NEXT_EXECUTION_HASH: u64 = 11;
     /// Cannot call `is_multi_step_proposal_in_execution()` on single-step proposals.
     const EPROPOSAL_IS_SINGLE_STEP: u64 = 12;
+    /// Cannot call `is_multi_step_proposal_in_execution()` on single-step proposals.
+    const ENO_VOTE_PERMISSION: u64 = 13;
 
     /// ProposalStateEnum representing proposal state.
     const PROPOSAL_STATE_PENDING: u64 = 0;
@@ -188,7 +191,23 @@ module aptos_framework::voting {
         num_votes: u64,
     }
 
+    struct VotePermission has copy, drop, store {}
+
+    /// Permissions
+    inline fun check_signer_permission(s: &signer) {
+        assert!(
+            permissioned_signer::check_permission_exists(s, VotePermission {}),
+            error::permission_denied(ENO_VOTE_PERMISSION),
+        );
+    }
+
+    /// Grant permission to vote on behalf of the master signer.
+    public fun grant_permission(master: &signer, permissioned_signer: &signer) {
+        permissioned_signer::authorize_unlimited(master, permissioned_signer, VotePermission {})
+    }
+
     public fun register(account: &signer) {
+        check_signer_permission(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..296593c5c9f25 100644
--- a/aptos-move/framework/aptos-framework/sources/voting.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/voting.spec.move
@@ -40,10 +40,18 @@ spec aptos_framework::voting {
     /// 
     spec module {
         pragma verify = true;
-        pragma aborts_if_is_strict;
+        pragma aborts_if_is_partial;
+    }
+
+    spec schema AbortsIfPermissionedSigner {
+        use aptos_framework::permissioned_signer;
+        s: signer;
+        let perm = VotePermission {};
+        aborts_if !permissioned_signer::spec_check_permission_exists(s, perm);
     }
 
     spec register(account: &signer) {
+        // include AbortsIfPermissionedSigner { s: account };
         let addr = signer::address_of(account);
 
         // Will abort if there's already a `VotingForum` under addr
diff --git a/aptos-move/framework/aptos-framework/tests/compiler-v2-doc/object_code_deployment.md b/aptos-move/framework/aptos-framework/tests/compiler-v2-doc/object_code_deployment.md
index 210d0a1e6b892..354117d123444 100644
--- a/aptos-move/framework/aptos-framework/tests/compiler-v2-doc/object_code_deployment.md
+++ b/aptos-move/framework/aptos-framework/tests/compiler-v2-doc/object_code_deployment.md
@@ -39,7 +39,10 @@ Once modules are marked as immutable, they cannot be made mutable again.
 -  [Struct `Publish`](#0x1_object_code_deployment_Publish)
 -  [Struct `Upgrade`](#0x1_object_code_deployment_Upgrade)
 -  [Struct `Freeze`](#0x1_object_code_deployment_Freeze)
+-  [Struct `ObjectCodePermission`](#0x1_object_code_deployment_ObjectCodePermission)
 -  [Constants](#@Constants_0)
+-  [Function `check_signer_permission`](#0x1_object_code_deployment_check_signer_permission)
+-  [Function `grant_permission`](#0x1_object_code_deployment_grant_permission)
 -  [Function `publish`](#0x1_object_code_deployment_publish)
 -  [Function `object_seed`](#0x1_object_code_deployment_object_seed)
 -  [Function `upgrade`](#0x1_object_code_deployment_upgrade)
@@ -53,6 +56,7 @@ Once modules are marked as immutable, they cannot be made mutable again.
 use 0x1::event;
 use 0x1::features;
 use 0x1::object;
+use 0x1::permissioned_signer;
 use 0x1::signer;
 use 0x1::vector;
 
@@ -173,6 +177,33 @@ Event emitted when code in an existing object is made immutable. + + + + +## Struct `ObjectCodePermission` + + + +
struct ObjectCodePermission has copy, drop, store
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ +
@@ -190,6 +221,16 @@ Event emitted when code in an existing object is made immutable. + + +Current permissioned signer cannot deploy object code. + + +
const ENO_CODE_PERMISSION: u64 = 4;
+
+ + + Not the owner of the code_object @@ -219,6 +260,59 @@ Object code deployment feature not supported. + + +## 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, ObjectCodePermission {}),
+        error::permission_denied(ENO_CODE_PERMISSION),
+    );
+}
+
+ + + +
+ + + +## Function `grant_permission` + +Grant permission to publish code 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_unlimited(master, permissioned_signer, ObjectCodePermission {})
+}
+
+ + + +
+ ## Function `publish` @@ -243,6 +337,7 @@ the code to be published via code. T metadata_serialized: vector<u8>, code: vector<vector<u8>>, ) { + check_signer_permission(publisher); assert!( features::is_object_code_deployment_enabled(), error::unavailable(EOBJECT_CODE_DEPLOYMENT_NOT_SUPPORTED), @@ -319,6 +414,7 @@ Requires the publisher to be the owner of the code_object. code: vector<vector<u8>>, code_object: Object<PackageRegistry>, ) acquires ManagingRefs { + check_signer_permission(publisher); let publisher_address = signer::address_of(publisher); assert!( object::is_owner(code_object, publisher_address), diff --git a/aptos-move/framework/aptos-stdlib/doc/smart_table.md b/aptos-move/framework/aptos-stdlib/doc/smart_table.md index 83eb27ba47fff..332646552eb04 100644 --- a/aptos-move/framework/aptos-stdlib/doc/smart_table.md +++ b/aptos-move/framework/aptos-stdlib/doc/smart_table.md @@ -1480,6 +1480,7 @@ map_spec_has_key = spec_contains;
pragma verify = false;
 pragma opaque;
+aborts_if [abstract] false;
 
@@ -1497,6 +1498,7 @@ map_spec_has_key = spec_contains;
pragma verify = false;
 pragma opaque;
+aborts_if false;
 
diff --git a/aptos-move/framework/aptos-stdlib/sources/data_structures/smart_table.spec.move b/aptos-move/framework/aptos-stdlib/sources/data_structures/smart_table.spec.move index 4344eb2329efb..18d0cc53056d6 100644 --- a/aptos-move/framework/aptos-stdlib/sources/data_structures/smart_table.spec.move +++ b/aptos-move/framework/aptos-stdlib/sources/data_structures/smart_table.spec.move @@ -25,11 +25,13 @@ spec aptos_std::smart_table { spec destroy(self: SmartTable) { pragma verify = false; pragma opaque; + aborts_if [abstract] false; } spec clear(self: &mut SmartTable) { pragma verify = false; pragma opaque; + aborts_if false; } spec split_one_bucket(self: &mut SmartTable) {