diff --git a/aptos-move/framework/aptos-framework/doc/managed_coin.md b/aptos-move/framework/aptos-framework/doc/managed_coin.md
index 8ae37e71a1f9c..50c2383fd111d 100644
--- a/aptos-move/framework/aptos-framework/doc/managed_coin.md
+++ b/aptos-move/framework/aptos-framework/doc/managed_coin.md
@@ -14,6 +14,8 @@ By utilizing this current module, a developer can create his own coin and care l
- [Function `initialize`](#0x1_managed_coin_initialize)
- [Function `mint`](#0x1_managed_coin_mint)
- [Function `register`](#0x1_managed_coin_register)
+- [Function `destroy_caps`](#0x1_managed_coin_destroy_caps)
+- [Function `remove_caps`](#0x1_managed_coin_remove_caps)
- [Specification](#@Specification_1)
- [High-level Requirements](#high-level-req)
- [Module-level Specification](#module-level-spec)
@@ -21,6 +23,8 @@ By utilizing this current module, a developer can create his own coin and care l
- [Function `initialize`](#@Specification_1_initialize)
- [Function `mint`](#@Specification_1_mint)
- [Function `register`](#@Specification_1_register)
+ - [Function `destroy_caps`](#@Specification_1_destroy_caps)
+ - [Function `remove_caps`](#@Specification_1_remove_caps)
use 0x1::coin;
@@ -231,6 +235,72 @@ Required if user wants to start accepting deposits of CoinType
in h
+
+
+
+
+## Function `destroy_caps`
+
+Destroys capabilities from the account, so that the user no longer has access to mint or burn.
+
+
+public entry fun destroy_caps<CoinType>(account: &signer)
+
+
+
+
+
+Implementation
+
+
+public entry fun destroy_caps<CoinType>(account: &signer) acquires Capabilities {
+ let (burn_cap, freeze_cap, mint_cap) = remove_caps<CoinType>(account);
+ destroy_burn_cap(burn_cap);
+ destroy_freeze_cap(freeze_cap);
+ destroy_mint_cap(mint_cap);
+}
+
+
+
+
+
+
+
+
+## Function `remove_caps`
+
+Removes capabilities from the account to be stored or destroyed elsewhere
+
+
+public fun remove_caps<CoinType>(account: &signer): (coin::BurnCapability<CoinType>, coin::FreezeCapability<CoinType>, coin::MintCapability<CoinType>)
+
+
+
+
+
+Implementation
+
+
+public fun remove_caps<CoinType>(
+ account: &signer
+): (BurnCapability<CoinType>, FreezeCapability<CoinType>, MintCapability<CoinType>) acquires Capabilities {
+ let account_addr = signer::address_of(account);
+ assert!(
+ exists<Capabilities<CoinType>>(account_addr),
+ error::not_found(ENO_CAPABILITIES),
+ );
+
+ let Capabilities<CoinType> {
+ burn_cap,
+ freeze_cap,
+ mint_cap,
+ } = move_from<Capabilities<CoinType>>(account_addr);
+ (burn_cap, freeze_cap, mint_cap)
+}
+
+
+
+
@@ -423,4 +493,40 @@ Updating Account.guid_creation_num
will not overflow.
+
+
+
+### Function `destroy_caps`
+
+
+public entry fun destroy_caps<CoinType>(account: &signer)
+
+
+
+
+
+let account_addr = signer::address_of(account);
+aborts_if !exists<Capabilities<CoinType>>(account_addr);
+ensures !exists<Capabilities<CoinType>>(account_addr);
+
+
+
+
+
+
+### Function `remove_caps`
+
+
+public fun remove_caps<CoinType>(account: &signer): (coin::BurnCapability<CoinType>, coin::FreezeCapability<CoinType>, coin::MintCapability<CoinType>)
+
+
+
+
+
+let account_addr = signer::address_of(account);
+aborts_if !exists<Capabilities<CoinType>>(account_addr);
+ensures !exists<Capabilities<CoinType>>(account_addr);
+
+
+
[move-book]: https://aptos.dev/move/book/SUMMARY
diff --git a/aptos-move/framework/aptos-framework/sources/managed_coin.move b/aptos-move/framework/aptos-framework/sources/managed_coin.move
index d2932ddb4edd7..a5da4b24ad5c9 100644
--- a/aptos-move/framework/aptos-framework/sources/managed_coin.move
+++ b/aptos-move/framework/aptos-framework/sources/managed_coin.move
@@ -6,7 +6,9 @@ module aptos_framework::managed_coin {
use std::error;
use std::signer;
- use aptos_framework::coin::{Self, BurnCapability, FreezeCapability, MintCapability};
+ use aptos_framework::coin::{Self, BurnCapability, FreezeCapability, MintCapability, destroy_burn_cap,
+ destroy_freeze_cap, destroy_mint_cap
+ };
//
// Errors
@@ -97,6 +99,32 @@ module aptos_framework::managed_coin {
coin::register(account);
}
+ /// Destroys capabilities from the account, so that the user no longer has access to mint or burn.
+ public entry fun destroy_caps(account: &signer) acquires Capabilities {
+ let (burn_cap, freeze_cap, mint_cap) = remove_caps(account);
+ destroy_burn_cap(burn_cap);
+ destroy_freeze_cap(freeze_cap);
+ destroy_mint_cap(mint_cap);
+ }
+
+ /// Removes capabilities from the account to be stored or destroyed elsewhere
+ public fun remove_caps(
+ account: &signer
+ ): (BurnCapability, FreezeCapability, MintCapability) acquires Capabilities {
+ let account_addr = signer::address_of(account);
+ assert!(
+ exists>(account_addr),
+ error::not_found(ENO_CAPABILITIES),
+ );
+
+ let Capabilities {
+ burn_cap,
+ freeze_cap,
+ mint_cap,
+ } = move_from>(account_addr);
+ (burn_cap, freeze_cap, mint_cap)
+ }
+
//
// Tests
//
@@ -156,6 +184,40 @@ module aptos_framework::managed_coin {
let new_supply = coin::supply();
assert!(option::extract(&mut new_supply) == 20, 2);
+
+ // Destroy mint capabilities
+ destroy_caps(&mod_account);
+ assert!(!exists>(signer::address_of(&mod_account)), 3);
+ }
+
+ #[test(source = @0xa11ce, destination = @0xb0b, mod_account = @0x1)]
+ public entry fun test_end_to_end_caps_removal(
+ source: signer,
+ destination: signer,
+ mod_account: signer
+ ) acquires Capabilities {
+ let source_addr = signer::address_of(&source);
+ let destination_addr = signer::address_of(&destination);
+ aptos_framework::account::create_account_for_test(source_addr);
+ aptos_framework::account::create_account_for_test(destination_addr);
+ aptos_framework::account::create_account_for_test(signer::address_of(&mod_account));
+ aggregator_factory::initialize_aggregator_factory_for_test(&mod_account);
+
+ initialize(
+ &mod_account,
+ b"Fake Money",
+ b"FMD",
+ 10,
+ true
+ );
+ assert!(coin::is_coin_initialized(), 0);
+
+ // Remove capabilities
+ let (burn_cap, freeze_cap, mint_cap) = remove_caps(&mod_account);
+ assert!(!exists>(signer::address_of(&mod_account)), 3);
+ coin::destroy_mint_cap(mint_cap);
+ coin::destroy_freeze_cap(freeze_cap);
+ coin::destroy_burn_cap(burn_cap);
}
#[test(source = @0xa11ce, destination = @0xb0b, mod_account = @0x1)]
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 e6eafd0904c11..344c9744f7c97 100644
--- a/aptos-move/framework/aptos-framework/sources/managed_coin.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/managed_coin.spec.move
@@ -147,4 +147,16 @@ spec aptos_framework::managed_coin {
aborts_if !exists>(account_addr) && !type_info::spec_is_struct();
ensures exists>(account_addr);
}
+
+ spec remove_caps(account: &signer): (BurnCapability, FreezeCapability, MintCapability) {
+ let account_addr = signer::address_of(account);
+ aborts_if !exists>(account_addr);
+ ensures !exists>(account_addr);
+ }
+
+ spec destroy_caps (account: &signer) {
+ let account_addr = signer::address_of(account);
+ aborts_if !exists>(account_addr);
+ ensures !exists>(account_addr);
+ }
}
diff --git a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
index aa41aa6ea1fd3..3fa25198f4e99 100644
--- a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
+++ b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
@@ -510,6 +510,11 @@ pub enum EntryFunctionCall {
amount: u64,
},
+ /// Destroys capabilities from the account, so that the user no longer has access to mint or burn.
+ ManagedCoinDestroyCaps {
+ coin_type: TypeTag,
+ },
+
/// Initialize new coin `CoinType` in Aptos Blockchain.
/// Mint and Burn Capabilities will be stored under `account` in `Capabilities` resource.
ManagedCoinInitialize {
@@ -1341,6 +1346,7 @@ impl EntryFunctionCall {
n_vec,
} => jwks_update_federated_jwk_set(iss, kid_vec, alg_vec, e_vec, n_vec),
ManagedCoinBurn { coin_type, amount } => managed_coin_burn(coin_type, amount),
+ ManagedCoinDestroyCaps { coin_type } => managed_coin_destroy_caps(coin_type),
ManagedCoinInitialize {
coin_type,
name,
@@ -2983,6 +2989,22 @@ pub fn managed_coin_burn(coin_type: TypeTag, amount: u64) -> TransactionPayload
))
}
+/// Destroys capabilities from the account, so that the user no longer has access to mint or burn.
+pub fn managed_coin_destroy_caps(coin_type: TypeTag) -> TransactionPayload {
+ TransactionPayload::EntryFunction(EntryFunction::new(
+ ModuleId::new(
+ AccountAddress::new([
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1,
+ ]),
+ ident_str!("managed_coin").to_owned(),
+ ),
+ ident_str!("destroy_caps").to_owned(),
+ vec![coin_type],
+ vec![],
+ ))
+}
+
/// Initialize new coin `CoinType` in Aptos Blockchain.
/// Mint and Burn Capabilities will be stored under `account` in `Capabilities` resource.
pub fn managed_coin_initialize(
@@ -5498,6 +5520,16 @@ mod decoder {
}
}
+ pub fn managed_coin_destroy_caps(payload: &TransactionPayload) -> Option {
+ if let TransactionPayload::EntryFunction(script) = payload {
+ Some(EntryFunctionCall::ManagedCoinDestroyCaps {
+ coin_type: script.ty_args().get(0)?.clone(),
+ })
+ } else {
+ None
+ }
+ }
+
pub fn managed_coin_initialize(payload: &TransactionPayload) -> Option {
if let TransactionPayload::EntryFunction(script) = payload {
Some(EntryFunctionCall::ManagedCoinInitialize {
@@ -6801,6 +6833,10 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy