diff --git a/aptos-move/framework/aptos-framework/doc/aptos_account.md b/aptos-move/framework/aptos-framework/doc/aptos_account.md
index 33cd0ff87e5a13..6b4c97226eece0 100644
--- a/aptos-move/framework/aptos-framework/doc/aptos_account.md
+++ b/aptos-move/framework/aptos-framework/doc/aptos_account.md
@@ -605,6 +605,7 @@ to transfer APT) - if we want to allow APT PFS without account itself
// as APT cannot be frozen or have dispatch, and PFS cannot be transfered
// (PFS could potentially be burned. regular transfer would permanently unburn the store.
// Ignoring the check here has the equivalent of unburning, transfers, and then burning again)
+ fungible_asset::withdraw_permission_check_by_address(source, @aptos_fungible_asset, amount);
fungible_asset::deposit_internal(recipient_store, fungible_asset::withdraw_internal(sender_store, amount));
}
diff --git a/aptos-move/framework/aptos-framework/doc/coin.md b/aptos-move/framework/aptos-framework/doc/coin.md
index 07e97171f99b19..93c6b94cdc8f5f 100644
--- a/aptos-move/framework/aptos-framework/doc/coin.md
+++ b/aptos-move/framework/aptos-framework/doc/coin.md
@@ -158,6 +158,7 @@ This module provides the foundation for typesafe Coins.
use 0x1::object;
use 0x1::option;
use 0x1::optional_aggregator;
+use 0x1::permissioned_signer;
use 0x1::primary_fungible_store;
use 0x1::signer;
use 0x1::string;
@@ -3423,6 +3424,13 @@ Withdraw specified amount
of coin CoinType
from the si
): Coin<CoinType> acquires CoinStore, CoinConversionMap, CoinInfo, PairedCoinType {
let account_addr = signer::address_of(account);
+ let metadata = paired_metadata<CoinType>();
+ if(option::is_some(&metadata)) {
+ fungible_asset::withdraw_permission_check_by_address(account, object::object_address(&option::destroy_some(metadata)), amount);
+ } else {
+ permissioned_signer::assert_master_signer(account);
+ };
+
let (coin_amount_to_withdraw, fa_amount_to_withdraw) = calculate_amount_to_withdraw<CoinType>(
account_addr,
amount
@@ -3814,64 +3822,6 @@ initialize, initialize_internal, initialize_with_parallelizable_supply;
-
-
-
-
-
fun spec_is_account_registered<CoinType>(account_addr: address): bool {
- let paired_metadata_opt = spec_paired_metadata<CoinType>();
- exists<CoinStore<CoinType>>(account_addr) || (option::spec_is_some(
- paired_metadata_opt
- ) && primary_fungible_store::spec_primary_store_exists(account_addr, option::spec_borrow(paired_metadata_opt)))
-}
-
-
-
-
-
-
-
-
-schema CoinSubAbortsIf<CoinType> {
- amount: u64;
- let addr = type_info::type_of<CoinType>().account_address;
- let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;
- include (option::is_some(
- maybe_supply
- )) ==> optional_aggregator::SubAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount };
-}
-
-
-
-
-
-
-
-
-schema CoinAddAbortsIf<CoinType> {
- amount: u64;
- let addr = type_info::type_of<CoinType>().account_address;
- let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;
- include (option::is_some(
- maybe_supply
- )) ==> optional_aggregator::AddAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount };
-}
-
-
-
-
-
-
-
-
-schema AbortsIfNotExistCoinInfo<CoinType> {
- let addr = type_info::type_of<CoinType>().account_address;
- aborts_if !exists<CoinInfo<CoinType>>(addr);
-}
-
-
-
-
### Struct `AggregatableCoin`
@@ -4215,6 +4165,64 @@ Get address by reflection.
+
+
+
+
+fun spec_is_account_registered<CoinType>(account_addr: address): bool {
+ let paired_metadata_opt = spec_paired_metadata<CoinType>();
+ exists<CoinStore<CoinType>>(account_addr) || (option::spec_is_some(
+ paired_metadata_opt
+ ) && primary_fungible_store::spec_primary_store_exists(account_addr, option::spec_borrow(paired_metadata_opt)))
+}
+
+
+
+
+
+
+
+
+schema CoinSubAbortsIf<CoinType> {
+ amount: u64;
+ let addr = type_info::type_of<CoinType>().account_address;
+ let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;
+ include (option::is_some(
+ maybe_supply
+ )) ==> optional_aggregator::SubAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount };
+}
+
+
+
+
+
+
+
+
+schema CoinAddAbortsIf<CoinType> {
+ amount: u64;
+ let addr = type_info::type_of<CoinType>().account_address;
+ let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;
+ include (option::is_some(
+ maybe_supply
+ )) ==> optional_aggregator::AddAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount };
+}
+
+
+
+
+
+
+
+
+schema AbortsIfNotExistCoinInfo<CoinType> {
+ let addr = type_info::type_of<CoinType>().account_address;
+ aborts_if !exists<CoinInfo<CoinType>>(addr);
+}
+
+
+
+
### Function `name`
@@ -4595,27 +4603,6 @@ The creator of CoinType
must be @aptos_framework
.
-Make sure name
and symbol
are legal length.
-Only the creator of CoinType
can initialize.
-
-
-
-
-
-schema InitializeInternalSchema<CoinType> {
- account: signer;
- name: vector<u8>;
- symbol: vector<u8>;
- let account_addr = signer::address_of(account);
- let coin_address = type_info::type_of<CoinType>().account_address;
- aborts_if coin_address != account_addr;
- aborts_if exists<CoinInfo<CoinType>>(account_addr);
- aborts_if len(name) > MAX_COIN_NAME_LENGTH;
- aborts_if len(symbol) > MAX_COIN_SYMBOL_LENGTH;
-}
-
-
-
diff --git a/aptos-move/framework/aptos-framework/doc/dispatchable_fungible_asset.md b/aptos-move/framework/aptos-framework/doc/dispatchable_fungible_asset.md
index b3b76f108128ca..da71484cc0c008 100644
--- a/aptos-move/framework/aptos-framework/doc/dispatchable_fungible_asset.md
+++ b/aptos-move/framework/aptos-framework/doc/dispatchable_fungible_asset.md
@@ -220,6 +220,7 @@ The semantics of deposit will be governed by the function specified in DispatchF
amount: u64,
): FungibleAsset acquires TransferRefStore {
fungible_asset::withdraw_sanity_check(owner, store, false);
+ fungible_asset::withdraw_permission_check(owner, store, amount);
let func_opt = fungible_asset::withdraw_dispatch_function(store);
if (option::is_some(&func_opt)) {
assert!(
diff --git a/aptos-move/framework/aptos-framework/doc/fungible_asset.md b/aptos-move/framework/aptos-framework/doc/fungible_asset.md
index f12ee14942b4f4..b3a42cd2297ba0 100644
--- a/aptos-move/framework/aptos-framework/doc/fungible_asset.md
+++ b/aptos-move/framework/aptos-framework/doc/fungible_asset.md
@@ -20,6 +20,7 @@ metadata object can be any object that equipped with use 0x1::function_info;
use 0x1::object;
use 0x1::option;
+use 0x1::permissioned_signer;
use 0x1::signer;
use 0x1::string;
@@ -557,6 +563,33 @@ MutateMetadataRef can be used to directly modify the fungible asset's Metadata.
+
+
+
+
+## Struct `WithdrawPermission`
+
+
+
+struct WithdrawPermission has copy, drop, store
+
+
+
+
+metadata_address: address
+const EWITHDRAW_PERMISSION_DENIED: u64 = 34;
+
+
+
+
@@ -2675,12 +2718,75 @@ Withdraw amount
of the fungible asset from store
by th
amount: u64,
): FungibleAsset acquires FungibleStore, DispatchFunctionStore, ConcurrentFungibleBalance {
withdraw_sanity_check(owner, store, true);
+ withdraw_permission_check(owner, store, amount);
withdraw_internal(object::object_address(&store), amount)
}
+
+
+
+
+## Function `withdraw_permission_check`
+
+Check the permission for withdraw operation.
+
+
+public(friend) fun withdraw_permission_check<T: key>(owner: &signer, store: object::Object<T>, amount: u64)
+
+
+
+
+public(friend) fun withdraw_permission_check<T: key>(
+ owner: &signer,
+ store: Object<T>,
+ amount: u64,
+) acquires FungibleStore {
+ assert!(permissioned_signer::check_permission(owner, amount as u256, WithdrawPermission {
+ metadata_address: object::object_address(&borrow_store_resource(&store).metadata)
+ }), error::permission_denied(EWITHDRAW_PERMISSION_DENIED));
+}
+
+
+
+
+public(friend) fun withdraw_permission_check_by_address(owner: &signer, metadata_address: address, amount: u64)
+
+
+
+
+public(friend) fun withdraw_permission_check_by_address(
+ owner: &signer,
+ metadata_address: address,
+ amount: u64,
+) {
+ assert!(permissioned_signer::check_permission(owner, amount as u256, WithdrawPermission {
+ metadata_address,
+ }), error::permission_denied(EWITHDRAW_PERMISSION_DENIED));
+}
+
+
+
+
+
+## Function `grant_permission`
+
+Permission management
+
+Master signer grant permissioned signer ability to withdraw a given amount of fungible asset.
+
+
+public fun grant_permission(master: &signer, permissioned: &signer, token_type: object::Object<fungible_asset::Metadata>, amount: u64)
+
+
+
+
+
+Implementation
+
+
+public fun grant_permission(
+ master: &signer,
+ permissioned: &signer,
+ token_type: Object<Metadata>,
+ amount: u64
+) {
+ permissioned_signer::authorize(
+ master,
+ permissioned,
+ amount as u256,
+ WithdrawPermission {
+ metadata_address: object::object_address(&token_type),
+ }
+ )
+}
+
+
+
+
+
+
+
+
+## Function `revoke_permission`
+
+Removing permissions from permissioned signer.
+
+
+public fun revoke_permission(permissioned: &signer, token_type: object::Object<fungible_asset::Metadata>)
+
+
+
+
+
+Implementation
+
+
+public fun revoke_permission(permissioned: &signer, token_type: Object<Metadata>) {
+ permissioned_signer::revoke_permission(permissioned, WithdrawPermission {
+ metadata_address: object::object_address(&token_type),
+ })
+}
+
+
+
+
diff --git a/aptos-move/framework/aptos-framework/sources/aptos_account.move b/aptos-move/framework/aptos-framework/sources/aptos_account.move
index 34addca77cf286..e13a84be4772f7 100644
--- a/aptos-move/framework/aptos-framework/sources/aptos_account.move
+++ b/aptos-move/framework/aptos-framework/sources/aptos_account.move
@@ -210,6 +210,7 @@ module aptos_framework::aptos_account {
// as APT cannot be frozen or have dispatch, and PFS cannot be transfered
// (PFS could potentially be burned. regular transfer would permanently unburn the store.
// Ignoring the check here has the equivalent of unburning, transfers, and then burning again)
+ fungible_asset::withdraw_permission_check_by_address(source, @aptos_fungible_asset, amount);
fungible_asset::deposit_internal(recipient_store, fungible_asset::withdraw_internal(sender_store, amount));
}
diff --git a/aptos-move/framework/aptos-framework/sources/coin.move b/aptos-move/framework/aptos-framework/sources/coin.move
index 91a54edb7fdddb..43c450a5caede7 100644
--- a/aptos-move/framework/aptos-framework/sources/coin.move
+++ b/aptos-move/framework/aptos-framework/sources/coin.move
@@ -13,6 +13,7 @@ module aptos_framework::coin {
use aptos_framework::event::{Self, EventHandle};
use aptos_framework::guid;
use aptos_framework::optional_aggregator::{Self, OptionalAggregator};
+ use aptos_framework::permissioned_signer;
use aptos_framework::system_addresses;
use aptos_framework::fungible_asset::{Self, FungibleAsset, Metadata, MintRef, TransferRef, BurnRef};
@@ -1168,6 +1169,13 @@ module aptos_framework::coin {
): Coin acquires CoinStore, CoinConversionMap, CoinInfo, PairedCoinType {
let account_addr = signer::address_of(account);
+ let metadata = paired_metadata();
+ if(option::is_some(&metadata)) {
+ fungible_asset::withdraw_permission_check_by_address(account, object::object_address(&option::destroy_some(metadata)), amount);
+ } else {
+ permissioned_signer::assert_master_signer(account);
+ };
+
let (coin_amount_to_withdraw, fa_amount_to_withdraw) = calculate_amount_to_withdraw(
account_addr,
amount
diff --git a/aptos-move/framework/aptos-framework/sources/dispatchable_fungible_asset.move b/aptos-move/framework/aptos-framework/sources/dispatchable_fungible_asset.move
index 5a70aff95d2c11..37c16214fd8795 100644
--- a/aptos-move/framework/aptos-framework/sources/dispatchable_fungible_asset.move
+++ b/aptos-move/framework/aptos-framework/sources/dispatchable_fungible_asset.move
@@ -77,6 +77,7 @@ module aptos_framework::dispatchable_fungible_asset {
amount: u64,
): FungibleAsset acquires TransferRefStore {
fungible_asset::withdraw_sanity_check(owner, store, false);
+ fungible_asset::withdraw_permission_check(owner, store, amount);
let func_opt = fungible_asset::withdraw_dispatch_function(store);
if (option::is_some(&func_opt)) {
assert!(