Skip to content

Commit

Permalink
add perimission checks to object
Browse files Browse the repository at this point in the history
  • Loading branch information
runtian-zhou committed Nov 26, 2024
1 parent 0d70077 commit 28c5962
Show file tree
Hide file tree
Showing 4 changed files with 356 additions and 0 deletions.
70 changes: 70 additions & 0 deletions aptos-move/framework/aptos-framework/sources/object.move
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -629,6 +639,10 @@ module aptos_framework::object {
) 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));
Expand Down Expand Up @@ -698,6 +712,18 @@ module aptos_framework::object {
obj_owner
}

public fun grant_permission<T>(
master: &signer,
permissioned_signer: &signer,
object: Object<T>,
) {
permissioned_signer::authorize_unlimited(
master,
permissioned_signer,
TransferPermission { object: object.inner }
)
}

#[test_only]
use std::option::{Self, Option};

Expand Down Expand Up @@ -1092,4 +1118,48 @@ module aptos_framework::object {
set_untransferable(&weapon_constructor_ref);
transfer_with_ref(linear_transfer_ref, @0x456);
}

#[test_only]
use aptos_framework::timestamp;

#[test(creator = @0x123)]
fun test_transfer_permission_e2e(
creator: &signer,
) acquires ObjectCore {
let aptos_framework = account::create_signer_for_test(@0x1);
timestamp::set_time_has_started_for_testing(&aptos_framework);

let (_, hero) = create_hero(creator);
let (_, weapon) = create_weapon(creator);

// Create a permissioned signer
let creator_permission_handle = permissioned_signer::create_permissioned_handle(creator);
let creator_permission_signer = permissioned_signer::signer_from_permissioned_handle(&creator_permission_handle);

// Grant aaron_permission_signer permission to transfer weapon object
grant_permission(creator, &creator_permission_signer, weapon);
transfer_to_object(&creator_permission_signer, weapon, hero);

permissioned_signer::destroy_permissioned_handle(creator_permission_handle);
}

#[test(creator = @0x123)]
#[expected_failure(abort_code = 327689, location = Self)]
fun test_transfer_no_permission(
creator: &signer,
) acquires ObjectCore {
let aptos_framework = account::create_signer_for_test(@0x1);
timestamp::set_time_has_started_for_testing(&aptos_framework);

let (_, hero) = create_hero(creator);
let (_, weapon) = create_weapon(creator);

// Create a permissioned signer
let creator_permission_handle = permissioned_signer::create_permissioned_handle(creator);
let creator_permission_signer = permissioned_signer::signer_from_permissioned_handle(&creator_permission_handle);

transfer_to_object(&creator_permission_signer, weapon, hero);

permissioned_signer::destroy_permissioned_handle(creator_permission_handle);
}
}
7 changes: 7 additions & 0 deletions aptos-move/framework/aptos-framework/sources/object.spec.move
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ spec aptos_framework::object {
pragma aborts_if_is_strict;
}

spec grant_permission {
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);
}

spec fun spec_exists_at<T: key>(object: address): bool;

