diff --git a/aptos-move/framework/aptos-framework/doc/account.md b/aptos-move/framework/aptos-framework/doc/account.md index 516ad6d386558..5a74228946a5b 100644 --- a/aptos-move/framework/aptos-framework/doc/account.md +++ b/aptos-move/framework/aptos-framework/doc/account.md @@ -63,6 +63,8 @@ - [Function `revoke_rotation_capability`](#@Specification_1_revoke_rotation_capability) - [Function `revoke_any_rotation_capability`](#@Specification_1_revoke_any_rotation_capability) - [Function `offer_signer_capability`](#@Specification_1_offer_signer_capability) + - [Function `is_signer_capability_offered`](#@Specification_1_is_signer_capability_offered) + - [Function `get_signer_capability_offer_for`](#@Specification_1_get_signer_capability_offer_for) - [Function `revoke_signer_capability`](#@Specification_1_revoke_signer_capability) - [Function `revoke_any_signer_capability`](#@Specification_1_revoke_any_signer_capability) - [Function `create_authorized_signer`](#@Specification_1_create_authorized_signer) @@ -2308,6 +2310,40 @@ The authentication scheme is ED25519_SCHEME and MULTI_ED25519_SCHEME. + + +### Function `is_signer_capability_offered` + + +
public fun is_signer_capability_offered(account_addr: address): bool
+
+ + + + +
aborts_if !exists<Account>(account_addr);
+
+ + + + + +### Function `get_signer_capability_offer_for` + + +
public fun get_signer_capability_offer_for(account_addr: address): address
+
+ + + + +
aborts_if !exists<Account>(account_addr);
+let account_resource = global<Account>(account_addr);
+aborts_if len(account_resource.signer_capability_offer.for.vec) == 0;
+
+ + + ### Function `revoke_signer_capability` diff --git a/aptos-move/framework/aptos-framework/doc/code.md b/aptos-move/framework/aptos-framework/doc/code.md index d274d1c5a974a..63a51bd7a63f4 100644 --- a/aptos-move/framework/aptos-framework/doc/code.md +++ b/aptos-move/framework/aptos-framework/doc/code.md @@ -28,6 +28,12 @@ This module supports functionality related to code management. - [Function `request_publish`](#0x1_code_request_publish) - [Function `request_publish_with_allowed_deps`](#0x1_code_request_publish_with_allowed_deps) - [Specification](#@Specification_1) + - [Function `initialize`](#@Specification_1_initialize) + - [Function `publish_package`](#@Specification_1_publish_package) + - [Function `publish_package_txn`](#@Specification_1_publish_package_txn) + - [Function `check_upgradability`](#@Specification_1_check_upgradability) + - [Function `check_coexistence`](#@Specification_1_check_coexistence) + - [Function `check_dependencies`](#@Specification_1_check_dependencies) - [Function `request_publish`](#@Specification_1_request_publish) - [Function `request_publish_with_allowed_deps`](#@Specification_1_request_publish_with_allowed_deps) @@ -888,6 +894,106 @@ Native function to initiate module loading, including a list of allowed dependen +
pragma verify = true;
+pragma aborts_if_is_strict;
+
+ + + + + +### Function `initialize` + + +
fun initialize(aptos_framework: &signer, package_owner: &signer, metadata: code::PackageMetadata)
+
+ + + + +
let aptos_addr = signer::address_of(aptos_framework);
+let owner_addr = signer::address_of(package_owner);
+aborts_if !system_addresses::is_aptos_framework_address(aptos_addr);
+ensures exists<PackageRegistry>(owner_addr);
+
+ + + + + +### Function `publish_package` + + +
public fun publish_package(owner: &signer, pack: code::PackageMetadata, code: vector<vector<u8>>)
+
+ + + + +
pragma verify = false;
+
+ + + + + +### Function `publish_package_txn` + + +
public entry fun publish_package_txn(owner: &signer, metadata_serialized: vector<u8>, code: vector<vector<u8>>)
+
+ + + + +
pragma verify = false;
+
+ + + + + +### Function `check_upgradability` + + +
fun check_upgradability(old_pack: &code::PackageMetadata, new_pack: &code::PackageMetadata, new_modules: &vector<string::String>)
+
+ + + + +
pragma verify = false;
+
+ + + + + +### Function `check_coexistence` + + +
fun check_coexistence(old_pack: &code::PackageMetadata, new_modules: &vector<string::String>)
+
+ + + + +
pragma verify = false;
+
+ + + + + +### Function `check_dependencies` + + +
fun check_dependencies(publish_address: address, pack: &code::PackageMetadata): vector<code::AllowedDep>
+
+ + + +
pragma verify = false;
 
diff --git a/aptos-move/framework/aptos-framework/doc/resource_account.md b/aptos-move/framework/aptos-framework/doc/resource_account.md index f75f7c856ed73..cc79514ad8b79 100644 --- a/aptos-move/framework/aptos-framework/doc/resource_account.md +++ b/aptos-move/framework/aptos-framework/doc/resource_account.md @@ -82,6 +82,12 @@ module.resource_signer_cap = option::some(resource_signer_cap); - [Function `create_resource_account_and_publish_package`](#0x1_resource_account_create_resource_account_and_publish_package) - [Function `rotate_account_authentication_key_and_store_capability`](#0x1_resource_account_rotate_account_authentication_key_and_store_capability) - [Function `retrieve_resource_account_cap`](#0x1_resource_account_retrieve_resource_account_cap) +- [Specification](#@Specification_3) + - [Function `create_resource_account`](#@Specification_3_create_resource_account) + - [Function `create_resource_account_and_fund`](#@Specification_3_create_resource_account_and_fund) + - [Function `create_resource_account_and_publish_package`](#@Specification_3_create_resource_account_and_publish_package) + - [Function `rotate_account_authentication_key_and_store_capability`](#@Specification_3_rotate_account_authentication_key_and_store_capability) + - [Function `retrieve_resource_account_cap`](#@Specification_3_retrieve_resource_account_cap)
use 0x1::account;
@@ -364,5 +370,120 @@ the SignerCapability.
 
 
 
+
+
+## Specification
+
+
+
+
pragma verify = true;
+pragma aborts_if_is_strict;
+
+ + + + + +### Function `create_resource_account` + + +
public entry fun create_resource_account(origin: &signer, seed: vector<u8>, optional_auth_key: vector<u8>)
+
+ + + + +
pragma verify = false;
+
+ + + + + +### Function `create_resource_account_and_fund` + + +
public entry fun create_resource_account_and_fund(origin: &signer, seed: vector<u8>, optional_auth_key: vector<u8>, fund_amount: u64)
+
+ + + + +
pragma verify = false;
+
+ + + + + +### Function `create_resource_account_and_publish_package` + + +
public entry fun create_resource_account_and_publish_package(origin: &signer, seed: vector<u8>, metadata_serialized: vector<u8>, code: vector<vector<u8>>)
+
+ + + + +
pragma verify = false;
+
+ + + + + +### Function `rotate_account_authentication_key_and_store_capability` + + +
fun rotate_account_authentication_key_and_store_capability(origin: &signer, resource: signer, resource_signer_cap: account::SignerCapability, optional_auth_key: vector<u8>)
+
+ + + + +
let resource_addr = signer::address_of(resource);
+include RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIf;
+
+ + + + + + + +
schema RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIf {
+    origin: signer;
+    resource_addr: address;
+    optional_auth_key: vector<u8>;
+    let origin_addr = signer::address_of(origin);
+    let container = global<Container>(origin_addr);
+    let get = len(optional_auth_key) == 0;
+    aborts_if get && !exists<Account>(origin_addr);
+    aborts_if exists<Container>(origin_addr) && simple_map::spec_contains_key(container.store, resource_addr);
+    aborts_if get && !(exists<Account>(resource_addr) && len(global<Account>(origin_addr).authentication_key) == 32);
+    aborts_if !get && !(exists<Account>(resource_addr) && len(optional_auth_key) == 32);
+}
+
+ + + + + +### Function `retrieve_resource_account_cap` + + +
public fun retrieve_resource_account_cap(resource: &signer, source_addr: address): account::SignerCapability
+
+ + + + +
aborts_if !exists<Container>(source_addr);
+let resource_addr = signer::address_of(resource);
+let container = borrow_global_mut<Container>(source_addr);
+aborts_if !simple_map::spec_contains_key(container.store, resource_addr);
+aborts_if !exists<account::Account>(resource_addr);
+
+ [move-book]: https://move-language.github.io/move/introduction.html diff --git a/aptos-move/framework/aptos-framework/doc/staking_contract.md b/aptos-move/framework/aptos-framework/doc/staking_contract.md index 51c8b55673706..3f6fe9321d326 100644 --- a/aptos-move/framework/aptos-framework/doc/staking_contract.md +++ b/aptos-move/framework/aptos-framework/doc/staking_contract.md @@ -84,6 +84,7 @@ pool. - [Function `add_stake`](#@Specification_1_add_stake) - [Function `update_voter`](#@Specification_1_update_voter) - [Function `reset_lockup`](#@Specification_1_reset_lockup) + - [Function `update_commision`](#@Specification_1_update_commision) - [Function `request_commission`](#@Specification_1_request_commission) - [Function `request_commission_internal`](#@Specification_1_request_commission_internal) - [Function `unlock_stake`](#@Specification_1_unlock_stake) @@ -2155,6 +2156,22 @@ Only active validator can update locked_until_secs. + + +### Function `update_commision` + + +
public entry fun update_commision(staker: &signer, operator: address, new_commission_percentage: u64)
+
+ + + + +
pragma verify = false;
+
+ + + ### Function `request_commission` diff --git a/aptos-move/framework/aptos-framework/doc/staking_proxy.md b/aptos-move/framework/aptos-framework/doc/staking_proxy.md index d49edc1e3f8cf..78894f68acf11 100644 --- a/aptos-move/framework/aptos-framework/doc/staking_proxy.md +++ b/aptos-move/framework/aptos-framework/doc/staking_proxy.md @@ -14,6 +14,14 @@ - [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) + - [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;
@@ -259,7 +267,202 @@
 
 
 
-
pragma verify = false;
+
pragma verify = true;
+pragma aborts_if_is_strict;
+
+ + + + + +### Function `set_operator` + + +
public entry fun set_operator(owner: &signer, old_operator: address, new_operator: address)
+
+ + +Aborts if conditions of SetStakePoolOperator are not met + + +
pragma aborts_if_is_partial;
+include SetStakePoolOperator;
+
+ + + + + +### Function `set_voter` + + +
public entry fun set_voter(owner: &signer, operator: address, new_voter: address)
+
+ + +Aborts if conditions of SetStackingContractVoter and SetStackPoolVoterAbortsIf are not met + + +
pragma aborts_if_is_partial;
+include SetStakingContractVoter;
+include SetStakePoolVoterAbortsIf;
+
+ + + + + +### Function `set_vesting_contract_operator` + + +
public entry fun set_vesting_contract_operator(owner: &signer, old_operator: address, new_operator: address)
+
+ + + + +
pragma aborts_if_is_partial;
+
+ + + + + +### Function `set_staking_contract_operator` + + +
public entry fun set_staking_contract_operator(owner: &signer, old_operator: address, new_operator: address)
+
+ + + + +
pragma aborts_if_is_partial;
+let owner_address = signer::address_of(owner);
+let store = borrow_global<Store>(owner_address);
+let staking_contract_exists = exists<Store>(owner_address) && simple_map::spec_contains_key(store.staking_contracts, old_operator);
+
+ + + + + +### Function `set_stake_pool_operator` + + +
public entry fun set_stake_pool_operator(owner: &signer, new_operator: address)
+
+ + +Aborts if stake_pool is exists and when OwnerCapability or stake_pool_exists +One of them are not exists + + +
include SetStakePoolOperator;
+
+ + + + + + + +
schema SetStakePoolOperator {
+    owner: &signer;
+    new_operator: address;
+    let owner_address = signer::address_of(owner);
+    let ownership_cap = borrow_global<stake::OwnerCapability>(owner_address);
+    let pool_address = ownership_cap.pool_address;
+    aborts_if stake::stake_pool_exists(owner_address) && !(exists<stake::OwnerCapability>(owner_address) && stake::stake_pool_exists(pool_address));
+}
+
+ + + + + +### Function `set_vesting_contract_voter` + + +
public entry fun set_vesting_contract_voter(owner: &signer, operator: address, new_voter: address)
+
+ + + + +
pragma aborts_if_is_partial;
+
+ + + + + +### Function `set_staking_contract_voter` + + +
public entry fun set_staking_contract_voter(owner: &signer, operator: address, new_voter: address)
+
+ + + + +
include SetStakingContractVoter;
+
+ + +Make sure staking_contract_exists first +Then abort if the resource is not exist + + + + + +
schema SetStakingContractVoter {
+    owner: &signer;
+    operator: address;
+    new_voter: address;
+    let owner_address = signer::address_of(owner);
+    let staker = owner_address;
+    let store = global<Store>(staker);
+    let staking_contract_exists = exists<Store>(staker) && simple_map::spec_contains_key(store.staking_contracts, operator);
+    let staker_address = owner_address;
+    let staking_contract = simple_map::spec_get(store.staking_contracts, operator);
+    let pool_address = staking_contract.pool_address;
+    aborts_if staking_contract_exists && !exists<stake::StakePool>(pool_address);
+    aborts_if staking_contract_exists && !exists<stake::StakePool>(staking_contract.owner_cap.pool_address);
+}
+
+ + + + + +### Function `set_stake_pool_voter` + + +
public entry fun set_stake_pool_voter(owner: &signer, new_voter: address)
+
+ + + + +
include SetStakePoolVoterAbortsIf;
+
+ + + + + + + +
schema SetStakePoolVoterAbortsIf {
+    owner: &signer;
+    new_voter: address;
+    let owner_address = signer::address_of(owner);
+    let ownership_cap = global<stake::OwnerCapability>(owner_address);
+    let pool_address = ownership_cap.pool_address;
+    aborts_if stake::stake_pool_exists(owner_address) && !(exists<stake::OwnerCapability>(owner_address) && stake::stake_pool_exists(pool_address));
+}
 
diff --git a/aptos-move/framework/aptos-framework/sources/account.spec.move b/aptos-move/framework/aptos-framework/sources/account.spec.move index 74c01087871a9..23c5a233a9885 100644 --- a/aptos-move/framework/aptos-framework/sources/account.spec.move +++ b/aptos-move/framework/aptos-framework/sources/account.spec.move @@ -254,6 +254,16 @@ spec aptos_framework::account { modifies global(source_address); } + spec is_signer_capability_offered(account_addr: address): bool { + aborts_if !exists(account_addr); + } + + spec get_signer_capability_offer_for(account_addr: address): address { + aborts_if !exists(account_addr); + let account_resource = global(account_addr); + aborts_if len(account_resource.signer_capability_offer.for.vec) == 0; + } + /// 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) { diff --git a/aptos-move/framework/aptos-framework/sources/code.spec.move b/aptos-move/framework/aptos-framework/sources/code.spec.move index 27b30f0311253..a71136e7ff335 100644 --- a/aptos-move/framework/aptos-framework/sources/code.spec.move +++ b/aptos-move/framework/aptos-framework/sources/code.spec.move @@ -1,6 +1,7 @@ spec aptos_framework::code { spec module { - pragma verify = false; + pragma verify = true; + pragma aborts_if_is_strict; } spec request_publish { @@ -12,4 +13,37 @@ spec aptos_framework::code { // TODO: temporary mockup. pragma opaque; } + + 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); + aborts_if !system_addresses::is_aptos_framework_address(aptos_addr); + + ensures exists(owner_addr); + } + + spec publish_package(owner: &signer, pack: PackageMetadata, code: vector>) { + // TODO: Can't verify `check_upgradability` in while loop. + pragma verify = false; + } + + spec publish_package_txn { + // TODO: Calls `publish_package`.` + pragma verify = false; + } + + spec check_upgradability(old_pack: &PackageMetadata, new_pack: &PackageMetadata, new_modules: &vector) { + // TODO: loop too deep. + pragma verify = false; + } + + spec check_dependencies(publish_address: address, pack: &PackageMetadata): vector { + // TODO: loop too deep. + pragma verify = false; + } + + spec check_coexistence(old_pack: &PackageMetadata, new_modules: &vector) { + // TODO: loop too deep. + pragma verify = false; + } } diff --git a/aptos-move/framework/aptos-framework/sources/resource_account.spec.move b/aptos-move/framework/aptos-framework/sources/resource_account.spec.move new file mode 100644 index 0000000000000..6d3edd0ca55de --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/resource_account.spec.move @@ -0,0 +1,73 @@ +spec aptos_framework::resource_account { + spec module { + pragma verify = true; + pragma aborts_if_is_strict; + } + + spec create_resource_account( + origin: &signer, + seed: vector, + optional_auth_key: vector, + ) { + // TODO: Could not verify `rotate_account_authentication_key_and_store_capability` because can't get `resource` and `resource_signer_cap`. + pragma verify = false; + } + + spec create_resource_account_and_fund( + origin: &signer, + seed: vector, + optional_auth_key: vector, + fund_amount: u64, + ) { + // TODO: Could not verify `rotate_account_authentication_key_and_store_capability` because can't get `resource` and `resource_signer_cap`. + pragma verify = false; + } + + spec create_resource_account_and_publish_package( + origin: &signer, + seed: vector, + metadata_serialized: vector, + code: vector>, + ) { + // TODO: Calls `code::publish_package_txn`. + pragma verify = false; + } + + spec rotate_account_authentication_key_and_store_capability( + origin: &signer, + resource: signer, + resource_signer_cap: account::SignerCapability, + optional_auth_key: vector, + ) { + let resource_addr = signer::address_of(resource); + include RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIf; + } + + spec schema RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIf { + use aptos_framework::account::{Account}; + origin: signer; + resource_addr: address; + optional_auth_key: vector; + + let origin_addr = signer::address_of(origin); + let container = global(origin_addr); + let get = len(optional_auth_key) == 0; + + aborts_if get && !exists(origin_addr); + aborts_if exists(origin_addr) && simple_map::spec_contains_key(container.store, resource_addr); + aborts_if get && !(exists(resource_addr) && len(global(origin_addr).authentication_key) == 32); + aborts_if !get && !(exists(resource_addr) && len(optional_auth_key) == 32); + } + + spec retrieve_resource_account_cap( + resource: &signer, + source_addr: address, + ) : account::SignerCapability { + aborts_if !exists(source_addr); + let resource_addr = signer::address_of(resource); + + let container = borrow_global_mut(source_addr); + aborts_if !simple_map::spec_contains_key(container.store, resource_addr); + aborts_if !exists(resource_addr); + } +} 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 a90d1713aef66..ab6bd9e2e8731 100644 --- a/aptos-move/framework/aptos-framework/sources/staking_contract.spec.move +++ b/aptos-move/framework/aptos-framework/sources/staking_contract.spec.move @@ -108,6 +108,11 @@ spec aptos_framework::staking_contract { include IncreaseLockupWithCapAbortsIf{staker: staker_address}; } + spec update_commision (staker: &signer, operator: address, new_commission_percentage: u64) { + // TODO: Call `distribute_internal` + pragma verify = false; + } + /// Only staker or operator can call this. spec request_commission(account: &signer, staker: address, operator: address) { // TODO: Call `update_distribution_pool` 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 4c14199c7b710..e30f467be967b 100644 --- a/aptos-move/framework/aptos-framework/sources/staking_proxy.spec.move +++ b/aptos-move/framework/aptos-framework/sources/staking_proxy.spec.move @@ -1,5 +1,104 @@ spec aptos_framework::staking_proxy { spec module { - pragma verify = false; + pragma verify = true; + pragma aborts_if_is_strict; + } + + /// Aborts if conditions of SetStakePoolOperator are not met + spec set_operator(owner: &signer, old_operator: address, new_operator: address) { + // TODO: set_vesting_contract_operator and set_staking_contract_operator too complicated. + pragma aborts_if_is_partial; + include SetStakePoolOperator; + } + + /// Aborts if conditions of SetStackingContractVoter and SetStackPoolVoterAbortsIf are not met + spec set_voter(owner: &signer, operator: address, new_voter: address) { + // TODO: set_vesting_contract_voter too complicated. + pragma aborts_if_is_partial; + include SetStakingContractVoter; + include SetStakePoolVoterAbortsIf; + } + + spec set_vesting_contract_operator(owner: &signer, old_operator: address, new_operator: address) { + // TODO: can't verify update_voter in while loop. + pragma aborts_if_is_partial; + } + + spec set_staking_contract_operator(owner: &signer, old_operator: address, new_operator: address) { + use aptos_framework::staking_contract::{Store}; + use aptos_framework::simple_map; + // TODO: Timeout & staking_contract::switch_operator. + pragma aborts_if_is_partial; + + let owner_address = signer::address_of(owner); + let store = borrow_global(owner_address); + let staking_contract_exists = exists(owner_address) && simple_map::spec_contains_key(store.staking_contracts, old_operator); + } + + spec set_vesting_contract_voter(owner: &signer, operator: address, new_voter: address) { + // TODO: The update_voter function logic is too complicated in the while loop + pragma aborts_if_is_partial; + } + + /// Aborts if stake_pool is exists and when OwnerCapability or stake_pool_exists + /// One of them are not exists + spec set_stake_pool_operator(owner: &signer, new_operator: address) { + include SetStakePoolOperator; + } + + spec schema SetStakePoolOperator { + owner: &signer; + new_operator: address; + + let owner_address = signer::address_of(owner); + let ownership_cap = borrow_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)); + } + + spec set_staking_contract_voter(owner: &signer, operator: address, new_voter: address) { + include SetStakingContractVoter; + } + + /// Make sure staking_contract_exists first + /// Then abort if the resource is not exist + spec schema SetStakingContractVoter { + use aptos_std::simple_map; + use aptos_framework::staking_contract::{Store}; + + owner: &signer; + operator: address; + new_voter: address; + + + let owner_address = signer::address_of(owner); + let staker = owner_address; + let store = global(staker); + + // in staking_contract_exists + let staking_contract_exists = exists(staker) && simple_map::spec_contains_key(store.staking_contracts, operator); + + // in update_voter + let staker_address = owner_address; + let staking_contract = simple_map::spec_get(store.staking_contracts, operator); + let pool_address = staking_contract.pool_address; + + aborts_if staking_contract_exists && !exists(pool_address); + aborts_if staking_contract_exists && !exists(staking_contract.owner_cap.pool_address); + + } + + spec set_stake_pool_voter(owner: &signer, new_voter: address) { + include SetStakePoolVoterAbortsIf; + } + + spec schema SetStakePoolVoterAbortsIf { + owner: &signer; + new_voter: address; + + 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)); } }