diff --git a/aptos-move/framework/aptos-framework/doc/object.md b/aptos-move/framework/aptos-framework/doc/object.md index cb633a173bf6c..16c4694e99897 100644 --- a/aptos-move/framework/aptos-framework/doc/object.md +++ b/aptos-move/framework/aptos-framework/doc/object.md @@ -32,6 +32,7 @@ make it so that a reference to a global object can be returned from a function. - [Struct `TransferRef`](#0x1_object_TransferRef) - [Struct `LinearTransferRef`](#0x1_object_LinearTransferRef) - [Struct `DeriveRef`](#0x1_object_DeriveRef) +- [Struct `TransferPermission`](#0x1_object_TransferPermission) - [Struct `TransferEvent`](#0x1_object_TransferEvent) - [Struct `Transfer`](#0x1_object_Transfer) - [Constants](#@Constants_0) @@ -89,6 +90,7 @@ make it so that a reference to a global object can be returned from a function. - [Function `is_owner`](#0x1_object_is_owner) - [Function `owns`](#0x1_object_owns) - [Function `root_owner`](#0x1_object_root_owner) +- [Function `grant_permission`](#0x1_object_grant_permission) - [Specification](#@Specification_1) - [High-level Requirements](#high-level-req) - [Module-level Specification](#module-level-spec) @@ -133,6 +135,7 @@ make it so that a reference to a global object can be returned from a function. - [Function `is_owner`](#@Specification_1_is_owner) - [Function `owns`](#@Specification_1_owns) - [Function `root_owner`](#@Specification_1_root_owner) + - [Function `grant_permission`](#@Specification_1_grant_permission)
use 0x1::account;
@@ -144,6 +147,7 @@ make it so that a reference to a global object can be returned from a function.
use 0x1::from_bcs;
use 0x1::guid;
use 0x1::hash;
+use 0x1::permissioned_signer;
use 0x1::signer;
use 0x1::transaction_context;
use 0x1::vector;
@@ -496,6 +500,34 @@ Used to create derived objects from a given objects.
+
+
+
+
+## Struct `TransferPermission`
+
+Permission to transfer object with permissioned signer.
+
+
+struct TransferPermission has copy, drop, store
+
+
+
+
+
+Fields
+
+
+
+-
+
object: address
+
+-
+
+
+
+
+
@@ -1999,6 +2031,10 @@ hierarchy.
to: address,
) acquires ObjectCore {
let owner_address = signer::address_of(owner);
+ assert!(
+ permissioned_signer::check_permission_exists(owner, TransferPermission { object }),
+ error::permission_denied(EOBJECT_NOT_TRANSFERRABLE)
+ );
verify_ungated_and_descendant(owner_address, object);
transfer_raw_inner(object, to);
}
@@ -2188,6 +2224,10 @@ Allow origin owners to reclaim any objects they previous burnt.
) acquires TombStone, ObjectCore {
let object_addr = object.inner;
assert!(exists<TombStone>(object_addr), error::invalid_argument(EOBJECT_NOT_BURNT));
+ assert!(
+ permissioned_signer::check_permission_exists(original_owner, TransferPermission { object: object_addr }),
+ error::permission_denied(EOBJECT_NOT_TRANSFERRABLE)
+ );
let TombStone { original_owner: original_owner_addr } = move_from<TombStone>(object_addr);
assert!(original_owner_addr == signer::address_of(original_owner), error::permission_denied(ENOT_OBJECT_OWNER));
@@ -2360,6 +2400,38 @@ to determine the identity of the starting point of ownership.
+
+
+
+
+## Function `grant_permission`
+
+
+
+public fun grant_permission<T>(master: &signer, permissioned_signer: &signer, object: object::Object<T>)
+
+
+
+
+
+Implementation
+
+
+public fun grant_permission<T>(
+ master: &signer,
+ permissioned_signer: &signer,
+ object: Object<T>,
+) {
+ permissioned_signer::authorize_unlimited(
+ master,
+ permissioned_signer,
+ TransferPermission { object: object.inner }
+ )
+}
+
+
+
+
@@ -2441,15 +2513,6 @@ to determine the identity of the starting point of ownership.
-
-
-
-
-fun spec_exists_at<T: key>(object: address): bool;
-
-
-
-
### Function `address_to_object`
@@ -3401,4 +3464,32 @@ to determine the identity of the starting point of ownership.
+
+
+
+### Function `grant_permission`
+
+
+public fun grant_permission<T>(master: &signer, permissioned_signer: &signer, object: object::Object<T>)
+
+
+
+
+
+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);
+
+
+
+
+
+
+
+
+fun spec_exists_at<T: key>(object: address): bool;
+
+
+
[move-book]: https://aptos.dev/move/book/SUMMARY
diff --git a/aptos-move/framework/aptos-framework/sources/object.move b/aptos-move/framework/aptos-framework/sources/object.move
index abca67bb2451a..c05b9414ad8cc 100644
--- a/aptos-move/framework/aptos-framework/sources/object.move
+++ b/aptos-move/framework/aptos-framework/sources/object.move
@@ -28,6 +28,7 @@ module aptos_framework::object {
use aptos_framework::create_signer::create_signer;
use aptos_framework::event;
use aptos_framework::guid;
+ use aptos_framework::permissioned_signer;
friend aptos_framework::coin;
friend aptos_framework::primary_fungible_store;
@@ -165,6 +166,11 @@ module aptos_framework::object {
self: address,
}
+ /// Permission to transfer object with permissioned signer.
+ struct TransferPermission has copy, drop, store {
+ object: address,
+ }
+
/// Emitted whenever the object's owner field is changed.
struct TransferEvent has drop, store {
object: address,
@@ -540,6 +546,10 @@ module aptos_framework::object {
to: address,
) acquires ObjectCore {
let owner_address = signer::address_of(owner);
+ assert!(
+ permissioned_signer::check_permission_exists(owner, TransferPermission { object }),
+ error::permission_denied(EOBJECT_NOT_TRANSFERRABLE)
+ );
verify_ungated_and_descendant(owner_address, object);
transfer_raw_inner(object, to);
}
@@ -629,6 +639,10 @@ module aptos_framework::object {
) acquires TombStone, ObjectCore {
let object_addr = object.inner;
assert!(existsuse 0x1::error;
use 0x1::object;
use 0x1::option;
+use 0x1::permissioned_signer;
use 0x1::signer;
use 0x1::string;
use 0x4::collection;
@@ -201,6 +208,60 @@ Storage state for managing the no-code Token.
+
+
+
+
+## Struct `TokenUpdatePermission`
+
+
+
+struct TokenUpdatePermission has copy, drop, store
+
+
+
+
+
+Fields
+
+
+
+-
+
token_address: address
+
+-
+
+
+
+
+
+
+
+
+
+## Struct `CollectionUpdatePermission`
+
+
+
+struct CollectionUpdatePermission has copy, drop, store
+
+
+
+
+
+Fields
+
+
+
+-
+
collection_address: address
+
+-
+
+
+
+
+
@@ -864,6 +925,11 @@ With an existing collection, directly mint a soul bound token into the recipient
token::creator(*token) == signer::address_of(creator),
error::permission_denied(ENOT_CREATOR),
);
+
+ assert!(
+ permissioned_signer::check_permission_capacity_above(creator, 0, TokenUpdatePermission { token_address }),
+ error::permission_denied(ENOT_CREATOR),
+ );
borrow_global<AptosToken>(token_address)
}
@@ -1561,6 +1627,11 @@ With an existing collection, directly mint a soul bound token into the recipient
collection::creator(*collection) == signer::address_of(creator),
error::permission_denied(ENOT_CREATOR),
);
+
+ assert!(
+ permissioned_signer::check_permission_capacity_above(creator, 0, CollectionUpdatePermission { collection_address }),
+ error::permission_denied(ENOT_CREATOR),
+ );
borrow_global<AptosCollection>(collection_address)
}
@@ -1697,6 +1768,140 @@ With an existing collection, directly mint a soul bound token into the recipient
+
+
+
+
+## Function `authorize_token_mutation`
+
+
+
+public fun authorize_token_mutation<T: key>(creator: &signer, permissioned_creator: &signer, token: object::Object<T>)
+
+
+
+
+public fun authorize_token_mutation<T: key>(
+ creator: &signer,
+ permissioned_creator: &signer,
+ token: Object<T>,
+) {
+ let token_address = object::object_address(&token);
+ assert!(
+ exists<AptosToken>(token_address),
+ error::not_found(ETOKEN_DOES_NOT_EXIST),
+ );
+ permissioned_signer::authorize_unlimited(
+ creator,
+ permissioned_creator,
+ TokenUpdatePermission { token_address },
+ )
+}
+
+
+
+
+public fun revoke_token_mutation<T: key>(permissioned_signer: &signer, token: object::Object<T>)
+
+
+
+
+public fun revoke_token_mutation<T: key>(
+ permissioned_signer: &signer,
+ token: Object<T>,
+) {
+ permissioned_signer::revoke_permission(
+ permissioned_signer,
+ TokenUpdatePermission { token_address: object::object_address(&token) },
+ )
+}
+
+
+
+
+public fun authorize_collection_mutation<T: key>(creator: &signer, permissioned_signer: &signer, collection: object::Object<T>)
+
+
+
+
+public fun authorize_collection_mutation<T: key>(
+ creator: &signer,
+ permissioned_signer: &signer,
+ collection: Object<T>,
+) {
+ let collection_address = object::object_address(&collection);
+ assert!(
+ exists<AptosCollection>(collection_address),
+ error::not_found(ETOKEN_DOES_NOT_EXIST),
+ );
+ permissioned_signer::authorize_unlimited(
+ creator,
+ permissioned_signer,
+ CollectionUpdatePermission { collection_address },
+ )
+}
+
+
+
+
+public fun revoke_collection_mutation<T: key>(permissioned_signer: &signer, collection: object::Object<T>)
+
+
+
+
+public fun revoke_collection_mutation<T: key>(
+ permissioned_signer: &signer,
+ collection: Object<T>,
+) {
+ permissioned_signer::revoke_permission(
+ permissioned_signer,
+ CollectionUpdatePermission { collection_address: object::object_address(&collection) },
+ )
+}
+
+
+
+