spec exists_at<T: key>(object: address): bool {
Expand Down
205 changes: 205 additions & 0 deletions aptos-move/framework/aptos-token-objects/doc/aptos_token.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ The key features are:

- [Resource `AptosCollection`](#0x4_aptos_token_AptosCollection)
- [Resource `AptosToken`](#0x4_aptos_token_AptosToken)
- [Struct `TokenUpdatePermission`](#0x4_aptos_token_TokenUpdatePermission)
- [Struct `CollectionUpdatePermission`](#0x4_aptos_token_CollectionUpdatePermission)
- [Constants](#@Constants_0)
- [Function `create_collection`](#0x4_aptos_token_create_collection)
- [Function `create_collection_object`](#0x4_aptos_token_create_collection_object)
Expand Down Expand Up @@ -58,11 +60,16 @@ The key features are:
- [Function `set_collection_royalties`](#0x4_aptos_token_set_collection_royalties)
- [Function `set_collection_royalties_call`](#0x4_aptos_token_set_collection_royalties_call)
- [Function `set_collection_uri`](#0x4_aptos_token_set_collection_uri)
- [Function `authorize_token_mutation`](#0x4_aptos_token_authorize_token_mutation)
- [Function `revoke_token_mutation`](#0x4_aptos_token_revoke_token_mutation)
- [Function `authorize_collection_mutation`](#0x4_aptos_token_authorize_collection_mutation)
- [Function `revoke_collection_mutation`](#0x4_aptos_token_revoke_collection_mutation)


<pre><code><b>use</b> <a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error">0x1::error</a>;
<b>use</b> <a href="../../aptos-framework/doc/object.md#0x1_object">0x1::object</a>;
<b>use</b> <a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/option.md#0x1_option">0x1::option</a>;
<b>use</b> <a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer">0x1::permissioned_signer</a>;
<b>use</b> <a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">0x1::signer</a>;
<b>use</b> <a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/string.md#0x1_string">0x1::string</a>;
<b>use</b> <a href="collection.md#0x4_collection">0x4::collection</a>;
Expand Down Expand Up @@ -201,6 +208,60 @@ Storage state for managing the no-code Token.
</dl>


</details>

<a id="0x4_aptos_token_TokenUpdatePermission"></a>

## Struct `TokenUpdatePermission`



<pre><code><b>struct</b> <a href="aptos_token.md#0x4_aptos_token_TokenUpdatePermission">TokenUpdatePermission</a> <b>has</b> <b>copy</b>, drop, store
</code></pre>



<details>
<summary>Fields</summary>


<dl>
<dt>
<code>token_address: <b>address</b></code>
</dt>
<dd>

</dd>
</dl>


</details>

<a id="0x4_aptos_token_CollectionUpdatePermission"></a>

## Struct `CollectionUpdatePermission`



<pre><code><b>struct</b> <a href="aptos_token.md#0x4_aptos_token_CollectionUpdatePermission">CollectionUpdatePermission</a> <b>has</b> <b>copy</b>, drop, store
</code></pre>



<details>
<summary>Fields</summary>


<dl>
<dt>
<code>collection_address: <b>address</b></code>
</dt>
<dd>

</dd>
</dl>


</details>

<a id="@Constants_0"></a>
Expand Down Expand Up @@ -864,6 +925,11 @@ With an existing collection, directly mint a soul bound token into the recipient
<a href="token.md#0x4_token_creator">token::creator</a>(*<a href="token.md#0x4_token">token</a>) == <a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(creator),
<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_permission_denied">error::permission_denied</a>(<a href="aptos_token.md#0x4_aptos_token_ENOT_CREATOR">ENOT_CREATOR</a>),
);

<b>assert</b>!(
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer_check_permission_capacity_above">permissioned_signer::check_permission_capacity_above</a>(creator, 0, <a href="aptos_token.md#0x4_aptos_token_TokenUpdatePermission">TokenUpdatePermission</a> { token_address }),
<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_permission_denied">error::permission_denied</a>(<a href="aptos_token.md#0x4_aptos_token_ENOT_CREATOR">ENOT_CREATOR</a>),
);
<b>borrow_global</b>&lt;<a href="aptos_token.md#0x4_aptos_token_AptosToken">AptosToken</a>&gt;(token_address)
}
</code></pre>
Expand Down Expand Up @@ -1561,6 +1627,11 @@ With an existing collection, directly mint a soul bound token into the recipient
<a href="collection.md#0x4_collection_creator">collection::creator</a>(*<a href="collection.md#0x4_collection">collection</a>) == <a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(creator),
<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_permission_denied">error::permission_denied</a>(<a href="aptos_token.md#0x4_aptos_token_ENOT_CREATOR">ENOT_CREATOR</a>),
);

<b>assert</b>!(
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer_check_permission_capacity_above">permissioned_signer::check_permission_capacity_above</a>(creator, 0, <a href="aptos_token.md#0x4_aptos_token_CollectionUpdatePermission">CollectionUpdatePermission</a> { collection_address }),
<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_permission_denied">error::permission_denied</a>(<a href="aptos_token.md#0x4_aptos_token_ENOT_CREATOR">ENOT_CREATOR</a>),
);
<b>borrow_global</b>&lt;<a href="aptos_token.md#0x4_aptos_token_AptosCollection">AptosCollection</a>&gt;(collection_address)
}
</code></pre>
Expand Down Expand Up @@ -1697,6 +1768,140 @@ With an existing collection, directly mint a soul bound token into the recipient



</details>

<a id="0x4_aptos_token_authorize_token_mutation"></a>

## Function `authorize_token_mutation`



<pre><code><b>public</b> <b>fun</b> <a href="aptos_token.md#0x4_aptos_token_authorize_token_mutation">authorize_token_mutation</a>&lt;T: key&gt;(creator: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, permissioned_creator: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, <a href="token.md#0x4_token">token</a>: <a href="../../aptos-framework/doc/object.md#0x1_object_Object">object::Object</a>&lt;T&gt;)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="aptos_token.md#0x4_aptos_token_authorize_token_mutation">authorize_token_mutation</a>&lt;T: key&gt;(
creator: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>,
permissioned_creator: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>,
<a href="token.md#0x4_token">token</a>: Object&lt;T&gt;,
) {
<b>let</b> token_address = <a href="../../aptos-framework/doc/object.md#0x1_object_object_address">object::object_address</a>(&<a href="token.md#0x4_token">token</a>);
<b>assert</b>!(
<b>exists</b>&lt;<a href="aptos_token.md#0x4_aptos_token_AptosToken">AptosToken</a>&gt;(token_address),
<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_not_found">error::not_found</a>(<a href="aptos_token.md#0x4_aptos_token_ETOKEN_DOES_NOT_EXIST">ETOKEN_DOES_NOT_EXIST</a>),
);
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer_authorize_unlimited">permissioned_signer::authorize_unlimited</a>(
creator,
permissioned_creator,
<a href="aptos_token.md#0x4_aptos_token_TokenUpdatePermission">TokenUpdatePermission</a> { token_address },
)
}
</code></pre>



</details>

<a id="0x4_aptos_token_revoke_token_mutation"></a>

## Function `revoke_token_mutation`



<pre><code><b>public</b> <b>fun</b> <a href="aptos_token.md#0x4_aptos_token_revoke_token_mutation">revoke_token_mutation</a>&lt;T: key&gt;(<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer">permissioned_signer</a>: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, <a href="token.md#0x4_token">token</a>: <a href="../../aptos-framework/doc/object.md#0x1_object_Object">object::Object</a>&lt;T&gt;)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="aptos_token.md#0x4_aptos_token_revoke_token_mutation">revoke_token_mutation</a>&lt;T: key&gt;(
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer">permissioned_signer</a>: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>,
<a href="token.md#0x4_token">token</a>: Object&lt;T&gt;,
) {
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer_revoke_permission">permissioned_signer::revoke_permission</a>(
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer">permissioned_signer</a>,
<a href="aptos_token.md#0x4_aptos_token_TokenUpdatePermission">TokenUpdatePermission</a> { token_address: <a href="../../aptos-framework/doc/object.md#0x1_object_object_address">object::object_address</a>(&<a href="token.md#0x4_token">token</a>) },
)
}
</code></pre>



</details>

<a id="0x4_aptos_token_authorize_collection_mutation"></a>

## Function `authorize_collection_mutation`



<pre><code><b>public</b> <b>fun</b> <a href="aptos_token.md#0x4_aptos_token_authorize_collection_mutation">authorize_collection_mutation</a>&lt;T: key&gt;(creator: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, <a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer">permissioned_signer</a>: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, <a href="collection.md#0x4_collection">collection</a>: <a href="../../aptos-framework/doc/object.md#0x1_object_Object">object::Object</a>&lt;T&gt;)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="aptos_token.md#0x4_aptos_token_authorize_collection_mutation">authorize_collection_mutation</a>&lt;T: key&gt;(
creator: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>,
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer">permissioned_signer</a>: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>,
<a href="collection.md#0x4_collection">collection</a>: Object&lt;T&gt;,
) {
<b>let</b> collection_address = <a href="../../aptos-framework/doc/object.md#0x1_object_object_address">object::object_address</a>(&<a href="collection.md#0x4_collection">collection</a>);
<b>assert</b>!(
<b>exists</b>&lt;<a href="aptos_token.md#0x4_aptos_token_AptosCollection">AptosCollection</a>&gt;(collection_address),
<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_not_found">error::not_found</a>(<a href="aptos_token.md#0x4_aptos_token_ETOKEN_DOES_NOT_EXIST">ETOKEN_DOES_NOT_EXIST</a>),
);
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer_authorize_unlimited">permissioned_signer::authorize_unlimited</a>(
creator,
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer">permissioned_signer</a>,
<a href="aptos_token.md#0x4_aptos_token_CollectionUpdatePermission">CollectionUpdatePermission</a> { collection_address },
)
}
</code></pre>



</details>

<a id="0x4_aptos_token_revoke_collection_mutation"></a>

## Function `revoke_collection_mutation`



<pre><code><b>public</b> <b>fun</b> <a href="aptos_token.md#0x4_aptos_token_revoke_collection_mutation">revoke_collection_mutation</a>&lt;T: key&gt;(<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer">permissioned_signer</a>: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, <a href="collection.md#0x4_collection">collection</a>: <a href="../../aptos-framework/doc/object.md#0x1_object_Object">object::Object</a>&lt;T&gt;)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="aptos_token.md#0x4_aptos_token_revoke_collection_mutation">revoke_collection_mutation</a>&lt;T: key&gt;(
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer">permissioned_signer</a>: &<a href="../../aptos-framework/../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>,
<a href="collection.md#0x4_collection">collection</a>: Object&lt;T&gt;,
) {
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer_revoke_permission">permissioned_signer::revoke_permission</a>(
<a href="../../aptos-framework/doc/permissioned_signer.md#0x1_permissioned_signer">permissioned_signer</a>,
<a href="aptos_token.md#0x4_aptos_token_CollectionUpdatePermission">CollectionUpdatePermission</a> { collection_address: <a href="../../aptos-framework/doc/object.md#0x1_object_object_address">object::object_address</a>(&<a href="collection.md#0x4_collection">collection</a>) },
)
}
</code></pre>



</details>


Expand Down
Loading

0 comments on commit 28c5962

Please sign in to comment.