diff --git a/aptos-move/framework/aptos-framework/sources/fungible_asset.move b/aptos-move/framework/aptos-framework/sources/fungible_asset.move index 4b4bd78393b37..e6aeea50a8262 100644 --- a/aptos-move/framework/aptos-framework/sources/fungible_asset.move +++ b/aptos-move/framework/aptos-framework/sources/fungible_asset.move @@ -6,7 +6,7 @@ module aptos_framework::fungible_asset { use aptos_framework::event; use aptos_framework::function_info::{Self, FunctionInfo}; use aptos_framework::object::{Self, Object, ConstructorRef, DeleteRef, ExtendRef}; - use aptos_framework::permissioned_signer; + use aptos_framework::permissioned_signer::{Self, Permission}; use std::string; use std::features; @@ -874,6 +874,21 @@ module aptos_framework::fungible_asset { unchecked_withdraw(object::object_address(&store), amount) } + public fun withdraw_with_permission( + perm: &mut Permission, + store: Object, + amount: u64, + ): FungibleAsset acquires FungibleStore, DispatchFunctionStore, ConcurrentFungibleBalance { + withdraw_sanity_check_impl(permissioned_signer::address_of(perm), store, true); + assert!( + permissioned_signer::consume_permission(perm, amount as u256, WithdrawPermission::ByStore { + store_address: object::object_address(&store), + }), + error::permission_denied(EWITHDRAW_PERMISSION_DENIED) + ); + unchecked_withdraw(object::object_address(&store), amount) + } + /// Check the permission for withdraw operation. public(friend) fun withdraw_permission_check( owner: &signer, diff --git a/aptos-move/framework/aptos-framework/sources/permissioned_signer.move b/aptos-move/framework/aptos-framework/sources/permissioned_signer.move index 9c090c8e5ae4d..71e1ea07ce04a 100644 --- a/aptos-move/framework/aptos-framework/sources/permissioned_signer.move +++ b/aptos-move/framework/aptos-framework/sources/permissioned_signer.move @@ -112,6 +112,14 @@ module aptos_framework::permissioned_signer { Capacity(u256), } + enum Permission { + V1 { + owner_address: address, + key: K, + perm: StoredPermission, + } + } + /// Create an ephermeral permission handle based on the master signer. /// /// This handle can be used to derive a signer that can be used in the context of @@ -582,6 +590,83 @@ module aptos_framework::permissioned_signer { } } + /// ===================================================================================================== + /// Another flavor of api to extract and store permissions + /// + public(package) fun extract_permission( + s: &signer, weight: u256, perm: PermKey + ): Permission acquires PermissionStorage { + assert!( + check_permission_consume(s, weight, perm), + error::permission_denied(ECANNOT_EXTRACT_PERMISSION) + ); + Permission::V1 { + owner_address: signer::address_of(s), + key: perm, + perm: StoredPermission::Capacity(weight), + } + } + + public(package) fun extract_all_permission( + s: &signer, perm_key: PermKey + ): Permission acquires PermissionStorage { + assert!( + is_permissioned_signer(s), + error::permission_denied(ECANNOT_EXTRACT_PERMISSION) + ); + let addr = permission_address(s); + assert!( + exists(addr), + error::permission_denied(ECANNOT_EXTRACT_PERMISSION) + ); + let key = copyable_any::pack(perm_key); + let storage = &mut borrow_global_mut(addr).perms; + let (_, value) = simple_map::remove(storage, &key); + + Permission::V1 { + owner_address: signer::address_of(s), + key: perm_key, + perm: value, + } + } + + public(package) fun address_of(perm: &Permission): address { + perm.owner_address + } + + public(package) fun consume_permission( + perm: &mut Permission, weight: u256, perm_key: PermKey + ): bool { + if (perm.key != perm_key) { + return false + }; + consume_capacity(&mut perm.perm, weight) + } + + public(package) fun store_permission( + s: &signer, perm: Permission + ) acquires PermissionStorage { + assert!( + is_permissioned_signer(s), + error::permission_denied(ENOT_PERMISSIONED_SIGNER) + ); + let Permission::V1 { key, perm, owner_address } = perm; + + assert!( + signer::address_of(s) == owner_address, + error::permission_denied(E_PERMISSION_MISMATCH) + ); + + insert_or( + s, + key, + |stored_permission| { + merge(stored_permission, perm); + }, + perm, + ) + } + // ===================================================================================================== // Native Functions ///